HTML5技术

那些年搞不懂的术语、概念:协变、逆变、不变体 - 农码一生

字号+ 作者:H5之家 来源:H5之家 2016-08-30 17:00 我要评论( )

简述什么是协变性、逆变性、不变性泛型委托的可变性 先使用框架定义的泛型委托Func和Action做例子( 不了解的 ) 协变: (string-object) Func ;Func object func2 = func1 ; 逆变: (object-string) Action object func3 = t = { };Action string func4 = fu

简述什么是协变性、逆变性、不变性 泛型委托的可变性

先使用框架定义的泛型委托Func和Action做例子(不了解的

协变:(string->object)

Func<; Func<object> func2 = func1;

逆变:(object->string)

Action<object> func3 = t => { }; Action<string> func4 = func3;

上面代码没有任何问题。

接着我们自己定义委托试试:

我X,看人不来哦。为什么自定义的委托却不能协变呢。

我看看系统定义的Func到底和我们自定义的有什么不同:

public delegate TResult Func<out TResult>();

多了一个out,什么鬼:

  • (来源)
  • 那么我们可以修改自定义委托:

    完美!

    那如果我们要实现逆变性呢:

    直接逆变是不可行的,我们需要修改泛型类型参数:

    我们发现整个委托参数都变了。本来的返回值,改成输入参数才行。

    结论:

  • in->输入参数->可逆变(父类到子类的转变[如 object->string])
  • out->返回值->可协变(子类到父类的转变[如 string->object])
  •  

    假设:如果泛型参数中既存在in又存在out改如何:

    delegate Tout MyFunc<in Tin, out Tout>(Tin obj);

    MyFunc<; MyFunc<string, string> str2 = str1;//第一个泛型的逆变(object->string) MyFunc<object, object> str3 = str1;//第二个泛型的协变(string->object) MyFunc<string, object> str4 = str1;//第一个泛型的逆变和第二个泛型的协变

    以上都是没有问题的。 

    然后我们看看编译后的C#代码:

    结论:

  • 所谓的逆变其实只是编译后进行了强制类型转换而已。
  • 以上代码也可以直接写成:

    //delegate Tout MyFunc<in Tin, out Tout>(Tin obj); MyFunc<; MyFunc<; MyFunc<;

    泛型接口的可变性

    接着看框架默认接口:

    协变:(子类->父类)

    IEnumerable<string> list = new List<string>(); IEnumerable<object> list2 = list;

    逆变:(父类-> 子类)

    IComparable<object> list3 = null; IComparable<string> list4 = list3;

    接下来我们试试自定泛型接口:

    首先定义测试类型、接口:

    People { } Teacher : People { } IMotion<T> { } Run<T> : IMotion<T> { }

    然后我们测试协变性:

    同样我们需要把接口 interface IMotion<T> 定义为 interface IMotion<out T> 

    IMotion<out T>{}

    IMotion<Teacher> x = new Run<Teacher>(); IMotion<People> y = x;

    如果我们要测试逆变性,则需要把 interface IMotion<T>  定义为 interface IMotion<in T> 

    IMotion<in T>{}

    IMotion<People> x2 = new Run<People>(); IMotion<Teacher> y2 = x2;

    泛型接口的逆变,编译后同样进行了强制转换:

    当然,我们也可以直接写成:

    IMotion<Teacher> y3 = new Run<People>();

    不变性

    从上面我们知道逆变性的代码编译后都会进行强制转换。假设:那我们不用out、in直接手动强制转换是否可以?:

    People { } Teacher : People { } IMotion<T> { } Run<T> : IMotion<T> { }

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 开源的那些事儿 (一)- 如何看待开源 - LeftNotEasy

      开源的那些事儿 (一)- 如何看待开源 - LeftNotEasy

      2016-08-24 10:00

    • 那些年我们一起过的JS闭包,作用域,this,让我们一起划上完美的句号。 - 追梦子

      那些年我们一起过的JS闭包,作用域,this,让我们一起划上完美的句号

      2016-08-19 18:00

    • 【腾讯Bugly干货分享】H5 视频直播那些事 - 腾讯bugly

      【腾讯Bugly干货分享】H5 视频直播那些事 - 腾讯bugly

      2016-08-14 15:00

    • 那些牛掰的 HTML5的API(二) - 小花大方

      那些牛掰的 HTML5的API(二) - 小花大方

      2016-06-16 13:00

    网友点评
    y