简体   繁体   English

使用内部类型作为接口转换泛型

[英]Casting generic with inner type as interface

.NET Fiddle .NET 小提琴

using System;

interface Interface { }
class Outer<T> : Interface
    where T : Interface { }
class Inner : Interface { }

public class Program
{
    public static void Main()
    {
        Type outer = typeof(Outer<>);
        Type inner = typeof(Inner);
        Type expectedType = typeof(Outer<Interface>);
        Type final = outer.MakeGenericType(inner);

        // This works
        Inner innerInstance = (Inner)Activator.CreateInstance(inner);

        // This works
        Outer<Inner> outerInstance = (Outer<Inner>)Activator.CreateInstance(final);

        // We can cast the real type
        Interface interfaceInstance = innerInstance;

        // But we cant cast with the interface as the inner type
        Outer<Interface> casted = (Outer<Interface>)outerInstance;
    }
}

This cast will fail (Outer<Interface>)outerInstance;此转换将失败(Outer<Interface>)outerInstance; as it doesn't recognise the inner type as Interface.因为它不将内部类型识别为接口。
Is there any way to force or conver it into the type Outer<Interface> rather than Outer<Inner> ?有什么方法可以强制或将其转换为类型Outer<Interface>而不是Outer<Inner>

To reduce this to what's minimally needed I renamed the types (because types named Interface , Inner , and Outer<T> scramble my brain.为了将其减少到最低需要,我重命名了类型(因为名为InterfaceInnerOuter<T>的类型扰乱了我的大脑。

interface IFoo { }

class Bar<T> : IFoo where T : IFoo
{ }

class Foo : IFoo { }

And when we simplify it, the question is why won't the compliler let us do this?当我们简化它时,问题是为什么编译器不让我们这样做?

Bar<IFoo> casted = new Bar<Foo>(); 

Every Foo is an IFoo , so why can't we do this?每个Foo都是一个IFoo ,那么为什么我们不能这样做呢?

There's always something that the compiler is protecting us from.总有一些东西是编译器保护我们的。 Sometimes it's hard to figure out what that something is.有时很难弄清楚那是什么东西。

It becomes clearer if we add a little bit to Bar<T> and another class:如果我们在Bar<T>和另一个 class 中添加一点,就会变得更清楚:

class Bar<T> : IFoo
    where T : IFoo
{
    private List<T> _foos = new List<T>();

    public void Add(T foo)
    {
        _foos.Add(foo);
    }
}

class OtherFoo : IFoo {}

If we have an instance of Bar<Foo> then the inner list contains items of types Foo .如果我们有一个Bar<Foo>的实例,那么内部列表包含Foo类型的项目。 Every item we add to the list must be of type Foo .我们添加到列表中的每个项目都必须是Foo类型。

If we could cast this as Bar<IFoo> then we could do this:如果我们可以将其转换为Bar<IFoo>那么我们可以这样做:

var x = new Bar<Foo>();
Bar<IFoo> y = (Bar<IFoo>)barOfFoo;
y.Add(new OtherFoo())

Now we can see what the compiler is preventing.现在我们可以看到编译器正在阻止什么。 x is a Bar<Foo> . xBar<Foo> Every item in the _foos list must be a Foo . _foos列表中的每个项目都必须是Foo

But by casting the object as Bar<IFoo> we would make it possible to add an OtherFoo to the list.但是通过将 object 转换为Bar<IFoo>我们可以将OtherFoo添加到列表中。 That wouldn't make any sense.那没有任何意义。 It's a List<Foo> , so how could we add something to the list that isn't a Foo ?这是一个List<Foo> ,那么我们如何向列表中添加一些不是Foo的东西呢?


Here's an even simpler version that illustrates the same principle with less noise:这是一个更简单的版本,它以更少的噪音说明了相同的原理:

var listOfFoo = new List<Foo>();
var listOfIFoo = (List<IFoo>)listOfFoo; // we can't do this!
listOfIFoo.Add(new OtherFoo());

We may have tried to do this at some point.我们可能在某个时候尝试过这样做。 The compiler doesn't allow it for exactly the same reason.出于完全相同的原因,编译器不允许这样做。 It would allow us to create a List<Foo> and then add something to it that's not a Foo .它允许我们创建一个List<Foo>然后向它添加一些不是Foo的东西。

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

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