你了解C#的协变和逆变吗,看完这篇就懂了

C#的协变和逆变是在面向对象里面的类型系统中的概念。在C# 2.0之前,这两个概念是不存在的,开发者只能通过强制类型转换来满足某些需求。在C# 2.0之后,引入了这两个概念,通过它们可以更加安全地进行类型转换,同时也提升了代码的可读性。

一、协变:

协变指的是能够将一个派生类的变量赋值给基类的变量,或者能够将一个方法的返回值类型声明为基类的类型。它的形态如下:

interface IAnimal { }
class Dog : IAnimal { }
class Cat : IAnimal { }

// 可以将Dog类型的变量赋值给IAnimal类型的变量
IAnimal animal = new Dog();
// 可以将返回值类型声明为IAnimal类型
IAnimal GetAnimal() { return new Dog(); }

二、逆变:

逆变指的是能够将一个基类的变量赋值给派生类的变量,或者可以将一个方法的参数类型声明为派生类的类型。它的形态如下:

interface IAnimal { }
class Dog : IAnimal { }
class Cat : IAnimal { }

// 可以将IAnimal类型的变量赋值给Dog类型的变量
Dog dog = (Dog)new IAnimal();
// 可以将参数类型声明为Dog类型
void AddDog(Dog dog) { }

示例一:协变

interface ILogger<out T> { 
    T Log();
}

class DbLogger<T> : ILogger<T> {
    public T Log() { 
        Console.WriteLine("DbLogger Log: " + typeof(T).ToString());
        return default(T); 
    }
}

class FileLogger<T> : ILogger<T> {
    public T Log() { 
        Console.WriteLine("FileLogger Log: " + typeof(T).ToString());
        return default(T); 
    }
}

ILogger<object> logger1 = new DbLogger<object>();
ILogger<object> logger2 = new FileLogger<object>();

上面的例子中,ILogger接口有一个占位符类型T,用于表示的具体的类型是什么。DbLogger和FileLogger都有一个Log方法,返回值类型为T。我们通过ILogger等同于ILogger来声明一个协变的泛型接口,然后分别声明一个DbLogger和FileLogger并赋值给ILogger类型的logger1和logger2变量来实现协变。

示例二:逆变

delegate T Func<T>();
delegate void Set<in T>(T value);

class Fruit { }
class Apple : Fruit { }

class Msg { }
class WarningMsg : Msg { }

void SetFruit(Set<Fruit> setFruit) { }
void GetApple(Func<Apple> getApple) { }

Set<Apple> setApple = a => { Console.WriteLine("Set Apple"); };
SetFruit(setApple); // 逆变

Func<Fruit> getFruit = () => { Console.WriteLine("Get Fruit"); return new Apple(); };
GetApple(getFruit); // 逆变

上面的例子中,我们先声明了两个delegate,Func和Set。它们分别有一个类型参数T,并且Set的类型参数类型是逆变的,Func的类型参数类型是协变的。然后我们声明了两个类Fruit和Apple,并且Apple是Fruit的子类。同样地,我们还声明了两个类Msg和WarningMsg,并且WarningMsg是Msg的子类。

接着,我们定义了两个方法SetFruit和GetApple。SetFruit要求传入一个Set类型的参数,而GetApple要求传入一个Func类型的参数。然后我们声明一个Set类型的变量setApple,它实现了Set。接着我们调用SetFruit方法,将setApple作为参数传入,这里setApple是在逆变的情况下实现了Set,可以看做是将Set类型的变量赋值给了Set类型的变量。

同理,我们声明一个Func类型的变量getFruit,实现了Func。接着我们调用GetApple方法,将getFruit作为参数传入,这里getFruit是在协变的情况下实现了Func,可以看做是将Func类型的变量赋值给了Func类型的变量。

总结:

协变和逆变可以让我们使用更加灵活的泛型类型,提高程序的安全性和可读性。协变是将派生类赋值给基类或者将返回值类型声明为基类,逆变是将基类赋值给派生类或者将参数类型声明为派生类。在编程中,我们可以根据需求来采用协变和逆变的形式,灵活运用泛型类型,来更加高效地编写代码。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:你了解C#的协变和逆变吗,看完这篇就懂了 - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • C#使用自定义算法对数组进行反转操作的方法

    C#使用自定义算法对数组进行反转操作的方法 反转数组是C#中常见的操作,本文将介绍如何通过自定义算法,在C#中实现对数组的反转操作。 1. 什么是反转? 数组的反转意味着数组中的元素顺序发生改变,从最后一个元素到第一个元素,或者从第一个元素到最后一个元素。比如,原数组 a = {1,2,3,4,5},反转后变成 a = {5,4,3,2,1}。 2. 算法思…

    C# 2023年6月7日
    00
  • JS、CSS和HTML实现注册页面

    下面是关于“JS、CSS和HTML实现注册页面”的完整攻略: 1.确定页面设计 在开始实现注册页面之前,我们需要先确定页面设计。包括布局、元素的排列和样式等方面。可以利用工具软件或者手绘草稿来完成页面设计。 2.HTML结构与元素 经过页面设计之后,我们就可以开始构建HTML结构和元素了。在这个过程中,我们需要考虑页面元素和布局,比如表单、按钮等。 以下示例…

    C# 2023年5月31日
    00
  • WinForm实现移除控件某个事件的方法

    WinForm中可以通过 Control 类提供的 RemoveHandler 方法,移除控件特定事件的处理程序。下面是实现移除控件某个事件的方法的完整攻略: 确定要被移除事件的控件和事件类型。 获取该控件当前事件的处理程序列表。 判断需要移除的事件处理程序是否在列表中,如果在,则移除该事件处理程序。如果不在,则无需进行移除操作。 下面是两个示例说明: 示例…

    C# 2023年6月7日
    00
  • C#随机生成Unicode类型字符串

    下面是C#随机生成Unicode类型字符串的完整攻略。 1. 确定生成的字符串长度 首先需要决定生成的字符串长度。例如,我们想要生成一个长度为6的随机字符串。 int length = 6; 2. 获取随机码点 Unicode是一个支持世界上大多数语言的编码方案。每个字符都有一个唯一的码点,用16进制数字表示。为了生成Unicode类型的字符串,需要从Uni…

    C# 2023年6月8日
    00
  • PowerShell查看Windows功能选项的方法

    PowerShell查看Windows功能选项的方法 在PowerShell中,我们可以使用Get-WindowsOptionalFeature cmdlet命令来查看Windows功能选项。本文将提供详细的“PowerShell查看Windows功能选项的方法”的完整攻略,包括如何使用Get-WindowsOptionalFeature命令,以及两个示例。…

    C# 2023年5月15日
    00
  • 基于Jenkins搭建.NET Core持续集成环境过程图解

    基于Jenkins搭建.NET Core持续集成环境过程图解 Jenkins是一个开源的自动化构建工具,可以用于构建、测试和部署软件。在本攻略中,我们将介绍如何使用Jenkins搭建.NET Core持续集成环境,并提供两个示例说明。 步骤一:安装Jenkins 安装Java Jenkins是基于Java开发的,因此需要先安装Java。可以从官方网站下载Ja…

    C# 2023年5月16日
    00
  • C#读取系统字体颜色与大小的方法

    下面就来详细讲解一下“C#读取系统字体颜色与大小的方法”的攻略。这个过程我会分为两个步骤来讲解:第一步是读取系统字体的大小,第二步是读取系统字体的颜色。 读取系统字体大小的方法 要读取系统字体的大小,我们可以使用SystemFonts这个类,其包含了许多可以用来读取系统字体的相关信息的静态属性和静态方法。其中,SystemFonts.CaptionFontS…

    C# 2023年6月7日
    00
  • Javascript 使用ajax与C#获取文件大小实例详解

    下面我将详细讲解 “Javascript使用ajax与C#获取文件大小实例详解” 的完整攻略。 什么是Ajax? Ajax(Asynchronous JavaScript And XML),指异步的JavaScript和XML。可以在不重新加载整个网页的情况下与服务器交换数据并更新部分网页内容。 通过Ajax获取文件大小的步骤 创建XMLHttpReques…

    C# 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部