C# 泛型编程学习总结
生活随笔
收集整理的這篇文章主要介紹了
C# 泛型编程学习总结
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
C#泛型編程
http://www.cnblogs.com/kid-li/archive/2006/11/29/577045.html? ? ? ?泛型:通過參數(shù)化類型來實現(xiàn)在同一份代碼上操作多種數(shù)據(jù)類型。利用“參數(shù)化類型”將類型抽象化,從而實現(xiàn)靈活的復用。
例子代碼:
class Program{static void Main(string[] args){int obj = 2;Test<int> test = new Test<int>(obj);Console.WriteLine("int:" + test.obj);string obj2 = "hello world";Test<string> test1 = new Test<string>(obj2);Console.WriteLine("String:" + test1.obj);Console.Read();}}class Test<T>{public T obj;public Test(T obj){this.obj = obj;} }
? ? int:2
String:hello world
?
程序分析:
1、 ?Test是一個泛型類。T是要實例化的范型類型。如果T被實例化為int型,那么成員變量obj就是int型的,如果T被實例化為string型,那么obj就是string類型的。
2、 ?根據(jù)不同的類型,上面的程序顯示出不同的值。
?
C#泛型機制:
C#泛型能力有CLR在運行時支持:C#泛型代碼在編譯為IL代碼和元數(shù)據(jù)時,采用特殊的占位符來表示范型類型,并用專有的IL指令支持泛型操作。而真正的泛型實例化工作以“on-demand”的方式,發(fā)生在JIT編譯時。
?
看看剛才的代碼中Main函數(shù)的元數(shù)據(jù)
.method private hidebysig static void Main(string[] args) cil managed {.entrypoint// Code size 79 (0x4f).maxstack 2.locals init ([0] int32 obj,[1] class CSharpStudy1.Test`1<int32> test,[2] string obj2,[3] class CSharpStudy1.Test`1<string> test1)IL_0000: nopIL_0001: ldc.i4.2IL_0002: stloc.0IL_0003: ldloc.0IL_0004: newobj instance void class CSharpStudy1.Test`1<int32>::.ctor(!0)IL_0009: stloc.1IL_000a: ldstr "int:"IL_000f: ldloc.1IL_0010: ldfld !0 class CSharpStudy1.Test`1<int32>::objIL_0015: box [mscorlib]System.Int32IL_001a: call string [mscorlib]System.String::Concat(object,object)IL_001f: call void [mscorlib]System.Console::WriteLine(string)IL_0024: nopIL_0025: ldstr "hello world"IL_002a: stloc.2IL_002b: ldloc.2IL_002c: newobj instance void class CSharpStudy1.Test`1<string>::.ctor(!0)IL_0031: stloc.3IL_0032: ldstr "String:"IL_0037: ldloc.3IL_0038: ldfld !0 class CSharpStudy1.Test`1<string>::objIL_003d: call string [mscorlib]System.String::Concat(string,string)IL_0042: call void [mscorlib]System.Console::WriteLine(string)IL_0047: nopIL_0048: call int32 [mscorlib]System.Console::Read()IL_004d: popIL_004e: ret } // end of method Program::Main
再來看看Test類中構造函數(shù)的元數(shù)據(jù)
.method public hidebysig specialname rtspecialnameinstance void .ctor(!T obj) cil managed {// Code size 17 (0x11).maxstack 8IL_0000: ldarg.0IL_0001: call instance void [mscorlib]System.Object::.ctor()IL_0006: nopIL_0007: nopIL_0008: ldarg.0IL_0009: ldarg.1IL_000a: stfld !0 class ConsoleCSharpTest1.Test`1<!T>::objIL_000f: nopIL_0010: ret } // end of method Test`1::.ctor
1、第一輪編譯時,編譯器只為Test<T>類型產生“泛型版”的IL代碼與元數(shù)據(jù)——并不進行泛型的實例化,T在中間只充當占位符。例如:Test類型元數(shù)據(jù)中顯示的<!T>
2、JIT編譯時,當JIT編譯器第一次遇到Test<int>時,將用int替換“范型版”IL代碼與元數(shù)據(jù)中的T——進行泛型類型的實例化。例如:Main函數(shù)中顯示的<int>
3、CLR為所有類型參數(shù)為“引用類型”的泛型類型產生同一份代碼;但是如果類型參數(shù)為“值類型”,對每一個不同的“值類型”,CLR將為其產生一份獨立的代碼。因為實例化一個引用類型的泛型,它在內存中分配的大小是一樣的,但是當實例化一個值類型的時候,在內存中分配的大小是不一樣的。
?
C#泛型特點:
1、如果實例化泛型類型的參數(shù)相同,那么JIT編輯器會重復使用該類型,因此C#的動態(tài)泛型能力避免了C++靜態(tài)模板可能導致的代碼膨脹的問題。
2、C#泛型類型攜帶有豐富的元數(shù)據(jù),因此C#的泛型類型可以應用于強大的反射技術。
3、C#的泛型采用“基類、接口、構造器,值類型/引用類型”的約束方式來實現(xiàn)對類型參數(shù)的“顯示約束”,提高了類型安全的同時,也喪失了C++模板基于“簽名”的隱式約束所具有的高靈活性
?
C#泛型繼承:
C#除了可以單獨聲明泛型類型(包括類與結構)外,也可以在基類中包含泛型類型的聲明。但基類如果是泛型類,它的類型要么以實例化,要么來源于子類(同樣是泛型類型)聲明的類型參數(shù),看如下類型
class C<U,V>
class D:C<string,int>
class E<U,V>:C<U,V>
class F<U,V>:C<string,int>
class G:C<U,V> ?//非法
E類型為C類型提供了U、V,也就是上面說的來源于子類
F類型繼承于C<string,int>,個人認為可以看成F繼承一個非泛型的類
G類型為非法的,因為G類型不是泛型,C是泛型,G無法給C提供泛型的實例化
?
泛型類型的成員:
泛型類型的成員可以使用泛型類型聲明中的類型參數(shù)。但類型參數(shù)如果沒有任何約束,則只能在該類型上使用從System.Object繼承的公有成員。如下圖:
?
泛型接口:
泛型接口的類型參數(shù)要么已實例化,要么來源于實現(xiàn)類聲明的類型參數(shù)
?
泛型委托:
泛型委托支持在委托返回值和參數(shù)上應用參數(shù)類型,這些參數(shù)類型同樣可以附帶合法的約束
delegate bool MyDelegate<T>(T value); class MyClass {static bool F(int i){...}static bool G(string s){...}static void Main(){MyDelegate<string> p2 = G;MyDelegate<int> p1 = new MyDelegate<int>(F);} }
?泛型方法:
1、C#泛型機制只支持“在方法聲明上包含類型參數(shù)”——即泛型方法。
2、C#泛型機制不支持在除方法外的其他成員(包括屬性、事件、索引器、構造器、析構器)的聲明上包含類型參數(shù),但這些成員本身可以包含在泛型類型中,并使用泛型類型的類型參數(shù)。
3、泛型方法既可以包含在泛型類型中,也可以包含在非泛型類型中。
?
泛型方法聲明:如下
public static int FunctionName<T>(T value){...}
?
泛型方法的重載:
public void Function1<T>(T a);
public void Function1<U>(U a);
這樣是不能構成泛型方法的重載。因為編譯器無法確定泛型類型T和U是否不同,也就無法確定這兩個方法是否不同
?
public void Function1<T>(int x);
public void Function1(int x);
這樣可以構成重載
?
public void Function1<T>(T t) where T:A;
public void Function1<T>(T t) where T:B;
這樣不能構成泛型方法的重載。因為編譯器無法確定約束條件中的A和B是否不同,也就無法確定這兩個方法是否不同
?
泛型方法重寫:
在重寫的過程中,抽象類中的抽象方法的約束是被默認繼承的。如下:
abstract class Base
{
? ? public abstract T F<T,U>(T t,U u) where U:T;
? ? public abstract T G<T>(T t) where T:IComparable;
}
?
class MyClass:Base
{
? ? public override X F<X,Y>(X x,Y y){...}
? ? public override T G<T>(T t) where T:IComparable{}
}
對于MyClass中兩個重寫的方法來說
F方法是合法的,約束被默認繼承
G方法是非法的,指定任何約束都是多余的
?
泛型約束:
1、C#泛型要求對“所有泛型類型或泛型方法的類型參數(shù)”的任何假定,都要基于“顯式的約束”,以維護C#所要求的類型安全。
2、“顯式約束”由where子句表達,可以指定“基類約束”,“接口約束”,“構造器約束”,“值類型/引用類型約束”共四種約束。
3、“顯式約束”并非必須,如果沒有指定“顯式約束”,范型類型參數(shù)將只能訪問System.Object類型中的公有方法。例如:在開始的例子中,定義的那個obj成員變量。比如我們在開始的那個例子中加入一個Test1類,在它當中定義兩個公共方法Func1、Func2,如下圖:
?
下面就開始分析這些約束:
?
基類約束:
class A{public void Func1(){ }}class B{public void Func2(){ }}class C<S, T>where S : Awhere T : B{public C(S s,T t){//S的變量可以調用Func1方法s.Func1();//T的變量可以調用Func2方法t.Func2();}}
接口約束:
interface IA<T>{T Func1();}interface IB{void Func2();}interface IC<T>{T Func3();}class MyClass<T, V>where T : IA<T>where V : IB, IC<V>{public MyClass(T t,V v){//T的對象可以調用Func1t.Func1();//V的對象可以調用Func2和Func3v.Func2();v.Func3();}}
構造器約束:
class A{public A(){ }}class B{public B(int i){ }}class C<T> where T : new(){T t;public C(){t = new T();}}class D{public void Func(){C<A> c = new C<A>();C<B> d = new C<B>();}}
? ? 注意:C#現(xiàn)在只支持無參的構造器約束
? ? 此時由于我們?yōu)锽類型寫入了一個有參構造器,使得系統(tǒng)不會再為B自動創(chuàng)建一個無參的構造器,但是如果我們將B類型中加一個無參構造器,那么對象d的實例化就不會報錯了。B類型定義如下:
? ? ? ? class B
? ? ? ? {
? ? ? ? ? ? public B()
? ? ? ? ? ? { }
? ? ? ? ? ? public B(int i)
? ? ? ? ? ? { }
? ? ? ? }
public struct A { }
? ? ? ? public class B { }
?
? ? ? ? public class C<T> where T : struct
? ? ? ? {
?
? ? ? ? }
?
? ? ? ? C<A> c1 = new C<A>();
? ? ? ? C<B> c2 = new C<B>();
? ? c2對象在編譯時報錯:The type 'B' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or methor 'C<T>'
? ?
總結:
1、C#的泛型能力由CLR在運行時支持,它既不同于C++在編譯時所支持的靜態(tài)模板,也不同于Java在編譯器層面使用“擦拭法”支持的簡單的泛型。
2、C#的泛型支持包括類、結構、接口、委托四種泛型類型,以及方法成員。
3、C#的泛型采用“基類,接口,構造器,值類型/引用類型”的約束方式來實現(xiàn)對類型參數(shù)的“顯式約束”,它不支持C++模板那樣的基于簽名的隱式約束。
========
C# 泛型編程之泛型類、泛型方法、泛型約束
http://www.cnblogs.com/arxive/p/6179972.html所謂泛型,即通過參數(shù)化類型來實現(xiàn)在同一份代碼上操作多種數(shù)據(jù)類型。
泛型編程是一種編程范式,它利用“參數(shù)化類型”將類型抽象化,從而實現(xiàn)更為靈活的復用。在定義泛型類時,在對客戶端代碼能夠在實例化類時,可以用類型參數(shù)的類型種類施加限制。
泛型方法
在C# 2.0中,方法可以定義特定于其執(zhí)行范圍的泛型參數(shù),如下所示:
復制代碼
public class MyClass<T>
{
? ? //指定MyMethod方法用以執(zhí)行類型為X的參數(shù)
? ? public void MyMethod<X>(X x)?
? ? {
? ? ? ? //
? ? }
? ? //此方法也可不指定方法參數(shù)
? ? public void MyMethod<X>()?
? ? {
? ? ? ? //
? ? }
} ??
復制代碼
即使包含類不適用泛型參數(shù),你也可以定義方法特定的泛型參數(shù),如下所示:
復制代碼
public class MyClass
{
? ? //指定MyMethod方法用以執(zhí)行類型為X的參數(shù)
? ? public void MyMethod<X>(X x)?
? ? {
? ? ? ? //
? ? }
? ? //此方法也可不指定方法參數(shù)
? ? public void MyMethod<X>()?
? ? {
? ? ? ? //
? ? }
}
復制代碼
注意:屬性和索引器不能指定自己的泛型參數(shù),它們只能使用所屬類中定義的泛型參數(shù)進行操作。
在調用泛型方法的時候,你可以提供要在調用場所使用的類型,如下所示:
//調用泛型方法
MyClass myClass = new MyClass();
myClass.MyMethod<int>(3);
?
泛型推理:
在調用泛型方法時,C#編譯器足夠聰明,基于傳入的參數(shù)類型來推斷出正確的類型,并且它允許完全省略類型規(guī)范,如下所示:
//泛型推理機制調用泛型方法
MyClass myClass = new MyClass();
myClass.MyMethod(3);
注意:泛型方法無法只根據(jù)返回值的類型推斷出類型,代碼如下:
復制代碼
public GenericMethodDemo()
{ ? ? ? ?
? ? MyClass myClass = new MyClass();
? ? /****************************************************
? ? 無法從用法中推理出方法“GenericMethodDemo.MyClass.MyMethod<T>()”的類型參數(shù)。
? ? 請嘗試顯式指定類型參數(shù)。
? ? ***************************************************/
? ? int number = myClass.MyMethod();
}
public class MyClass
{
? ? public T MyMethod<T>()?
? ? {
? ? ? ? //
? ? }
}
復制代碼
泛型方法中泛型參數(shù)的約束,如下:
復制代碼
public class MyClass
{
? ??
? ? public void MyMethod<X>(X x) where X:IComparable<X>
? ? {
? ? ? ? //
? ? }
}
復制代碼
泛型類
無法為類級別的泛型參數(shù)提供方法級別的約束。類級別泛型參數(shù)的所有約束都必須在類作用范圍中定義,代碼如下所示
復制代碼
public class MyClass<T>
{
? ??
? ? public void MyMethod<X>(X x,T t) where X:IComparable<X> where T:IComparer<T>
? ? {
? ? ? ? //
? ? }
}
復制代碼
而下面的代碼是正確的:
復制代碼
public class MyClass<T> where T:IComparable<T>
{
? ??
? ? public void MyMethod<X>(X x,T t) where X:IComparable<X>?
? ? {
? ? ? ? //
? ? }
}
復制代碼
泛型參數(shù)虛方法的重寫:子類方法必須重新定義該方法特定的泛型參數(shù),代碼如下
復制代碼
public class MyBaseClass
{
? ? public virtual void SomeMethod<T>(T t)
? ? {
? ? ? ? //
? ? }
}
public class MyClass :MyBaseClass
{
? ? public override void SomeMethod<X>(X x)
? ? {
? ? ? ??
? ? }
}
復制代碼
同時子類中的泛型方法不能重復基類泛型方法的約束,這一點和泛型類中的虛方法重寫是有區(qū)別的,代碼如下
復制代碼
public class MyBaseClass
{
? ? public virtual void SomeMethod<T>(T t) where T:new()
? ? {
? ? ? ? //
? ? }
}
public class MyClass :MyBaseClass
{
? ? //正確寫法
? ? public override void SomeMethod<X>(X x)
? ? {
? ? ? ??
? ? }
? ? 錯誤 重寫和顯式接口實現(xiàn)方法的約束是從基方法繼承的,因此不能直接指定這些約束
? ? //public override void SomeMethod<X>(X x) where X:new()
? ? //{
? ? //}
}
復制代碼
?
子類方法調用虛擬方法的基類實現(xiàn):它必須指定要代替泛型基礎方法類型所使用的類型實參。你可以自己顯式的指定它,也可以依靠類型推理(如果可能的話)代碼如下:
復制代碼
public class MyBaseClass
{
? ? public virtual void SomeMethod<T>(T t) where T:new()
? ? {
? ? ? ? //
? ? }
}
public class MyClass :MyBaseClass
{
? ? //正確寫法
? ? public override void SomeMethod<X>(X x)
? ? {
? ? ? ? base.SomeMethod<X>(x);
? ? ? ? base.SomeMethod(x);
? ? }
}
復制代碼
泛型委托
在某個類中定義的委托可以使用該類的泛型參數(shù),代碼如下
復制代碼
public class MyClass<T>
{
? ? public delegate void GenericDelegate(T t);
? ? public void SomeMethod(T t)
? ? {
?
? ? }
}
public GenericMethodDemo()
{
? ? MyClass<int> obj = new MyClass<int>();
? ? MyClass<int>.GenericDelegate del;
? ? del = new MyClass<int>.GenericDelegate(obj.SomeMethod);
? ? del(3);
}
復制代碼?
委托推理:C#2.0使你可以將方法引用的直接分配轉變?yōu)槲凶兞俊⑸厦娴拇a改造如下
復制代碼
public class MyClass<T>
{
? ? public delegate void GenericDelegate(T t);
? ? public void SomeMethod(T t)
? ? {
?
? ? }
}
public GenericMethodDemo()
{
? ? MyClass<int> obj = new MyClass<int>();
? ? MyClass<int>.GenericDelegate del;
? ? //委托推理
? del = obj.SomeMethod;
? ? del(3);
?} ?
復制代碼
泛型委托的約束:
委托級別的約束只在聲明委托變量和實例化委托時使用,類似于在類型和方法的作用范圍中實施的其他任何約束。
泛型和反射
在Net2.0當中,擴展了反射以支持泛型參數(shù)。類型Type現(xiàn)在可以表示帶有特定類型的實參(或綁定類型)或未指定類型的泛型(或稱未綁定類型)。像C#1.1中那樣,您可以通過使用typeof運算符或通過調用每個類型支持的GetType()來獲得任何類型的Type。代碼如下:
復制代碼
LinkedList<int> list = new LinkedList<int>();
?Type type1 = typeof(LinkedList<int>);
?Type type2 = list.GetType();
?Response.Write(type1 == type2);
?typeof和GetType()也可以對泛型參數(shù)進行操作,如下
public class MyClass<T>
{
public void SomeMethod(T t)
{
? ? Type type = typeof(T);
? ? HttpContext.Current.Response.Write(type==t.GetType());
}
}
復制代碼
typeof還可以對未綁定的泛型進行操作,代碼如下
復制代碼
protected void Page_Load(object sender, EventArgs e)
{
? ? if (!IsPostBack)
? ? {
? ? ? ? Type unboundType = typeof(MyClass<>);
? ? ? ? Response.Write(unboundType.ToString());
? ? }
}
public class MyClass<T>
{
? ? public void SomeMethod(T t)
? ? {
? ? ? ? Type type = typeof(T);
? ? ? ? HttpContext.Current.Response.Write(type==t.GetType());
? ? }
}
復制代碼
?
請注意"<>"的用法。要對帶有多個類型參數(shù)的未綁定泛型類進行操作,請在"<>"中使用","
Type類中添加了新的方法和屬性,用于提供有關該類型的泛型方面的反射信息,見MSDN。
.net泛型約束 ?
如果客戶端代碼嘗試使用某個約束所不允許的類型來實例化類,則會產生編譯時錯誤。這些限制稱為約束。約束是使用 where 上下文關鍵字指定的。
一、 約束
下表列出了五種類型的約束:
約束 說明
T:struct
類型參數(shù)必須是值類型。可以指定除 Nullable 以外的任何值類型。
T:class
類型參數(shù)必須是引用類型,包括任何類、接口、委托或數(shù)組類型。
T:new()
類型參數(shù)必須具有無參數(shù)的公共構造函數(shù)。當與其他約束一起使用時,new() 約束必須最后指定。
T:<基類名>
類型參數(shù)必須是指定的基類或派生自指定的基類。
T:<接口名稱>
類型參數(shù)必須是指定的接口或實現(xiàn)指定的接口。可以指定多個接口約束。約束接口也可以是泛型的。
T:U
為 T 提供的類型參數(shù)必須是為 U 提供的參數(shù)或派生自為 U 提供的參數(shù)。這稱為裸類型約束.
?
派生約束
1.常見的
public class MyClass5<T> where T :IComparable { }
2.約束放在類的實際派生之后
public class B { }
public class MyClass6<T> : B where T : IComparable { }
3.可以繼承一個基類和多個接口,且基類在接口前面
public class B { }
public class MyClass7<T> where T : B, IComparable, ICloneable { }
構造函數(shù)約束
1.常見的
public class MyClass8<T> where T : ?new() { }
2.可以將構造函數(shù)約束和派生約束組合起來,前提是構造函數(shù)約束出現(xiàn)在約束列表的最后
public class MyClass8<T> where T : IComparable, new() { }
值約束
1.常見的
public class MyClass9<T> where T : struct { }
2.與接口約束同時使用,在最前面(不能與基類約束,構造函數(shù)約束一起使用)
public class MyClass11<T> where T : struct, IComparable { }
引用約束
常見的
public class MyClass10<T> where T : class { }
多個泛型參數(shù)
?public class MyClass12<T, U> where T : IComparable ?where U : class { }
?
二、 繼承和泛型
public class B<T>{ }
1. 在從泛型基類派生時,可以提供類型實參,而不是基類泛型參數(shù)
? ? public class SubClass11 : B<int>
? ? { }
2.如果子類是泛型,而非具體的類型實參,則可以使用子類泛型參數(shù)作為泛型基類的指定類型
? ? public class SubClass12<R> : B<R>
? ? { }
3.在子類重復基類的約束(在使用子類泛型參數(shù)時,必須在子類級別重復在基類級別規(guī)定的任何約束)
? ? public class B<T> where T : ISomeInterface { }
? ? public class SubClass2<T> : B<T> where T : ISomeInterface { }
4.構造函數(shù)約束
? ? public class B<T> where T : new()
? ? {
? ? ? ? public T SomeMethod()
? ? ? ? {
? ? ? ? ? ? return new T();
? ? ? ? }
? ? }
? ? public class SubClass3<T> : B<T> where T : new(){ }
三、泛型方法
(C#2.0泛型機制支持在"方法聲名上包含類型參數(shù)",這就是泛型方法)
1.泛型方法既可以包含在泛型類型中,又可以包含在非泛型類型中
public class MyClass5
? ? {
? ? ? ? public void MyMethod<T>(T t){ }
? ? }
2.泛型方法的聲明與調用
復制代碼
public class MyClass5
{
? ? public void MyMethod<T>(T t){ }
}
public class App5
{
? ? public void CallMethod()
? ? {
? ? ? ? MyClass5 myclass5 = new MyClass5();
? ? ? ? myclass5.MyMethod<int>(3);
? ? }
}
復制代碼
3.泛型方法的重載
復制代碼
//第一組重載
?void MyMethod1<T>(T t, int i){ }
?void MyMethod1<U>(U u, int i){ }
//第二組重載
?void MyMethod2<T>(int i){ }
?void MyMethod2(int i){ }
//第三組重載,假設有兩個泛型參數(shù)
?void MyMethod3<T>(T t) where T : A { }
void MyMethod3<T>(T t) where T : B { }
//第四組重載
public class MyClass8<T,U>
{
? ? public T MyMothed(T a, U b)
? ? {
? ? ? ? return a;
? ? }
? ? public T MyMothed(U a, T b)
? ? {
? ? ? ? return b;
? ? }
? ? public int MyMothed(int a, int b)
? ? {
? ? ? ? return a + b;
? ? }
}
復制代碼
?
4.泛型方法的覆寫
(1)public class MyBaseClass1
? ? {
? ? ? ? public virtual void MyMothed<T>(T t) where T : new() { }
? ? }
? ? public class MySubClass1:MyBaseClass1
? ? {
? ? ? ? public override void MyMothed<T>(T t) //不能重復任何約束
? ? ? ? { }
? ? }
(2)public class MyBaseClass2
? ? {
? ? ? ? public virtual void MyMothed<T>(T t)
? ? ? ? { }
? ? }
? ? public class MySubClass2 : MyBaseClass2
? ? {
? ? ? ? public override void MyMothed<T>(T t) //重新定義泛型參數(shù)T
? ? ? ? { }
? ? }
四、虛擬方法
復制代碼
public class BaseClass4<T>
{
? ? public virtual T SomeMethod()
? ? {
? ? ? ? return default(T);
? ? }
}
public class SubClass4 : BaseClass4<int> //使用實參繼承的時候方法要使用實參的類型
{
? ? public override int SomeMethod()
? ? {
? ? ? ? return 0;
? ? }
}
public class SubClass5<T> : BaseClass4<T> //使用泛型繼承時,方法也是泛型
{
? ? public override T SomeMethod()
? ? {
? ? ? ? return default(T);
? ? }
}
五、泛型參數(shù)隱式強制轉換
編譯器只允許將泛型參數(shù)隱式強制轉換到 Object 或約束指定的類型。
class MyClass<T> where T : BaseClass, ISomeInterface
{
? ? void SomeMethod(T t)
? ? {
? ? ? ? ISomeInterface obj1 = t;
? ? ? ? BaseClass obj2 = t;
? ? ? ? object obj3 = t;
? ? }
}
復制代碼?
?
變通方法:使用臨時的 Object 變量,將泛型參數(shù)強制轉換到其他任何類型
class MyClass2<T>
{
? ? void SomeMethod(T t)
? ? {
? ? ? ? object temp = t;
? ? ? ? BaseClass obj = (BaseClass)temp;
? ? }
}
?
六、 泛型參數(shù)顯式強制轉換
編譯器允許您將泛型參數(shù)顯式強制轉換到其它任何接口,但不能將其轉換到類
class MyClass1<T>
{
? ? void SomeMethod(T t)
? ? {
? ? ? ? ISomeInterface obj1 = (ISomeInterface)t; ?
? ? ? ? //BaseClass obj2 = (BaseClass)t; ? ? ? ? ? //不能通過編譯
? ? }
}
七、 泛型參數(shù)強制轉換到其他任何類型
使用臨時的 Object 變量,將泛型參數(shù)強制轉換到其他任何類型
class MyClass2<T>
{
? ? void SomeMethod(T t)
? ? {
? ? ? ? object temp = t;
? ? ? ? BaseClass obj = (BaseClass)temp;
? ? }
}
八、使用is和as運算符
public class MyClass3<T>
{
? ? public void SomeMethod(T t)
? ? {
? ? ? ? if (t is int) { }
? ? ? ? if (t is LinkedList<int>) { }
? ? ? ? string str = t as string;
? ? ? ? if (str != null) { }
? ? ? ? LinkedList<int> list = t as LinkedList<int>;
? ? ? ? if (list != null) { }
? ? }
}
========
泛型介紹(C# 編程指南)
https://msdn.microsoft.com/zh-cn/library/0x6a29h6.aspx泛型類和泛型方法同時具備可重用性、類型安全和效率,這是非泛型類和非泛型方法無法具備的。 泛型通常用與集合以及作用于集合的方法一起使用。 .NET Framework 2.0 版類庫提供一個新的命名空間 System.Collections.Generic,其中包含幾個新的基于泛型的集合類。 建議面向 .NET Framework 2.0 及更高版本的所有應用程序都使用新的泛型集合類,而不要使用舊的非泛型集合類如 ArrayList。 有關更多信息,請參見 .NET Framework 類庫中的泛型。
當然,也可以創(chuàng)建自定義泛型類型和方法,以提供自己的通用解決方案,設計類型安全的高效模式。 下面的代碼示例演示一個用于演示用途的簡單泛型鏈接列表類。 (大多數(shù)情況下,應使用 .NET Framework 類庫提供的 List<T> 類,而不是自行創(chuàng)建類。)在通常使用具體類型來指示列表中存儲的項的類型的場合,可使用類型參數(shù) T。 其使用方法如下:
在 AddHead 方法中作為方法參數(shù)的類型。
在 Node 嵌套類中作為公共方法 GetNext 和 Data 屬性的返回類型。
在嵌套類中作為私有成員數(shù)據(jù)的類型。
注意,T 可用于 Node 嵌套類。 如果使用具體類型實例化 GenericList<T>(例如,作為 GenericList<int>),則所有的 T 都將被替換為 int。
C#
? ? ? ? // type parameter T in angle brackets
? ? ? ? public class GenericList<T>?
? ? ? ? {
? ? ? ? ? ? // The nested class is also generic on T.
? ? ? ? ? ? private class Node
? ? ? ? ? ? {
? ? ? ? ? ? ? ? // T used in non-generic constructor.
? ? ? ? ? ? ? ? public Node(T t)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? next = null;
? ? ? ? ? ? ? ? ? ? data = t;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? private Node next;
? ? ? ? ? ? ? ? public Node Next
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? get { return next; }
? ? ? ? ? ? ? ? ? ? set { next = value; }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? // T as private member data type.
? ? ? ? ? ? ? ? private T data;
? ? ? ? ? ? ? ? // T as return type of property.
? ? ? ? ? ? ? ? public T Data ?
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? get { return data; }
? ? ? ? ? ? ? ? ? ? set { data = value; }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? private Node head;
? ? ? ? ? ??
? ? ? ? ? ? // constructor
? ? ? ? ? ? public GenericList()?
? ? ? ? ? ? {
? ? ? ? ? ? ? ? head = null;
? ? ? ? ? ? }
? ? ? ? ? ? // T as method parameter type:
? ? ? ? ? ? public void AddHead(T t)?
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Node n = new Node(t);
? ? ? ? ? ? ? ? n.Next = head;
? ? ? ? ? ? ? ? head = n;
? ? ? ? ? ? }
? ? ? ? ? ? public IEnumerator<T> GetEnumerator()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Node current = head;
? ? ? ? ? ? ? ? while (current != null)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? yield return current.Data;
? ? ? ? ? ? ? ? ? ? current = current.Next;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
下面的代碼示例演示客戶端代碼如何使用泛型 GenericList<T> 類來創(chuàng)建整數(shù)列表。 只需更改類型參數(shù),即可方便地修改下面的代碼示例,創(chuàng)建字符串或任何其他自定義類型的列表:
C#
? ? ? ? class TestGenericList
? ? ? ? {
? ? ? ? ? ? static void Main()
? ? ? ? ? ? {
? ? ? ? ? ? ? ? // int is the type argument
? ? ? ? ? ? ? ? GenericList<int> list = new GenericList<int>();
? ? ? ? ? ? ? ? for (int x = 0; x < 10; x++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? list.AddHead(x);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? foreach (int i in list)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? System.Console.Write(i + " ");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? System.Console.WriteLine("\nDone");
? ? ? ? ? ? }
? ? ? ? }
請參閱
System.Collections.Generic
C# 編程指南
泛型
========
總結
以上是生活随笔為你收集整理的C# 泛型编程学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# rdlc 报表学习总结
- 下一篇: C# 字符串操作学习总结