C# 如何访问动态程序集中的匿名字段?
.net Framework 4.7.2 编译后的表达式可以访问私有字段。当我使用完全相同的表达式并使用C# 如何访问动态程序集中的匿名字段?,c#,.net,.net-4.0,reflection.emit,reflectionpermission,C#,.net,.net 4.0,Reflection.emit,Reflectionpermission,.net Framework 4.7.2 编译后的表达式可以访问私有字段。当我使用完全相同的表达式并使用CompileToMethod将其写入动态程序集时,在尝试读取私有字段时,会得到一个System.FieldAccessException 我可以做些什么来允许动态程序集拥有与编译表达式相同的访问权限吗?古老的传说说你不能。但我找不到任何类似于这种说法的主要来源。我不敢相信没有某种形式的程序集属性或许可证允许访问 如果改为保存程序集,是否可以执行此操作?(将缓存的封送程序集写入磁盘可能是将来的
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);
在查看.net源代码后,似乎很确定,
程序集
无法绕过字段访问检查
指出Linq表达式使用的后门DynamicMethod
构造函数提供了一个skipVisibility
参数,该参数允许生成可以访问非公共字段和方法的IL。但是无法将DynamicMethod
s与动态程序集集成,也无法将它们发送到保存的程序集
考虑到DynamicMethod
s的局限性,似乎没有任何理由选择它们而不是Linq表达式,因为Linq表达式API使用IL.Emit API要容易得多
最后,我使用了对模板类的调用,这些模板类生成由静态构造函数中的Linq表达式生成的结构序列化委托
如果您遵循相同的路径,那么您可能想看看C#7.2中引入的“非托管”结构,它允许对完全由
ValueType
成员组成的结构进行优化序列化。假设String
s是引用类,它的值通常是有限的。但考虑到我正在尝试编写无分配序列化程序,它们对我的目的很有用。一个提示可能是DynamicMethod
s能够跳过可见性检查。看看构造函数列表,有几个构造函数具有skipVisibility
boolean参数。很久以前,我试图找出它是如何工作的以及为什么工作的,但在这个过程中我迷失了方向。还可以查看那里的所有者类型
或模块
参数:@thehennyy Yes。这似乎是表达的后门。非同寻常!
// (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);