最近学习Emit,在使用Emit动态生成对象时碰到一些“蛋疼”的问题,如下:
1、安全透明方法“XXX.XX()”尝试访问安全关键方法“YYY.YY()”失败。
2、方法“XXX(System.Object[])”尝试访问方法“YYY.ctor()”失败。
    上面两个都是System.MethodAccessException异常。刚开始一看,懵B了。这提示信息也太少了吧。没办法就这么残酷,只好硬着头皮,顺藤摸瓜找原因。功夫不负有心人,终于找到原因了,阿弥陀佛!
说道造成System.MethodAccessException异常的原因,就得先说一下反射安全
    从 .NET Framework 4 版开始,仅受信任的代码才能使用反射访问安全关键成员。而且,也只有受信任的代码才能使用反射访问非公共成员。最后,使用反射访问安全关键成员的代码必须具有安全关键成员要求的任何权限。
那什么是安全关键成员呢?满足下面一下条件之一的:具有 SecurityCriticalAttribute;属于一个具有 SecurityCriticalAttribute 的类型;或者位于一个安全关键程序集中;
    访问安全关键成员的规则如下所示:

  • 透明代码不能使用反射来访问安全关键成员,即使代码是完全受信任的也是如此。 将引发 MethodAccessException、FieldAccessException 或 TypeAccessException。
  • 以部分信任方式运行的代码将被视为透明的。

    无论安全关键成员是由已编辑代码直接访问,还是通过使用反射访问,这些规则都是相同的。 
    公共语言运行时将根据多个因素来确定类型或成员的透明度级别,这些因素包括程序集的信任级别和应用程序域的信任级别。 反射提供 IsSecurityCritical、IsSecuritySafeCritical 和 IsSecurityTransparent 属性以使您能够发现类型的透明度级别。 下表显示了这些属性的有效组合。

安全级别 IsSecurityCritical IsSecuritySafeCritical IsSecurityTransparent
安全级别高的 true false false
安全关键的 true true false
透明的 false false true

MethodBase 、FieldInfo、TypeBuilder、MethodBuilder 和 DynamicMethod 类都有相似的属性。
    若要使用反射来调用根据公共语言运行时的可访问性规则不可访问的成员,代码中必须授予带有 ReflectionPermissionFlag.MemberAccess 标志的 ReflectionPermission。需要注意的是默认情况下,.NET安全策略拒绝向源自 Internet 的代码授予此权限。 所以也不要向源自 Internet 的代码授予此权限。
    理解了上面的概念,System.MethodAccessException异常也就迎刃而解了,解决方案:
1、要Emit的代码中有非公开的成员。我查看一下代码,果然有一个类是internal的。这个简单把它改成public就可以了。
2、本来想加上ReflectionPermissionFlag.MemberAccess ,但总感觉不太好,破坏了程序集的安全性。经过不断的测试,找到了一个完美的解决方案,下面举例说明:
首先,我原先动态生成对象的方法时这样写的

  private static CreateOjectHandler CreateHandler(Type type, Type[] paramsTypes)
{ ConstructorInfo constructor = type.GetConstructor(paramsTypes);
DynamicMethod method = new DynamicMethod("DynamicCreateOject", typeof(object),
new Type[] { typeof(object[]) }, typeof(FastObjectCreater).Module); ILGenerator il = method.GetILGenerator(); for (int i = 0; i < paramsTypes.Length; i++)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref);
if (paramsTypes[i].IsValueType)
{
il.Emit(OpCodes.Unbox_Any, paramsTypes[i]);
}
else
{
il.Emit(OpCodes.Castclass, paramsTypes[i]);
}
}
il.Emit(OpCodes.Newobj, constructor);
il.Emit(OpCodes.Ret); return (CreateOjectHandler)method.CreateDelegate(typeof(CreateOjectHandler));
}

上面的代码放到项目A中,然后在项目B中调用

    class Program
{
static void Main(string[] args)
{
var chinese = FastObjectCreater.CreateInstance<Chinese>();
chinese.SayHello(); Console.ReadKey();
} public class Chinese
{
public Chinese()
{
} public Chinese(string name)
{
} public void SayHello()
{
Console.WriteLine("你好!!!");
} public override string ToString()
{
return "中国人";
}
} }

    上面代码在项目B中定义。接着,运行项目B就会出现问题2的异常。

    请注意这段代码 DynamicMethod method = new DynamicMethod("DynamicCreateOject", typeof(object),new Type[] { typeof(object[]) }, typeof(FastObjectCreater).Module); 它就是罪魁祸首。因为DynamicCreateOject方法生成在项目A中,而且项目B的Program方法是私有的,Chinese类是它的内部类,所以在Main方法中访问Chinese类是私有的级别。.NET 4不允许非受信任的代码用反射访问非公共成员,所以在执行FastObjectCreater.CreateInstance<Chinese>();代码时就引发了异常。所以解决的方法很简单,只要把DynamicMethod类的module参数改为constructor.DeclaringType.Module。这就把原来的属于项目A的DynamicCreateOject方法变成项目B的DynamicCreateOject方法,也就不存在非信任代码的问题。

    OK,终于写完了,回家喽!

