调用Emit构造的方法时报System.MethodAccessException 错误
System.MethodAccessException:“方法“DynamicClass.CopyProductPropertiesMethod_31(IMCOA.Sale.Data.LISTING_QUEUE_INFO_WISH, WaitCopyProperty)”尝试访问方法“DynamicClass.CopyProductPropertiesMethod_31(IMCOA.Sale.Data.LISTING_QUEUE_INFO_WISH, WaitCopyProperty)”失败。”
异常原因总结:
说道造成System.MethodAccessException异常的原因,就得先说一下反射安全从 .NET Framework 4 版开始,仅受信任的代码才能使用反射访问安全关键成员。
而且,也只有受信任的代码才能使用反射访问非公共成员。最后,使用反射访问安全关键成员的代码必须具有安全关键成员要求的任何权限。
那什么是安全关键成员呢?满足下面一下条件之一的:具有 SecurityCriticalAttribute;属于一个具有 SecurityCriticalAttribute 的类型;或者位于一个安全关键程序集中;
访问安全关键成员的规则如下所示:
安全级别 | 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的代码中有非公开的成员。
2、本来想加上ReflectionPermissionFlag.MemberAccess ,但总感觉不太好,破坏了程序集的安全性
private Func<LISTING_QUEUE_INFO_WISH, WaitCopyProperty, LISTING_QUEUE_INFO_WISH> BuilderCopyMethod(CopyProductProperitesEnum copyProductProperitesEnum )
{
var methodName="CopyProductPropertiesMethod_"+(int)copyProductProperitesEnum;
if (_copyMethodDataset.ContainsKey(methodName))
{
return _copyMethodDataset[methodName];
}
var parmType = typeof(LISTING_QUEUE_INFO_WISH);
var parmTypeTwo = typeof(WaitCopyProperty); //因为WaitCopyProperty 被定义为内部类导致的
DynamicMethod method = new DynamicMethod(methodName, parmType, new Type[] { parmType, parmTypeTwo });
var il = method.GetILGenerator();
Action<string, string> action = (propertyNameOne, propertyNameTwo) =>
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, parmTypeTwo.GetProperty(propertyNameTwo).GetGetMethod());
il.Emit(OpCodes.Call, parmType.GetProperty(propertyNameOne).GetSetMethod());
};
if (EnumIsTrue(copyProductProperitesEnum, CopyProductProperitesEnum.Title))
{
action(nameof(LISTING_QUEUE_INFO_WISH.LIS_TITLE), nameof(WaitCopyProperty.Title));
}
if (EnumIsTrue(copyProductProperitesEnum, CopyProductProperitesEnum.Description))
{
action(nameof(LISTING_QUEUE_INFO_WISH.LIS_DETAILS), nameof(WaitCopyProperty.Details));
}
if (EnumIsTrue(copyProductProperitesEnum, CopyProductProperitesEnum.TAGS))
{
action(nameof(LISTING_QUEUE_INFO_WISH.LIS_TAGS), nameof(WaitCopyProperty.TAGS));
}
if (EnumIsTrue(copyProductProperitesEnum, CopyProductProperitesEnum.Color))
{
var colorFieldNameOne = nameof(LISTING_QUEUE_INFO_WISH.LIS_VARIATIONS);
var colorFieldNameTwo = nameof(WaitCopyProperty.Variation);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, parmTypeTwo.GetProperty(colorFieldNameTwo).GetGetMethod());
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, parmType.GetProperty(colorFieldNameOne).GetGetMethod());
il.Emit(OpCodes.Ldstr, "Color");
il.Emit(OpCodes.Call, typeof(WishCopyProductPublishInformation).GetMethod("ReplaceColorOrSize", new Type[] { typeof(string), typeof(string), typeof(string) }));
il.Emit(OpCodes.Call, parmType.GetProperty(colorFieldNameOne).GetSetMethod());
}
if (EnumIsTrue(copyProductProperitesEnum, CopyProductProperitesEnum.Size))
{
var sizeFieldNameOne = nameof(LISTING_QUEUE_INFO_WISH.LIS_VARIATIONS);
var sizeFieldNameTwo = nameof(WaitCopyProperty.Variation);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, parmTypeTwo.GetProperty(sizeFieldNameTwo).GetGetMethod());
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, parmType.GetProperty(sizeFieldNameOne).GetGetMethod());
il.Emit(OpCodes.Ldstr, "Size");
il.Emit(OpCodes.Call, typeof(WishCopyProductPublishInformation).GetMethod("ReplaceColorOrSize", new Type[] { typeof(string), typeof(string), typeof(string) }));
il.Emit(OpCodes.Call, parmType.GetProperty(sizeFieldNameOne).GetSetMethod());
}
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ret);
var result = (Func<LISTING_QUEUE_INFO_WISH, WaitCopyProperty, LISTING_QUEUE_INFO_WISH>)method.CreateDelegate(typeof(Func<LISTING_QUEUE_INFO_WISH, WaitCopyProperty, LISTING_QUEUE_INFO_WISH>));
_copyMethodDataset.Add(methodName, result);
return result;
}
这个方法中英文有参数被定义为内部类且状态为private导致的这个问题,把它从内部内中取出来并改为public执行即可.
这里的话不是反射问题,可以直接把方法所有者加入到当前类,就不会出现访问冲突了。
`DynamicMethod method = new DynamicMethod(methodName, parmType, new Type[] { parmType, parmTypeTwo }, this.GetType());`