簡體   English   中英

如何將對象轉換為自己的類型?

[英]How do I cast an object to its own type?

我已經閱讀了幾個關於這個問題的帖子,但沒有一個答案似乎適合我。 這是情況 - 我有一個通用函數來調用另一個類:

public class Dispatcher<T> where T : Event {
    public void Notify<X>(X tEvent) where X : Event {
        if (someField is IListener<X, T>) {
             //this never executes--X is Event regardless of its derived type
        }
    }
}

和調用代碼:

public class Effect {
    public Event myEvent;

    public CallNotify() {
        Dispatcher.Notify(myEvent);
    }
}

問題是Event有幾十個派生類型,我需要將Notify()調用與派生類型一起發生為X.到目前為止,它只調用Notify <Event>(),無論我傳入什么類型的事件。編譯的唯一解決方案是調用Notify(myEvent作為DerivedEvent),但必須對每種類型進行硬編碼 - 這是不可接受的。

如果我從派生類的實例中給它一個“this”指針,那么類似的函數會正確推斷。

當然,這里有一個使用Reflection的解決方案。

你有兩個問題。

首先,你的泛型正在泄漏。 每當您需要確定特定實例的類型時,您的函數就不再是通用的。 考慮您的設計存在缺陷,並重新檢查您要做的事情。

其次, IListener<X,Y>不是一種類型。 泛型在.NET中不通用; 運行時確定應用程序將需要的所有實際類型並創建它們。 例如,如果您在應用程序中實際使用了IListener<int,string> ,那么它將創建一個類型IListener<int,string>

var foo = new List<int>();
var bar = foo.GetType() == typeof(List<>);

在這個考試中, barfalse

即使有這一切,是的,這是可能的。 您只需要了解泛型類型定義的反射是如何工作的。 這是MSDN上一個非常好的鏈接,解釋了它的工作原理。

我強烈建議你以這種方式重新考慮使用泛型。 有時抽象廣告荒謬不是最好的事情......

為了像你期望的那樣調用它,你必須使用反射來生成myEvent的實際類型的方法。 但我要強調的是,執行以下操作是一個不好的想法,可能意味着您的設計需要重新考慮。

MethodInfo openGenericMethod = OtherClass.GetType().GetMethod("Notify");
MethodInfo closedGenericMethod = openGenericMethod.MakeGenericMethod(myEvent.GetType());

closedGenericMethod.Invoke(OtherClass, new object[]{ myEvent });, 

我實際上沒有測試上面的代碼,但它看起來像那樣

你可以放棄約束並檢查以確保它派生自Event ,如下所示:

public class Dispatcher<T> where T : Event {
    public void Notify<X>(X tEvent) {
        if(typeof(tEvent).IsSubclassOf(typeof(Event))
        {
            if (someField is IListener<X, T>) {
                //this never executes--X is Event regardless of its derived type
            }
        }
    }
}

所以我似乎已經找到了另一端的解決方法。 代替

public class Dispatcher<T> where T : Event {
    public void Notify<X>(X tEvent) where X : Event {
        foreach (Object l in listeners) {
            if (l is IListener<X, T>) { //never true
                (l as IListener<X, T>).OnEvent();
            }
        }
    }
}

我有這個混蛋:

public class Dispatcher<T> where T : Event {
    public void Notify<X>(X tEvent) where X : Event {
        foreach (Object l in listeners) {
            foreach (Type t in l.GetType().GetInterfaces()) {
                Type[] temp = t.GetGenericArguments();
                if (temp.Count() > 0 && temp[0] == tEvent.GetType()) {
                    MethodInfo mi = t.GetMethod("OnEvent", new Type[] {tEvent.GetType()});
                    mi.Invoke(l, new object[] { tEvent });
                }
            }
        }
    }
}

這似乎工作,雖然我不喜歡測試每個接口(Windows窗體至少有10個接口)。 我將嘗試使用BrandonAGr的解決方案

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM