【Emit】关于System.MethodAccessException解决方案
最近学习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解决方案的更多相关文章
- [C#] 解决Silverlight反射安全关键(SecuritySafeCritical)时报“System.MethodAccessException: 安全透明方法 XXX 无法使用反射访问”的问题
作者: zyl910 一.缘由 在Silverlight中使用反射动态访问时,经常遇到"System.MethodAccessException: 安全透明方法 XXX 无法使用反射访问-- ...
- MySQL Unable to convert MySQL datetime value to System.DateTime 解决方案
Unable to convert MySQL date/time value to System.DateTime 解决方案 这个问题发生在MySQL数据里面有Date类型数据,在C#中查询出来时候 ...
- Android 开发中遇到Read-only file system问题解决方案
问题描述: 在往scdcard中复制mp3文件时,复制不成功.查看了一下sdcard里面没有内容,且无法直接在里面创建文件会出现-- read only file system类似的内容提示. ...
- Sql server 打不开了,无法识别的配置节 system.serviceModel 解决方案
异常描述: System.Configuration.ConfigurationErrorsException: 配置系统未能初始化 ---> System.Configuration.Conf ...
- .netcore中无法使用System.Drawing --解决方案
问题重现: 无法正常使用 解决方法: 安装System.Drawing.Common的NuGet就能正常使用了 操作之后: 这个是.netcoe中的解决办法,.net framework解决方案中添 ...
- Rvm 进行gem安装时必须输入密码Your user account isn't allowed to install to the system RubyGems 解决方案
今天开发过程中,从master拉下代码后重启项目,想用控制台时,却发现需要密码??并且三次密码确认后还是疯狂报错. 当时第一想到是rvm版本不一致,随即则检查了版本跟gem生成,当确认rvm版本无误时 ...
- log4j:WARN Please initialize the log4j system properly.解决方案
在使用quarz任务调度框架时的错误,实际上这个问题很常见,并不影响程序的使用,只是缺少日志输出,完整错误信息: log4j:WARN No appenders could be found for ...
- 关于read only file system问题解决方案
切换到超级用户sudo -sadb kill-serveradb rebootadb remount
- 开机出现loading Operating System的解决方案
今天清理机箱之后开机发现电脑屏幕出现以下界面,提示的内容是"正在加载操作系统,磁盘启动失败,请插入系统盘..",出现这种状况的原因有以下几种: 1.主引导的扇区的损坏或者信息的错乱 ...
随机推荐
- http://blog.csdn.net/i_bruce/article/details/39555417
http://blog.csdn.net/i_bruce/article/details/39555417
- 【Docker】Docker管理平台 Rancher ---- 你应该学学Rancher是怎么做容器的管理的
Elasticsearch is a Lucene-based search engine developed by the open-source vendor, elastic. With pri ...
- redhat mount iso as one yum repository
prepare redhat DVD iso rhel-server-6.4-x86_64-dvd.iso mount cd / mkdir /mnt/rhel mount -o loop rhel- ...
- android开发常用地址
一. android市场占用率的url http://developer.android.com/about/dashboards/ 二. ADT下载 下载地址是:http://developer.a ...
- 转:svn 更新指定文件夹
通常由于创建很多个branch和tag,当我们要去checkout指定tag和branch的时候,会不得不把整个branch/tag目录checkout出来.是不是有点傻??!!! 那么如何有选择ch ...
- C5:单例模式 Singleton
保证一个类仅有一个实例,并提供一个访问它的全局访问点. 应用场景:A.一个无状态的类使用单例,可以节省内存B.全局或配置类(其实这个也是无状态的)C.脚本或程序从运行开始到结束,仅需要一个实例来保证数 ...
- mysql_affected_rows的注意点
取得最近一次与 link_identifier 关联的 INSERT,UPDATE 或 DELETE 查询所影响的记录行数. 1.执行成功,则返回受影响的行的数目,如果最近一次查询失败的话,函数返回 ...
- jquery技术揭秘静态工具函数源码重构
1.调用页面 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...
- MySQL优化时可以设置的几个参数
back_log:back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中.也就是说,如果MySql的连接数据达到max_connections时,新来的请求将会被 ...
- hdu 5371 Hotaru's problem【manacher】
题目链接: http://acm.hdu.edu.cn/showproblem.php? pid=5371 题意: 给出一个长度为n的串,要求找出一条最长连续子串.这个子串要满足:1:能够平均分成三段 ...