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

PEVerify fails on explicit interface property when the interface is in a Portable Class Library

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

查看 ILDASM -> MetaInfo -> Show,您会看到 mscorlibSystem.Runtime 程序集引用都已导入。这发生在调用 DefineMethodOverride 期间(观看 AssemblyBuilder.GetReferencedAssemblies() 以查看)。您还可以看到 IEnumerable`1 作为 TypeRef 从两个程序集中引入,这似乎是问题所在。

当不将接口分离为 PCL 时,或者当将类型更改为其他内容时,它可以工作并且不包括 System.Runtime 引用。要尝试 string,请在界面中将 IEnumerable<int> 替换为 string 以及 DefineProperty/DefineMethod 调用。

使用修改后的示例 from MSDN 作为重现此问题的简化方法,将下面的代码放入控制台项目中,一切正常。将 interface I 移至可移植的 class 库项目,您将明白我的意思。

如何消除 PEVerify 错误?

Error: MethodImpl's Decl (token=0x0a000001) and Body (token=0x00610072) method signatures do not match. [token:0x19000001] [hr: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)

(PEVerify 和 ILDASM 版本 4.0.30319.33440 来自 C:\Program Files (x86)\Microsoft SDKs\Windows\v8。1A\bin\NETFX 4.5.1 Tools\x64)

谢谢!

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

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