泛型(Generics)
泛型是CLR 2.0中引入的最重要的新特性,使得可以在类、方法中对使用的类型进行参数化。
例如,这里定义了一个泛型类:
class MyCollection<T> { T variable1; private void Add(T param){ } }
使用的时候:MyCollection<string> list2 = new MyCollection<string>(); MyCollection<Object> list3 = new MyCollection<Object>();
泛型的好处
编译时就可以保证类型安全
不用做类型装换,获得一定的性能提升
泛型方法、泛型委托、泛型接口
除了泛型类之外,还有泛型方法、泛型委托、泛型接口:
//泛型委托 public static delegate T1 MyDelegate<T1, T2>(T2 item); MyDelegate<Int32, String> MyFunc = new MyDelegate<Int32, String>(SomeMethd); //泛型接口 public class MyClass<T1, T2, T3> : MyInteface<T1, T2, T3> { public T1 Method1(T2 param1, T3 param2) { throw new NotImplementedException(); } } interface MyInteface<T1, T2, T3> { T1 Method1(T2 param1, T3 param2); }
//泛型方法 static void Swap<T>(ref T t1, ref T t2) { T temp = t1; t1 = t2; t2 = temp; } String str1 = "a"; String str2 = "b"; Swap<String>(ref str1, ref str2);
泛型约束(constraints) 可以给泛型的类型参数上加约束,可以要求这些类型参数满足一定的条件约束
说明
where T: struct 类型参数需是值类型
where T : class 类型参数需是引用类型
where T : new() 类型参数要有一个public的无参构造函数
where T : <base class name> 类型参数要派生自某个基类
where T : <interface name> 类型参数要实现了某个接口
where T : U 这里T和U都是类型参数,T必须是或者派生自U
这些约束,可以同时一起使用:
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new() { // ... }
default 关键字
这个关键可以使用在类型参数上:
default(T);
对于值类型,返回0,引用类型,返回null,对于结构类型,会返回一个成员值全部为0的结构实例。
迭代器(iterator)
可以在不实现IEnumerable就能使用foreach语句,在编译器碰到yield return时,它会自动生成IEnumerable 接口的方法。在实现迭代器的方法或属性中,返回类型必须是IEnumerable, IEnumerator, IEnumerable<T>,或 IEnumerator<T>。迭代器使得遍历一些零碎数据的时候很方便,不用去实现Current, MoveNext 这些方法。
public System.Collections.IEnumerator GetEnumerator() { yield return -1; for (int i = 1; i < max; i++) { yield return i; } }
可空类型(Nullable Type)
可空类型System.Nullable<T>,可空类型仅针对于值类型,不能针对引用类型去创建。System.Nullable<T>简写为T ?。
int? num = null; if (num.HasValue == true) { System.Console.WriteLine("num = " + num.Value); } else { System.Console.WriteLine("num = Null"); }
如果HasValue为false,那么在使用value值的时候会抛出异常。把一个Nullable的变量x赋值给一个非Nullable的变量y可以这么写:
int y = x ?? -1;
匿名方法(Anonymous Method)
在C#2.0之前,给只能用一个已经申明好的方法去创建一个委托。有了匿名方法后,可以在创建委托的时候直接传一个代码块过去。
delegate void Del(int x); Del d = delegate(int k) { /* ... */ }; System.Threading.Thread t1 = new System.Threading.Thread (delegate() { System.Console.Write("Hello, "); } ); 委托语法的简化// C# 1.0的写法 ThreadStart ts1 = new ThreadStart(Method1); // C# 2.0可以这么写 ThreadStart ts2 = Method1;
委托的协变和逆变(covariance and contravariance)
有下面的两个类:
class Parent { } class Child: Parent { }
然后看下面的两个委托:
public delegate Parent DelgParent();
public delegate Child DelgChild();
public static Parent Method1() { return null; }
public static Child Method2() { return null; }
static void Main() { DelgParent del1= Method1; DelgChild del2= Method2; del1 = del2; }