协变与逆变

using System;
using System.Collections.Generic;
using System.Drawing;

/*
 * 协变:能够使用比原始指定的派生类型的派生程度更大的类型。
 * 逆变:能够使用比原始指定的派生类型的派生类型更小的类型。
 * 
 * 注1:只有泛型接口和泛型委托支持协变、逆变。
 * 注2:协变、逆变使泛型支持多态。
 */
namespace CovariantAndContravariant
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Dog dog = new Dog("大黄");
            Animal animal = dog;// 子类可以转换为父类
            Console.WriteLine(animal.Name);
            //List<Animal> animals = new List<Dog>();// 虽然Animal和Dog之间存在继承关系,但是List<Animal>和List<Dog>之间不存在继承关系,所以编译时报错
            IEnumerable<Animal> _animals = new List<Dog>();// 虽然Animal和Dog之间不存在继承关系,但是List<Dog>可以转换为IEnumerable<Animal>,因为泛型接口IEnumerable<out T>支持“协变”,所以不会报错

            Console.WriteLine("\r\n=================================华丽的分割线=================================\r\n");

            Animal animal1 = new Animal();
            //Snake snake = animal1;// 编译时报错,父类无法直接转换为子类
            //Snake snake = (Snake)animal1;// 父类强制转换为子类,编译时不会报错,但运行时报错,Animal无法转换成Snake
            Action<Snake> action = new Action<Animal>(s => { Console.WriteLine(s.Name); });// 虽然Animal无法转换成Snake,但是Action<Animal>可以转换为Action<Snake>,因为泛型委托Action<in T>支持“逆变”,所以不会报错
            action(new Snake("小青"));

            Console.WriteLine("\r\n=================================华丽的分割线=================================\r\n");

            // 自定义协变
            ICustomCovariant<Animal> customCovariant = new CustomCovariant<Dog>();
            Dog dog1 = customCovariant.Get() as Dog;
            Console.WriteLine(dog1.Name);

            // 自定义逆变
            ICustomContravariant<Snake> customContravariant = new CuntomContravariant<Animal>();
            Animal animal2 = new Snake("小青");
            customContravariant.Set(animal2 as Snake);

            Console.ReadLine();
        }
    }

    public class Animal
    {
        public string Name = "null";
    }

    public class Dog : Animal
    {
        /// <summary>
        /// 毛发颜色
        /// </summary>
        public Color HairColor = Color.Yellow;

        public Dog(string name)
        {
            Name = nameof(Dog) + "---" + name;
        }
    }

    public class Snake : Animal
    {
        /// <summary>
        /// 皮肤颜色
        /// </summary>
        public Color SkinColor = Color.Cyan;

        public Snake(string name)
        {
            Name = nameof(Snake) + "---" + name;
        }
    }

    #region 自定义协变
    public interface ICustomCovariant<out T>// out表示给接口支持“协变”
    {
        T Get();
    }

    public class CustomCovariant<T> : ICustomCovariant<T>
    {
        public T Get()
        {
            if (typeof(T) == typeof(Dog))
            {
                Dog dog = new Dog("大黄---协变");
                object obj = dog;

                return (T)obj;
            }
            else
            {
                return default(T);
            }
        }
    }
    #endregion

    #region 自定义逆变
    public interface ICustomContravariant<in T>// in表示该接口支持“逆变”
    {
        void Set(T value);
    }

    public class CuntomContravariant<T> : ICustomContravariant<T>
    {
        public void Set(T value)
        {
            if (value is Snake snake)
            {
                snake.Name += "---逆变";
                Console.WriteLine(snake.Name);
            }
        }
    }
    #endregion
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dart 是一种支持泛型的面向对象语言,它允许我们在定义类、函数或方法时使用参数化类型。泛型允许我们在不指定具体类型的情况下编写通用的代码,提高代码的重用性和安全性。 在 Dart 中,泛型的类型变化可分为两种:类型的协变(Covariance)和类型的逆变(Contravariance)。 类型的协变指的是可以将泛型类型的子类型赋值给父类型,这样就可以确保在使用泛型类型时不会发生类型不匹配的错误。例如,如果有一个泛型类 Animal<T>,其中 T 是一个类型参数,那么 Animal<Dog> 就是 Animal<Animal> 的子类型。这样我们可以使用 Animal<Animal> 类型的变量来持有 Animal<Dog> 的实例,而不会出现类型错误。 类型的逆变协变相反,指的是可以将泛型类型的父类型赋值给子类型。这样可以更灵活地使用泛型类型,更好地符合实际的业务需求。例如,如果有一个泛型类 Comparator<T>,其中 T 是一个类型参数,那么 Comparator<Animal> 就是 Comparator<Dog> 的父类型。这样我们可以使用 Comparator<Dog> 类型的变量来持有 Comparator<Animal> 的实例,而不会出现类型错误。 泛型的型变在 Dart 中使用通配符来表示,泛型类型的协变使用 extends 关键字,逆变使用 super 关键字。例如,在声明一个泛型类型时,我们可以使用 Animal<? extends Animal> 表示协变,使用 Comparator<? super Dog> 表示逆变。这样的声明帮助我们在使用泛型类型时确保类型的正确性。 总结来说,Dart 中的泛型支持类型的协变逆变,这样可以更灵活、更安全地使用泛型类型。泛型的型变通过使用通配符、extends 和 super 关键字来表示,使得泛型类型的赋值更加灵活,能够满足不同的业务需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值