c#泛型
目录
泛型
一.泛型的作用
跨类型可复用的代码:继承 和 泛型.
继承 => 基类
泛型 => 带有"(类型)占位符"的"模板"
二.泛型类型
泛型会声明类型参数-泛型的消费者需要提欧共类型参数来把占位符类型填充上.
// 泛型类
public class Stack<T>{
int position;
T[] data = new T[100];
public void Push(T ojb) => data[poisition++] = ojb;
public T Pop() => data[--poistion]
}
// 使用泛型
Stack<int> stack = new Stack<int>();
stack.Push(12); // poistion = 1
stack.Push(15); // poistion = 2
int x = stack.Pop(); // poisiton = 1 ,data[1] x = 2;
int y = stack.Pop(); // y = 1
// 推导
public class ###{
int position;
int data = new int[100];
public void Push(int ojb) => data[poisition++] = ojb;
public int Pop() => data[--poistion]
}
OPEN TYPE & CLOSE TYPE
Stack
Open Type(开发类型) Stack
Close Type(封闭类型) 在运行时,所有的泛型类型实际都是封闭的(占位符类型已经被填充了)
var stack = new Stack<T>(); // 异常!
// 下面是允许的
public class Stack<T>{
...
public Stack<T> Clone(){
Stack<T> clone = new Stack<T>();
...
}
}
泛型为什么会出现
public class Stack{
int position;
object data = new object[100];
public void Push(object ojb) => data[poisition++] = ojb;
public object Pop() => data[--poistion]
}
需要装箱子和向下转换,这种转换在编译时无法进行检查
stack.Push("s"); // 装箱
int i = (int)stack.Pop(); // 无法向下转换报错!!!
三.泛型方法
泛型方法在方法的签名内也可以声明类型参数
// 泛型方法
static void Swap<T>(ref T a,ref T b){
T temp = a;
a = b;
b = temp;
}
// 调用
int a = 2;
int b = 3;
Swap(ref a,ref b);
Console.WriteLine($"{a},{b}"); // a=3 b=2
在泛型类型里面的方法,除非也引入了类型参数T ,否则是不会归为泛型方法的
public class Stack<T>{
int position;
T[] data = new T[100];
public void Push(T ojb) => data[poisition++] = ojb;
public T Pop() => data[--poistion] //这个不是泛型方法
}
只有类型和方法可以引入类型参数,属性,索引器,事件,字段,构造函数,操作符等都不可以声明类型参数,但是他们可以使用他们所在的泛型类型的类型参数.
四.声明类型参数
在声明class,struct,interface,delegated的时候可以引入类型参数.
其他的例如属性,就不可以引入类型参数,但是可以使用类型参数
public struct Nullable<T>{
public T Value{get;;}
}
泛型类型/泛型方法也可有多个类型参数
class Dictionary<Tkey,Tvalue>{....};
Dictionary<int,stirng> myDic = new Dictionary}<int, string>();
var myDic = new Dictionary}<int, string>();
泛型类型/泛型方法的名称可以被重载,条件是参数类型的个数不同
class A{}
class A<T> {}
class A<T1,T2>{}
// 按照约定,泛型类型/泛型方法如果只有一个类型参数,那么就叫T
// 当使用多个类型参数的时候,每个类型参数都使用T作为前缀,随后跟着具体的描述性的名字
typeof与未绑定的泛型类型
开发的泛型类型在编译后就编程了封闭的泛型类型
但是如果作为Type对象,那么为绑定的泛型类在运行时是可以存在的. 只能通过
typeof
操作符来实现
class A<T>{}
class A<T1,T2>{}
Type a1 = typeof(A<>);
Type a2 = typeof(A<,>);
Type a3 = typeof (A<int,int>);
class B<T>{void X(){Type t = typeof(T);}}
五.泛型的默认值
使用
default
关键字来获取泛型类型参数的默认值
static void Zap<T>(T[] array){
for(int i =0;i<array.Length;i++){
array[i] = default(T) // t是引用类型那么是null t是值类型是0
}
}
六.泛型的约束
默认情况下,泛型的类型参数可以是任何类的类型
如果只允许使用特定的类型参数,就可以指定约束
where T :struct // 类型T必须是值类型
where T :class // T必须是引用类型
where T :IFoo // T必须实现接口IFoo
where T :Foo // T必须派生自基类Foo
where T :new() // 指定类型T必须有个一默认构造函数
where T :T2 // 类型T派生自泛型类型T2
public class MyClass<T> where T:new(){
...
}
class SomeClass{}
interface Interface1{}
class GenericaClass<T,U> where T: SomeClass,Interface1 // 必须继承SomeClass 且 实现 Interface接口
where U:new() // 必须有个构造函数
{...}
泛型类型的子类
泛型class可以有子类,在子类里,可以继续让父类的类型参数保持开放
class Stack<T>{...}
class SpecialStack<T>:Stack<T>
在子类李,也可以使用具体的类型来关闭(封闭)父类的类型参数
class IntStack:Stack<int>{...}
子类型也可以引入新的类型参数
class List<T>{...}
class KeyedList<T,Tkey>:List<T>
自引用的泛型类型
在封闭类型参数的时候,改类型可以把他自己作为具体的类型
public interface IEquatable<T> {bool Equals(T obj);}
public class Balloon:IEquatable<Balloon>{
...
public bool Equals(Balloon b){
if(b==null)return false;
return true;
}
}
静态数据
针对每一个封闭类型,静态数据是唯一的
class Bob<T> { public static int Count; }
static class Test
{
public static void set_bob()
{
Console.WriteLine(++Bob<int>.Count); //1
Console.WriteLine(++Bob<int>.Count); //2
Console.WriteLine(++Bob<string>.Count); //1
Console.WriteLine(++Bob<object>.Count); //1
}
}
类型参数转换
- c#的类型操作符支持下列转换
- 数值转换
- 引用转换
- 装箱拆箱转换
- 自定义转换
- 决定采用的是那种转换,发生在编译时,根据已知类型的操作数来决定
public StringBuilder foo<T>(T arg){
StringBuilder sb = arg as StringBuilder;
.....
}
吾虽浪迹,却未迷失本心