【问题标题】:How to access anonymous fields in a dynamic assembly?如何访问动态程序集中的匿名字段?
【发布时间】:2020-08-12 14:43:36
【问题描述】:

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

【问题讨论】:

  • 一个提示可能是DynamicMethods 能够跳过可见性检查。看看构造函数列表,有一些构造函数具有skipVisibility 布尔参数。很久以前,我试图找出它是如何以及为什么起作用的,但我在这个过程中迷路了。还可以查看ownerTypemodule 参数:docs.microsoft.com/en-us/dotnet/api/…
  • @thehennyy 是的。这似乎是表达式的后门。非凡!

标签: c# .net .net-4.0 reflection.emit reflectionpermission


【解决方案1】:

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-31
    • 2021-02-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    相关资源
    最近更新 更多