Unity 3D中使用泛型


C#2所带来的最重要的一个功能就是引入了泛型。

泛型所提供的好处有以下3点

  1. 类型安全:使用泛型类型或泛型方法来操作一个具体的数据类型时,编译器能够理解开发人员的意图,并且保证只有与制定数据类型兼容的对象才能用于该泛型类型或泛型方法。当使用不兼容类型的对象时,则会造成编译错误,甚至是在运行时抛出异常。例如在上面的代码中,对一个声明了操作类型为string的列表添加int型数据时,编译器会报错。
  2. 更加清晰的代码:正如本章开始所说的,在没有引入泛型机制的C#1的时代,源代码中不得不进行的强制类型转换次数是很多的,因此代码相对不易维护和拓展。在引入了泛型机制后,源代码中不必进行很多强制类型转换,因此代码变得更加容易维护。例如在上面的代码中,将List<T>中索引为0的元素取出来,并且赋值给一个stirng型的变量s的过程并没有强制类型转换。
  3. 更加优秀的性能:同样在本章开始就提到过的,如果没有泛型机制的话,为了使用同一套常规化的逻辑方法,则必须使用object作为参数或返回值的类型。但一个不得不承认的事实是,object类型其本身其实是一个很“没有用”的存在,这是由于如果要使用object做一些真正具体有意义的事情,则几乎不得不进行强制类型转换,转换成目标类型。同时,由于object是引用类型,当实际操作类型是值类型时,则又面临另一个十分影响性能的操作——装箱操作。Mono运行时将不得不在调用该逻辑方法之前对值类型实例进行装箱。但是,引入泛型机制后,由于能够通过该机制创建一个泛型类型或泛型方法来操作值类型,因此值类型的实例就无须执行装箱操作,反而可以直接通过传值的方式来传递了。与此同时,由于无须进行强制类型转换,因此在Mono运行时无须去验证这种转型是否类型安全。泛型机制使得大量的安全检查从运行时转移到了编译时进行,因此提高了代码的运行速度。

C#提供的泛型机制主要可以分为以下两种形式

  1. 泛型类型:包括类、接口、委托以及结构(值类型),但是需要注意的是并不包括泛型枚举。
  2. 泛型方法

Mono运行时对泛型机制的优化

Mono运行时内部采用了一套优化机制来避免这种情况的发生,也就是使某个编译后的“方法/实参类型”组合能够复用。假如某个特定的类型是某个泛型方法的类型实参,该“方法/实参类型”组合只需要被编译一次,之后再调用该方法就不需要再次编译了。例如一个Dictionary<string, int>被编译一次,之后代码中再出现Dictionary<string, int>就不需要编译了。
另一个优化,就是它认为所有的引用类型的实参都是完全相同的,这是因为所有的引用类型的实参,甚至是变量都是指向托管堆上某个对象的指针,因此可以采用统一的方式来处理。例如,List<String>和List<Stream>的代码编译之后都是相同的,因为它们的类型实参String和Stream都是引用类型。但是与此相反的是,如果类型实参是值类型,则必须单独编译成原生代码。

泛型委托

泛型委托中需要特别指出的一点是,泛型委托类型实参的逆变性和协变性。

泛型委托中的泛型类型参数可以是以下3种中的其中一种:

  1. 不变量:即泛型类型参数无法更改。
  2. 逆变量:即泛型类型参数可以从一个类更换为该类的某个派生类。在C#游戏脚本中使用关键字in来标识一个泛型类型参数是逆变量。需要注意的是,逆变量泛型参数只能出现在传入的位置,例如方法的参数。
  3. 协变量:即泛型类型参数可以从一个类更换为该类的某个基类。在C#游戏脚本中使用关键字out来标识一个泛型类型参数是协变量。需要注意的是,协变量泛型参数只能出现在输出的位置,例如方法的返回值的类型。

什么是泛型约束

让泛型的类型有一定的限制
关键字:where

泛型约束一共有6种:

  1. 值类型 where 泛型字母:struct
  2. 引用类型 where 泛型字母:class
  3. 存在无参公共构造函数 where 泛型字母:new()
  4. 某个类本身或者其派生类 where 泛型字母:类名
  5. 某个接口的派生类型 where 泛型字母:接口名
  6. 另一个泛型类型本身或者派生类型 where 泛型字母:另一个泛型字母

泛型中的类型约束的几种形式

  • 第1种约束——引用类型约束 引用类型约束是常见的一种约束形式。它保证了使用的类型实参必须是引用类型的。写作“T : Class”且必须是类型参数的第一个约束。指定了引用类型约束后,类型实参只能是类、接口、数组、委托等引用类型。
  • 第2种约束——值类型约束 值类型约束和引用类型约束对应,它保证了类型实参必须是值类型,写作“T : struct”。指定了值类型约束后,类型实参只能是结构、枚举等值类型。
  • 第3种约束——构造函数类型约束 顾名思义,构造函数类型约束主要用来检查类型实参是否有可用于创建类型实例的无参数构造函数,写作“T : new()”且必须是类型参数的所有约束的最后一个。构造函数类型约束经常被用在工厂风格的设计模式中,在这种模式中,一个对象会在需要时创建另一个对象。
  • 第4种约束——转换类型约束 转换类型约束的特点是指定的类型实参的类型必须可以通过一致性转换引用转换,甚至是装箱来转换为约束的类型。虽然转换类型约束只能指定一个类,但是却可以指定多个接口。

类型约束的组合

让我们将一组类型约束的组合中的约束划分一下,可以得到几个分类,分别是主要约束、次要约束,以及构造函数约束

  • 主要约束包括引用类型约束、值类型约束,以及指定为类的转换类型约束
  • 次要约束则包括接口其他类型参数的转换类型约束
  • 这样我们的类型约束组合的组成就变得十分清晰了,主要约束是可选的,但只能有一个;次要约束可以有多个
  • 构造函数约束也是可选的,只不过当主要约束是值类型约束时就不再需要构造函数约束了。
合法的约束组合
  • class Example<T> where T : class, IComparab<T>, IDisposable, new()
  • class Example<T> where T : struct,IDisposable。
  • class Example<T, U> where T : struct where U : class.
  • class Example<T, U> where T : String where U : IComparable<T>
不合法的约束组合
  • class Example<T> where T : class, struct.
  • class Example<T> where T : struct, new().
  • class Example<T> where T : new(), Stream.
  • class Example<T> where T : IDisposable, Stream.
  • class Example<T, U> where T : struct where U : class, T.

泛型的类型推断

C#中类型推断的基本步骤。

  1. 对于方法中的每一个方法实参(不是类型实参),都进行推断来确定其类型。
  2. 验证上一步中的所有方法实参的类型都是一致的,如果从一个方法实参推断出的类型实参和从另一个方法实参推断出的类型实参不一致,那么这次方法调用的类型推断便是失败的。
  3. 验证泛型方法所需要的所有类型实参都已经被推断出来。让编译器推断一部分,而自己显式的指定一部分是不被允许的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值