Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Reflection.Emit to implement generic interface

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.

like image 369
Anthony Avatar asked Jan 10 '14 03:01

Anthony


1 Answers

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.

like image 122
Luaan Avatar answered Oct 06 '22 20:10

Luaan