我正在发出一个类,它使用get方法显式地实现一个简单的接口属性。只要在可移植类库中没有定义接口,就不会有任何问题。但是,当将接口移动到PCL并仅使用特定类型(如IEnumerable<int>
)时,PEVerify将失败。
查看ILDASM -> MetaInfo -> Show,您将看到mscorlib
和System.Runtime
程序集引用都是导入的。这发生在对DefineMethodOverride
的调用过程中(观察AssemblyBuilder.GetReferencedAssemblies()
以查看)。您还可以看到,IEnumerable`1 `1是作为来自两个程序集的TypeRef引入的,这似乎就是问题所在。
当不将接口分离到PCL,或者将类型更改为其他类型时,它可以工作,并且不包含System.Runtime
引用。要尝试string
,请将IEnumerable<int>
替换为接口中的string
以及DefineProperty
/DefineMethod
调用。
使用修改后的示例来自MSDN作为重现此问题的简化方法,将下面的代码放在控制台项目中,一切都很好。将interface I
移动到一个可移植类库项目中,您将看到我的确切意思。
如何消除PEVerify错误?
错误:MethodImpl‘match (token=0x0a000001)和Body (token=0x00610072)方法签名不匹配。令牌:0x19000001
public interface I
{
IEnumerable<int> E { get; }
}
class Test
{
static void Main()
{
string name = "DefineMethodOverrideExample";
AssemblyName asmName = new AssemblyName(name);
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule(name, name + ".dll");
TypeBuilder tb = mb.DefineType("C", TypeAttributes.Public);
tb.AddInterfaceImplementation(typeof(I));
PropertyBuilder prop = tb.DefineProperty("I.E", PropertyAttributes.None, typeof(IEnumerable<int>), Type.EmptyTypes);
MethodBuilder mbIM = tb.DefineMethod(
"I.get_E",
MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName,
typeof(IEnumerable<int>),
Type.EmptyTypes);
prop.SetGetMethod(mbIM);
ILGenerator il = mbIM.GetILGenerator();
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Ret);
tb.DefineMethodOverride(mbIM, typeof(I).GetProperty("E").GetGetMethod());
Type tc = tb.CreateType();
ab.Save(name + ".dll");
}
}
(.Net 4.5.1)
(PEVerify和ILDASM版本4.0.30319.33440来自C:\Program (x86)\Microsoft \Windows\v8.1A\bin\NETFX4.5.1工具\x64)
谢谢!
发布于 2015-02-04 12:26:28
在与已发出和编译的示例进行更多比较之后,以及深入研究.NET库之后,我能够发现关键的区别在于对ModuleBuilder.DefineMethodOverrideNoLock
-> GetMethodTokenInternalNoLock
(在接口上)的调用,其中有一个测试提供的MethodInfo
是否为RuntimeMethodInfo
。最终,对GetMemberRefOfMethodInfo
的调用会导致System.Runtime
的包含,从而为某些类型产生冲突的结果,例如IEnumerable
。
要以不需要反映到私有成员的方式解决这个问题,您可以创建继承MethodInfo
的代理或包装器,该代理或包装器覆盖所有方法以返回来自原始RuntimeMethodInfo
的结果。这将导致ILDASM显示出现在编译(未发出)程序集中的TypeRef和TypeSpec元素,试图显式实现PCL接口方法。我能够使用此技术成功地验证发出的程序集。
https://stackoverflow.com/questions/28310167
复制