2013-08-24 4 views
2

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

У меня есть интерфейс

public interface ICustomTransmitter<T> : IDataTransmitter where T : EventArgs 
{ 
    event EventHandler<T> DataEvent; 
} 

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

public bool IsTypeOf(Type baseType, Type interfaceType, 
    out Type argumenType) 
{ 
    var interfaces = baseType.GetInterfaces(); 
    argumenType = null; 

    foreach (Type @interface in interfaces) 
    { 
     if (@interface.Name != interfaceType.Name) continue; 
     if (@interface.IsGenericType) 
     { 
      argumenType = @interface.GetGenericArguments()[0]; 
     } 
     return true; 
    } 
    return false; 
} 

И функция, которая использует магию выше

Type argument; 
var generic = typeof (ICustomTransmitter<>); 
if (IsTypeOf(receiver.GetType(),generic ,out argument)) 
{ 
    var created = generic.MakeGenericType(new[] {argument}); 

    //the line of code missing is below 
    receiver as created 
} 

ли это возможно чтобы передать получателю этот созданный тип? Также мне нужно иметь решение, которое работает как в dot net 3.5, так и в dot net 4.

+0

Я отредактировал ваше название. Пожалуйста, смотрите: «Если вопросы включают« теги »в их названиях?] (Http://meta.stackexchange.com/questions/19190/), где консенсус« нет, они не должны ». –

+0

Спасибо @JohnSaunders, отметил – Bernard

ответ

2

Нет никакого каста, который сделает это. Кастинг - это проверка того, является ли тип времени выполнения известным типом времени компиляции. У вас даже нет типа времени компиляции.

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

При подключении обработчика событий вы вызываете его метод add. Компилятор генерирует имя для этого метода, который имеет форму «add_EventName». Вот пример кода, который делает все это:

using System; 
using System.Reflection; 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     object o = new CustomArgsTransmitter(); 

     // make sure we've got the interface 
     var interf = o.GetType().GetInterface("ICustomTransmitter`1"); 

     // get the arg type. 
     var argType = interf.GetGenericArguments()[0]; 

     // create a delegate for the handler based on the arg type above 
     var handlerMethodInfo = typeof(Program).GetMethod("Handler", BindingFlags.Static | BindingFlags.Public) 
     var del = Delegate.CreateDelegate(typeof(EventHandler<>).MakeGenericType(argType), handlerMethodInfo); 

     // Invoke the add method of the event. 
     o.GetType().InvokeMember("add_DataEvent", BindingFlags.InvokeMethod, null, o, new object[] { del }); 

     // just test code at this point. 
     // fire event to make sure it is signed up. 
     // It should print a message to the console. 
     ((CustomArgsTransmitter)o).FireEvent(); 

    } 

    public static void Handler(object sender, EventArgs e) 
    { 
     Console.WriteLine("Got event {0} from {1}", e, sender); 
    } 
} 

public interface IDataTransmitter { } 

public interface ICustomTransmitter<T> : IDataTransmitter where T : EventArgs 
{ 
    event EventHandler<T> DataEvent; 
} 

public class MyArgs : EventArgs { } 

public class CustomArgsTransmitter : ICustomTransmitter<MyArgs> 
{ 
    public event EventHandler<MyArgs> DataEvent; 

    public void FireEvent() 
    { 
     DataEvent(this, new MyArgs()); 
    } 
} 
+0

Моя доброта, это прекрасное решение. Я расширил его, чтобы иметь дело с настраиваемым типом события, и как только я понял, что все это прекрасно работает! спасибо большое кучу. Не думаю, что я бы получил там один! – Bernard

1

Нет. Вы не можете использовать выражение для типа, который неизвестен во время компиляции. (Под «известным», я имею в виду разрешение на Type, общие параметры которого закрыты.)

Сказав это, я думаю, что это может быть возможно с помощью выражения API. Идея состоит в том, что вы создадите лямбда-выражение определенного вами типа (который может быть строго типизирован), скомпилируйте его, а затем выполните его на вашем объекте, чтобы выполнить трансляцию. Если вам это нужно 100%, это направление, которое я бы посмотрел.

Смежные вопросы