c# - 跳过不使用 DynamicMethod 的动态生成方法的可见性检查
问题描述
这个问题与其他两个问题非常相似,请参见:first,second。然而,这些至少可以说已经过时了,我希望 .Net 5 改变了一切。
现在首先让我澄清这个问题。用一个简单的例子来尝试获取 a 的底层数组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[]>));
System.FieldAccessException:尝试通过方法 'GetUnderlyingArrayClass.GetUnderlyingArray(System.Collections.Generic.List'1)' 访问字段 'System.Collections.Generic.List'1<System.Int32>._items' 失败。+ GetUnderlyingArrayClass.GetUnderlyingArray(列表)
现在,我提到的问题之一指向以下属性ReflectionPermissionAttribute
。但是,正如文档中所述Code Access Security is not supported or honored by the runtime.
。据我了解,这基本上意味着 .Net Core/.Net 5不支持 CAS。
这是我感到困惑的地方。将skipVisibility
参数设置为true
orfalse
并不重要。我认为这是因为我在 .Net 5 环境中运行代码。但是,如果 .Net 5 不支持 CAS,为什么我仍然能够读出私有字段?
目标显然是使用DefineType
/ DefineMethod
API 从动态生成的方法访问私有字段/方法。
解决方案
我仍然无法解释为什么将skipVisibility
参数设置为true
/false
并不重要,但是来自csharp 运行时讨论存储库的 GitHub 上的PathogenDavid向我展示了一个比预期更容易的解决方案。
// 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 中定义,因此您必须自己定义它。
推荐阅读
- .htaccess - 如何使用 htaccess 将域重写为 s3
- java - 二叉搜索树删除功能擦除整个树
- jquery - 如何使下拉菜单出现在内容上而不是向下推送内容?
- python-3.x - 将安装的 pip 包添加到路径
- typescript - 在打字稿中扩展类与代码重复
- java - Gradle 项目中的 IntelliJ IDEA 编码问题
- angular - 部署应用程序后没有“Access-Control-Allow-Origin”
- java - 如果解析失败,取消表格单元格编辑的规范方法
- java - 调用列表
超时并收集结果 - sql-server - 在从文本文件批量插入期间,数据文件中遇到了意外的文件结尾