0

I'm emitting a class that explicitly implements a simple interface property with a get method. There are no problems so long as the interface is not defined in a portable class library. However, when moving the interface to a PCL and using only specific types such as IEnumerable<int>, PEVerify will fail.

Looking at ILDASM -> MetaInfo -> Show, you would see that both mscorlib and System.Runtime assembly references are imported. This occurs during the call to DefineMethodOverride (watch AssemblyBuilder.GetReferencedAssemblies() to see). You can also see that IEnumerable`1 is brought in as a TypeRef from both assemblies, which seems to be the problem.

When not separating the interface to a PCL, or when changing the type to something else, it works and the System.Runtime reference is not included. To try string, replace IEnumerable<int> with string in the interface as well as DefineProperty/DefineMethod calls.

Using a modified example from MSDN as a simplified way to reproduce this issue, drop the code below in a console project and everything works great. Move interface I to a portable class library project and you will see exactly what I mean.

How can I get rid of the PEVerify error?

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 and ILDASM versions 4.0.30319.33440 from C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\x64)

Thanks!

Eric
  • 33
  • 2
  • This is normal, the [AssemblyVersion] for IEnumerable won't match. Should work just fine at runtime when the CLR remaps it from 2.0.5.0 to 4.0.0.0, have you tried it? – Hans Passant Feb 04 '15 at 00:21
  • Yes it does in fact work, but my concern is that there are some places where verification must succeed. For example if I used such a type in a lambda expression passed to entity framework, verification is called at runtime on the expression (I think so that it works in partial trust if I remember). – Eric Feb 04 '15 at 00:37
  • Well, that's a perceived problem that you completely failed to document in your question. Come back when it turns real. – Hans Passant Feb 04 '15 at 00:41
  • Please address the question without the hostility. I was not trying to describe all usage scenarios, I asked specifically how to remove the PEVerify error. This is one of numerous scenarios that cause runtime verification, and this one EF example is in fact presently 'real' in the project. – Eric Feb 04 '15 at 00:47

1 Answers1

0

After doing some more comparisons with emitted and compiled examples, as well as digging into the .NET libraries, I was able to discover the key distinction was in the call to ModuleBuilder.DefineMethodOverrideNoLock -> GetMethodTokenInternalNoLock (on the interface), in where there is a test for whether the provided MethodInfo is a RuntimeMethodInfo. Ultimately a call to GetMemberRefOfMethodInfo causes the inclusion of System.Runtime, producing conflicting results for certain types, such as IEnumerable.

To solve this in a manner that doesn't require reflecting into private members, you can create a proxy or wrapper that inherits MethodInfo which overrides all methods to return results from the original RuntimeMethodInfo. This will cause the ILDASM to show the TypeRef and TypeSpec elements that appear in a compiled (non-emitted) assembly trying to explicitly implement a PCL interface method. I was able to successfully verify an emitted assembly using this technique.

Eric
  • 33
  • 2