我发布了一个使用get方法显式实现简单接口属性的类。只要接口未在可移植类库中定义,就没有问题。但是,将接口移动到PCL并仅使用IEnumerable<int>
等特定类型时,PEVerify将失败。
查看 ILDASM - &gt; MetaInfo - &gt;显示,您会看到导入了mscorlib
和System.Runtime
程序集引用。这在调用DefineMethodOverride
期间发生(请注意AssemblyBuilder.GetReferencedAssemblies()
)。您还可以看到IEnumerable`1作为TypeRef从两个程序集中引入,这似乎是问题所在。
如果不将接口分离到PCL,或者将类型更改为其他类型,则可以正常工作,并且不包括System.Runtime
引用。要尝试string
,请将IEnumerable<int>
替换为界面中的string
以及DefineProperty
/ DefineMethod
来电。
使用修改后的示例from MSDN作为重现此问题的简化方法,将以下代码放在控制台项目中,一切运行良好。将interface I
移动到便携式类库项目,您将看到我的意思。
如何摆脱PEVerify错误?
错误:MethodImpl&#39; s Decl(令牌= 0x0a000001)和Body (标记= 0x00610072)方法签名不匹配。 [令牌:0x19000001] [小时:0x801312F4]
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)
(来自C:\ Program Files(x86)\ Microsoft SDKs \ Windows \ v8.1A \ bin \ NETFX 4.5.1 Tools \ x64的PEVerify和ILDASM版本4.0.30319.33440
谢谢!
答案 0 :(得分:0)
在对发布和编译的示例进行更多比较之后,以及深入研究.NET libraries,我能够发现关键区别在于对ModuleBuilder.DefineMethodOverrideNoLock
- &gt;的调用。 GetMethodTokenInternalNoLock
(在界面上),其中测试所提供的MethodInfo
是否为RuntimeMethodInfo
。最终,对GetMemberRefOfMethodInfo
的调用导致包含System.Runtime
,从而对某些类型产生冲突结果,例如IEnumerable
。
要以不需要反映私有成员的方式解决此问题,您可以创建一个继承MethodInfo
的代理或包装器,它覆盖所有方法以返回原始RuntimeMethodInfo
的结果。这将导致ILDASM显示出现在编译(非发射)程序集中的TypeRef和TypeSpec元素,这些元素试图显式实现PCL接口方法。我能够使用这种技术成功验证发射的组件。