如何在动态汇编中访问匿名字段?

问题描述 投票:1回答:1

.net Framework 4.7.2....

编译后的表达式可以访问私有字段。当我使用完全相同的表达式并将其写入动态程序集时,使用的是 CompileToMethod,我得到一个 System.FieldAccessException 而试图读取私有字段。

我有什么办法可以让动态汇编拥有与编译表达式一样的访问权限吗?有一个古老的传说说你不能这样做。但我找不到任何类似于主要来源的说法。我不相信没有某种形式的汇编属性或权限可以允许访问。

如果我把汇编保存起来,能不能做到呢?将缓存的marshalling汇编写入磁盘是未来可能的功能)。

该应用是将结构的marshalling到一个特定领域的计算机音乐语言的流中。序列化不是一个选项(另一个在动态汇编中违反访问的动态代码的例子)。

示例代码。

lambda表达式成功地读取了ComplexStruct的私有字段的值(下面给出)。如果使用CompileToMethod将相同的表达式发射到动态汇编中,则会以访问异常失败。

    ComplexStruct s = new ComplexStruct();

    s.String1 = "abc";

    // Pick a private field (one of the backing fields for a property)
    FieldInfo fieldInfo = typeof(ComplexStruct).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)[0];

    var structArgument = Expression.Parameter(typeof(ComplexStruct));

    var lambda = Expression.Lambda<Func<ComplexStruct,String>>(
        Expression.Field(structArgument, fieldInfo), // return the value of the private field.
        structArgument);
    Func<ComplexStruct,String> fn = lambda.Compile();

    String result = fn(s);
    Assert.AreEqual(structArgument.String1, result);

一个带有私有字段的结构。

// (Complex compared to simple struct where all fields 
// are public or the struct is unmanaged in case you were wondering)
public struct ComplexStruct : IEquatable<ComplexStruct>
{

    public String String1 { get; set; } // the backing field for this property gets read.
    public String String2 { get; set; }
    public String String3 { get;  }

    public ComplexStruct(String v1, String v2)
    {
        String1 = v1;
        String2 = v2;
    }

    public bool Equals(ComplexStruct other)
    {
        return String1 == other.String1 && String2 == other.String2;
    }
}

创建汇编。

    AppDomain myAppDomain = Thread.GetDomain();
    AssemblyName myAsmName = new AssemblyName();
    myAsmName.Name = "DynamicAssembly";

    this.saveAssembly = ServiceBase.DEBUG;

    assemblyBuilder = myAppDomain.DefineDynamicAssembly(
                         myAsmName,
                         saveAssembly? AssemblyBuilderAccess.RunAndSave: AssemblyBuilderAccess.RunAndCollect);
c# .net .net-4.0 reflection.emit reflectionpermission
1个回答
1
投票

在回顾了.net源码之后,似乎可以肯定,没有办法让一个简单的表达式访问私有字段。Assembly 以绕过现场准入检查。

Thehennyy 指出了Linq Expressions使用的后门。DynamicMethod 构造函数提供了一个 skipVisibility 参数,允许生成可以访问非公共字段和方法的IL。但是没有办法将 DynamicMethod或将它们发射到已保存的汇编中。

鉴于 DynamicMethod的,似乎没有任何理由比Linq Expressions更喜欢它们,因为Linq Expression APIs比IL.Emit APIs更容易使用。

最后,我使用了对模板类的调用,在静态构造函数中生成Linq Expressions产生的结构序列化委托。

如果你也在走同样的路,你可能想看看C# 7.2中引入的 "非托管 "结构,它允许完全由以下结构组成的优化序列化结构 ValueType 成员。鉴于 String的是引用类,通常价值有限。但考虑到我正试图编写免分配的序列器,它们对我的目的很有用。

© www.soinside.com 2019 - 2024. All rights reserved.