C#泛型详细介绍与实例说明(详细)

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

决定在何时何地使用泛型问题您希望在一个新工程内使用泛型,或者想把已有项目中的非泛型类转换为等价的泛型版本。但您并非了解为何要这样做,也不知道哪个非泛型类应该被转换为泛型类。解决方案决定在何时何地使用泛型,您需要考虑以下几件事件:您所使用的类型是否包含或操作未指定的数据类型(如集合类型)?如果是这样,如果是这样,创建泛型类型将能提供更多的好处。如果您的类型只操作单一的指定类型,那么就没有必要去创建一个泛型类。如果您的类型将操作值类型,那么就会产生装箱和拆箱操作,就应该考虑使用泛型来防止装箱和拆箱操作。泛型的强类型检查有助于快速查找错误(也就是编译期而非运行期),从而缩短bug修复周期。在编写多个类操作多个数据类型时是否遭遇到“代码膨胀”问题(如一个ArrayList只存储StreamReaders而另一个存储StreamWriters)?其实编写一次代码并让它工作于多个数据类型非常简单。泛型使得代码更为清晰。通过消除代码膨胀并进行强制检查,您的代码将变得更易于阅读和理解。讨论很多时候,使用泛型类型将使您受益。泛型将使得代码重用更有效率,具有更快的执行速度,进行强制类型检查,获得更易读的代码。阅读参考MSDN文档中的“GenericsOverview”和“BenefitsofGenerics”主题。4.2理解泛型类型问题您需要理解泛型类型在.NET中是如何工作的,它跟一般的.NET类型有什么不同。解决方案几个小实验就可以演示一般类型和泛型类型之间的区别。例4-1中的StandardClass类就是一个般类型。例4-1StandardClass:一般的.NET类型publicclassStandardClass{staticint_count=0;//StandardClass类的对象的表态计数器int_maxItemCount;//项数目的昀大值object[]_items;//保存项的数组int_currentItem=0;//当前项数目publicStandardClass(intitems)//构造函数{_count++;//对象数目加_maxItemCount=items;_items=newobject[_maxItemCount];//数组初始化}//用于添加项,为了适用于任何类型,使用了object类型publicintAddItem(objectitem){if(_currentItem_maxItemCount){_items[_currentItem]=item;return_currentItem++;//返回添加的项的索引}elsethrownewException(Itemqueueisfull);}//用于从类中取得指定项publicobjectGetItem(intindex){Debug.Assert(index_maxItemCount);//设置断言if(index=_maxItemCount)thrownewArgumentOutOfRangeException(index);return_items[index];//返回指定项}publicintItemCount//属性,指示当前项数目{get{return_currentItem;}}publicoverridestringToString(){//重载ToString方法,用于介绍类的情况returnThereare+_count.ToString()+instancesof+this.GetType().ToString()+whichcontains+_currentItem+itemsoftype+_items.GetType().ToString()+;}}StandardClass类有一个整型静态成员变量_count,用于在实例构造器中计数。重载的ToString()方法打印在这个应用程序域中StandardClass类实例的数目。StandardClass类还包括一个object数组(_item),它的长度由构造方法中的传递的参数来决定。它实现了添加和获得项的方法(AddItem,GetItem),还有一个只读属性来获取数组中的项的数目(ItemCount)。GenericClassT类是一个泛型类型,同样有静态成员变量_count,实例构造器中对实例数目进行计算,重载的ToString()方法告诉您有多少GenericClassT类的实例存在。GenericClassT也有一个_itmes数组和StandardClass类中的相应方法,请参考例4-2。Example4-2GenericClassT:泛型类publicclassGenericClassT{staticint_count=0;int_maxItemCount;T[]_items;int_currentItem=0;publicGenericClass(intitems){_count++;__maxItemCount=items;_items=newT[_maxItemCount];}publicintAddItem(Titem){if(_currentItem_maxItemCount){_items[_currentItem]=item;return_currentItem++;}elsethrownewException(Itemqueueisfull);}publicTGetItem(intindex){Debug.Assert(index_maxItemCount);if(index=_maxItemCount)thrownewArgumentOutOfRangeException(index);return_items[index];}publicintItemCount{get{return_currentItem;}}publicoverridestringToString(){returnThereare+_count.ToString()+instancesof+this.GetType().ToString()+whichcontains+_currentItem+itemsoftype+_items.GetType().ToString()+;}}从GenericClassT中的少许不同点开始,看看_items数组的声明。它声明为:T[]_items;而不是object[]_items;_items数组使用泛型类(T)做为类型参数以决定在_itmes数组中接收哪种类型的项。StandarClass在_itmes数组中使用Objcec以使得所有类型都可以做为项存储在数组中(因为所有类型都继承自object)。而GenericClassT通过使用类型参数指示允许使用的对象类型来提供类型安全。下一个不同在于AddItem和GetItem方法的声明。AddItem现在使用一个类型T做为参数,而在StandardClass中使用object类型做为参数。GetItem现在的返回值类型T,StandardClass返回值为object类型。这个改变允许GenericClassT中的方法在数组中存储和获得具体的类型而非StandardClass中的允许存储所有的object类型。publicintAddItem(Titem){if(_currentItem_maxItemCount){_items[_currentItem]=item;return_currentItem++;}elsethrownewException(Itemqueueisfull);}publicTGetItem(intindex){Debug.Assert(index_maxItemCount);if(index=_maxItemCount)thrownewArgumentOutOfRangeException(index);return_items[index];}这样做的优势在于,首先通过GenericClassT为数组中的项提供了类型安全。在StandardClass中可能会这样写代码://一般类StandardClassC=newStandardClass(5);Console.WriteLine(C);strings1=s1;strings2=s2;strings3=s3;inti1=1;//在一般类中以object的形式添加项C.AddItem(s1);C.AddItem(s2);C.AddItem(s3);//在字符串数组中添加一个整数,也被允许C.AddItem(i1);但在GenericClassT中做同样的事情将导致编译错误://泛型类GenericClassstringgC=newGenericClassstring(5);Console.WriteLine(gC);strings1=s1;strings2=s2;strings3=s3;inti1=1;//把字符串添加进泛型类.gC.AddItem(s1);gC.AddItem(s2);gC.AddItem(s3);//尝试在字符串实例中添加整数,将被编译器拒绝//errorCS1503:Argument'1':cannotconvertfrom'int'to'string'//GC.AddItem(i1);编译器防止它成为运行时源码的bug,这是一件非常美妙的事情。虽然并非显而易见,但在StandardClass中把整数添加进object数组会导致装箱操作,这一点可以StandardClass调用GetItem方法时的IL代码:IL_0170:ldloc.2IL_0171:ldloc.si1IL_0173:box[mscorlib]System.Int32IL_0178:callvirtinstanceint32CSharpRecipes.Generics/StandardClass::AddItem(object)这个装箱操作把做为值类型的整数转换为引用类型(object),从而可以在数组中存储。这导致了在object数组中存储值类型时需要增加额外的工作。当您在运行StandardClass并从类中返回一个项时,还会产生一个问题,来看看StandardClass.GetItem如何返回一个项://存储返回的字符串.stringsHolder;//发生错误CS0266://Cannotimplicitlyconverttype'object'to'string'…sHolder=(string)C.GetItem(1);因为StandardClass.GetItem返回的是object类型,而您希望通过索引1获得一个字符串类型,所以需要把它转换为字符串类型。然而它有可能并非字符串-----只能确定它是一个object-----但为了赋值正确,您不得不把它转换为更明确的类型。字符串比较特殊,所有对象都可以自行提供一个字符串描述,但当数组接收一个double类型并把它赋给一个布尔类型就会出问题。这两个问题在GenericClassT中被全部解决。无需再进行拆箱,因为GetItem所返回的是一个具体类型,编译器会检查返回值以强近它执行。stringsHolder;intiHolder;//不需要再进行转换sHolder=gC.GetItem(1);//尝试把字符串变为整数.将出现//错误CS0029:Cannotimplicitlyconverttype'string'to'int'//iHolder=gC.GetItem(1);为了了解两种类型的其他不同点,分别给出它们的示例代码://一般类StandardClassA=newStandardClass();Console.WriteLine(A);StandardClassB=newStandardClass();Console.WriteLine(B);Sta

1 / 62
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功