我已经阅读了几个关于这个问题的帖子,但没有一个答案似乎适合我。这是情况 - 我有一个通用函数来调用另一个类:
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&lt;事件&gt;()无论我传入什么类型的事件。编译的唯一解决方案是调用Notify(myEvent作为DerivedEvent),但必须对每种类型进行硬编码 - 不可接受。
如果我从派生类的实例中给它一个“this”指针,那么类似的函数会正确推断。
当然,这里有一个使用Reflection的解决方案。
答案 0 :(得分:2)
你有两个问题。
首先,你的仿制品正在泄漏。每当您需要确定特定实例的类型时,您的函数就不再是通用的。考虑一下你的设计存在缺陷,并重新审视你想要做的事情。
其次,IListener<X,Y>
不是一种类型。泛型在.NET中不通用;运行时确定应用程序将需要的所有实际类型并创建它们。例如,如果您在应用程序中实际使用了类型IListener<int,string>
,则运行时将创建类型var foo = new List<int>();
var bar = foo.GetType() == typeof(List<>);
。
bar
在此次考试中,false
为{{1}}。
即使有这一切,是的,这是可能的。您只需要了解泛型类型定义的反射是如何工作的。 This is a pretty good link at MSDN that explains how it works.
我强烈建议您以这种方式重新考虑使用泛型。有时抽象广告荒谬并不是最好的事情......
答案 1 :(得分:2)
为了按照您的预期调用它,您必须使用反射来生成myEvent的实际类型的方法。但我要强调的是,执行以下操作是一个不好的想法,可能意味着您的设计需要重新考虑。
MethodInfo openGenericMethod = OtherClass.GetType().GetMethod("Notify");
MethodInfo closedGenericMethod = openGenericMethod.MakeGenericMethod(myEvent.GetType());
closedGenericMethod.Invoke(OtherClass, new object[]{ myEvent });,
我实际上没有测试上面的代码,但它看起来像那样
答案 2 :(得分:0)
您可以放弃约束并检查以确保它派生自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
}
}
}
}
答案 3 :(得分:0)
所以我似乎已经找到了另一端的解决方法。而不是
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的解决方案