<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Fork me on GitHub

      泛型和反射

      1.1.1 摘要

      在前一博文《.NET 中的泛型 101》中我們介紹了泛型的基本用法,現在我們繼續介紹泛型的進階用法(如:泛型的比較接口、迭代實現、泛型類型和方法的反射)。

      泛型的比較接口提供了實現對象比較和排序。

      由于公共語言運行庫 (CLR) 能夠在運行時(Run time)訪問泛型類型信息,所以可以使用反射獲取關于泛型類型的信息,方法與用于非泛型類型的方法相同。

      在.NET Framework 1.0中,我們可以使用Type.GetType()獲取Type類型的對象,當然1.0時,還沒有引入泛型。

      在.NET Framework 2.0,Type類增添了幾個新成員以獲取泛型類型的運行時(Run time)信息。

      本文目錄

      1.1.2 正文

      泛型比較接口

      泛型的四種比較接口:IComparer<T>、IComparable<T>、IEqualityComparer<T>和IEquatable<T>。

      其中,IComparer<T>和IComparable<T>實現比較排序,而IEqualityComparer<T>和IEquatable<T>實現條件比較并且獲取相應元素的哈希值。

      IComparer<T>和IEqualityComparer<T>可以實現不同類型之間的比較,而IComparable<T>和IEquatable<T>只能在同一類型中進行比較。

      假設,我們定義了一個學生類,它用來記錄學生的基本信息(如:Id、FirstName、LastName和Tel等),具體定義如下:

      /// <summary>
      /// The student model.
      /// </summary>
      public class Student
      {
          public long Id { get; set; }
          public string FirstName { get; set; }
          public string LastName { get; set; }
          public long Tel { get; set; }
      }

      現在,我們創建一個Student類型的List。

      // Creates student object with initializer.
      var students = new List<Student>()
          {
              new Student() { Id = 245712348, FirstName = "Ann", LastName = "Chen", Tel = "18022007281" },
              new Student() { Id = 245712345, FirstName = "Ada", LastName = "Cao", Tel = "18022007281" },
              new Student() { Id = 245712347, FirstName = "Rush", LastName = "Huang", Tel = "18022007281" },
              new Student() { Id = 245712346, FirstName = "Jackson", LastName = "Huang", Tel = "18022007281" },
              new Student() { Id = 245712349, FirstName = "Maggie", LastName = "Yip", Tel = "18022007281" },
          };

      上面,我們在List中創建了五個學生對象,如果我們要根據學號(Id)對學生對象進行排序,這時可以通過實現IComparable<T>接口實現對象排序。

      /// <summary>
      /// The student model.
      /// </summary>
      public class Student : IComparable<Student>
      {
          public long Id { get; set; }
          public string FirstName { get; set; }
          public string LastName { get; set; }
          public string Tel { get; set; }
      
          #region Implementation of IComparable<Student>
      
          public int CompareTo(Student other)
          {
              if (this.Id > other.Id)
              {
                  return 1;
              }
          }
      
          #endregion
      }

      我們通過實現IComparable<T>接口,讓List根據Id進行排序,我們需要實現CompareTo()方法根據Id排序。

      現在,我們又有一個疑問:如果Student類不僅僅根據Id排序,還希望根據LastName或FirstName排序,這時,我們可以給CompareTo()方法增加LastName或FirstName排序條件就OK了。

      /// <summary>
      /// The student model.
      /// </summary>
      public class Student : IComparable<Student>
      {
          public long Id { get; set; }
          public string FirstName { get; set; }
          public string LastName { get; set; }
          public string Tel { get; set; }
      
          #region Implementation of IComparable<Student>
      
          public int CompareTo(Student other)
          {
              if (this.Id > other.Id)
              {
                  return 1;
              }
      
              // If the id is the same, then comparing lastname and first name.
              return string.Compare(
                  this.LastName, other.LastName) != 0 ?
                  string.Compare(this.LastName, other.LastName) : string.Compare(this.FirstName, other.FirstName);
          }
      
          #endregion
      }

      假設,需求變得更加糟糕排序條件不固定,有可能根據Id排序,也有可能根據LastName或FirstName排序。

      這時,我們可以通過自定義類并且實現IComparer<T>接口,讓List根據自定義排序條件排序,而且需要實現compare()方法;它包含兩個對象的參數分別是x和y,如果x小于y返回一個負值,相等返回零,x大于y返回一個正數。

      接下來,讓我們定義排序條件根據學生的姓名進行排序,具體實現如下:

      /// <summary>
      /// The student comparer.
      /// </summary>
      public class StudnetComparer : IComparer<Student>
      {
          #region Implementation of IComparer<Student>
      
          // Compares the lastname of students.
          public int Compare(Student x, Student y)
          {
              return string.Compare(x.LastName, y.LastName);
          }
      
          #endregion
      }

      上面,我們定義排序類StudnetComparer,它實現了IComparer<T>接口并且添加了排序條件,讓StudnetComparer根據學生的姓名進行排序。

      假設我們想根據Id排序,那么我們可以擴展StudnetComparer的Compare()方法,當讓我們也可以定義一個新的比較類。

      generic0

      圖1排序結果

      泛型迭代

      迭代是集合中最常用的操作之一,通過迭代可以訪問集合中的元素,相信大家都使用foreach語句來訪問集合中的元素,它就是通過迭代的方式去訪問集合中的元素。

      在C# 1.0中,迭代訪問集合需要實現System.Collections.IEnumerable接口或有一個GetEnumerator()方法返回一個合適類型對象,通過該對象的MoveNext()方法和Current屬性訪問集合中的元素。

      接下來,我們通過foreach語句迭代訪問ArrayList集合中的元素,對于大家來說這再簡單不過了,示例如下:

      foreach (var number in numberArray)
      {
          Console.WriteLine(string.Format("number: {0}", number));
      }

      我們知道只有類型實現了IEnumerable接口或有一個GetEnumerator()方法才可以通過foreach語句迭代訪問,現在我們就有一個疑問foreach語句具體進行了哪些操作呢?

      其實,foreach語句簡化了整個迭代訪問的過程,接下來我們將給出foreach語句的具體實現。

      ArrayList numberArray = new ArrayList() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
      
      IEnumerator enumerator = numberArray.GetEnumerator();
      while (enumerator.MoveNext())
      {
          // Inboxing operation.
          Object number = enumerator.Current;
          Console.WriteLine(string.Format("number: {0}", number));
      }

      首先,numberArray調用GetEnumerator()方法獲取一個IEnumerator對象,接著遍歷訪問enumerator中的元素,這里我們要注意enumerator.Current獲取的是ArrayList中的元素,由于集合中的元素是值類型,所以轉換為引用類型(Object)需要進行裝箱操作。

      clip_image002

      圖2排序結果

      在C# 2.0中,由于引入了泛型并且使用泛型接口IEnumerable<T>擴展了IEnumerable接口,那么foreach語句將可以使用IEnumerable或IEnumerable<T>接口訪問集合中的元素。

      generic1

      圖3 IEnumerable<T>接口

      在前面給出的例子中,如果訪問值類型集合時,那么值類型元素需要進行裝箱操作;當訪問泛型集合時(如:List<int>),那么值類型元素是否需要裝箱操作呢?

      IEnumerator<int> enumerator = numberArray.GetEnumerator();
      while (enumerator.MoveNext())
      {
          int number = enumerator.Current;
          Console.WriteLine(string.Format("number: {0}", number));
          ////string.Format(
          ////"Id:{0} FirstName:{1} LastName:{2} Tel:{3}",
          ////student.Id, student.FirstName, student.LastName, student.Tel));
      }
      
      var disposable = enumerator as IDisposable;
      disposable.Dispose();

      上面,我們給出了值類型泛型集合的訪問實現,我們發現值類型元素無需轉換為引用類型,所以無需進行裝箱操作。

      接下來,我們將通過foreach語句迭代訪問引用類型集合studnets中的元素,具體實現如下:

      foreach (var student in students)
      {
          Console.WriteLine(
              string.Format(
              "Id:{0} FirstName:{1} LastName:{2} Tel:{3}",
              student.Id, student.FirstName, student.LastName, student.Tel));
      }

      其實,foreach語句背后的操作,首先,調用了students集合的GetEnumerator()方法,然后,通過MoveNext()方法遍歷集合中的元素,接著通過Current屬性獲取當前元素對象。

      IEnumerator enumerator = students.GetEnumerator();
      while (enumerator.MoveNext())
      {
          Student student = enumerator.Current as Student;
          Console.WriteLine(
              string.Format(
              "Id:{0} FirstName:{1} LastName:{2} Tel:{3}",
              student.Id, student.FirstName, student.LastName, student.Tel));
      }
      
      var disposable = enumerator as IDisposable;
      disposable.Dispose();

      泛型類型的反射

      反射提供了封裝程序集、模塊和類型的對象(Type 類型),我們可以通過反射動態創建類型的實例,將類型綁定到現有對象,或從現有對象獲取類型并調用其方法或訪問其字段和屬性。如果代碼中使用了屬性,可以利用反射對它們進行訪問。

      C#使用typeof()方法來獲的編譯時類型。

      在泛型中,typeof()方法有兩種用法,一種用來獲取“開放”泛型(Generic type)的Type對象,另一種是獲取“封閉”泛型即構造泛型(Constructed type)的Type對象。

      現在,我們有一個疑問什么是“開放”泛型,什么是“封閉”泛型呢?

      其實,理解所有這一切的關鍵是理解兩種不同的Type對象和泛型類之間的關系,假設我們定義了一個泛型類,然后,給它添加一個或多個類型不確定的成員,直到真正調用它的時候類型才確定下來,這就是所謂的“開放”泛型;當我們聲明了一個“開放”泛型的引用并且提供具體的成員類型,這就是所謂的“封閉”泛型即構造泛型。

      接下來,我們將介紹通過typeof()方法獲取公開和封閉泛型的Type對象。

      Console.WriteLine(typeof(string));
      // Open type.
      Console.WriteLine(typeof(List<>));
      // If have mutiple parameter, should keep commas.
      Console.WriteLine(typeof(Dictionary<,>));
      
      // Constructed type.
      Console.WriteLine(typeof(List<string>));
      Console.WriteLine(typeof(Dictionary<string, long>));
      Console.WriteLine(typeof(List<long>));
      Console.WriteLine(typeof(Dictionary<long, Guid>));
      generic3

      圖4 typeof方法獲取Type對象

      上面,我們通過typeof()方法獲取“開放”和“封閉”泛型的Type對象。

      其中有兩點是我們要注意的,首先輸出結果中包含的數字如:‘1或‘2表示參數個數,而且,我們發現對于“開放”泛型參數類型都是不確定,它們使用了如:T或TValue占位符,而“封閉”泛型參數類型都確定的。

      前面,我們使用typeof()方法獲取泛型類型的Type對象,其實,我們還可以使用Type類的成員方法獲取泛型類型的Type對象,它們分別是 GetGenericTypeDefinition()和MakeGenericType()。

      GetGenericTypeDefinition()方法獲取一個表示可用于構造當前泛型類型的泛型類型定義的 Type對象,MakeGenericType()方法替代由當前泛型類型定義的類型參數組成的類型數組的元素,并返回表示結果構造類型的 Type 對象。

      這兩個方法的描述十分繞口,簡而言之,我們通過GetGenericTypeDefinition()方法獲取“封閉”泛型的泛型定義,而MakeGenericType()方法根據泛型定義獲取“封閉”類型。

      其實,在C# 1.0中也包含類似功能的方法Type.GetType()和Assembly.GetType()方法。

      接下來,我們將使用Type的成員方法獲取泛型類型的Type對象。

      string listTypeName = "System.Collections.Generic.List`1";
      
      Type defByName = Type.GetType(listTypeName);
      
      // Retrieves the type of List<string> through the approach as below.
      Type closedByName = Type.GetType(listTypeName + "[System.String]");
      Type closedByMethod = defByName.MakeGenericType(typeof(string));
      Type closedByTypeof = typeof(List<string>);
      
      Console.WriteLine(closedByMethod == closedByName);
      Console.WriteLine(closedByName == closedByTypeof);
      
      // Retrieves open type object through the approach as below.
      Type defByTypeof = typeof(List<>);
      Type defByMethod = closedByName.GetGenericTypeDefinition();
      
      Console.WriteLine(defByMethod == defByName);
      Console.WriteLine(defByName == defByTypeof);
      
      Console.ReadKey();
      
      // OUTPUT:
      // True
      // True
      // True
      // True

      上面的輸出結果都為True,但我們注意到defByMethod、defByName、defByName和defByTypeof都是特定類型Type對象,而我們使用了“==”判斷兩個Type對象是否相同,也就是說,對于同一泛型類型分別通過typeof()或GetType()方法得到的是同一個Type對象引用。

      泛型方法的反射

      前面,我們介紹了使用typeof()方法或Type的成員方法獲取泛型類型的Type對象,至于泛型方法的反射,我們使用的是MethodInfo類的成員方法MakeGenericMethod()。

      /// <summary>
      /// Defines a generic class.
      /// </summary>
      /// <typeparam name="T">T can be value or reference type.</typeparam>
      public class GenericClass<T>
      {
          private T _t = default(T);
      
          public GenericClass(T t)
          {
              _t = t;
              Console.WriteLine("GenericClass<{0}>( {1} ) object created",
                      typeof(T).FullName, _t.ToString());
          }
          
          public T GetValue()
          {
              Console.WriteLine("GetValue() method invoked, returning {0}", _t.ToString());
              return _t;
          }
      
          public static U StaticGetValue<U>(U u)
          {
              Console.WriteLine("StaticGetValue<{0}>( {1} ) method invoked",
                      typeof(U).FullName, u.ToString());
              return u;
          }
      }

      上面,我們定義了泛型類GenericClass<T>,接下來,我們將使用MakeGenericMethod()方法獲取泛型方法的MethodInfo對象,接著通過Invoke()方法調用該泛型方法。

      // Invokes the static template method directly
      GenericClass<int>.StaticGetValue(23);
      
      // Gets the open generic method type
      // Notes, we should specify the class type T first.
      MethodInfo openGenericMethod = typeof(GenericClass<string>).GetMethod("StaticGetValue");
      
      // Gets the close generic method type, by supplying the generic parameter type
      MethodInfo closedGenericMethod = openGenericMethod.MakeGenericMethod(typeof(int));
      
      object o2 = closedGenericMethod.Invoke(null, new object[] { 20120929 });
      
      Console.WriteLine("o2 = {0}", o2.ToString());

      generic4

      圖5 泛型方法的反射

      首先,我們使用GetMethod()方法獲取開放的泛型方法,接著使用MakeGenericMethod()構造封閉的泛型方法,最后調用MethodInfo對象的Invoke()方法傳遞參數和調用泛型方法StaticGetValue<U>()。

      1.1.3 總結

      本文介紹泛型的進階使用方法,如:泛型接口、迭代的實現、泛型類型的反射和泛型方法的反射。

      泛型接口實現對象比較和排序,如:實現IComparer<T>、IComparable<T>、IEqualityComparer<T>和IEquatable<T>接口。

      對于迭代訪問集合中的元素,我們一般可以使用foreach語句實現,這里我們介紹了foreach語句的迭代訪問實現。

      最后,通過介紹“開放”泛型類型、“封閉”泛型類型、“開放”泛型方法和“封閉”泛型方法;我們學會了如何根據Type對象獲取相應的泛型對象或方法,我們學習了如何使用MakeGenericType()方法構造“封閉”泛型類型,這樣我們就可以通過Activator.CreateInstance()方法實例化該類型;通過MakeGenericMethod()方法構造封閉”泛型方法,然后調用MethodInfo對象的Invoke()方法傳遞參數和調用泛型方法。

      祝大家中秋和國慶節快樂,身體健康。

      參考

      [1] http://en.csharp-online.net/Generic_types

      [2] http://www.codeproject.com/Articles/22088/Reflecting-on-Generics

      [3] http://www.amazon.cn/C-in-Depth-Skeet-Jon/dp/1935182471/ref=sr_1_2?ie=UTF8&qid=1348972408&sr=8-2

      posted @ 2012-09-30 10:34  JK_Rush  閱讀(15620)  評論(17)    收藏  舉報
      主站蜘蛛池模板: 亚洲国产午夜理论片不卡| 国产成人精品一区二区三区| 亚洲av永久无码精品水牛影视| 国产精品一二三中文字幕| 国产亚洲精品成人aa片新蒲金| 日韩中文字幕精品人妻| 99久久婷婷国产综合精品青草漫画| 老熟妇乱子交视频一区| 91精品亚洲一区二区三区| 在线天堂中文新版www| 最新亚洲av日韩av二区| 无码av免费毛片一区二区| 92国产精品午夜福利免费| 甘肃省| 国产精品白浆在线观看免费| 国产精品 无码专区| 天堂在线精品亚洲综合网| 亚洲人午夜精品射精日韩| 久久天天躁狠狠躁夜夜2020老熟妇 | 中文字幕日韩有码国产| 大地资源高清免费观看| 日本东京热不卡一区二区| 午夜天堂av天堂久久久| 自拍视频亚洲精品在线| 好男人官网资源在线观看| 日韩有码国产精品一区| 亚洲顶级裸体av片| 国产999精品2卡3卡4卡| 蒙城县| 国产精品国产三级国产试看| 国产网友愉拍精品视频手机| 高清精品视频一区二区三区| 国产成人精品午夜2022| 国产在线亚州精品内射| 潮喷失禁大喷水无码| 野花社区www视频日本| 国产精品一精品二精品三| 永久免费在线观看蜜桃视频| 国产欧美另类精品久久久| 四虎国产精品久久免费地址| 国产精品无码一区二区桃花视频|