Unity 基础之 Where约束与协变、逆变

简介: 约束描述where T: struct类型参数必须为值类型where T : class类型参数必须为引用类型where T : new()类型参数必须有一个公有、无参的构造函数。
约束 描述
where T: struct 类型参数必须为值类型
where T : class 类型参数必须为引用类型
where T : new() 类型参数必须有一个公有、无参的构造函数。当于其它约束联合使用时,new()约束必须放在最后。
where T : <base class name> 类型参数必须是指定的基类型或是派生自指定的基类型
where T : <interface name> 类型参数必须是指定的接口或是指定接口的实现。可以指定多个接口约束。接口约束也可以是泛型的

示例

img_6967e241a2acfe0c01e2dd9c818a5fb9.png
Play函数传入的参数必须满足
  • 参数为引用类型
  • 必须是CustomClass01的子类或者派生类
  • 必须含有无参构造函数
  • 必须继承Iplay接口
public class CustomClass01
{
    public int id;
}
public interface IPlay
{
    void PlayGame();
}

public class CustomGeneric
{

    public void Play<T>(T parameter) where T : CustomClass01, IPlay,new()
    {
        int Tempi = parameter.id;
        parameter.PlayGame();
        parameter = null;
    }
}

协变&&逆变

在具有继承关系的两个类 Father(基类)和Son(派生类)中,会出现如下编译错误

img_dd80ce59d9d4cbd9f4d8e8cd16426dd3.png

常规泛型解决办法
img_9e01d14885c5a575a87d81bdec3d8902.png

                List<Father> FatherList3 = new List<Son>().Select(c => (Father)c).ToList();

但是使用协变和逆变可解决上面的问题

img_b5849b7b205a22c99a60342ae6dbdd36.png

协变与逆变也有他们对应的约束

  • 协变 out 只能是返回结果 修饰返回值
  • 逆变 in 只能是参数 修饰传入参数
  • 协变逆变 只能放在接口或者委托的泛型参数前面
相应全部代码
    /// <summary>
    /// .net4.0
    /// 只能放在接口或者委托的泛型参数前面
    /// out 协变covariant    修饰返回值 
    /// in  逆变contravariant  修饰传入参数
    /// </summary>
    public class Test
    {
        public static void Show()
        {
            {
                Father bird1 = new Father();
                Father bird2 = new Son();
                Son Son1 = new Son();
                //Son Son2 = new Father();
            }

            {
                List<Father> birdList1 = new List<Father>();
                //List<Father> FatherList2 = new List<Son>();


                List<Father> FatherList3 = new List<Son>().Select(c => (Father)c).ToList();
            }
            {
                //协变
                IEnumerable<Father> FatherList1 = new List<Father>();
                IEnumerable<Father> FatherList2 = new List<Son>();

                Func<Father> func = new Func<Son>(() => null);

                ICustomerListOut<Father> customerList1 = new CustomerListOut<Father>();
                ICustomerListOut<Father> customerList2 = new CustomerListOut<Son>();
            }
            {//逆变
                ICustomerListIn<Son> customerList2 = new CustomerListIn<Son>();
                ICustomerListIn<Son> customerList1 = new CustomerListIn<Father>();

                ICustomerListIn<Father> FatherList1 = new CustomerListIn<Father>();
                FatherList1.Show(new Son());
                FatherList1.Show(new Father());

                Action<Son> act = new Action<Father>((Father i) => { });
            }


            {
                IMyList<Son, Father> myList1 = new MyList<Son, Father>();
                IMyList<Son, Father> myList2 = new MyList<Son, Son>();//协变
                IMyList<Son, Father> myList3 = new MyList<Father, Father>();//逆变
                IMyList<Son, Father> myList4 = new MyList<Father, Son>();//逆变+协变
            }
        }
    }

    public class Father
    {
        public int Id { get; set; }
    }
    public class Son : Father
    {
        public string Name { get; set; }
    }

    /// <summary>
    /// 逆变in只能是参数
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface ICustomerListIn<in T>
    {
        void Show(T t);
    }

    public class CustomerListIn<T> : ICustomerListIn<T>
    {
        public void Show(T t)
        {
        }
    }

    /// <summary>
    /// out 协变 只能是返回结果
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface ICustomerListOut<out T>
    {
        T Get();
    }

    public class CustomerListOut<T> : ICustomerListOut<T>
    {
        public T Get()
        {
            return default(T);
        }
    }

    public interface IMyList<in inT, out outT>
    {
        void Show(inT t);
        outT Get();
        outT Do(inT t);

        ////out 只能是返回值   in只能是参数

    }

    public class MyList<T1, T2> : IMyList<T1, T2>
    {

        public void Show(T1 t)
        {
            Console.WriteLine(t.GetType().Name);
        }

        public T2 Get()
        {
            Console.WriteLine(typeof(T2).Name);
            return default(T2);
        }

        public T2 Do(T1 t)
        {
            Console.WriteLine(t.GetType().Name);
            Console.WriteLine(typeof(T2).Name);
            return default(T2);
        }
    }
