.NET中的逆变协变
MSDN上的说法:
协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型----------(注意,这里说的可以使用更具体的类型是指可以给跟具体的类型传递相对不太具体的参数)。 泛型类型参数支持协变和逆变,可在分配和使用泛型类型方面提供更大的灵活性。 在引用类型系统时,协变、逆变和不变性具有如下定义。 这些示例假定一个名为 Base 的基类和一个名为 Derived 的派生类。使你能够使用比原始指定的类型更泛型(派生程度更小)的类型。你可以向 IEnumerable<Derived> 类型的变量分配 IEnumerable<Base>(在 Visual Basic 中为 IEnumerable(Of Base))的实例。
感觉MSDN说的还是有些拗口。
逆变:Contravariance,类型参数用 in 关键字。
简单来说就是假设有一个泛型逆变接口IDo<in T>,有两个可以替换T的类型A和B时,B如果继承自A时,可以将IDo<A>的实例赋值给IDo<B>,例如:
private void button1_Click(object sender, EventArgs e)
{ IDo<A> a = new DoT<A>();
IDo<B> b = new DoT<B>(); Run run = new Run();
run.Set<D>(a);
} interface IDo<in T>
{
void Do(T t); } class A { }
class B : A { }
class D : B { }
class C : A { }
class E : C { } class DoT<T> : IDo<T>
{
public void Do(T t)
{
MessageBox.Show(t.GetType().ToString());
}
} class Run
{
public void Set<T>(IDo<T> it) where T : new()
{
it.Do(new T());//返回D的类型
MessageBox.Show(it.GetType().ToString());//返回A的接口类型
}
}
协变:Covariance,类型使用out关键字。
这个相对于逆变来说更容易理解,当有接口IDo<out T>时,有两个可以替换T的类型A和B时,B如果继承自A时,可以将IDo<B>的实例赋值给IDo<A>,说这更容易理解是因为里氏替换大家会熟悉些,这个看起来有些像,不过不要混淆,这是两回事,例子:
interface IDo<out T>
{
T get();
} private void button1_Click(object sender, EventArgs e)
{
IDo<A> a = new DoT<A>();
IDo<B> b = new DoT<B>(); Run run = new Run();
run.Set<A>(b);
}
另外需要注意的,使用了in的T只能用做输入参数,不能用做返回值。使用了out做参数的只能用做返回值,不能做输入参数。
我曾经写过一个随笔,实现中使用了协变的特性:由继承演变为角色扮演。
.NET中的逆变协变的更多相关文章
- Java中的逆变与协变
看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...
- Java中的逆变与协变(转)
看下面一段代码 Number num = new Integer(1); ArrayList<Number> list = new ArrayList<Integer>(); ...
- OOP中的逆变和协变
逆变和协变在存在于强类型语言中,尽管非常少提及.可是里面蕴含了面向对象的世界观.感谢和我一起讨论这个问题的人. 这里用了C#.Scala的语法作为演示样例.事实上逆变和协变的概念跟语言本身关系不大.事 ...
- Java中的逆变与协变 专题
结论先行: PECS总结: 要从泛型类取数据时,用extends: 协变 要往泛型类写数据时,用super: 逆变 既要取又要写,就不用通配符(即extends与super都不用) 不变 List&l ...
- Java中的逆变与协变 很直接不饶弯的讲出来了
```java 协变 extends只能new 辈分比自己低的家伙 List<? extends Number> list001 = new ArrayList<Integer> ...
- C#中的逆变和协变
msdn 解释如下: “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型. “逆变”则是指能够使用派生程度更小的类型. 解释的很正确,大致就是这样,不过不够直白. 直白的理解: “协变” ...
- 【温故而知新-万花筒】C# 异步编程 逆变 协变 委托 事件 事件参数 迭代 线程、多线程、线程池、后台线程
额基本脱离了2.0 3.5的时代了.在.net 4.0+ 时代.一切都是辣么简单! 参考文档: http://www.cnblogs.com/linzheng/archive/2012/04/11/2 ...
- C#-逆变 协变 反射 代码
首先看一段测试代码,自己写的 class Program { static void Main(string[] args) { man OneMan = new man(); var d = One ...
- .NET 4.0中的泛型的协变和逆变
转自:http://www.cnblogs.com/jingzhongliumei/archive/2012/07/02/2573149.html 先做点准备工作,定义两个类:Animal类和其子类D ...
随机推荐
- 细说WebSocket - Node篇
在上一篇提高到了 web 通信的各种方式,包括 轮询.长连接 以及各种 HTML5 中提到的手段.本文将详细描述 WebSocket协议 在 web通讯 中的实现. 一.WebSocket 协议 1. ...
- Android数据加密之Base64编码算法
前言: 前面学习总结了平时开发中遇见的各种数据加密方式,最终都会对加密后的二进制数据进行Base64编码,起到一种二次加密的效果,其实呢Base64从严格意义上来说的话不是一种加密算法,而是一种编码算 ...
- LeetCode[5] 最长的回文子串
题目描述 Given a string S, find the longest palindromic substring in S. You may assume that the maximum ...
- Android SDK 在线更新镜像服务器资源
本文转自:http://blog.kuoruan.com/24.html.感谢原作者. 什么是Android SDK SDK:(software development kit)软件开发工具包.被软件 ...
- document.compatMode
在我电脑屏幕上显示的 电脑是 1920*1080这是在document.compatMode:css1Compat模式 window.screen.availWidth 1920 window.scr ...
- Android—Volley:接收服务端发送的json数据乱码问题解决
new JsonObjectRequest中重写方法parseNetworkResponse,内容如下: /** * 重写此方法不会导致乱码 */ @Override protected Respon ...
- XAMARIN.ANDROID SIGNALR 实时消息接收发送示例
SignalR 是一个开发实时 Web 应用的 .NET 类库,使用 SignalR 可以很容易的构建基于 ASP.NET 的实时 Web 应用.SignalR 支持多种服务器和客户端,可以 Host ...
- windows10安装mysql5.7.17是这样安装的吗?
操作 全允许
- sql server 取文件名函数 转载
/****** Object: UserDefinedFunction [dbo].[GetDirectoryPath] Script Date: 2016-12-16 16:54:05 ****** ...
- 你从未知道如此强大的ASP.NET MVC DefaultModelBinder
看到很多ASP.NET MVC项目还在从request.querystring或者formContext里面获取数据,这实在是非常落后的做法.也有的项目建了大量的自定义的modelbinder,以为很 ...