1

.net 框架 4.7.2...

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

我能做些什么来让动态程序集拥有与编译表达式相同的访问权限吗?有古老的传说说你不能。但我找不到任何类似于该声明的主要来源的东西。我不敢相信没有某种形式的程序集属性或允许访问的权限。

如果我保存程序集,我可以这样做吗?(将缓存的编组程序集写入磁盘是未来可能的功能)。

该应用程序将结构编组为特定领域的计算机音乐语言中的流。序列化不是一种选择(动态程序集中的动态代码违反访问的另一个示例)。

示例代码:

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);
4

1 回答 1

1

在查看 .net 源代码后,似乎可以肯定没有办法Assembly绕过字段访问检查。

thehennyy指出了 Linq Expressions 使用的后门。DynamicMethod构造函数提供了一个skipVisibility参数,允许生成可以访问非公共字段和方法的 IL。但是没有办法将DynamicMethods 与动态程序集集成,或者将它们发送到保存的程序集。

鉴于DynamicMethods 的局限性,似乎没有任何理由比 Linq 表达式更喜欢它们,因为 Linq 表达式 API 比 IL.Emit API 更容易使用。

最后,我使用调用模板类生成由静态构造函数中的 Linq 表达式生成的结构序列化委托。

如果您遵循相同的路径,您可能需要查看在 C# 7.2 中引入的“非托管”结构,它允许对完全由ValueType成员组成的结构进行优化序列化。鉴于Strings 是参考类,这通常具有有限的价值。但是鉴于我正在尝试编写免分配序列化程序,它们对我的目的很有用。

于 2020-05-01T19:36:53.157 回答