版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_41660162/article/details/79839017
泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性。泛型为.NET框架引入了类型参数(type parameters)的概念。类型参数使得设计类和方法时,不必确定一个或多个具体参数,其的具体参数可延迟到客户代码中声明、实现。这意味着使用泛型的类型参数T,写一个类MyList,客户代码可以这样调用:MyList, MyList或 MyList。这避免了运行时类型转换或装箱操作的代价和风险。
以前类型的泛化(generalization)是靠类型与全局基类System.Object的相互转换来实现。
- 如果这些元素是值类型,那么当加入到列表中时,它们必须被装箱;当重新取回它们时,要拆箱。类型转换和装箱、拆箱的操作都降低了性能;
- 另一个局限是缺乏编译时的类型检查,当一个ArrayList把任何类型都转换为Object,就无法在编译时预防客户代码错误,而这个错误直到运行的时候才会被发现。
泛型的性能测试:
//普通方法、Object方法、Generic方法
public class GenericMethodTest
{
/// <summary>
/// 打印个int值
/// </summary>
/// <param name="iParameter"></param>
public static void ShowInt(int iParameter)
{
int _Int1 = iParameter;
}
/// <summary>
/// 打印个string值
/// </summary>
/// <param name="sParameter"></param>
public static void ShowString(string sParameter)
{
string _Str1 = sParameter;
}
/// <summary>
/// 打印个object值
/// 1 任何父类出现的地方,都可以使用子类来替换
/// 2 object是一切类型的父类
/// </summary>
/// <param name="oParameter"></param>
public static void ShowObject(object oParameter)
{
int intO = (int)oParameter;
}
/// <summary>
/// 延迟声明:把参数类型的声明推迟到调用
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void ShowGeneric<T>(T tParameter)
{
T intT = tParameter;
}
}
//控制台测试代码:
class Program
{
static void Main(string[] args)
{
SafeInvoke(() =>
{//通过委托实现通用的异常处理
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 100000000; i++)
{
GenericMethodTest.ShowInt(1);
}
sw.Stop();
TimeSpan ts1 = sw.Elapsed;
Console.WriteLine("ShowInt总共花费{0}ms.", ts1.TotalMilliseconds);
Stopwatch sw1 = new Stopwatch();
sw1.Start();
for (int i = 0; i < 100000000; i++)
{
GenericMethodTest.ShowString("test");
}
sw1.Stop();
TimeSpan ts2 = sw1.Elapsed;
Console.WriteLine("ShowString总共花费{0}ms.", ts2.TotalMilliseconds);
Stopwatch sw2 = new Stopwatch();
sw2.Start();
for (int i = 0; i < 100000000; i++)
{
GenericMethodTest.ShowObject(1);
}
sw2.Stop();
TimeSpan ts3 = sw2.Elapsed;
Console.WriteLine("ShowObject总共花费{0}ms.", ts3.TotalMilliseconds);
Stopwatch sw3 = new Stopwatch();
sw3.Start();
for (int i = 0; i < 100000000; i++)
{
GenericMethodTest.ShowGeneric<int>(1);
}
sw3.Stop();
TimeSpan ts4 = sw3.Elapsed;
Console.WriteLine("ShowGeneric总共花费{0}ms.", ts4.TotalMilliseconds);
});
}
/// <summary>
/// 通用的异常处理
/// </summary>
/// <param name="act">对应任何的逻辑</param>
public static void SafeInvoke(Action act)
{
try
{
act.Invoke();
}
catch (Exception ex)//按异常类型区分处理
{
Console.WriteLine(ex.Message);
}
}
}
测试会发现泛型的速度居然比普通的方法耗时还会少一点,那么我们对于一系列的不同对象需要做相同的操作的时候我们是否可以考虑用泛型来实现呢?
在泛型类型或泛型方法的定义中,类型参数是一个占位符(placeholder),那么带来的一个问题是:编译器并不知道这个占位符类型T到底是什么对象,可以调用哪些方法,因此无约束的泛型方法所可以调用的方法就很少。因此就需要引入另一个话题:以约束换权利。
同一个类型参数可应用多个约束。约束自身也可以是泛型类,如下:
class MyList<T> where T: Employee, IEmployee, IComparable<T>, new()
{…}
下表列出了五类约束:
约束 描述
where T: struct 类型参数必须为值类型。
where T : class 类型参数必须为引用类型。
where T : new() 类型参数必须有一个公有、无参的构造函数。当于其它约束联合使用时,new()约束必须放在最后。
where T : <base class name> 类型参数必须是指定的基类型或是派生自指定的基类型。
where T : <interface name> 类型参数必须是指定的接口或是指定接口的实现。可以指定多个接口约束。接口约束也可以是泛型的。
应用:以父类或接口来约束泛型,调用泛型方法时传入不同的子类,同时还能使用其共同拥有的方法。