今天咱们来学习在C#的泛型技巧,传统的课本都在讲解什么是泛型,而后列举一大堆代码示例告诉你什么是泛型,今天咱们就来聊聊更加本质的东西,我为何要用泛型?它是来解决什么问题的?底层原理是什么?c++
简单来讲,泛型解决的是什么问题呢?算法重用和提高性能的。程序员
最最经典的例子是什么?就是微软支持的List<T>类型,想必绝大多的程序员都是使用过这个类的。若是没有这个类,咱们能够想象下,若是要你开发一个算法类,支持对数组的长度动态扩展的,还支持一些广泛的数组操做的话。你会怎么写?算法
好比我要写 int 数据类型的数组操做功能,写了一遍的 ListInt 类,若是这时候咱们须要写一个 float 类型的数组操做对象,咱们又得写一遍 ListFloat, 也就是说,每用到一个新的类型的时候,都须要写一遍类,而这之间的代码绝大部分都是类似的。数组
你可能会提出我搞一个 ListObject 类就能够了,这样就能够知足全部的状况了,恭喜你,这真的是个很不错的想法,不管你的类型是什么?都会转换为object进行数组的操做,这样只要写一套代码就能够了。只是,当你用了一段时间以后,它会碰到2个比较麻烦的问题性能
1. 我实例化了 ListObject 类,Add了不少了int类型的数据,我如今要获取全部的int类型的数组,好比int[],这个比较麻烦,须要对全部object数据进行强制转换。数组的长度比较大的时候,这时候性能就不好,为何说c和c++性能高,都是地址基于地址的操做,没有类型转换一说。学习
2. 我实例化了 ListObject 类,Add了不少了int类型的数据,可是我在用的时候,很容易就误觉得是float类型的,从而转换失败,下降了开发的效率。对象
这时候咱们就要让泛型出场了,List<T>类型,将数组通常的操做逻辑都进行了封装,add,remove,insert,clear,等等操做。当你须要使用int类型的时候,就能够定义List<int>的对象,当你须要short类型的时候,就能够定义List<short>对象,并且不用再转换来转换去了。blog
彷佛除了上述的状况须要泛型外,彷佛咱们实际中已经不须要泛型了,答案固然是否认的、ci
假设,咱们须要编写一个公共的方法。是对数组操做的,好比咱们会写一个方法,将数组扩充到指定长度开发
/// <summary> /// 将一个数组进行扩充到指定长度,或是缩短到指定长度 -> /// Extend an array to a specified length, or shorten to a specified length or fill /// </summary> /// <typeparam name="T">数组的类型</typeparam> /// <param name="data">原先数据的数据</param> /// <param name="length">新数组的长度</param> /// <returns>新数组长度信息</returns> public static T[] ArrayExpandToLength<T>( T[] data, int length ) { if (data == null) return new T[length]; if (data.Length == length) return data; T[] buffer = new T[length]; Array.Copy( data, buffer, Math.Min( data.Length, buffer.Length ) ); return buffer; }
这么来看,这个就特别是否写成泛型,和类型无关的状况。
以前是数组的例子,咱们再来看看另外一个实际的例子。咱们先看看代码:
/// <summary> /// 操做结果的泛型类,容许带一个用户自定义的泛型对象,推荐使用这个类 /// </summary> /// <typeparam name="T">泛型类</typeparam> public class OperateResult<T> : OperateResult { #region Constructor /// <summary> /// 实例化一个默认的结果对象 /// </summary> public OperateResult( ) : base( ) { } /// <summary> /// 使用指定的消息实例化一个默认的结果对象 /// </summary> /// <param name="msg">错误消息</param> public OperateResult( string msg ) : base( msg ) { } /// <summary> /// 使用错误代码,消息文原本实例化对象 /// </summary> /// <param name="err">错误代码</param> /// <param name="msg">错误消息</param> public OperateResult( int err, string msg ) : base( err, msg ) { } #endregion /// <summary> /// 用户自定义的泛型数据 /// </summary> public T Content { get; set; } }
当你的自定义类须要携带一个数据时,而这个数据多是任意类型的时候,这时候可使用泛型。好比这里的 OperateResult<int> 就是很是好的例子。能够用来携带任意的自定义的数据。甚至是数组
OperateResult<List<int>> 这样也是能够的。
未完待与