泛型
c#2.0比c#1.0有一点最大的改进就是加入对泛型的支持。泛型起源于c++语言的模板机制。这样在c#中就避免了不必要的拆装箱操作,而且还加强了编译时的安全性,强类型的检查。
CLR#允许创建泛型引用类型,值类型,但是不许创建泛型枚举类型。 还可以创建泛型接口,委托,以及最常见的泛型方法。
//c#中的泛型集合类:
List<T>
Dictionary<TKey, TValue>
SortedDictionary<TKey, TValue>
Stack<T>
Queue<T>
LinkedList<T>
//c#中的泛型接口:
IList<T>
IDictionary<TKey, TValue>
IConection<T>
IEnumerator<T>
IEnumerable<T>
IComparer<T>
IComparable<T>
List<T>
Dictionary<TKey, TValue>
SortedDictionary<TKey, TValue>
Stack<T>
Queue<T>
LinkedList<T>
//c#中的泛型接口:
IList<T>
IDictionary<TKey, TValue>
IConection<T>
IEnumerator<T>
IEnumerable<T>
IComparer<T>
IComparable<T>
下面展示如何使用其中的一些泛型方法:
public static void Main() {
Byte[] byteArray = new Byte[] {5, 1, 4, 2, 3};
Array.Sort<Byte>(byteArray);
Int32 i = Array.BinarySearch<Byte>(byteArray, 1);
Console.WriteLine(i); // Displays "0"
}
Byte[] byteArray = new Byte[] {5, 1, 4, 2, 3};
Array.Sort<Byte>(byteArray);
Int32 i = Array.BinarySearch<Byte>(byteArray, 1);
Console.WriteLine(i); // Displays "0"
}
下面看一下泛型的同一性:
internal sealed class DateTimeList : List<DateTime> {
}
DateTimeList dt = new DateTimeList(); //这样写省去了<>括号,看起来简便了
/*这样会返回false,也就是如果一个方法参数允许接受DateTimeList类型,那么我们不可以把List<DateTime>传给他,因为这两个类型不相等,但是如果一个方法参数允许接受List<DateTime>类型,那么可以把一个DateTimeList传过去,因为他们之间存在继承关系*/
Boolean sameType = (typeof(List<DateTime>) == typeof(DateTimeList));
//如果我们想简便写法,可以像下面这样写:
using DateTimeList = System.Collections.Generic.List<System.DateTime>;
Boolean sameType = (typeof(List<DateTime>) == typeof(DateTimeList)); //返回true
}
DateTimeList dt = new DateTimeList(); //这样写省去了<>括号,看起来简便了
/*这样会返回false,也就是如果一个方法参数允许接受DateTimeList类型,那么我们不可以把List<DateTime>传给他,因为这两个类型不相等,但是如果一个方法参数允许接受List<DateTime>类型,那么可以把一个DateTimeList传过去,因为他们之间存在继承关系*/
Boolean sameType = (typeof(List<DateTime>) == typeof(DateTimeList));
//如果我们想简便写法,可以像下面这样写:
using DateTimeList = System.Collections.Generic.List<System.DateTime>;
Boolean sameType = (typeof(List<DateTime>) == typeof(DateTimeList)); //返回true
记住显示的方法优于泛型方法被调用:
void Swap<T>(T arg1,Targ2)
{
Console.Write("Generic");
}
void Swap(double arg1,double,arg2)
{
Console.Write("Common");
}
//下面将会调用第二个方法
Swap(12.36,36.21);
{
Console.Write("Generic");
}
void Swap(double arg1,double,arg2)
{
Console.Write("Common");
}
//下面将会调用第二个方法
Swap(12.36,36.21);
下面看一下泛型约束,这一点是c#泛型的优势:
约束分为三种:主要约束,次要约束,和构造器约束
/*主要约束:类型参数可以指定0或者1个主要的泛型约束,主要约束可以是值类型也可以是引用类型,指定引用类型时,那么就意味着参数必须是这个引用类型或者从这个引用类型派生,还有两个特殊的主要约束:即class和struct约束,下面看一下代码:*/
internal sealed class PrimaryConstraintOfStream<T> where T : Stream {
public void M(T stream) {
stream.Close();// OK
}
}
PrimaryConstraintOfStream<Stream> pcs=new PrimaryConstraintOfStream<Stream>(); // 合法
PrimaryConstraintOfStream<FileStream> pcs=new PrimaryConstraintOfStream<FileStream>(); //合法
PrimaryConstraintOfStream<int> pcs=new PrimaryConstraintOfStream<int>(); //非法
//class约束
internal sealed class PrimaryConstraintOfClass<T> where T : class {
public void M() {
T temp = null; //合法,因为已经约束了T为引用类型
}
}
//struct约束
internal sealed class PrimaryConstraintOfStruct<T> where T : struct {
public static T Factory() {
return new T();
}
}
internal sealed class PrimaryConstraintOfStream<T> where T : Stream {
public void M(T stream) {
stream.Close();// OK
}
}
PrimaryConstraintOfStream<Stream> pcs=new PrimaryConstraintOfStream<Stream>(); // 合法
PrimaryConstraintOfStream<FileStream> pcs=new PrimaryConstraintOfStream<FileStream>(); //合法
PrimaryConstraintOfStream<int> pcs=new PrimaryConstraintOfStream<int>(); //非法
//class约束
internal sealed class PrimaryConstraintOfClass<T> where T : class {
public void M() {
T temp = null; //合法,因为已经约束了T为引用类型
}
}
//struct约束
internal sealed class PrimaryConstraintOfStruct<T> where T : struct {
public static T Factory() {
return new T();
}
}
/*次要约束:一个类型参数可以指定0个或者多个次要约束。次要类型代表的是一个接口约束。还有一种辅助约束是类型参数之间必须存在某种关系。下面看个例子:*/
private static List<TBase> ConvertIList<T, TBase>(IList<T> list)
where T : TBase {
List<TBase> baseList = new List<TBase>(list.Count);
for (Int32 index = 0; index < list.Count; index++) {
baseList.Add(list[index]);
}
return baseList;
}
private static void CallingConvertIList() {
IList<String> ls = new List<String>();
ls.Add("A String");
IList<Object> To = ConvertIList<String, Object>(ls);
IList<IComparable> lc = ConvertIList<String, IComparable>(ls);
IList<IComparable<String>> lcs =ConvertIList<String, IComparable<String>>(ls);
IList<String> ls2 = ConvertIList<String, String>(ls);
IList<Exception> le = ConvertIList<String, Exception>(ls); // Error,string类型和Exception没有关系
}
private static List<TBase> ConvertIList<T, TBase>(IList<T> list)
where T : TBase {
List<TBase> baseList = new List<TBase>(list.Count);
for (Int32 index = 0; index < list.Count; index++) {
baseList.Add(list[index]);
}
return baseList;
}
private static void CallingConvertIList() {
IList<String> ls = new List<String>();
ls.Add("A String");
IList<Object> To = ConvertIList<String, Object>(ls);
IList<IComparable> lc = ConvertIList<String, IComparable>(ls);
IList<IComparable<String>> lcs =ConvertIList<String, IComparable<String>>(ls);
IList<String> ls2 = ConvertIList<String, String>(ls);
IList<Exception> le = ConvertIList<String, Exception>(ls); // Error,string类型和Exception没有关系
}
//构造器约束:一个指定的类型实参实现了一个public无参构造器的一个非抽象类型。如果同时指定了构造器约束和struct约束,编译器会报错,因为值类型都隐式的提供了一个无参构造器*/
internal sealed class ConstructorConstraint<T> where T : new() {
public static T Factory() {
return new T(); //指定了构造器约束,我们可以肯定能够返回一个T类型的实例
}
}
internal sealed class ConstructorConstraint<T> where T : new() {
public static T Factory() {
return new T(); //指定了构造器约束,我们可以肯定能够返回一个T类型的实例
}
}
下面我们在看一些其他的问题:
private static void SettingAGenericTypeVariableToDefaultValue<T>() {
T temp = default(T); // OK
}
//如果我们在不指定约束的时候想初始化T类型,那么我们必须使用default关键字,这样当T是引用类型时,temp被初始化为null,如果T为值类型temp被初始化为0
T temp = default(T); // OK
}
//如果我们在不指定约束的时候想初始化T类型,那么我们必须使用default关键字,这样当T是引用类型时,temp被初始化为null,如果T为值类型temp被初始化为0
还有就是一些基元操作符(/,*,+,-,等等)不能应用在泛型参数上:
private static T Sum<T>(T num) where T : struct {
T sum = default(T) ;
for (T n = default(T); n < num; n++)
sum += n;
return sum;
}
//编译器报错
• error CS0019: Operator '<' cannot be applied to operands of type 'T' and 'T'
• error CS0023: Operator '++' cannot be applied to operand of type 'T'
• error CS0019: Operator '+=' cannot be applied to operands of type 'T' and 'T'
T sum = default(T) ;
for (T n = default(T); n < num; n++)
sum += n;
return sum;
}
//编译器报错
• error CS0019: Operator '<' cannot be applied to operands of type 'T' and 'T'
• error CS0023: Operator '++' cannot be applied to operand of type 'T'
• error CS0019: Operator '+=' cannot be applied to operands of type 'T' and 'T'