C#将带有接口的泛型,继承类型转换为具有相同接口的基类型

时间:2017-02-19 16:00:55

标签: c# generics

美好的一天,所有。

我可以问你逻辑为什么这是不可能的? 我在学习界面&现在通用,我认为这是可能的,因为集团实现了iPoppable& amp; iPushable。但编译器抱怨说,将iPoppable转换为Group是不可能的。我想知道为什么这是不可能的逻辑。

interface iPoppable<out T>{T Pop();}
interface iPushable<in T>{void Push(T ag_t);}

class Program
{
    static void Main()
    {
        iPoppable<Lion> lions = new Group<Lion>();
        iPoppable<Animal> animals = lions; //Possible
        Group<Lion> lions2 = lions; //Not possible
    }
}

class Animal{}
class Lion:Animal{}

class Group<T>:iPoppable<T>, iPushable<T>
{
    public void Push(T ag_t){}
    public T Pop(){return something;}
}

1 个答案:

答案 0 :(得分:3)

好的,一步一步。

iPoppable<Lion> lions = new Group<Lion>();

Works,因为Group实现了iPoppable,而通用参数T是相同的。

iPoppable<Animal> animals = lions;

可以使用,因为iPoppableLion都来自Animal。更正式地说,这是协方差的一个例子。

  

使用更多派生类型参数实例化的对象将分配给使用较少派生类型参数实例化的对象。保留分配兼容性。

Microsoft Docs

Group<Lion> lions2 = lions;

不起作用,因为您将接口类型分配给类类型。 iPoppable只是说lionsLion Pop();方法,不再有!通过说Group<Lion> lions2 = lions;,您声称lions2是一个功能齐全的Group对象,它具有Group类的所有方法和属性。哪个不一定为真,这就是编译器抱怨的原因。

您可以通过说

来帮助编译
Group<Lion> lions2 = (Group<Lion>)lions;

因为你知道一个事实,特别是lions,虽然类型iPoppable实际上是Group

为了说明编译器害怕的内容,请参阅以下代码段。

interface iPoppable<out T>
{
    T Pop();
}
interface iPushable<in T>
{
    void Push(T ag_t);
}

class Program
{
    static void Main()
    {
        // Here, we know the truth, so we cast
        iPoppable<bool> group = new Group<bool>();
        Group<bool> group2 = (Group<bool>)group; // Possible

        // What about here? We also convert iPoppable to Group...
        iPoppable<bool> notGroup = new NotGroup<bool>();
        Group<bool> notGroup2 = (Group<bool>)notGroup; // Bad... Compiler was right...

        notGroup2.HelloGroup = true; // HA! Runtime exception.
        // That's what compiler was worrying about.

        // System.InvalidCastException: Unable to cast object of 
        // type 'NotGroup`1[System.Boolean]' to type 'Group`1[System.Boolean]
    }
}

class Group<T> : iPoppable<T>, iPushable<T>
{
    public void Push(T ag_t) { }
    public T Pop() { return default(T); }

    public bool HelloGroup { get; set; }
}

class NotGroup<T> : iPoppable<T>, iPushable<T>
{
    public void Push(T ag_t) { }
    public T Pop() { return default(T); }

    public bool HelloNotGroup { get; set; }
}