zoukankan      html  css  js  c++  java
  • C# 协变 逆变

    逆变,协变

    定义:

    逆变 :指能够使用比原始指定的派生类型的 派生程度更小(不太具体的)的类型。

    协变 :能够使用比原始指定的派生类型的 派生程度更大(更具体的)的类型。

    看了上面一脸懵逼,下面会解释

    示例

    这是用来讲解例子的两个类

    public class Father
    {
        public string Name { get; set; }
    }
    
    public class Son : Father
    {
        public int Age { get; set; }
    }
    

    协变 out

    Father f = new Son();
    

    先来看这一句 这是我们熟悉的, 因为Son继承自Father, 所以编译可以通过。

    我们可以认为:

    Father(基类) 相对于 Son(子类) 是派生程度更大(更具体的)的类型。 具体,代表一个父类可以有多个子类。所以相对而言基类更具体 子类不太具体

    Son(子类) 相对于 Father(基类) 是派生程度更小(不太具体的)的类型

    再来看这一句

    List<Son> sons = new List<Son>();
    List<Father> fathers = sons; // error
    

    为什么为编译失败呢,因为编译器知道 Father 和 Son 是继承关系,但是不知道List< Father > 和 List< Son > 是什么关系。

    List<Son> sons = new List<Son>();
    IEnumerable<Father> fathers = sons; // success
    

    这是协变,可以允许使用比原指定类型派生程度更大(更具体的)的类型。

    逆变 in
    逆变也称为不正常的变化
    比如Father转为Son,这肯定不行。

    
    static void Main(string[] args)
    {
        ISay<Father> fatherSay = new FatherSay();
    
        ISay<Son> son1 = fatherSay;
        son1.Say(new Son()); // new Son()这里就是 传的是派生程度更低的类型,  而指定的是父类,我对父类的操作肯定也可以传递到子类
    } 
    
    public interface ISay<in T>
    {
        void Say(T t); 
    }
    
    public class FatherSay : ISay<Father>
    {
        public void Say(Father t)
        {
            Console.WriteLine(t.Name);
        }
    }
    

    定义ISay接口 我指定的类型是Father 既然father有say().Name 为什么Son不能呢,所以使用逆变.

    这是逆变 可以使用比原指定类型派生程度更小(不太具体的)的类型。

    其实就是希望当作为返回的时候,期望的是派生程度更高的类型,你指定一个子类,我希望他能返回,他的父类,或者父类的父类。这样我才能保证输出的正确,比如我返回个父类,你却非要子类,而子类里入上例有一个属于自己的age属性,所以就不满足

    而作为参数类型,我希望传的是派生程度更低的类型,因为你指定的是父类,我对父类的操作肯定也可以传递到子类。而为什么不能传派生程度更高的类型,比如你指定的是子类,但是传的是父类, 那你怎么保证对子类的操作,会传递到父类。

    相当于
    协变: Father f() => new Son(); 所以作为返回值时可以更具体
    逆变:指定父类Father Say(Father f)=> f.Name我传入子类Say(Son s) => s.Name一定满足, 而如果我指定子类Son Say(Son s) => s.Age
    然后传入父类 Say(Father f) => f.Age ?可以看到父类是没有age的 所以逆变我们需要传入派生程度更低(不具体)的类型

  • 相关阅读:
    golang实现并发爬虫一(单任务版本爬虫功能)
    golang实现rabbitmq的五种模式
    KNN笔记
    Observer Pattern
    关于data-属性
    Python中的装饰器
    Python中的高阶函数与匿名函数
    Python中的列表生成式和多层表达式
    Thymeleaf读取国际化文本时出现??xxxxxx_zh_CN??问题
    Java8新特性(1):Lambda表达式
  • 原文地址:https://www.cnblogs.com/caiyangcc/p/14151552.html
Copyright © 2011-2022 走看看