c# 协变与抗变
定义
- 协变:与原始类型转换方向相同的可变性称为协变。
- 抗变:与派生类型转换方向相同的可变性称为抗变。
补充:
- 参数是协变的,可以使用派生类对象传入需要基类参数的方法,反之不行
- 返回值是抗变的,不能使用派生类对象接收返回了基类对象的方法返回值,反之可以
代码展示
public class 协变和抗变
{
/// <summary>
/// 基类
/// </summary>
public class Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override string ToString() => $"width:{Width},height:{Height}";
}
/// <summary>
/// 派生类
/// </summary>
public class Rect : Shape
{
}
#region 协变接口
/// <summary>
/// 协变接口 --------------- 协变--》属性和索引器必须实现get
/// </summary>
public interface IIndex<out T> // out声明接口为协变类型接口,继承了该接口的对象可以实现协变的隐式转换。 --对应调用方法中的shapes
{
T this[int index] { get; }
int Count { get; }
}
/// <summary>
/// 接口实现类
/// </summary>
public class RectCollection : IIndex<Rect>
{
private Rect[] data = new Rect[3] {
new Rect{ Height=2,Width=5},
new Rect{ Height=3,Width=7},
new Rect{ Height=4.5,Width=2.9},
};
private static RectCollection _coll;
public static RectCollection GetRect() => _coll ?? (_coll = new RectCollection());
public Rect this[int index]
{
get
{
if (index < 0 || index > data.Length)
throw new ArgumentOutOfRangeException("index is out of range");
return data[index];
}
}
public int Count => data.Length;
}
#endregion
#region 抗变接口
/// <summary>
/// 抗变接口 --------------- 抗变--》属性和索引器必须实现set
/// </summary>
public interface IDisplay<in T> // in声明接口为抗变类型接口,继承了该接口的对象可以实现抗变的隐式转换。 --对应调用方法中的rectDisplay
{
void Show (T item);
}
/// <summary>
/// 抗变实现类
/// </summary>
public class ShapeDisplay : IDisplay<Shape>
{
public void Show(Shape item) =>
Console.WriteLine($"{item.GetType().Name} width:{item.Width} height:{item.Height}");
}
#endregion
static void Main()
{
// 协变调用 Rect-》Shape 向派生程度低的类装换
IIndex<Rect> rects = RectCollection.GetRect();
IIndex<Shape> shapes = rects; // 如果IIndex接口的参数没有使用out修饰为协变,则转换报错(隐式转换会编译错误,显示转换会运行错误)
for (int i = 0; i < shapes.Count; i++)
{
Console.WriteLine(shapes[i]);
}
// 抗变调用 Shape-》Rect 向派生程度高的类转换
IDisplay<Shape> shapeDisplay = new ShapeDisplay();
IDisplay<Rect> rectDisplay = shapeDisplay; // 如果IDisplay接口的参数没有使用in修饰为抗变,则转换报错
rectDisplay.Show(rects[0]);
}
}
c# 协变与抗变的更多相关文章
- C#中协变与抗变(逆变)
泛型在.NET 2.0中正式的引入.在使用泛型的过程中,联系上面向对象的继承性.往往很容易想当然敲出类似以下代码 List<Animal> animalLst=new List<Do ...
- 让我们用心感受泛型接口的协变和抗变out和in
关键字out和in相信大家都不陌生,系统定义的很多泛型类型大家F12都或多或少看见了.但是实际中又很少会用到,以前在红皮书里看到,两三页就介绍完了.有的概念感觉直接搬出来的,只是说这样写会怎样,并没有 ...
- C#泛型中的抗变和协变
在.net4之前,泛型接口是不变的..net4通过协变和抗变为泛型接口和泛型委托添加了一个重要的拓展 1.抗变:如果泛型类型用out关键字标注,泛型接口就是协变的.这也意味着返回类型只能是T. 实例: ...
- 《C#高级编程》学习笔记------抗变和协变
1.协变和抗变 在.NET 4之前,泛型接口是不变的..NET 4通过协变和抗变为泛型接口和泛型委托添加了一个重要的扩展.协变和抗变指对参数和返回值的类型进行转换.例如,可以给一个需要Shape参数的 ...
- 解读经典《C#高级编程》最全泛型协变逆变解读 页127-131.章4
前言 本篇继续讲解泛型.上一篇讲解了泛型类的定义细节.本篇继续讲解泛型接口. 泛型接口 使用泛型可定义接口,即在接口中定义的方法可以带泛型参数.然后由继承接口的类实现泛型方法.用法和继承泛型类基本没有 ...
- C#中泛型方法与泛型接口 C#泛型接口 List<IAll> arssr = new List<IAll>(); interface IPerson<T> c# List<接口>小技巧 泛型接口协变逆变的几个问题
http://blog.csdn.net/aladdinty/article/details/3486532 using System; using System.Collections.Generi ...
- .NET C#杂谈(1):变体 - 协变、逆变与不变
0. 文章目的: 介绍变体的概念,并介绍其对C#的意义 1. 阅读基础 了解C#进阶语言功能的使用(尤其是泛型.委托.接口) 2. 从示例入手,理解变体 变体这一概念用于描述存在继承关系的 ...
- C#
1.类型推导 ; Console.WriteLine(age.GetType().ToString()); var 关键字还可以配合生成匿名类型,如: , Time = }: 如果有可以将对象转成JS ...
- C#_基础:委托速讲
1定义:委托=函数指针 C# public delegate void Test(string str); 等价C++ public void (*Test)(string str): 委托赋值(初始 ...
随机推荐
- WEB服务器与应用服务器解疑
1.WEB服务器: 理解WEB服务器,首先你要理解什么是WEB?WEB你可以简单理解为你所看到的HTML页面就是WEB的数据元素,处理这些数据元素的应用软件就叫WEB服务器,如IIS.apache. ...
- linux永久关闭防火墙
- Hadoop 系列(二)安装配置
Hadoop 系列(二)安装配置 Hadoop 官网:http://hadoop.apache.or 一.Hadoop 安装 1.1 Hadoop 依赖的组件 JDK :从 Oracle 官网下载,设 ...
- wcf服务契约的重载
a. 服务端 .服务端 契约用OperationContract的Name实现重载 using System; using System.Collections.Generic; using Syst ...
- Plugin 'Scala' is incompatible with this.installation
==问题=== 手动安装IDEA的Scala插件,报这个错误. ===原因=== IDEA的版本与Scala插件的版本不兼容. ===解决=== 1.查看一下IDEA的版本 2.下载对应版本的Scal ...
- python函数、装饰器、迭代器、生成器
目录: 函数补充进阶 函数对象 函数的嵌套 名称空间与作用域 闭包函数 函数之装饰器 函数之迭代器 函数之生成器 内置函数 一.函数补充进阶 1.函数对象: 函数是第一类对象,即函数可以当作数据传递 ...
- Silverlight StoryBoard 动态切换ImageSource
Silverlight StoryBoard 动态切换ImageSource <StackPanel Grid.Row="1" Orientation="Horiz ...
- 2018.06.30 BZOJ3083: 遥远的国度(换根树剖)
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 512 MB Description 描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国 ...
- SIM900 AT来电显示开启,一些代码
/*Note: this code is a demo for how to using gprs shield to send sms message, dial a voice call and ...
- ssh到远程执行命令并返回
假设有三台机器 host1,host2,host3,host1能免密登录其他两台.要在第一台的机器里面写一个脚本分别删除每台机器的/root/test.txt rm -rf /root/test.tx ...