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 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.
User contributions licensed under CC BY-SA 3.0