微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

跳过不使用 DynamicMethod 的动态生成方法的可见性检查

如何解决跳过不使用 DynamicMethod 的动态生成方法的可见性检查

这个问题与另外两个问题非常相似,参见:first,second。然而,至少可以说这些已经过时了,我希望 .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,new[] { typeof(List<int>) });

var ilGenerator = method.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld,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[]>));

System.FieldAccessException: 尝试通过方法 'GetUnderlyingArrayClass.GetUnderlyingArray(System.Collections.Generic.List'1)' 访问字段 'System.Collections.Generic.List'1._items' 失败。 + GetUnderlyingArrayClass.GetUnderlyingArray(List)

Here is a .Net fiddle link with the code shown above.

现在,我提到的问题之一指向以下属性 ReflectionPermissionAttribute。但是,正如它在文档 Code Access Security is not supported or honored by the runtime. 中所述。据我了解,这基本上意味着 .Net Core/.Net 5 do not support CAS.

这就是我感到困惑的地方。将 skipVisibility 参数设置为 truefalse 实际上并不重要。我认为这是因为我在 .Net 5 环境中运行代码。但是,如果 .Net 5 不支持 CAS,为什么我仍然可以读出私有字段?

目标显然是使用 DefineType/DefineMethod API 从动态生成方法访问私有字段/方法

解决方法

我仍然无法解释为什么将 skipVisibility 参数设置为 true/false 无关紧要,但是 PathogenDavid 在 {{ 3}} 向我展示了一个比预期容易得多的解决方案。

// Add IgnoresAccessChecksTo attribute
var ignoresAccessChecksTo = new CustomAttributeBuilder
(
    typeof(IgnoresAccessChecksToAttribute).GetConstructor(new Type[] { typeof(string) }),new object[] { typeof(List<>).Assembly.GetName().Name }
);

assemblyBuilder.SetCustomAttribute(ignoresAccessChecksTo);

请参阅 csharp runtime discussion repository .Net Fiddle 以获取工作示例。

正如他所说,IgnoresAccessChecksTo 属性用于绕过检查。

运行时理解该属性,但它并未在 BCL 中定义,因此您必须自己定义。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。