相关文章
|
3月前
|
存储 安全 编译器
C# 11.0中的泛型属性:类型安全的新篇章
【1月更文挑战第23天】C# 11.0引入了泛型属性的概念,这一新特性为开发者提供了更高级别的类型安全性和灵活性。本文将详细探讨C# 11.0中泛型属性的工作原理、使用场景以及它们对现有编程模式的改进。通过深入了解泛型属性,开发者将能够编写更加健壮、可维护的代码,并充分利用C#语言的最新发展。
|
6月前
|
JavaScript Java
带你读《现代TypeScript高级教程》十三、类型兼容:协变和逆变(1)
带你读《现代TypeScript高级教程》十三、类型兼容:协变和逆变(1)
|
6月前
|
JavaScript 安全
带你读《现代TypeScript高级教程》十三、类型兼容:协变和逆变(2)
带你读《现代TypeScript高级教程》十三、类型兼容:协变和逆变(2)
|
7月前
|
JavaScript
TypeScript逆变 :条件、推断和泛型的应用
有一个名为 `test` 的函数,它接受两个参数。第一个参数是函数 `fn`,第二个参数 `options` 受到 `fn` 参数的限制。乍一看,这个问题貌似并不复杂,不是吗?糊业务的时候,这种不是常见的需求嘛。
95 1
 TypeScript逆变 :条件、推断和泛型的应用
|
9月前
|
JavaScript 安全 Java
《现代Typescript高级教程》协变和逆变
类型兼容:协变和逆变 引言 在类型系统中,协变和逆变是对类型比较(类型兼容)一种形式化描述。在一些类型系统中,例如 Java,这些概念是显式嵌入到语言中的,例如使用extends关键字表示协变,使用super关键字表示逆变。在其他一些类型系统中,例如 TypeScript,协变和逆变的规则是隐式嵌入的,通过类型兼容性检查来实现。
69 0
|
Java
Java泛型04:自定义泛型类的使用
Java泛型04:自定义泛型类的使用
127 0
C++ 继承与派生中的赋值兼容规则问题探究
C++ 继承与派生中的赋值兼容规则问题探究
133 0
C++ 继承与派生中的赋值兼容规则问题探究
|
JavaScript
手摸手一起学习Typescript第六天 - 泛型 Generics / 泛型约束 / 泛型与类和接口
手摸手一起学习Typescript第六天 - 泛型 Generics / 泛型约束 / 泛型与类和接口
|
Java Kotlin
Kotlin 范型之泛型约束、类型投影、星号投影
Kotlin 范型之泛型约束、类型投影、星号投影
390 0
|
设计模式 Java 编译器
java泛型特性,你了解多少?
对java泛型特性的了解,很多时候是从集合对象接触到的,今天小编带大家一起去深入的了解泛型的缘由和使用方式!