Reputation: 12407
I'm using Reflection.Emit to define a new type, and I'd like the type to implement IComparable(T)
, where T
would be the newly defined type.
class DefinedType : IComparable<DefinedType>
{
//...
}
It seems to me like I have a chicken-and-egg problem.
As a fallback, I can always just implement IComparable
, but if possible I'd like the generic interface; I just can't see how I can do it using Emit, because the type doesn't exist before I define it.
Upvotes: 5
Views: 1221
Reputation: 63772
This should work:
var tb = mb.DefineType("Test", TypeAttributes.Public);
var iface = typeof(IComparable<>).MakeGenericType(tb);
tb.AddInterfaceImplementation(iface);
var meb = tb.DefineMethod("CompareTo", MethodAttributes.Public | MethodAttributes.Virtual, typeof(int), new [] { tb } );
var il = meb.GetILGenerator();
il.ThrowException(typeof(Exception));
var type = tb.CreateType();
Fortunately, TypeBuilder inherits from Type, so you can use it in MakeGenericType
.
As a verification, this works:
var o1 = Activator.CreateInstance(type);
var o2 = Activator.CreateInstance(type);
typeof(IComparable<>).MakeGenericType(o1.GetType()).GetMethod("CompareTo").Invoke(o1, new [] { o2 }).Dump();
You don't have to bind the generated method to the interface in any way, it's enough that their signature is the same. Doing explicit interface implementation might be a bit more tricky, but you shouldn't need that.
Upvotes: 4
Reputation: 244998
When calling MakeGenericType()
to turn IComparable<>
into IComparable<DefinedType>
, you can just pass it your TypeBuilder
. The code could look something like:
var boundComparerType = typeof(IComparable<>).MakeGenericType(typeBuilder);
typeBuilder.AddInterfaceImplementation(boundComparerType);
Upvotes: 2