当接口位于可移植类库中时,PEVerify在显式接口属性上失败

时间:2015-02-03 22:42:49

标签: c# reflection.emit peverify

我发布了一个使用get方法显式实现简单接口属性的类。只要接口未在可移植类库中定义,就没有问题。但是,将接口移动到PCL并仅使用IEnumerable<int>等特定类型时,PEVerify将失败。

查看 ILDASM - &gt; MetaInfo - &gt;显示,您会看到导入了mscorlibSystem.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

谢谢!

1 个答案:

答案 0 :(得分:0)

在对发布和编译的示例进行更多比较之后,以及深入研究.NET libraries,我能够发现关键区别在于对ModuleBuilder.DefineMethodOverrideNoLock - &gt;的调用。 GetMethodTokenInternalNoLock(在界面上),其中测试所提供的MethodInfo是否为RuntimeMethodInfo。最终,对GetMemberRefOfMethodInfo的调用导致包含System.Runtime,从而对某些类型产生冲突结果,例如IEnumerable

要以不需要反映私有成员的方式解决此问题,您可以创建一个继承MethodInfo的代理或包装器,它覆盖所有方法以返回原始RuntimeMethodInfo的结果。这将导致ILDASM显示出现在编译(非发射)程序集中的TypeRef和TypeSpec元素,这些元素试图显式实现PCL接口方法。我能够使用这种技术成功验证发射的组件。