C#泛型知识整理

1.作用
代码的复用
最开始是使用object类型,但是涉及到装拆箱,导致性能变差。

2.泛型类型
泛型会声明类型参数–生产类型,消费者提供类型参数(argument)来把占位符类型填充上

public class Stack<T>
{
T a;
return a ;
}

var stack =new Stack<int>();//合成发生在运行时。

编译的时候
stack = new string();会报错

Stack 开发类型
Stack封闭类型
运行时,泛型类型实例都是封闭的。但可以使用Typeof来使泛型在编译的时候保持开放。

3.泛型方法(必须引用了,在泛型类型里面,使用(T a )的时候是普通方法)

class TClassDemo<T>
{
public void factionName(T a){...}//普通方法
}


void factionName<T> (T a)//泛型方法
{
...
}

调用的时候根据传进的参数

4.允许引入类型参数的只有类型(class struct interface delegate)和方法

5.泛型类型/泛型方法的名称可以被重载

class A
class A<T>
class A<T1,T2>

以上名称相同的class的存在并不冲突。
另外按照约定,只有一个类型参数的时候一般使用T。

6.type对象允许未绑定类型的泛型类型在运行时存在

class A<T>{}
class A<T1,T2>

Type a1=typeof(A<>)
Type a2=typeof(A<,>)

与反射使用

7.泛型类型参数的默认值
使用default关键字。值类型按位归0的值,应用类型为null。

8.泛型约束
裸类型约束,不指定约束,指定约束 where T
where T:base-class //继承了自某个父类
where T:interface //实现了某个接口
where T:class //引用类型
where T:struct //值类型
where T:new() //有一个无参的构造函数
where U:T //U继承对于T的约束

9.泛型类的子类
在子类里可以让类型参数保持开放

class Stack<T> {...}
class SpecialStack<T>:Stack<T> {...}

也可以关闭

class SpecialStack:Stack<int>{...}

也可以加入新的类型参数

class List<T> {...}
class KeyedList<TElement,TKey>:List<TElement>

子类继承父类的时候可以这样理解会先关闭类型参数,然后重新打开,为类型参数带来新的名称或者含义,如classKeyedList<TElement,TKey>

10.自引用的泛型声明

public interface IEquatable<T>{...}
public class Ballon:IEquateble<Ballon>

可以这样使用,但是不常用

11.针对每一个封闭类型,静态数据是唯一的

class Bod<T>{public static int Count;}

class Test
{
static void Main()
{
Console.WriteLine(++Bob<int>.Count);//1
Console.WriteLine(++Bob<int>.Count);//2
Console.WriteLine(++Bob<string>.Count);//1
Console.WriteLine(++Bob<bool>.Count);//1
}

}

12.泛型的转换
当不确定类型参数的时候,直接转换的时候会报错。

转换的过程涉及到协变,逆变。(类型参数关闭后)
协变,逆变是先对于变量而言。泛型变量关闭后,和普通的变量并没有区别,一个变量要么是支持协变,要么是支持逆变,要么是不变的。
协变的类型转换过程是从子类到父类的过程,支持隐式转换。在使用泛型过程中,如果使用out关键字声明泛型的类型参数,那么该类型只能作为返回值类型使用。
逆变的类型转换过程是从父类到子类的过程,需要显示的转换,或者使用as操作符,在使用泛型过程中,如果泛型的类型参数,用in 关键字声明,则在使用过程不用显示的转换,也能够完成从父类到子类的转换
不变的类型转换过程是需要显示的转换,或者使用as操作符,且在使用泛型过程中,不使用out,in关键字来标明

(1)如IList 这个类型参数在声明的时候,并没有使用out或者in的关键字。使用过程如果是使用了隐式的类型转换则会报错。

IList<string> strings =new List<string>{"a" ,"b","c"};
IList<object> objects =strings;//报错,无法隐式的转换

如果想用IList类型的参数,来使用的话,可以使用strings.ToList();或者strings.Cast().ToList();来得到List类型的变量的返回值。注意,得到返回值类型就是object类型,把返回值赋过去的过程是不涉及类型转换的。

IList<string> list1 = new List<string> { "a", "b", "c" };
IList<object> list2 = list1.ToList<object>();

(2)IEnumerable 这个类型参数T 的声明是public interface IEnumerable : IEnumerable out T的,是支持从子类到父类的协变的,string为object的子类,所以是支持隐式转换的

IEnumerable<string> strings = new List<string> { "a", "b", "c" };
 IEnumerable<object> objs = strings;

(3)Action这个类型的参数的声明是public delegate void Action in T的,支持从父类到子类的转换,object为string的父类,actionObject转换成actionString的过程是逆变。一般的object转为string的过程是需要显示类似转换或者as操作符的,但是当类型参数T,用了in关键字说明,这其中的转换就不需要使用了,但是用这中类型参数声明的变量,只能作为输入值使用。

Action<object> actionObject;
Action<string> actionString;
actionString = actionObject;

即out T 引入类型参数的时候,T的参数只能作为返回,允许协变子类变为父类,Covariance,协变,子类转为父类,或者本体转换的隐式转换方式。

class Testout<out T>
{
public T returnOneT (int a,int b)
{
return T;
}
}

in T引入类型参数的时候,T只能作为输入,允许父类转为子类,Contravariance,逆变,一般不被允许,需要显示转换的过程。

class Testout<inT>
{
public void returnOneT (T a,T b)
{
}
}

可以这样理解记忆:作为返回的值的时候,最主要的是得到数据,而不是对数据做处理,故而父类的类型就够用。作为输入使用的时候,希望实现的越多越好,故而需要子类的类型。
没有修饰符的,作为invariance。封闭后的类型转换是不安全的。故而需要的是显示类型转换或者是as操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值