2014-01-10 2 views
5

Я использую Reflection.Emit для определения нового типа, и я бы хотел, чтобы тип реализовал IComparable(T), где T был бы новым типом.Использование Reflection.Emit для реализации общего интерфейса

class DefinedType : IComparable<DefinedType> 
{ 
//... 
} 

Мне кажется, что у меня проблема с курицей и яйцом.

Как резерв, я всегда могу просто реализовать IComparable, но, если возможно, мне нужен общий интерфейс; Я просто не могу понять, как я могу это сделать, используя Emit, потому что тип не существует до того, как я его определю.

+0

Желание у меня было время, чтобы поиграть с этим .., но я с нетерпением жду другого, кто отвечает! –

+0

Я вижу метод ['addInterfaceImplementation'] (http://msdn.microsoft.com/en-us/library/system.reflection.emit.typebuilder.addinterfaceimplementation (v = vs.110) .aspx), который вы можете вызвать на вашем ['TypeBuilder'] (http://msdn.microsoft.com/en-us/library/system.reflection.emit.typebuilder (v = vs.110) .aspx) после того, как вы построили новый тип. Разве вы не сможете добавить 'Comparable ' после этого к вашему типу с помощью этого метода? –

+0

@JeroenVannevel Я не думаю, что это разрешено. Я уверен, что вы можете только один раз вызвать CreateType. – Anthony

ответ

3

Это должно работать:

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(); 

К счастью, TypeBuilder наследуется от типа, так что вы можете использовать его в MakeGenericType.

Как проверки, это работает:

var o1 = Activator.CreateInstance(type); 
var o2 = Activator.CreateInstance(type); 

typeof(IComparable<>).MakeGenericType(o1.GetType()).GetMethod("CompareTo").Invoke(o1, new [] { o2 }).Dump(); 

Вам не нужно связывать сгенерированный метод интерфейса в любом случае, это достаточно того, что их подпись такая же. Выполнение явной реализации интерфейса может быть немного сложнее, но вам это не нужно.

+0

О, я вижу, ответ svick уже предлагает это. Ну, вот полный рабочий образец, так что не стесняйтесь принимать ответ svick или мой, как вы пожелаете :) – Luaan

2

При звонке MakeGenericType(), чтобы позвонить IComparable<> в IComparable<DefinedType>, вы можете просто передать его TypeBuilder. Код может выглядеть примерно так:

var boundComparerType = typeof(IComparable<>).MakeGenericType(typeBuilder); 
typeBuilder.AddInterfaceImplementation(boundComparerType);