0

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

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

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

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

如何摆脱 PEVerify 错误?

错误:MethodImpl 的 Decl (token=0x0a000001) 和 Body (token=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)

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

谢谢!

4

1 回答 1

0

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

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

于 2015-02-04T20:26:28.663 回答