#前言
来了,来了。
本文将结合C#在Unity中的应用讲解,代码编辑器使用Visual Studio。讲解内容来自《C#高级编程 第10版》和我的理解,如果有错希望大佬指出(骂我,不要客气!)。
下面是《C#高级编程 第10版》的pdf文件分享
#正文
#泛型概述
泛型是C#和.NET的一个重要概念。有了泛型,就可以创建独立于被包含类型的的类和方法。
我们不必给不同的类型编写功能相同的许多方法或类,只创建一个方法或类即可。
泛型给我的最大体验就是节省了代码,写一个泛型类或者泛型方法,可以在不同的地方使用。(虽然结果是这样,但这句话并不适合用于理解泛型。)
另一个减少代码的选项是使用Object类(《C#高级编程》这个Object提的很好),我们知道Object类是全部类型的基类,所有值类型和引用类型都可以转换为Object类(值类型转变为引用类型设计装箱和拆箱操作,下一篇文章讲),我们可以使用Object类对任何类型进行存储,在需要时使用强制类型转换的方式将存储类型取出转为我们所需要使用的类型。例如,ArrayList类似于一种特殊的List,它存储的是类型是Object,所有存入的类型都会被转换为Object,取出时需要自己进行强制类型转换。
泛型与上面提到的Object类有一些相似,我们可以在使用时指定需要存储或者使用的类型,之后便可以放入那个类型。例如,List<T>我们之前就提到过,我们需要指定存储的类型,存储int类型写成List<int>,之后便可以放入int类型和拿出int类型。
下面介绍一下泛型的特点。
-
性能
-
类型安全性
-
二进制代码重用
-
代码的扩展
-
命名约束
-
性能
泛型一个主要的优点是性能。这句更准确的来说是在节省代码的基础上,泛型比起Object类(上面提到的那种用法)更加节省性能。
Object类型因为使用过程中需要将别的类型和Object类进行类型转换,虽然代码上看挺简单的,但性能损失比较大。泛型则会在JIT(Just-In-Time)编辑器动态生成新类,不进行类型转换。
-
类型安全
泛型另一个特性是类型安全。
Object类因为放入的类型全都被转变为了Object类,这意味这我们可以放入各种各样的类,但我们将类型取出时,可能出现转换为错误的类型的情况,这个时候我们就会得到一个运行时的报错。泛型则因为使用时指定了类型,并不会出现这种情况,所以是类型安全的。
-
二进制代码的重用(节省代码量)
泛型允许更好地重用二进制代码。泛型类可以定义一次,并且可以用许多不同的类型实例化。
-
代码的扩展
这段其实我没有怎么看懂。复述一下大概是泛型类在编译为IL代码(中间代码)时并不会因为指定了泛型类型而去复制这些类,但在JIT编译器把泛型类编译为本地代码时,会为每个值类型创建一个新类,引用类型则共享同一个本地类的所有相同实现。因为引用类型变量存储着的是内存地址,值类型则各不相同。
是在说代码的编译过程中的细节吧,我猜的。
-
命名约束
命名约束是大家约定俗成的,用于区分泛型类型和非泛型类型的手段。下面是泛型类型的命名规则:
-
泛型类型的名称用字母T作为前缀。
-
如果没有特殊要求,泛型类型允许使用任意类型替代,并且只使用了一个泛型类型,就可以用字符T作为泛型类型的名称。
-
如果泛型类型有特定的要求(例如,他必须实现一个接口或派生自基类),或者使用了两个或者或者多个泛型类型,就应该给泛型类型使用描述性的名称(参考平时的类命名吧,前面加个T)。
#泛型类
-
创建泛型类
(下面的代码全部截取自《C#高级编程》)
《C#高级编程》中使用链表进行了举例,
(截图真快,好爽)
这段是没有泛型的链表,或者说是用了Object类的链表,鸡合(我故意打错字的,为什么jihe算敏感词呀)那章我不是没举例链表的代码吗,刚好大家现在看一下。
首先我们可以看到这是个双向链表,因为链表中的元素(Node)有两个指针,一个向前一个向后,然后元素中存放一个Object类。
然后我们看到链表本体LinkedList,有一个指向开头的和指向结尾的,从代码中可以看出,这个指向开头的是指在第一个元素上(有些链表是在第一个元素前放一个元素,然后让头指针指在上面)。链表还实现了IEnumerable接口,在鸡合的那章我们提到过这个接口,实现这个接口可以让类可以被 foreach 语句遍历,从代码上看是从前往后遍历元素的值。
感觉使用起来和ArrayList好像诶。
接下来我看看泛型版本:
上面命名规范上曾说过当可以使用任何类型,并且只有一个时,就可以用 T 来表示泛型。
看着好多的<T>呀,但我们把这些 <T> 都去了,会发现这段代码与之前的代码,区别主要在于Object被替换成了T,其实我们在外面修改就相当于修改这个T。当然这些<T>是不能去掉的,因为这是泛型呀,直接写T会报错的。
上面就是说泛型大概的使用内容,就是用使用时指定的类型来替换原来类中没有明确定义(泛型)的类型。
-
泛型类的功能
默认值
这是说到关于泛型类初始化的问题,我们刚刚说到泛型类可能会支持所有类型,也就是说包括值类型和引用类型,引用类型的可以设为null,值类型则不可以,所以这里就提到了使用 default(T) 个关键字,通过这个关键字可以将泛型T设置为默认值。
T
t
=
default
(
T
)
;
顺带一提swtich中搭配的也是default。
约束
这个是指限定某泛型只能咋样咋样才能使用。下面的表单有约束的说明:
继承
这是说泛型类继承的问题,非泛型类可以继承泛型类,泛型类可以继承非泛型类之类的。
静态成员
我们知道静态变量在一个类的所有实例中是共享的,在泛型类的静态成员中则是所有同一类型的泛型,它们共享一个静态变量,其他类型则不是。
#泛型接口
概括一下泛型接口,和泛型类其实长得差不多。我们还是来看一下不一样的地方。
-
协变和抗变
这点我就不献丑了,我这里我推荐一篇文章,大家可以
点这里
,我并不推荐大家去看《C#高级编程》这段的讲解。
Shape shape= new Rectange(); 就是说“子类引用可以直接转化成父类引用”,或者说Rectange类和Shape类之间存在一种安全的隐式转换。
像这种与原始类型转换方向相同的可变性就称作协变(covariant)。
与协变中子类引用转化为父类引用相反,将父类引用转化为子类引用的就称之为抗变。
1.仅有泛型接口和泛型委托支持对类型参数的可变性,泛型类或泛型方法是不支持的。
2.值类型不参与协变或抗变,IFoo<int>永远无法协变成IFoo<object>,不管有无声明out。因为.NET泛型,每个值类型会生成专属的封闭构造类型,与引用类型版本不兼容。
3.声明属性时要注意,可读写的属性会将类型同时用于参数和返回值。因此只有只读属性才允许使用out类型参数,只写属性能够使用in参数。
协变和多态的表现形式类似,抗变则是反过来,在泛型接口中T的协变和抗变是可选的。
#泛型方法
-
泛型方法示例
泛型方法可在非泛型类中定义。(里面的ref是指强制参数以引用传入,与泛型无关。)
-
带约束的泛型方法
#结束语
-
建议
其实我讲的内容是简化的,很多地方可能还没有讲清楚。如果大家哪里没有看懂,可以去翻看一下《C#高级编程 第10版》,如果还是没有搞懂,欢迎在评论区询问,我会尽力回答的。以上提到的内容都是基础中的基础,是绝对不允许出现不理解的情况的。
如果害羞不好意思在评论区询问,欢迎大家加我QQ来讨论哦。QQ:2243211562
-
杂谈
我出来了,终于可以出来了(;´༎ຶД༎ຶ`),我已经在小区里被关了快两周了,外面的世界真好,我在家都要发霉了。冷起来了呀,不愧是成都,我的秋天体验卡这么快就到期了。不愧是我,天天在家都可以感冒,诶,今天打了好几个喷嚏了,不过每年冬天我都要感冒的,不是说感冒一次之后那年就没那么容易再感冒了吗,大家也要注意加衣服啊。
天越来越黑了,看上去马上要下雨了呀,我刚刚做核酸的时候一点点的感觉天空越来越黑了,我都怕我排到一半被雨淋,但愿晚点下,不然我待会下班回家都成问题。
这次就到这吧,谢谢大家的观看,下次再见。
1281

被折叠的 条评论
为什么被折叠?



