2013-08-24 137 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 
} 

神奇的功能是它可以將接收器投射到創建的類型?此外,我需要有一個解決方案,在網點3.5和網點4都可以使用。

+0

我編輯了您的標題。請參閱:「[應該在其標題中包含」標籤「](http://meta.stackexchange.com/questions/19190/)」,其中的共識是「不,他們不應該」。 –

+0

謝謝@JohnSaunders,注意到 – Bernard

回答

2

沒有一種鑄件可以做到這一點。 Casting是關於檢查運行時類型是否是已知的編譯時類型。你甚至沒有編譯時間類型。

你需要做的是使用反射來尋找接口,提取泛型類型參數,創建一個兼容的委託,並掛接委託處理程序。你有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。這個想法是,你會建立一個你確定類型的lambda表達式(可以是強類型的),編譯它,然後在你的對象上執行它來執行轉換。如果你100%需要這樣做,這是我看的方向。