一、泛型的概念
泛型的思想表现出一个重要的架构思想:延迟思想,推迟一切可以推迟的,使程序拥有更多的灵活性和扩展性
泛型在编译时,类型是不明确的,类型参数会被系统编译成占位符,在运行时,JIT即时编译器会根据程序中调用泛型方法时候给它指定的类型参数替换
泛型的目的在于“算法重用”,即逻辑相同类型不同时,使用泛型
1.1、泛型概述
C#有两种不同的机制来编写跨类型可复用的代码:继承和泛型。但继承的复用性来自基类,而泛型的复用性是通过带有“占位符”的“模板”类型实现的。
泛型是CLR和编程语言提供的一种特殊机制,它支持另一种形式的代码重用,即“算法重用”。其以实例化过程中提供的类型或类为基础建立的,可以轻易对对象进行强类型转换。同时,可以把用于实例化泛型类的类型限制为支持某个给定的接口,或派生自某种类型,从而只允许使用类型的一个子集。泛型并不限于类,还可以创建泛型接口、泛型方法(可以在非泛型类上定义),甚至泛型委托。
定义泛型类型或方法时,为类型指定的任何变量都称为类型参数。使用泛型类型或方法时指定的具体数据类型成为类型实参。
在泛型中,只有引入类型参数(用尖括号标出)的方法才可归为泛型方法。
唯有方法和类可以引入类型参数。属性、索引器、事件、字段、构造器、运算符等都不能声明类型参数,虽然它们可以参与使用所在类型中已经声明的类型参数。
1.2、泛型优势示例
①提高代码的重用度(泛型类就像一个模板,可以在需要时传入任何需要的类型)
②获取强类型的支持,避免了隐士的装箱和拆箱以及运行时的类型转换错误
③类型安全
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
//检测泛型的性能优势
//如果ArrayList存取的是引用类型,则性能上并不会有差异,但存取的若是值类型,则会有大量的
//装箱和拆箱操作,影响性能
ValueArrayTest();
ReferenceTypeTest();
Console.ReadKey();
}
public static void ValueArrayTest()
{
const int count = 100000000;
using (new OperationTimer("List<int>"))
{
List<int> vs = new List<int>();
for (int i = 0; i < count; i++)
{
vs.Add(i);//不发生装箱
int x = vs[i];//不发生拆箱
}
vs = null;//垃圾回收
}
using (new OperationTimer("ArrayList of int"))
{
ArrayList vs = new ArrayList();
for (int i = 0; i < count; i++)
{
vs.Add(i);//装箱
int x = (int)vs[i];//发生拆箱
}
vs = null;//垃圾回收
}
}
public static void ReferenceTypeTest()
{
const int count = 100000000;
using(new OperationTimer("ArrayList of string"))
{
ArrayList vs = new ArrayList();
for (int i = 0; i < count; i++)
{
vs.Add("X");
string x = (string)vs[i];//检查强制类型转换 & 复制引用
}
vs = null;
}
using (new OperationTimer("List<string>"))
{
List<string> vs = new List<string>();
for (int i = 0; i < count; i++)
{
vs.Add("X");
string x = vs[i];
}
vs = null;
}
}
}
/// <summary>
/// 用于进行运算性能计时
/// </summary>
public sealed class OperationTimer : IDisposable
{
private Stopwatch m_stopwatch;//提供一组方法和属性,可用于准确的测量运行时间
private string m_text;
private int m_collectionCount;
public OperationTimer(string text)
{
PrepareForOperation();
m_text = text;
m_collectionCount = GC.CollectionCount(0);
//这应该是方法的最后一个语句,从而最大程度保证计时的准确性
m_stopwatch = Stopwatch.StartNew();
}
public void Dispose()
{
Console.WriteLine("{0} (GCs={1,3}) {2}", (m_stopwatch.Elapsed), GC.CollectionCount(0) - m_collectionCount, m_text);
}
public static void PrepareForOperation()
{
GC.Collect();//强制对所有代进行即时垃圾回收
GC.WaitForPendingFinalizers();//挂起当前线程,直到处理终结器队列的线程清空该队列为止。
GC.Collect();
}
}
}
二、开放类型和封闭类型
开放类型:具有泛型类型参数的类型称为开放类型,CLR禁止构造开放类型的任何实例。
封闭类型:代码引用泛型类型时可指定一组泛型类型实参。为所有类型参数都传递了实际的数据类型,类型就成为封闭类型。
using System;
using System.Collections.Generic;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
object o = null;
//Dictionary<,>是开放类型,有2个类型参数
o = CreateInstance(typeof(D