c# - 复制/反射。发射静态数组

标签 c# .net reflection reflection.emit emit

我正在尝试将静态初始值设定项从一个 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);

基本上这将为您提供上面提到的“二进制数据”。

问题 1:Dictionary 会怎样?这仍然有效吗?我无法弄清楚这里到底发生了什么(它似乎被反编译隐藏了)...

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

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

--

版本? .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> 中的每个字段:

  • 使用值类型或引用类型。
  • 值类型可以携带数据,引用类型不能。引用类型在使用前进行初始化(作为 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 statics。

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

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

关于c# - 复制/反射。发射静态数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30303834/

相关文章:

c# - 在 C# 中显示完整的 SSH shell 输出,包括登录消息和提示

c# - 从回调中获取 oauth_verifier

C#:无法绕过缓存 (WebClient)

.net - FTP使用.NET上传多个文件而无需断开连接

c# - 通过 nuget 安装时引用 Bootstrap 的问题

java - JUnit5-木星 : Composed ( ="meta") annotation does not resolve to annotation definition

c# - 反射不触发参数化构造函数c#

c# - 使复选框不可点击 ASP.NET MVC5

c# - 将属性传递给方法以更改该属性

c# - 检查用户是否正确输入了 IP 地址