[英]How can I use reflection to cast to a generic interface?
I have a dictionary that I'm using to facilitate some internal routing based on api version numbers. 我有一个字典,我正在使用它来促进基于api版本号的内部路由。 Essentially what happens is that I look up and operation in the dictionary and attempt to call it's RUN method. 基本上发生的是我在字典中查找和操作并尝试调用它的RUN方法。 But in order to do this, I need to be able to cast the object to it's interface. 但为了做到这一点,我需要能够将对象转换为它的界面。 Here's what I mean, this is the dictionary: 这就是我的意思,这是字典:
public Dictionary<string, Type> Routing = new Dictionary<string, Type>();
public VersionRouter()
{
Routing.Add("1.0", typeof(OperationV1<RequestObjectV1, ResponseObjectV1>));
Routing.Add("2.0", typeof(OperationV1<RequestObjectV2, ResponseObjectV1>));
Routing.Add("3.0", typeof(OperationV1<RequestObjectV2, ResponseObjectV2>));
}
I can grab the correct type that I want to instantiate like so: 我可以抓住我想要实例化的正确类型:
var myOperation = Routing["2.0"];
And then under normal circumstances, I'd just instantiate and cast it like this: 然后在正常情况下,我只是实例化并将其转换为:
var myInstance = (MyInterface) Activator.CreateInstance(myOperation);
However, the interface is generic because it needs to know what the Request and Response types are: 但是,接口是通用的,因为它需要知道Request和Response类型是什么:
var myInstance = (MyInterface<TRequest, TResponse>) Activator.CreateInstance(myOperation);
I don't know how to tell it what those request and response types are at this stage. 我不知道如何告诉它在这个阶段这些请求和响应类型是什么。 I'm assuming it can be done with reflection. 我假设它可以用反射来完成。 I've found that I can get those generic parameters out through something like myOperation.GetGenericArguments() but I'm not sure how to use that to my advantage at this stage. 我发现我可以通过像myOperation.GetGenericArguments()之类的东西来获取那些通用参数,但我不确定如何在这个阶段使用它对我有利。 Does anyone know how to do this? 有谁知道如何做到这一点?
In order to expand on SLaks answer: 为了扩展SLaks答案:
There is no logical way of dealing with your scenario. 没有合理的方法来处理您的场景。 What you're trying to do is have a single piece of code work with different types at run time. 您要做的是在运行时使用不同类型的单个代码。 This can only be done by building separate code branches (which can be done) or by falling back to dynamics/reflection. 这只能通过构建单独的代码分支(可以完成)或回退到动态/反射来完成。 To clarify this: 澄清一下:
class Apple { }
class Pear { }
void Handle(object what)
{
// either
if (what is Apple) {}
else if (what is Pear) {}
// or
dynamic x = what;
x.LetsHopeThisMethodExists();
// or
what.GetType().GetMethod('lorem').Invoke(what, null);
}
Now, we can stick with SLaks proposal of declaring a base type for both Apple
and Pear
, namely Fruit
. 现在,我们可以坚持使用SLaks为Apple
和Pear
宣布基本类型的提议,即Fruit
。 That way, Handle
can accept a Fruit
and perform logic on the common functionality available on both Apple
s and Pear
s. 这样, Handle
可以接受Fruit
并对Apple
和Pear
上的常用功能执行逻辑。
That begs the question, how to do this with generics. 这引出了一个问题,如何用泛型来做到这一点。 Generics by default do not support variance, however in .NET 4.0, it's certainly possible. 默认情况下,泛型不支持方差,但在.NET 4.0中,它当然是可能的。 You can declare an interface (but only an interface) as covariant by applying the out
keyword on the type parameter. 您可以通过在type参数上应用out
关键字将接口(但只是一个接口)声明为协变。 This allows you to do something like: 这允许您执行以下操作:
interface IFruit { }
interface IBasket<out TFruit> where TFruit : IFruit { }
class Apple : IFruit { }
class Pear : IFruit { }
class FruitBasket<TFruit> : IBasket<TFruit> where TFruit : IFruit { }
void Handle(IBasket<IFruit> what) { }
Handle(new FruitBasket<Apple>());
Handle(new FruitBasket<Pear>());
That's inherently impossible. 这本质上是不可能的。
You cannot express this type at compile-time, since you don't know the type parameters until runtime. 您无法在编译时表达此类型,因为在运行时之前您不知道类型参数。
Therefore, you cannot cast to it, or have a variable of that type. 因此,您无法转换为该类型或具有该类型的变量。
If possible, you should make the interface covariant, and cast it to use a base type. 如果可能,您应该使接口协变,并将其转换为使用基类型。
Alternatively, you can make a non-generic or covariant base interface and use that instead. 或者,您可以创建非泛型或协变的基本接口并使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.