I am attempting to generate a dynamic class implementing an interface, but where one or more of the members already exists in the base. I compiled the following code in C# a
The C# compiler actually emits different code for BaseType
depending on whether your SubClass
definition is in the same assembly or not. So if you just have this:
interface IStuff
{
string Bob { get; }
}
public class BaseClass
{
public string Bob
{
get { return "Bob"; }
}
}
and then define SubClass
in another C# project, then the compiler will actually emit an explicit interface implementation within it. This is because in this case, BaseClass.get_Bob
will be defined as non-virtual, which means that it can't be used to satisfy the interface's contract.
See also Why are C# interface methods not declared abstract or virtual?, which explicitly discusses this oddity at the end of the answer.
It looks like with TypeBuilder
you will have to add a private pass-thru, just to make it happy (below). You could also try using the IKVM builder - almost identical API, but it might not have this limitation.
using System;
using System.Reflection;
using System.Reflection.Emit;
public class BaseClass
{
public string Bob
{
get { return "Bob"; }
}
}
public interface IStuff
{
string Bob { get; }
}
static class Program
{
static void Main()
{
var name = new AssemblyName("foo");
var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
var mod = asm.DefineDynamicModule("foo");
var parent = typeof(BaseClass);
var type = mod.DefineType("SubClass", parent.Attributes, parent);
type.AddInterfaceImplementation(typeof(IStuff));
var bob_get = type.DefineMethod("bob_get", MethodAttributes.Virtual | MethodAttributes.Private,
typeof(string), Type.EmptyTypes);
var il = bob_get.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Callvirt, parent.GetProperty("Bob").GetGetMethod(), null);
il.Emit(OpCodes.Ret);
type.DefineMethodOverride(bob_get, typeof(IStuff).GetProperty("Bob").GetGetMethod());
var final = type.CreateType();
IStuff obj = (IStuff) Activator.CreateInstance(final);
Console.WriteLine(obj.Bob);
}
}