首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >CoVariance反差

CoVariance反差
EN

Stack Overflow用户
提问于 2011-09-15 22:24:13
回答 2查看 265关注 0票数 2

我对CoVariance和ContraVariance有一点怀疑。请参阅以下代码。

代码语言:javascript
运行
复制
interface IGetElement<out T>
{
    int Counter { get; }
    T GetNext();
}

interface IAddElement<in T>
{
    void Add(T t);
}

class Collection<T> : IAddElement<T>, IGetElement<T> where T : Fruit
{
    List<T> tList = new List<T>();

    private int _counter = 0;

    public int Count { get { return tList.Count; } }

    public void Add(T t)
    {
        tList.Add(t);
    }

    int IGetElement<T>.Counter
    {
        get { return _counter; }
    }

    public T GetNext()
    {
        return tList[_counter++];
    }

    public void Rset()
    {
        _counter = 0;
    }
}

abstract class Fruit
{
    public abstract void Taste();
}

class Apple : Fruit
{
    public override void Taste()
    {
        Console.WriteLine("Like Apple");
    }
}

这是示例代码..现在客户是

代码语言:javascript
运行
复制
 static void Main(string[] args)
 {
        IGetElement<Fruit> covarience = new Collection<Apple>(); // CoVarience..

        IAddElement<Apple> contravarience = new Collection<Fruit>();//ContraVarience.. Compiling fine and working also fine... :)

        IGetElement<Fruit> fruits = new Collection<Apple>();

        IAddElement<Fruit> apples2 = fruits as IAddElement<Apple>;//Here its Compiler error : Cannot implicitly convert type 'Test.IAddElement<Test.Apple>' to 'Test.IAddElement<Test.Fruit>'. An explicit conversion exists (are you missing a cast?)  

        IAddElement<Apple> apples1 = fruits as IAddElement<Fruit>;//This is not posible  
        /* Why this is not possible..? In this case No Compiler Error But Run Time error ie., 
       apples1 is NULL.. I don't know why.. because.. in fruits cantains apple only but 
       It is unable it caste it as ContrVariantly..  ?------------1 */

        IAddElement<Apple> apples = fruits as IAddElement<Apple>;//This is posible 


        IGetElement<Fruit> f = apples as IGetElement<Apple>;//This is posible.. 
        /* Why this is posible.. ? here we are casting t as CoVariantly..
        If ------------1 is not posible how this would be posible... yes.. I am casting to    
        actual object which is not Null.. ? -----------2 */
  }

请在评论源代码中回答我的问题...:) -1,-2.

谢谢和问候,Dinesh

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-09-15 22:54:46

在James的回答上做一点扩展:

  1. 为什么这是不可能的?在这种情况下,没有编译器错误,但在运行时apples1为null。我不知道为什么。

运行时的局部变量fruits引用Collection<Apple>类型的对象。也就是说,一个只包含苹果的集合。

你在问“我能不能把any水果添加到这个集合中?”不是的。你只能添加苹果,不能添加任何水果。因此,结果为空。

这在运行时失败而不是在编译时失败的原因是因为水果的编译时类型是接口类型,而您正在将其转换为不同的接口类型。任何两个接口都可以由给定的对象实现;编译器不会进行流分析来确定fruits只分配了一种特定的类型。因此,只有在运行时才能进行检查。

  1. 为什么这是可能的?在这里,我们进行协变转换。

这里有两个转换。首先,苹果被转换为IGetElement<Apple>,然后被协变地转换为IGetElement<Fruit>

第一次转换成功是因为局部变量apples引用了实现IGetElement<Apple>Collection<Apple>。你在问“这个物体能递给我一个苹果吗?”答案是肯定的。

第二次转换成功是因为编译器知道“一个可以递给我一个苹果的对象”可以被安全地视为“一个可以递给我一个水果的对象”。

现在清楚了吗?

票数 5
EN

Stack Overflow用户

发布于 2011-09-15 22:38:53

#1上,IAddElement<in T>是逆变的,in让你知道它与更“限制性”的类型兼容,即更窄。由于您是as,将Collection<Apple>转换为IAddElement<Fruit>,您正在扩大(使其更通用)协方差而不是逆方差的类型,因此这在运行时失败,并且从返回空作为强制转换。

请注意,它失败的原因是您的作为强制转换,而不是从IAddElement<Fruit>IAddElement<Apple>的逆变量赋值,这是逆变量和合法的。但是由于作为的转换不起作用,它返回null,然后赋值。

#2上,是一个Collection<Apple>,而苹果仍然指水果。当你把苹果扔给IGetElement<Apple>时,这是可行的,因为Collection<Apple>很好地实现了IGetElement<Apple>

这既不是协变也不是逆变,因为类型是相同的(Apple)。然后可以将其分配给IGetElement<Fruit>,这是一个加宽操作(协变),由于IGetElement<Fruit>被标记出来,因此它支持这一点。

希望这能有所帮助!

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7432447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档