简体   繁体   English

如何使用反射转换为通用接口?

[英]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为ApplePear宣布基本类型的提议,即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并对ApplePear上的常用功能执行逻辑。

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.

相关问题 如何使用反射来查找开放泛型类型上的哪个开放泛型参数实现泛型接口? - How can I use reflection to find which open generic argument on an open generic type implements a generic interface? 如何使用反射获取通用接口的实现 - How to use reflection to get implementations of a generic interface 如何将命令对象投射到其通用接口? - How can I cast my command object to its generic interface? 如何使用反射将一个对象动态转换为另一个对象? - How can I use reflection to dynamically cast one object to another? C#:如何使用反射来投射对象? - C#: How can I use reflection in order to cast an object? C#如何重构代码以使用接口反射 - C# How can I refactor code to use interface reflection 如何使用反射将未知属性正确地转换为从公共基础派生的通用列表? - How do I use reflection to properly cast an unknown property to a generic list that derives from a common base? 如何转换此通用接口? - How do I cast this generic interface? 为什么不能从具有通用参数的类型转换为通用接口,该类型是接口中通用参数的子类型? - Why can I not cast to a generic interface from a type with a generic argument which is a subtype of the generic argument in my interface? 可以转换为接口,但不能转换为泛型 - Can cast to interface, but not to generic type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM