图文详解C#中的协变与逆变

图文详解C#中的协变与逆变

什么是协变与逆变

协变和逆变是指可以使用派生类型来代替基类型的能力。协变用于返回值类型,逆变用于参数类型。在C#中,协变和逆变可以应用于委托(delegate)和泛型(generic)类型。

协变

协变可用于返回类型,指一个方法返回类型可以使用它继承的类型。使用out关键字可实现协变。

示例1

class Program
{
    static void Main(string[] args)
    {
        IAnimalContainer<Cat> catContainer = new AnimalContainer<Cat>();
        IAnimalContainer<Animal> animalContainer = catContainer;
        Console.WriteLine(animalContainer.GetType()); //输出AnimalContainer`1

        Console.ReadKey();
    }
}

interface IAnimalContainer<out T>
{
    T GetAnimal();
}

class AnimalContainer<T> : IAnimalContainer<T> where T : Animal, new()
{
    public T GetAnimal()
    {
        Console.WriteLine("Create a {0}", typeof(T).Name);
        return new T();
    }
}

class Animal
{
}

class Cat : Animal
{
}

上面代码片段中定义了三个类AnimalCatAnimalContainer<T>AnimalCat是继承关系,AnimalContainer<T>为泛型接口IAnimalContainer<T>的实现类,并且AnimalContainer<T>类中的T的限制为继承Animal,并且具有默认公共构造函数。

Main方法中,我们定义了两个对象catContaineranimalContainer,分别是IAnimalContainer<Cat>IAnimalContainer<Animal>类型的,catContainer对象是具体类型AnimalContainer<Cat>的实例。然后我们将catContainer赋值给animalContainer,由于out关键字的使用,这行代码是合法的,可以成功编译。

最后我们输出了animalContainer对象的类型,结果是AnimalContainer,即像我们预期的类型成功变成了它的基类类型。这就是协变的示例。

逆变

逆变用于参数类型,表示一个方法的参数可以使用其基类型。使用in关键字可实现逆变。

示例2

class Program
{
    static void Main(string[] args)
    {
        IAnimalTracker<Cat> catTracker = new CatTracker();
        IAnimalTracker<Animal> animalTracker = catTracker;
        animalTracker.Track(new Animal());
        Console.ReadKey();
    }
}

interface IAnimalTracker<in T>
{
    void Track(T animal);
}

class CatTracker : IAnimalTracker<Cat>
{
    public void Track(Cat cat)
    {
        Console.WriteLine("Tracking a cat");
    }

    public void Track(Animal animal)
    {
        Console.WriteLine("Tracking an animal");
    }
}

class Animal
{
}

class Cat : Animal
{
}

上面代码片段中定义了三个类AnimalCatCatTrackerAnimalCat是继承关系,CatTracker为泛型接口IAnimalTracker<T>的实现类,并且IAnimalTracker<T>中的T使用in关键字实现逆变。

Main方法中,我们定义了两个对象catTrackeranimalTracker,分别是IAnimalTracker<Cat>IAnimalTracker<Animal>类型的,catTracker对象是具体类型CatTracker的实例。然后我们将catTracker赋值给animalTracker,由于in关键字的使用,这行代码是合法的,可以成功编译。

最后我们对animalTracker对象执行了Track方法,并且传入了一个具体类型为Animal的对象,运行结果仍然是Tracking a cat,我们传入的具体类型为Animal的参数成功转换为基类型Cat,这就是逆变的示例。

结论

协变和逆变是C#中非常有用的特性,可用于泛型和委托中。协变可用于返回类型,逆变可用于参数类型。当一个类型可以被替换为他的基类型或者继承类型时,我们可以使用协变或逆变。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:图文详解C#中的协变与逆变 - Python技术站

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

相关文章

  • 浅析C#中数组,ArrayList与List对象的区别

    浅析C#中数组,ArrayList与List对象的区别 在 C# 编程语言中,数组,ArrayList 和 List 都是常用的数据结构。虽然在某些场景下它们可以互相替代,但它们之间还是存在一些区别。 数组 数组是一种固定大小的、连续的数据结构,其中可以存储相同类型的元素。在 C# 中,创建数组的方式有两种。一种是使用数组初始化器,将元素的值直接传递给数组。…

    C# 2023年5月15日
    00
  • Win10 20H1快速预览版18875更新后部分软件无法使用怎么办?

    下面是关于“Win1020H1快速预览版18875更新后部分软件无法使用怎么办?”的完整攻略,包含两个示例。 1. Win1020H1快速预览版18875更新后部分软件无法使用问题简介 在使用Win1020H1快速预览版18875时,可能会遇到部分软件无法使用的问题。这可能是由于更新后的系统不兼容某些软件或者更新过程中出现了错误导致的。下面是解决这个问题的步…

    C# 2023年5月15日
    00
  • Unity 实现贴花效果的制作教程

    下面是“Unity 实现贴花效果的制作教程”的完整攻略。 1. 概述 贴花效果指的是将一张图片或纹理贴在另一张图片或物体表面上,从而增强物体的细节和真实感。在 Unity 中,可以通过材质球和 Shader 实现贴花效果。 本文将介绍如何使用 Shader 在 Unity 中制作贴花效果。本文的 Shader 脚本实现了在物体表面绘制标准材质球的副本和一张透…

    C# 2023年6月3日
    00
  • C#找不到类型名”SqlConnection”的有效解决方法

    为了解决 “C#找不到类型名”SqlConnection” 的报错问题,有如下几个有效的解决方法: 1. 添加System.Data.SqlClient引用 在使用 SqlConnection 的代码文件中,我们需要添加 System.Data.SqlClient 引用,这是用于连接 SQL Server 的命名空间。 步骤如下: 打开你的项目 右键点击”引…

    C# 2023年5月15日
    00
  • C#学习基础概念二十五问续2

    “C#学习基础概念二十五问续2”是一篇介绍C#语言基础概念的文章,主要讲解了25个问题。以下是这篇文章的完整攻略: 1. 概述 在概述中,应该简要介绍文章的主题和内容,解释本文旨在帮助哪些读者,以及文章的阅读难度等信息。 2. C#是什么 这一节主要介绍了C#是一种什么类型的语言,它的特点和用途是什么等等。这里可以举一个示例,如以展示C#代码如何使用控制台输…

    C# 2023年6月6日
    00
  • 关于C# dynamic装箱问题

    这里是关于C# dynamic装箱问题的完整攻略: 什么是C#装箱和拆箱 C#装箱和拆箱是指将值类型转换为引用类型,以及将引用类型转换为值类型的过程。在C#中,值类型是指整数、浮点数、字符等基本数据类型,而引用类型是指静态类型、类实例、数组对象等。 C#装箱和拆箱的问题 在C#中,对于动态类型dynamic,其底层是以object表示的。而对于值类型的dyn…

    C# 2023年5月14日
    00
  • asp.net core下给网站做安全设置的方法详解

    ASP.NET Core 下给网站做安全设置的方法详解 在 ASP.NET Core 中,我们可以通过一些安全设置来保护我们的网站免受攻击。本攻略将介绍 ASP.NET Core 下给网站做安全设置的方法。 步骤 以下是在 ASP.NET Core 中给网站做安全设置的步骤: 使用 HTTPS 使用 HTTPS 可以保护我们的网站免受中间人攻击。我们可以在 …

    C# 2023年5月17日
    00
  • C#多线程学习(一) 多线程的相关概念

    C#多线程学习(一) 多线程的相关概念 什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。 而一个进程又是由多个线程所组成的。 什么是线程? 线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等), 但代码区是共享的,即不同的线程可以执行同样的函数。 什么是多线程? 多线程是指程序…

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