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# and examined it in reflector to see what the C# compiler does.
class BaseClass
{
public string Bob
{
get { return "Bob"; }
}
}
interface IStuff
{
string Bob { get; }
}
class SubClass : BaseClass, IStuff
{
}
Reflector does not show any implementation in SubClass.
.class private auto ansi beforefieldinit SubClass
extends Enterprise.Services.OperationalActions.Business.Filters.BaseClass
implements Enterprise.Services.OperationalActions.Business.Filters.IStuff
{
}
But if I do not emit the member explicitly, TypeBuilder.CreateType()
throws an InvalidOperationException
stating that the member does not have an implementation. So my question is, how do I tell TypeBuilder
that an interface member should take it's implementation from the base?
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);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With