如何从 .NET 程序集中读取数组初始值设定项
How to read array initializer values from .NET assembly
如何从包含此代码的 assembly 中读取值,比方说:'99'?
using Sytem;
public class Class1
{
public Class1() {
// array initializer, want to read '99', '100'... from assembly
var a = new double[,] { { 1, 2, 3 }, { 99, 100, 101 } };
// ...
}
}
到目前为止我做了什么
ILDASM中的方法:
.method /*06000001*/ public hidebysig specialname rtspecialname
instance void .ctor() cil managed
// SIG: 20 00 01
{
// Method begins at RVA 0x2080
// Code size 29 (0x1d)
.maxstack 3
.locals /*11000001*/ init ([0] float64[0...,0...] a)
.language '{3F5162F8-07C6-11D3-9053-00C04FA302A1}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}'
// Source File 'c:\Users\heini19\Documents\Visual Studio 2013\Projects\WcfService1\ClassLibrary1\Class1.cs'
//000005: public Class1() {
IL_0000: /* 02 | */ ldarg.0
IL_0001: /* 28 | (0A)000011 */ call instance void [mscorlib/*23000001*/]System.Object/*01000001*/::.ctor() /* 0A000011 */
IL_0006: /* 00 | */ nop
IL_0007: /* 00 | */ nop
//000006: // array initializer, want to read '99', '100' etc.
//000007: var a = new double[,] { { 1, 2, 3 }, { 99, 100, 101 } };
IL_0008: /* 18 | */ ldc.i4.2
IL_0009: /* 19 | */ ldc.i4.3
IL_000a: /* 73 | (0A)000012 */ newobj instance void float64[0...,0...]/*1B000001*/::.ctor(int32,
int32) /* 0A000012 */
IL_000f: /* 25 | */ dup
IL_0010: /* D0 | (04)000001 */ ldtoken field valuetype '<PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}'/*02000003*//'__StaticArrayInitTypeSize=48'/*02000004*/ '<PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}'/*02000003*/::'$$method0x6000001-1' /* 04000001 */
IL_0015: /* 28 | (0A)000014 */ call void [mscorlib/*23000001*/]System.Runtime.CompilerServices.RuntimeHelpers/*01000015*/::InitializeArray(class [mscorlib/*23000001*/]System.Array/*01000016*/,
valuetype [mscorlib/*23000001*/]System.RuntimeFieldHandle/*01000017*/) /* 0A000014 */
IL_001a: /* 0A | */ stloc.0
//000008: // ...
//000009: }
IL_001b: /* 00 | */ nop
IL_001c: /* 2A | */ ret
} // end of method Class1::.ctor
编译器创建了结构 <PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}
,字段 $$method0x6000001-1
作为初始化值,并使用 RuntimeHelpers.InitializeArray
以便在运行时初始化新数组。 C# 中定义的原始值似乎存储在字段中并通过使用字段句柄进行复制?但是这些值是如何设置的呢?
一定有一些 better/easier 方法可以从程序集中读取这些常量?
无反应
您尝试做的事情几乎不可能完成(请注意,您示例中的单个案例可能是可行的,但可能无法满足您的全部需求)
<PrivateImplementationDetails>
仅在某些情况下由 C# 编译器创建(似乎是超过一定大小的数字数组)。对于所有其他情况,构造函数中的直接初始化已完成。有关示例,请参阅 http://goo.gl/iC6MRv。
请注意,您看到的 IL 代码不是 "written in the stone"...没有规则指示 C# 编译器应如何创建数组初始值设定项。例如 Roslyn(我给出的 link 是由 Roslyn 生成的)使用 PrivateImplementationDetails
而不是 <PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}
。谁知道 Mono 编译器生成了什么代码。
在大多数情况下,如果不执行构造函数(因此实例化 class)并查看获得的对象,就不可能知道已初始化数组的值。但这显然还有其他问题(class 的初始化可能有副作用,或者可能需要参数)
如何从包含此代码的 assembly 中读取值,比方说:'99'?
using Sytem;
public class Class1
{
public Class1() {
// array initializer, want to read '99', '100'... from assembly
var a = new double[,] { { 1, 2, 3 }, { 99, 100, 101 } };
// ...
}
}
到目前为止我做了什么
ILDASM中的方法:
.method /*06000001*/ public hidebysig specialname rtspecialname
instance void .ctor() cil managed
// SIG: 20 00 01
{
// Method begins at RVA 0x2080
// Code size 29 (0x1d)
.maxstack 3
.locals /*11000001*/ init ([0] float64[0...,0...] a)
.language '{3F5162F8-07C6-11D3-9053-00C04FA302A1}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}'
// Source File 'c:\Users\heini19\Documents\Visual Studio 2013\Projects\WcfService1\ClassLibrary1\Class1.cs'
//000005: public Class1() {
IL_0000: /* 02 | */ ldarg.0
IL_0001: /* 28 | (0A)000011 */ call instance void [mscorlib/*23000001*/]System.Object/*01000001*/::.ctor() /* 0A000011 */
IL_0006: /* 00 | */ nop
IL_0007: /* 00 | */ nop
//000006: // array initializer, want to read '99', '100' etc.
//000007: var a = new double[,] { { 1, 2, 3 }, { 99, 100, 101 } };
IL_0008: /* 18 | */ ldc.i4.2
IL_0009: /* 19 | */ ldc.i4.3
IL_000a: /* 73 | (0A)000012 */ newobj instance void float64[0...,0...]/*1B000001*/::.ctor(int32,
int32) /* 0A000012 */
IL_000f: /* 25 | */ dup
IL_0010: /* D0 | (04)000001 */ ldtoken field valuetype '<PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}'/*02000003*//'__StaticArrayInitTypeSize=48'/*02000004*/ '<PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}'/*02000003*/::'$$method0x6000001-1' /* 04000001 */
IL_0015: /* 28 | (0A)000014 */ call void [mscorlib/*23000001*/]System.Runtime.CompilerServices.RuntimeHelpers/*01000015*/::InitializeArray(class [mscorlib/*23000001*/]System.Array/*01000016*/,
valuetype [mscorlib/*23000001*/]System.RuntimeFieldHandle/*01000017*/) /* 0A000014 */
IL_001a: /* 0A | */ stloc.0
//000008: // ...
//000009: }
IL_001b: /* 00 | */ nop
IL_001c: /* 2A | */ ret
} // end of method Class1::.ctor
编译器创建了结构 <PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}
,字段 $$method0x6000001-1
作为初始化值,并使用 RuntimeHelpers.InitializeArray
以便在运行时初始化新数组。 C# 中定义的原始值似乎存储在字段中并通过使用字段句柄进行复制?但是这些值是如何设置的呢?
一定有一些 better/easier 方法可以从程序集中读取这些常量?
无反应
您尝试做的事情几乎不可能完成(请注意,您示例中的单个案例可能是可行的,但可能无法满足您的全部需求)
<PrivateImplementationDetails>
仅在某些情况下由 C# 编译器创建(似乎是超过一定大小的数字数组)。对于所有其他情况,构造函数中的直接初始化已完成。有关示例,请参阅 http://goo.gl/iC6MRv。
请注意,您看到的 IL 代码不是 "written in the stone"...没有规则指示 C# 编译器应如何创建数组初始值设定项。例如 Roslyn(我给出的 link 是由 Roslyn 生成的)使用 PrivateImplementationDetails
而不是 <PrivateImplementationDetails>{975506E6-7C24-4C2B-8956-C1B9CF8B80C4}
。谁知道 Mono 编译器生成了什么代码。
在大多数情况下,如果不执行构造函数(因此实例化 class)并查看获得的对象,就不可能知道已初始化数组的值。但这显然还有其他问题(class 的初始化可能有副作用,或者可能需要参数)