2

我正在尝试将静态初始化程序从一个 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 : 's会发生什么?这仍然有效吗?我很难弄清楚这里到底发生了什么(它似乎被反编译隐藏了)......

我已经发现在实现细节中使用的 GUID 是ModuleBuilder. 使用其他显式字段信息意味着您应该能够复制数据。

问题 2:如何将数据写回另一个ModuleBuilder/FieldBuilder使用 Reflection.Emit?

--

版本?.NET 4.5(VS2013 默认)

似乎对Dictionary弹出的 's 感到困惑。我在我的代码中进行了一些挖掘,它们似乎作为 [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”,如果它们有这样的花哨数据,不管类型等如何,同时保留名称。由于 IL 和数据在不同的 DLL 中以相同的方式处理,因此无论编译器恕我直言,这总是可能的,对吧?

4

1 回答 1

1

经过几个小时的摆弄,这似乎是它的工作方式:

...对于每个字段<PrivateImplementationDetails>

  • 使用值类型或引用类型。
  • 值类型可以携带数据,引用类型不能。引用类型在使用之前被初始化(作为 volatile 静态变量,f.ex. 在与它们使用相同的范围内)。

field.FieldType.IsValueType可以通过RuntimeHelpers调用从值类型 ( ) 中获取数据:

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());
}

如果它是引用类型,则无需执行任何操作,因为它们在使用时会被初始化为 volatile 静态变量。

在此之后,您需要确保使用生成的字段信息而不是原始字段;它们将包含相同的数据。至于引用,这些被初始化为null.

显然,您不想弄乱实现细节本身或它们的使用方式......

于 2015-05-18T16:31:29.607 回答