C#泛型初识2
.Net平台最基础的容器就是System.Array 类。C#数组允许我们定义一组固定上限的同一类型的项(包括System.Object的数组,它本质上标识任何类型的数组)。 虽然通常这可以满足我们的要求,但是在很多时候我们需要更灵活的数据结构,比如动态增长和收缩的容器或者容器只可以保存符合某个条件的对象。
自从.NET 平台第一次发布以后,程序员经常使用System.Collections 命名空间来以更灵活的方式管理数据,然而自从.Net2.0发布之后,C#编程语言就增强了,开始支持泛型(字面意思通用类型)。基于此,在基础类库中引入了一个以集合为中心的新命名空间:System.Collections.Generic 命名空间
泛型的容器和他们的非泛型版本相比,在很多方面要优越得多,因为他们提供了更多的类型安全和性能优势。所以有必要强调:任何使用 .NET2.0或更高版本创建的项目都应该放弃使用System.Collections中的类,而使用System.Collections.Generic中的类。
1.使用List<T>类
在泛型类型或方法定义中,类型参数是客户端在实例化泛型类型的变量时指定的特定类型的占位符。客户端代码必须通过指定尖括号中的类型参数来声明和实例化构造类型。 此特定类的类型参数可以是编译器识别的任何类型。 可以创建任意数目的构造类型实例,每个实例使用不同的类型参数,如下所示:
GenericList<float> list1 = new GenericList<float>(); GenericList<ExampleClass> list2 = new GenericList<ExampleClass>(); GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>();
在每个 GenericList<T> 实例中,类中出现的每个 T 都会在运行时替换为相应的类型参数。 通过这种替换方式,我们使用一个类定义创建了三个独立的类型安全的有效对象。
自定义泛型类,并实例化,如下:
class Program { static void Main(string[] args) { int obj = 2; Test<int> test = new Test<int>(obj); Console.WriteLine("int:" + test.obj); string obj2 = "hello world"; Test<string> test1 = new Test<string>(obj2); Console.WriteLine("String:" + test1.obj); Console.Read(); } } class Test<T> { public T obj; public Test(T obj) { this.obj = obj; } }
Test为自定义的类或结构,这段代码片段可以读成 a List<> of T,T为Test类型。 或更简单第读作 Test 对象列表。
2.泛型方法
泛型方法是使用类型参数声明的方法,如下所示:
static void Swap<T>(ref T lhs, ref T rhs) { T temp; temp = lhs; lhs = rhs; rhs = temp; }
下面的代码示例演示一种使用 int 作为类型参数的方法调用方式:
public static void TestSwap() { int a = 1; int b = 2; Swap<int>(ref a, ref b); System.Console.WriteLine(a + " " + b); }
也可以省略类型参数,编译器将推断出该参数。 下面对 Swap 的调用等效于前面的调用:
Swap(ref a, ref b);
相同的类型推理规则也适用于静态方法和实例方法。 编译器能够根据传入的方法实参推断类型形参;它无法仅从约束或返回值推断类型形参。 因此,类型推理不适用于没有参数的方法。 类型推理在编译时、编译器尝试解析重载方法签名之前进行。 编译器向共享相同名称的所有泛型方法应用类型推理逻辑。 在重载解析步骤中,编译器仅包括类型推理取得成功的那些泛型方法。
在泛型类中,非泛型方法可以访问类级别类型参数,如下所示:
class SampleClass<T> { void Swap(ref T lhs, ref T rhs) { } }