简体   繁体   English

如何将对象转换为自己的类型?

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

I've read several posts on this problem but none of the answers seem to work for me. 我已经阅读了几个关于这个问题的帖子,但没有一个答案似乎适合我。 Here is the situation--I have a generic function to call in another class: 这是情况 - 我有一个通用函数来调用另一个类:

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
        }
    }
}

and the calling code: 和调用代码:

public class Effect {
    public Event myEvent;

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

The problem is that Event has dozens of derived types, and I need the Notify() call to happen with the derived type as X. So far, it just calls Notify< Event >() no matter what kind of Event I pass in. The only solution that compiles is to call Notify(myEvent as DerivedEvent), but that has to be hardcoded for every single type--not acceptable. 问题是Event有几十个派生类型,我需要将Notify()调用与派生类型一起发生为X.到目前为止,它只调用Notify <Event>(),无论我传入什么类型的事件。编译的唯一解决方案是调用Notify(myEvent作为DerivedEvent),但必须对每种类型进行硬编码 - 这是不可接受的。

A similar function infers properly if I give it a "this" pointer from an instance of the derived class. 如果我从派生类的实例中给它一个“this”指针,那么类似的函数会正确推断。

Surely there's a solution using Reflection here. 当然,这里有一个使用Reflection的解决方案。

You've got two issues. 你有两个问题。

First, your generics are leaking. 首先,你的泛型正在泄漏。 Whenever you need to determine what type a particular instance is, your function is no longer generic. 每当您需要确定特定实例的类型时,您的函数就不再是通用的。 Consider your design flawed and re-examine what you are trying to do. 考虑您的设计存在缺陷,并重新检查您要做的事情。

Second, IListener<X,Y> is not a type. 其次, IListener<X,Y>不是一种类型。 Generics aren't generic in .NET; 泛型在.NET中不通用; the runtime determines all actual types your application will require and creates them. 运行时确定应用程序将需要的所有实际类型并创建它们。 The runtim will create, for example, a type IListener<int,string> if you actually use that in your application. 例如,如果您在应用程序中实际使用了IListener<int,string> ,那么它将创建一个类型IListener<int,string>

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

In this examle, bar is false . 在这个考试中, barfalse

Even with all this, yes, it is possible. 即使有这一切,是的,这是可能的。 You just have to understand how reflection with generic type definitions works. 您只需要了解泛型类型定义的反射是如何工作的。 This is a pretty good link at MSDN that explains how it works. 这是MSDN上一个非常好的链接,解释了它的工作原理。

I would strongly suggest that you reconsider using generics in this manner. 我强烈建议你以这种方式重新考虑使用泛型。 Sometimes abstraction ad absurdum isn't the best thing... 有时抽象广告荒谬不是最好的事情......

In order to call it as you seem to expect you would have to use reflection to generate a method of the actual type of myEvent. 为了像你期望的那样调用它,你必须使用反射来生成myEvent的实际类型的方法。 But I would stress that doing the following is a BAD idea and probably means your design needs to be rethought out. 但我要强调的是,执行以下操作是一个不好的想法,可能意味着您的设计需要重新考虑。

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

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

I didn't actually test the above code, but it would look something like that 我实际上没有测试上面的代码,但它看起来像那样

Could you just drop the constraint and check to make sure it derives from Event , like this: 你可以放弃约束并检查以确保它派生自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
            }
        }
    }
}

So I seem to have figured out a workaround on the other end. 所以我似乎已经找到了另一端的解决方法。 Instead of 代替

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

I have this mishmash: 我有这个混蛋:

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

This seems to work although I don't like having to test every interface (Windows Forms have at least 10 interfaces). 这似乎工作,虽然我不喜欢测试每个接口(Windows窗体至少有10个接口)。 I'm going to try the solution from BrandonAGr 我将尝试使用BrandonAGr的解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM