簡體   English   中英

復制/反射。發射靜態數組

[英]Copy / Reflection.Emit'ting static arrays

我正在嘗試將靜態初始化程序從一個DLL復制到另一個DLL。

如果您在C#中有一個靜態數組初始值設定項,則會得到以下信息:

.class private auto ansi <PrivateImplementationDetails>{0D3E8B0E-F218-435F-989D-9D04F550A786}
    extends [mscorlib]System.Object
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
    .field assembly static valuetype <PrivateImplementationDetails>{0D3E8B0E-F218-435F-989D-9D04F550A786}/__StaticArrayInitTypeSize=120 $$method0x6000060-1 = ((binary data))

我找到了讀取此數據以使用此方法的最簡單方法:

int size = field.FieldType.StructLayoutAttribute.Size;
byte[] data = new byte[size];
RuntimeHelpers.InitializeArray(data, field.FieldHandle);

基本上,這將為您提供上述的“二進制數據”。

問題1Dictionary會發生什么? 這仍然有效嗎? 我在弄清楚這里到底發生什么時遇到了麻煩(它似乎在反編譯中是隱藏的)...

我已經發現在實現細節中使用的GUID是ModuleBuilder的版本ID。 使用其他顯式字段信息意味着您應該能夠復制數據。

問題2:你怎么能寫回的數據在另一個ModuleBuilder / FieldBuilder使用Reflection.Emit的?

-

版? .NET 4.5(VS2013默認)

似乎對彈出的Dictionary感到困惑。 我在代碼中做了一些挖掘,它們似乎以[string-> int]字典的形式彈出,用於解析switch / case語句。

例如,請參見mscorlib.dll v4.0.30319.18444中可以找到它們。 在Reflector中,它們如下所示:

.field assembly static class System.Collections.Generic.Dictionary`2<string, int32> $$method0x6003a20-1

至於原因:在對它們執行一些測試之前,我正在更改DLL。 具有諷刺意味的是,我想要這樣做的原因是因為我不想弄亂實現細節:-),並且因為多個實例可能會帶來麻煩。

換句話說,我基本上只想復制所有它們,就像它們是二進制blob一樣,如果它們具有這樣的奇特數據,而不管類型如何,同時保留名稱。 由於在不同的DLL中以相同的方式對待IL和數據,因此無論編譯器恕我直言,這應該總是可能的,對嗎?

經過數小時的擺弄,這似乎是它的工作方式:

...對於<PrivateImplementationDetails>每個字段:

  • 使用值類型或引用類型。
  • 值類型可以攜帶數據,引用類型不能攜帶數據。 引用類型在使用之前已初始化(作為易失性靜態變量,例如與使用它們的作用域相同)。

可以通過RuntimeHelpers調用從值類型( field.FieldType.IsValueType )中獲取數據:

int size = GetManagedSize(field.FieldType);
byte[] data = new byte[size];

RuntimeHelpers.InitializeArray(data, field.FieldHandle);

FieldBuilder mappedField = myType.DefineInitializedData(
    field.Name, data, field.Attributes);

有:

public static int GetManagedSize(Type type)
{
    var method = new DynamicMethod("GetManagedSizeImpl", typeof(uint), new Type[0], 
        GetType().Assembly, false);

    ILGenerator gen = method.GetILGenerator();

    gen.Emit(OpCodes.Sizeof, type);
    gen.Emit(OpCodes.Ret);

    var func = (Func<uint>)method.CreateDelegate(typeof(Func<uint>));
    return checked((int)func());
}

如果是引用類型,則無需執行任何操作,因為使用它們時,它們會初始化為易失性靜態變量。

之后,您需要確保使用生成的fieldinfo代替原始字段。 它們將包含相同的數據。 至於引用,它們被初始化為null

顯然,您不想弄亂實現細節本身或使用它們的方式...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM