标签:ogr hid 形式 lis 使用 方法 编码 alt 标记
最近在项目开发当中使用泛型委托Func较多,查看Func的定义就会发现Func的入参都会都会标记上in,出参都会标记上out.
in 和out和泛型类型实参有关, 其中in代表逆变,out代表协变.自己协变和逆变在设计接口或者委托的时候也没有定义过,
因此就详细了解一下其用法.
一.关于协变和逆变
在c# 4.0后,泛型类型参数分为以下三种请情况
1.不变量 这带便泛型参数类型参数不能更改
2.协变量 泛型类型参数可以从一个类更改为它的某个基类.c#中使用out关键字标记协变量形式的泛型类型参数.
协变量泛型类型参数只能出现在输出位置,作为方法的返回类型
3.逆变量 泛型类型参数可以从一个类更改为它的某个派生类.c#中使用in关键字标记逆变量形式的泛型类型参数
逆变量泛型类型参数只能出现在输入位置,作为方法的入参
比如在上述截图的代码中,T1和T2作为委托的入参,Tresult作为委托的出参
二 引入协变逆变
我们看如下代码
class Program { static void Main(string[] args) { //1. { //List<A> list = new List<B>(); error List<B>并不是List<A>的子类 } //2. { IEnumerable<A> list = new List<B>(); // IEnumerable<B> list1 = new List<A>();// ERROR } //3. { Func<A> func = null; Func<B> func1 = null; func = func1; // func1 = func; ERROR } //4. { Action<A> action = null; Action<B> action1 = null; action1 = action; // action = action1; error } } } public interface A { } public class B : A { }
(1)其中第一个注释部分很明显示编译不过的,因为前后关系并不是继承关系.
(2)第二个编译器能编译通过,第2个不能编译通过,
我们看下 IEnumerable接口的定义
public interface IEnumerable<out T> : IEnumerable
泛型类型前面标识为out
(3)第三个泛型委托中,第1个能编译通过,第二个不能
我们看下Func的定义
public delegate TResult Func<out TResult>();
泛型类型前面标识为out
(4)第四个泛型委托中,第1个能编译通过,第2个不能
我们看下Action的定义
public delegate void Action<in T>(T obj)
泛型类型前面标识为in
以上代码展示了协变和逆变的基本特性
即协变时,泛型类型参数可以从一个类更改为它的某个基类,且该类型仅可作为出参
逆变时,泛型类型参数可以从一个类更改为它的某个派生类,且该类型仅可作为入参
总结
为什必须显示使用in或则out标记类型类型参数,因为我们在编码过程中,需要我们自己去定义协议,
明确告诉编译器允许什么,那么在编译器就能识别出你的泛型类型参数到底能存在什么样的位置上,
若果不用定这个协议,那么编译器在编译时不能识别出,在运行时将会抛出未知的错误.
协变和逆变在设计框架时会有较大的帮助,后续会继续分享在设计框架时协变逆变的用法.
标签:ogr hid 形式 lis 使用 方法 编码 alt 标记
原文地址:https://www.cnblogs.com/xxue/p/9863805.html