I have written a compiler that generates IL using System.Reflection.Emit. This works fine for code but I don't know how to emit large initialised tables that I also need to include. The whole point of the compiler is to generate those tables, and it's not possible to calculate the initialisers at runtime.

I tried to store the initialisation data in strings loaded using Ldstr but it turns out there is a hard limit on how long in total those strings can get.

I also tried to emit code that allocates an array then assigns the initialisers (a[0]=const0; a[1]=const1; a[2]=const2, ...). This works but seems to slow down the execution a lot even though it's only done once at initialisation. I am guessing that the JIT compiler does not much like lots of linear code.

I suppose I could try including the initialisers as a resource file though I imagine that parsing it won't be all that fast. Ideally, I would like to use some method that lets me store everything in one dll.

What is the "usual" way for initialising a large amount of data in .net please?

有帮助吗?

解决方案

Take a look at how C# initializes static arrays of value-types. (This might only work with valuetypes). IT creates a class in the - namespace where <module> is located, called <PrivateImplementationDetails>{GUID_OF_YOUR_ASSEMBLY}

In this class it creates a struct to initialize the array using the attribute:

[StructLayout(LayoutKind.Explicit, Size=SIZE_OF_ARRAY_IN_BYTES, Pack=1)]
private struct __StaticArrayInitTypeSize=SIZE_OF_ARRAY_IN_BYTES
{
}

Where SIZE_OF_ARRAY_IN_BYTES is the number of bytes for the element times the length of the array. (e.g. int[] foo={0,1,2,3,4,5,6,7,8,9} will be Size=40)

in the assembly it assigns the binary representation of the array to a internal static readonly field in <PrivateImplementationDetails>.

Finally, it loads a runtimefield handle to the field holding the arrays body, and calls the method System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray

Unfortunately, the documentation on this method is awful. It looks like you pass it the array and then pass it the handle to a field. The IL for my example static initializer looks like this, hope this helps::

.method private hidebysig specialname rtspecialname static void .cctor() cil managed
{
    .maxstack 8
    L_0000: ldc.i4.s 0x15
    L_0002: newarr int32
    L_0007: dup 
    L_0008: ldtoken valuetype <PrivateImplementationDetails>{D28836D0-542D-4735-8815-954F79B1D29C}/__StaticArrayInitTypeSize=84 <PrivateImplementationDetails>{D28836D0-542D-4735-8815-954F79B1D29C}::$$method0x6000003-1
    L_000d: call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
    L_0012: stsfld int32[] Test.Program::vals
    L_0017: ret 
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top