用泛型实现参数化类型
生活随笔
收集整理的這篇文章主要介紹了
用泛型实现参数化类型
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
泛型將大量安全檢查從執行時轉移到了編譯時進行,泛型實現了類型和方法的參數化。
為什么需要泛型- 將額外的信息作為方法或類型聲明的一部分加以說明
- IDE能基于額外的信息向程序員提供智能感知
- 方法調用者對自己傳遞的值和方法返回值更有把握
- 維護代碼時,可以更好的掌握代碼思路
如果指定了類型實參,就是一個已構造類型。已構造類型可以是開發或封閉的,開放類型還包括一個類型參數,封閉類型每個部分都是明確的 可以認為封閉類型擁有開放類型的API。 泛型方法和判讀泛型聲明
static double TakeSquareRoot(int x)//平方根3-2返回 { return Math.Sqrt(x); } #region 3-2List<T>.ConcertAll<TOutput> List<int> integer = new List<int>();//創建并填充整個列表 integer.Add(1); integer.Add(2); integer.Add(3); integer.Add(4); Converter<int, double> converter = TakeSquareRoot;//創建委托 List<double> doubles; doubles = integer.ConvertAll<double>(converter);//調用泛型方法來轉換列表 foreach (double d in doubles) { Console.WriteLine(d); } #endregion 在非泛型方法中實現泛型方法 static List<T> MakeList<T>(T first, T second) { List<T> list = new List<T>(); list.Add(first); list.Add(second); return list; } List<string> list = MakeList<string>("Line 1", "Line 2"); List<string> list1 = MakeList("Line 1", "Line 2");//類型推斷:只適用于泛型方法,不適用于泛型類型 Console.WriteLine(list.Capacity); foreach (string i in list) { Console.WriteLine(i); } 深化與提高 類型約束 類型參數可以被指定為任意類型時,它們未被約束 引用類型約束 確保使用的類型實參是引用類型。類型實參任何類,接口,委托,或已知是引用類型的另一個類型參數。 struct TefSample1<T> where T : class//引用類型約束,使用這種方式約束一個類型實參后,可以用==和!=來比較引用(包括NULL) { ? } 值類型約束 確保使用的類型實參是值類型,包括枚舉,但是將可空類型排除在外 class TefSample<T> where T : struct//值類型約束,使用這種方式約束一個類型實參后,不可以用==和!=來比較 { } 構造函數類型約束 必須是所有類型參數的最后一個約束,它檢查是否有一個可用創建類型實例的無參構造函數。所有值類型都有一個默認的無參構造函數,而且顯示聲明的構造函數和無參構造函數是用相同的語法來調用的。 public static T CreateUbstance<T>() where T : new()//檢查類型實例是否有一個可用于創建類型實例的構造函數 { return new T(); } T為int和object都是有效的,但T為string是無效的,因為string沒有一個無參構造函數 轉換類型約束 可以規定一個類型實參必須可以轉換成另一個類型實參 class Sample<T> where T : Stream//轉換類型約束 { ? } Sample<Stream> s = new Sample<Stream>(); 組合約束 class Sqmple<T, U> where T : class where U : struct,T//組合約束,每一個值類型都有一個構造函數,假如已經有了一個值類型約束,就不允許在有構造函數約束 { ? } //指定多個接口,但只能指定一個類 class Sample2<T> where T : Stream, IEnumerable<string>, IComparable<int> { ? } 泛型方法類型實參的類型推斷
類型推斷只適用于泛型方法,不適用于泛型類型
實現泛型 默認值表達式 //3-4將一個值與類型默認值比較 static int CompaerToDefault<T>(T value) where T : IComparable<T> { return value.CompareTo(default(T)); } #region 3-4以一個泛型方式將一個給定的值和一個默認值比較 Console.WriteLine(CompaerToDefault("x")); Console.WriteLine(CompaerToDefault(10)); Console.WriteLine(CompaerToDefault(0)); Console.WriteLine(CompaerToDefault(-10)); Console.WriteLine(CompaerToDefault(DateTime.MinValue)); #endregion 直接比較 static bool AreReferencesEqual<T>(T first, T second) where T : class { return first == second; } #region 3-5 用==和!=進行引用比較 string name = "Jon"; string intro1 = "My name is" + name; string intro2 = "My name is" + name; Console.WriteLine(intro1 == intro2); Console.WriteLine(AreReferencesEqual(intro1, intro2)); #endregion 對==進行重載,AreReferenxesEqual使用object 表示一對值 #region 表示一對值的泛型類 public sealed class Pair<T1, T2> : IEquatable<Pair<T1, T2>> { //每個封閉類型都有它自己的靜態集 private static readonly IEqualityComparer<T1> FirstComparer = EqualityComparer<T1>.Default; private static readonly IEqualityComparer<T2> SecondComparer = EqualityComparer<T2>.Default; ? private readonly T1 first; private readonly T2 second; ? public Pair(T1 first, T2 second) { this.first = first; this.second = second; } ? public T1 First { get { return first; } } ? public T2 Second { get { return second; } } ? public bool Equals(Pair<T1, T2> other) { return other != null && FirstComparer.Equals(this.First, other.First) && SecondComparer.Equals(this.Second, other.Second); } ? public override bool Equals(object obj)//重寫 { return base.Equals(obj as Pair<T1, T2>); } ? public override int GetHashCode() { return FirstComparer.GetHashCode(first) * 37 + SecondComparer.GetHashCode(second); } ? } #endregion #region 使用泛型方法的非泛型類型進行推斷 public static class Pair { public static Pair<T1, T2> Of<T1, T2>(T1 first, T2 second) { return new Pair<T1, T2>(first, second); } } #endregion #region 表示一對值的泛型類 Pair<int, string> pair = new Pair<int, string>(10, "value"); #endregion ? #region 使用泛型方法的非泛型類型進行推斷 Pair<int, string> pair1 = Pair.Of(10, "VALUE");//類型推斷根據方法進行,對于每一個方法實參,都嘗試推斷泛型方法的一些實參(簡單推斷技術),對于泛型方法要么推斷要么全部顯示指定。 ? #endregion 高級泛型 靜態字段和靜態構造函數 每個封閉的類型都有它自己的靜態字段集 #region 3-8 證明不通的封閉類型具有不同的靜態字段 //每個封閉類型有一個靜態字段 TypeWithField<int>.field = "First"; TypeWithField<string>.field = "Secind"; TypeWithField<DateTime>.field = "Third"; ? TypeWithField<int>.PrinfField(); TypeWithField<string>.PrinfField(); TypeWithField<DateTime>.PrinfField(); #endregion class TypeWithField<T> { public static string field; public static void PrinfField() { Console.WriteLine(field + ":" + typeof(T).Name); } } 一個泛型類型可能嵌套在另一個泛型類型中,而且一個類型可能有多個泛型參數。 #region 3-9 嵌套泛型類型的靜態構造函數 Outer<int> o = Outer.Of<int>(); ? Outer<int>.Inner<String, DateTime>.DummyMethod(); Outer<string>.Inner<int, int>.DummyMethod(); Outer<object>.Inner<string, object>.DummyMethod(); Outer<string>.Inner<string, object>.DummyMethod(); Outer<object>.Inner<object, string>.DummyMethod(); Outer<int>.Inner<string, DateTime>.DummyMethod();//任何封閉類型的構造函數只執行一次 ? #endregion public class Outer<T> { public class Inner<U, V> { static Inner() { Console.WriteLine("Outer<{0}>.Inner<{1},{2}>", typeof(T).Name, typeof(U).Name, typeof(V).Name); } public static void DummyMethod() { } } } JIT編譯器如果處理泛型 JIT為每個以值類型作為類型實參的封閉類型都創建不同的代碼,所有使用引用類型作為類型實參的封閉類型都共享本地代碼(所有引用都具有相同的大小。32位CLR上是4字節,64位CLR上是8字節)棧上一個引用所需空間始終相同。 ArrayList中,需要對每個字節進行裝箱。 在32位CLR上: ArrayList:8字節對象開銷,4字節(1字節)數據本身,引用4字節 Liat<byte>:2字節(數據實際1字節) 泛型迭代 使用foreach,需要將集合的類型實參作為迭代變量類型使用 #region 3-10 class CountingEnumerable : IEnumerable<int> { public IEnumerator<int> GetEnumerator()//隱式實現IEnumerable<T> { return new CountingEnumerator(); } IEnumerator IEnumerable.GetEnumerator()//顯示實現IEnumerable { return GetEnumerator(); } ? } ? class CountingEnumerator : IEnumerator<int> { int current = -1; ? public bool MoveNext() //接口IEnumerator的實現,將枚舉數推進到集合的下一個元素。 { current++; return current < 10; } ? public int Current { get { return current; } }//隱式實現IEnumerator<T>.Current ? object IEnumerator.Current { get { return Current; } }//顯示實現IEnumerator.Current ? public void Reset() //接口IEnumerator的實現,將枚舉數設置為其初始位置,該位置位于集合中第一個元素之前。 { current = -1; } ? public void Dispose() { }//接口IDisposable,執行與釋放或重置非托管資源相關的應用程序定義的任務。 } #endregion #region 3-10 一個完整的泛型枚舉 CountingEnumerable counter = new CountingEnumerable(); foreach (int x in counter)//foreach會自動負責Dispose調用事項,用于結束迭代時釋放資源 { Console.WriteLine(x); } #endregion 反射和泛型 1.對泛型使用typeof typeof可以通過兩種方式作用于泛型類型——獲取泛型定義和獲取特定的構造函數 #region 3-11對類型參數使用tupeof操作符 DemonstrateTypeof<int>(); #endregion #region 3-11 static void DemonstrateTypeof<X>() { Console.WriteLine(typeof(X));//顯示方法的類型參數 ? Console.WriteLine(typeof(List<>));//顯示泛型類型 Console.WriteLine(typeof(Dictionary<,>)); ? Console.WriteLine(typeof(List<X>));//顯示封閉類型(使用了類型參數) Console.WriteLine(typeof(Dictionary<string, X>)); ? Console.WriteLine(typeof(List<long>));//顯示封閉類型 Console.WriteLine(typeof(Dictionary<long, Guid>)); ? Console.WriteLine(typeof(Pair<,>)); Console.WriteLine(typeof(TypeWithField<>)); } #endregion 在IL中,類型參數的數量是在框架所用的完整類型名稱中指定的,在完整類型名稱之后,會添加一個‘,然后是參數數量。 2.System。Type的屬性和方法 任何特定的類型中有一個Type對象 #region 獲取泛型和以構造Type對象的各種方式 string listTypeName = "System.Collections.Generic.List`1";//System.Collections.Generic.List`1 ? Type defByName = Type.GetType(listTypeName); ? Type closedByName = Type.GetType(listTypeName + "[System.String]");//將類型實參放入方括號中 Type closeByMethod = defByName.MakeGenericType(typeof(string)); Type closedByTypeof = typeof(List<string>); ? Console.WriteLine(closeByMethod == closedByName); Console.WriteLine(closedByName == closedByTypeof); ? Type defByTypeof = typeof(List<>); Type defByMethod = closedByName.GetGenericTypeDefinition(); ? Console.WriteLine(defByMethod == defByName); Console.WriteLine(defByName == defByTypeof); #endregion 返回4次true
轉載于:https://www.cnblogs.com/Tan-sir/p/5169200.html
總結
以上是生活随笔為你收集整理的用泛型实现参数化类型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apache用户认证配置文件
- 下一篇: 绘图中的drawRect