这个问题和另外两个问题很相似见:第一,第二。然而,这些都已经过时了,我希望在。net 5中有所改变。
首先让我澄清这个问题。通过一个简单的示例,试图获得List<int>.
var method = new DynamicMethod("GetUnderlyingArray", typeof(int[]), new[] { typeof(List<int>) }, typeof(List<int>), true);
var ilGenerator = method.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, typeof(List<int>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance));
ilGenerator.Emit(OpCodes.Ret);
var arrayGetter = (Func<List<int>, int[]>)method.CreateDelegate(typeof(Func<List<int>, int[]>));
这工作得很好,因为我能够告诉DynamicMethod
跳过可见性检查(即使它工作得很好,当DynamicMethod
构造器true
的最后一个参数被删除时)。
然而,当我试图对下面的例子做同样的事情时,它会抛出一个FieldAccessException
.
var assemblyName = new AssemblyName("Example");
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var dynamicModule = assemblyBuilder.DefineDynamicModule(assemblyName.Name + ".dll");
var type = dynamicModule.DefineType("GetUnderlyingArrayClass");
var method = type.DefineMethod("GetUnderlyingArray", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, typeof(int[]), new[] { typeof(List<int>) });
var ilGenerator = method.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, typeof(List<int>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance));
ilGenerator.Emit(OpCodes.Ret);
type.CreateType();
var arrayGetter = (Func<List<int>, int[]>)type.GetMethod("GetUnderlyingArray").CreateDelegate(typeof(Func<List<int>, int[]>));
系统。FieldAccessException:尝试使用方法'GetUnderlyingArrayClass.GetUnderlyingArray(System.Collections.Generic.List'1)'访问字段'System.Collections.Generic.List'1
。_items"失败了。+ GetUnderlyingArrayClass.GetUnderlyingArray(列表)
这是一个. net fiddle链接,上面显示了代码。
现在,我提到的一个问题指向以下属性ReflectionPermissionAttribute
。然而,正如文档Code Access Security is not supported or honored by the runtime.
所述。从我的理解来看,这基本上意味着。net Core/。Net 5不支持CAS
这就是我感到困惑的地方。将skipVisibility
参数设置为true
或false
实际上并不重要。我认为这是因为我是在。net 5环境中运行代码的。但是,如果。net 5不支持CAS,为什么我仍然能够读出私有字段?
目标显然是使用DefineType
/DefineMethod
API从动态生成的方法中访问私有字段/方法。
我仍然无法解释为什么将skipVisibility
参数设置为true
/false
并不重要,但是PathogenDavid在GitHub上从csharp运行时讨论存储库向我展示了一个比预期更容易的解决方案。
// Add IgnoresAccessChecksTo attribute
var ignoresAccessChecksTo = new CustomAttributeBuilder
(
typeof(IgnoresAccessChecksToAttribute).GetConstructor(new Type[] { typeof(string) }),
new object[] { typeof(List<>).Assembly.GetName().Name }
);
assemblyBuilder.SetCustomAttribute(ignoresAccessChecksTo);
查看这个。net Fiddle的工作示例。
正如他所说,IgnoresAccessChecksTo
属性是用来绕过检查的。
运行时理解该属性,但它没有在BCL中定义,因此您必须自己定义它。