【Emit】关于System.MethodAccessException解决方案的更多相关文章

  1. [C#] 解决Silverlight反射安全关键(SecuritySafeCritical)时报“System.MethodAccessException: 安全透明方法 XXX 无法使用反射访问”的问题

    作者: zyl910 一.缘由 在Silverlight中使用反射动态访问时,经常遇到"System.MethodAccessException: 安全透明方法 XXX 无法使用反射访问-- ...

  2. MySQL Unable to convert MySQL datetime value to System.DateTime 解决方案

    Unable to convert MySQL date/time value to System.DateTime 解决方案 这个问题发生在MySQL数据里面有Date类型数据,在C#中查询出来时候 ...

  3. Android 开发中遇到Read-only file system问题解决方案

    问题描述: 在往scdcard中复制mp3文件时,复制不成功.查看了一下sdcard里面没有内容,且无法直接在里面创建文件会出现--    read only file system类似的内容提示. ...

  4. Sql server 打不开了,无法识别的配置节 system.serviceModel 解决方案

    异常描述: System.Configuration.ConfigurationErrorsException: 配置系统未能初始化 ---> System.Configuration.Conf ...

  5. .netcore中无法使用System.Drawing --解决方案

    问题重现: 无法正常使用  解决方法: 安装System.Drawing.Common的NuGet就能正常使用了 操作之后: 这个是.netcoe中的解决办法,.net framework解决方案中添 ...

  6. Rvm 进行gem安装时必须输入密码Your user account isn't allowed to install to the system RubyGems 解决方案

    今天开发过程中,从master拉下代码后重启项目,想用控制台时,却发现需要密码??并且三次密码确认后还是疯狂报错. 当时第一想到是rvm版本不一致,随即则检查了版本跟gem生成,当确认rvm版本无误时 ...

  7. log4j:WARN Please initialize the log4j system properly.解决方案

    在使用quarz任务调度框架时的错误,实际上这个问题很常见,并不影响程序的使用,只是缺少日志输出,完整错误信息: log4j:WARN No appenders could be found for ...

  8. 关于read only file system问题解决方案

    切换到超级用户sudo -sadb kill-serveradb rebootadb remount

  9. 开机出现loading Operating System的解决方案

    今天清理机箱之后开机发现电脑屏幕出现以下界面,提示的内容是"正在加载操作系统,磁盘启动失败,请插入系统盘..",出现这种状况的原因有以下几种: 1.主引导的扇区的损坏或者信息的错乱 ...

随机推荐

  1. UserAgent伪装浏览器

    经常逛论坛的朋友经常会遇到这样的问题:论坛个性签名里的JS代码把个人浏览器信息等被人一览无余,我并不想他们得到我的这类信息. 咋办?很简单的办法就是伪装,怎么伪装?对于chrome.firefox等这 ...

  2. Spring IoC Container and Spring Bean Example Tutorial

    Spring Framework is built on the Inversion of Control (IOC) principle. Dependency injection is the t ...

  3. 一个例子理解Predicate、Consumer和Stream

    一个需求: 把年龄大于20的学生的信息打印出来. 面向对象编程 public class Student { private String name; private int age; private ...

  4. Servlet的API(二)

    web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表响应的response对象.request和response对象既然代表请求和响应,那我们获取 ...

  5. NSMutableAttributedString 的使用方法,设置格式

    NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:title]; NS ...

  6. asp.net core mvc视频A:笔记2-4.ActionResult(动作结果,即返回值)

    json类型测试 方法一:实例化对象方式 代码 运行结果 方法二:封装方式 代码改动 运行结果 重点视图返回介绍,其他的不做介绍了 项目文件目录及文件添加 代码 运行结果 如果要显示的不是默认视图,可 ...

  7. c++打印蛇形矩阵

    一个m*n的矩阵里按照下图形式填充,最后形成的矩阵即为蛇形矩阵,下图是m=4, n =5时的蛇形矩阵: 方法一:逐层循环 #include <iostream> using namespa ...

  8. BNU 34990 Justice String (hash+二分求LCP)

    思路:枚举第一个字符串的位置,然后枚举最长公共前缀的长度,时间即会下降-- #pragma comment(linker, "/STACK:1024000000,1024000000&quo ...

  9. 关于javaSocket中 Software caused connection abort: recv failed问题

    在学习Socket中今天突然遇到了以下这种问题 原来是网路连接出了问题,由于我測试的是远程连接所以是在学校的局域网下,结果非常不稳定,開始还以为怎么了一会连上了一会又出现故障然后把IP地址改为本机的1 ...

  10. asp.net core 系列之Response caching(1)

    这篇文章简单的讲解了response caching: 讲解了cache-control,及对其中的头和值的作用,及设置来控制response caching; 简单的罗列了其他的缓存技术:In-me ...