《C#高级编程》【第五章】泛型 -- 学习笔记
来源:互联网 发布:无印良品水乳 知乎 编辑:程序博客网 时间:2024/06/13 17:41
泛型是高级程序设计语言的一种特性。泛型的引入使得程序开发的效率得到提高,代码的重用性大大的提升。有了泛型,我们可以创建独立于被包含类型的类和方法,我们不必给不同的类编写功能相同的很多方法或者类,只创建一个方法或类就可以了。现在我们看看泛型的优点
性能上,泛型不需要进行类型转换(也就是拆箱和装箱)。
类型安全,和Object类相比,Object类属于非类型安全的,而泛型使用泛型类型,可以根据需要用特定的类型替换泛型类型,这样就保证了类型安全类。在编译时,只要与泛型类型T定义的允许使用的类型不同,编译器就会报错,这样我们就可以尽早的发现错误。
二进制代码重用,在C#中可以一次定义多次使用,然而C++却要不断的访问源码。
代码的扩展,对于引用类型,他们将会共享本地类的所有相同代码。只有值类型,才会每次实例化一个新类。
我们看完了泛型的优点,我们现在可以来看看泛型具体怎么使用。我们先看一幅图,了解一下泛型的组成。
1、泛型类
我们先看看泛型类型的命名方法:<1>一大写字母T开头 <2>如果泛型类型没有特定的要求,或者使用了两个、两个以上的泛型类型,就需要给出描述性的名称。(如:TValue,TKey等等)。
现在我们看看泛型类的声明语法:
[访问权限修饰符] class 类名<T>{//类体}
类名的T就是泛型类型,具体类型实例化时给出。然而在类体中就可以直接将T当成一个具体的类型来使用。每个处理对象类型的类都可以有泛型实现方式。如果类使用了层次结构,那么泛型就可以很好的消除类型转换的操作。
注意:T两边的’<’和’>’不能少。
在创建泛型类时,我们还需要考虑一些问题。首先我们应该怎么初始化成员变量呢?然而我们并不知道究竟是引用类型还是值类型,为了解决这个问题我们就引入了default关键字。语法如下:
T value = default(T)
这样我们就圆满的解决成员变量初始化的问题。default会给值类型赋值为0,引用类型赋值为null。
如果泛型类需要调用泛型类型的方法,那么就必须添加约束。那么什么是约束呢?约束就是让泛型类型只能使用我们所约束的类型。我们使用where关键字来声明约束。公有以下6种约束:
<1>where T : struct 结构约束,类型T必须为值类型
<2>where T : class 引用约束,类型T必须是引用类型
<3>where T : IFoo 接口约束,类型T必须实现接口IFoo
<4>where T : Foo 类约束,类型T必须派生自基类Foo
<5>where T : new() 类型T必须有一个默认的构造函数
<6>where T1 : T2 裸型约束,类型T1派生自泛型T2。
对于裸型约束,我们来具体说说吧。我们举个例子:
public class Test<T1, T2> where T1 : T2{//类体}
我们重点看看实例化的时候
var MyTest = new Test<Class1, Class2>();
那么此时,Class1类就必须派生自Class2类,否则编译器就会报错。
使用泛型类型还可以组合多个约束,例如:
public class MyClass<T> where T : IFoo, new(){//类体}
泛型类,既然作为类那么它必然可以继承。泛型类可以实现泛型接口,也可以派生自泛型基类。例:
public class Myclass<T> : IDD<T>{//类体}或者这样
public class Base<T>{}public class MySub<T>: Base<T>{}
也可以是这样:
public class MySub<T>: Base<string>{}
派生类可以是泛型类还可以是非泛型类。
public classMysub: Base<int>{}
泛型类,比较特别的应该就是它的静态成员了。因为泛型类的静态成员只能在类的一个实例中共享。假设类MySub<T>存在静态字段x,那么如果同时对一个int型和string型使用了Mysub<T>类,所以就存在两组字段:Mysub<int>.x和MySub<string>.x
2、泛型接口
看到泛型接口,我们就要提到,抗变与协变。现在我们就看看什么抗变与协变。
假设:TSub是TParent的子类。
协变:如果一个泛型接口IFoo<T>,IFoo<TSub>可以转换为IFoo<TParent>的话,我们称这个过程为协变,IFoo支持对参数T的协变。
逆变:如果一个泛型接口IFoo<T>,IFoo<TParent>可以转换为IFoo<TSub>的话,我们称这个过程为逆变,IFoo支持对参数T的逆变。
泛型类型的协变用关键字out声明,泛型接口就是协变的,这就意味着其返回类型只能是T。
public interface IIndex<out T>{T this[int index] {get ;}}
泛型类型的抗变用关键字in声明,泛型接口就是抗变的。这样泛型类型T就只能作为方法输入。例如:
public interface IDisplay<in T>{void Show(T test);}
通常只有具备继承关系的对象才可以发生隐式类型转换,如Base b=new sub()。
协变和逆变可以使得更多的类型之间能够实现隐式类型转换、类型安全性得到保障。
3、泛型结构
其实泛型结构和泛型类几乎是一致的,只是泛型结构没有继承的特性。.Net平台提供的一个泛型结构是(可空类型)Nullable<T>。可空类型的引入,主要是为了解决数据库语言中的数字与编程语言中的数字的区别(数据库中数字可以为空,编程语言中数字不可为空)。因为Nullable<T>使用过于的繁琐,于是我们就引入了一种特殊的语法,使用‘?’运算符。例:
int? x1;Nullable<int> x2;在上面的例子中,x1与x2这两种方式定义是等价的。
非空类型可以转化为可空类型。(总是成功的且可以隐式转化)
可空类型可以转化为非空类型。当可空类型的值为null时就会抛出异常。(需要显示转化)
如果不进行显示转化,我们就可以使用”??”运算符。如下:
int? x1 = GetNullableType();int y1 = x1 ?? 0;
这样的话,当x1为null时,就会赋给y1一个0。
4、泛型方法
除了可以定义泛型类,泛型也是可以定义成方法的。语法如下:
[返回值类型] 方法名称<T>(参数列表){}其余的用法就和普通方法是一样的,唯一的区别就是它有一个通用类型T。
泛型方法和类一样,也可以加约束,具体约束的方法和泛型类是一样的。语法如下:
[返回值类型] 方法名称<T>(参数列表) where T : [约束方式]{}
以上就是泛型的内容了
- 《C#高级编程》【第五章】泛型 -- 学习笔记
- pp看书笔记---C#高级编程第九版 第五章 【泛型】
- Unix环境高级编程学习笔记(第五章)
- 《csharp高级编程》 学习笔记 第五章 数组
- [学习笔记]C#高级编程(第5章 泛型)
- C#高级编程 学习笔记
- 《C#高级编程》【第二章】核心C#编程 -- 学习笔记
- 深入.NET平台和C#编程 第五章 学习笔记
- Geekband_C++面向对象高级编程_第五周学习笔记
- [学习笔记]C#高级编程(1、2章)
- [学习笔记]C#高级编程(第3章)
- [学习笔记]C#高级编程(第4章)
- [学习笔记]C#高级编程第6、7章
- 《C#高级编程》【第三章】对象和类型 -- 学习笔记
- 《C#高级编程》【第四章】继承 -- 学习笔记
- 《C#高级编程》【第六章】数组 -- 学习笔记
- C#高级编程学习笔记(1)
- C#高级编程学习笔记--------构造函数
- Magento迁移服务器
- C#.ToString()格式大全
- weka实战005:基于HashSet实现的apriori关联规则算法
- codeforces 510c Fox And Names 拓扑排序
- Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
- 《C#高级编程》【第五章】泛型 -- 学习笔记
- UIImage类中的常用拉伸方法
- STL Vector整理
- 重新认识史蒂夫·乔布斯
- Swift流程控制
- 【Trie】【cogs647】有道搜索框
- 线程同步 资源锁定(一)
- Spring自带mock测试Controller
- 慧团网床上用品四件套家纺大全