泛型(Generics):一种代码重用(算法重用algorithm reuse)的机制。
使用泛型类型或方法时,用于指定类型的变量称为类型实参。(When defining a generic type or method, any variables it specifies for types (such as T) are called type parameters.)
泛型的优势
1)源代码保护(Source code protection);
2)类型安全(Type safety);
3)更清晰的代码(Cleaner code);
4)更佳的性能(Better performance):在用于值类型时,可减少装箱(boxing)与拆箱(unboxing),间接减少垃圾回收次数;减少代码中强制类型转换的次数(CLR无需验证这种转换是否安全)。
不足
1)调用特定数据类型方法时,CLR都会为该方法生成本机代码,这会增大应用程序的工作集(working set),从而损害性能。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace MyGenerics
{
class Program
{
static void Main(string[] args)
{
ValueTypePerfTest();
ReferenceTypePerfTest();
Console.ReadKey();
}
private static void ValueTypePerfTest()
{
const int count = 100000000;
using (new OperationTimer("List<int>"))
{
List<int> list = new List<int>();
for (int n = 0; n < count; n++)
{
list.Add(n); // No boxing
int x = list[n]; // No unboxing
}
list = null; // Make sure this gets garbage collected
}
using (new OperationTimer("ArrayList of Int32"))
{
ArrayList a = new ArrayList();
for (int n = 0; n < count; n++)
{
a.Add(n); // Boxing
int x = (int)a[n]; // Unboxing
}
a = null; // Make sure this gets garbage collected
}
}
private static void ReferenceTypePerfTest()
{
const int count = 100000000;
using (new OperationTimer("List<string>"))
{
List<string> list = new List<string>();
for (int n = 0; n < count; n++)
{
list.Add("X"); // Reference copy
string x = list[n]; // Reference copy
}
list = null; // Make sure this gets garbage collected
}
using (new OperationTimer("ArrayList of string"))
{
ArrayList a = new ArrayList();
for (int n = 0; n < count; n++)
{
a.Add("X"); // Reference copy
string x = (string)a[n]; // Cast check & reference copy
}
}
}
}
// This class is useful for doing operation performance timing
internal sealed class OperationTimer : IDisposable
{
private Stopwatch m_stopwacth;
private string m_text;
private int m_collectionCount;
public OperationTimer(string text)
{
PrepareForOperation();
m_text = text;
m_collectionCount = GC.CollectionCount(0);
// This should be the last statement in this
// method to keep timing as accurate as possible
m_stopwacth = Stopwatch.StartNew();
}
public void Dispose()
{
Console.WriteLine("{0} (GCs={1,3} {2})", m_stopwacth.Elapsed,
GC.CollectionCount(0) - m_collectionCount, m_text);
}
private static void PrepareForOperation()
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
}