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!
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 providedMethodInfois aRuntimeMethodInfo. Ultimately a call toGetMemberRefOfMethodInfocauses the inclusion ofSystem.Runtime, producing conflicting results for certain types, such asIEnumerable.To solve this in a manner that doesn't require reflecting into private members, you can create a proxy or wrapper that inherits
MethodInfowhich overrides all methods to return results from the originalRuntimeMethodInfo. 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.