C#泛型方法解析

    C#2.0引入了泛型這個特性,因爲泛型的引入,在必定程度上極大的加強了C#的生命力,能夠完成C#1.0時須要編寫複雜代碼才能夠完成的一些功能。可是做爲開發者,對於泛型可謂是又愛又恨,愛的是其強大的功能,以及該特性帶來的效率的提高,恨的是泛型在複雜的時候,會呈現至關複雜的語法結構。這種複雜不只是對於初學者,對於一些有開發經驗的.NET開發者,也是一個不那麼容易掌握的特性。算法

   接下來咱們來了解一下C#2.0加入的特性:泛型。數組

一.泛型的基本特性概述:

    在實際項目開發中,任何API只要將object做爲參數類型和返回類型使用,就可能在某個時候涉及強類型轉換。提到強類型轉換,估計不少開發者第一反應就是「效率」這個次,對於強類型的利弊主要看使用者使用的環境,天底下沒有絕對的壞事,也沒有絕對的好事,有關強類型的問題不是本次的重點,不作重點介紹。安全

    泛型是CLR和C#提供的一種特殊機制,支持另外一種形式的代碼重用,即「算法重用」。泛型實現了類型和方法的參數化,泛型類型和方法也可讓參數告訴使用者使用什麼類型。ide

    泛型所帶來的好處:更好的編譯時檢查,更多在代碼中能直接表現的信息,更多的IDE支持,更好的性能。可能有人會疑問,爲何泛型會帶來這麼多好處,使用一個不能區分不一樣類型的常規API,至關於在一個動態環境中訪問那個API。函數

    CLR容許建立泛型引用和泛型值類型,可是不容許建立泛型枚舉,而且CLR容許建立泛型接口和泛型委託,CLR容許在引用類型、值類型或接口中定義泛型方法。定義泛型類型或方法時,爲類型指定了任何變量(如:T)都稱爲類型參數。(T是一個變量名,在源代碼中可以使用一個數據類型的任何位置,均可以使用T)在C#中泛型參數變量要麼成爲T,要麼至少一大寫T開頭。性能

二.泛型類、泛型接口和泛型委託概述:

   1.泛型類:

     泛型類型仍然是類型,因此能夠從任何類型派生。使用一個泛型類型並指定類型實參時,實際是在CLR中定義一個新類型對象,新類型對象是從泛型派生自的那個類型派生的。使用泛型類型參數的一個方法在基尼險那個JIT編譯時,CLR獲取IL,用指定的類型實參進行替換,而後建立恰當的本地代碼。學習

    若是沒有爲泛型類型參數提供類型實參,那就麼就是未綁定泛型類型。若是指定了類型實參,該類型就是已構造類型。已構造類型能夠是開發或封閉的,開發類型還包含一個類ixngcanshu,而封閉類型則不是開發的,類型的每一個部分都是明確的。全部代碼實際都是在一個封閉的已構造類型的上下文中執行。ui

   泛型類在.NET的應用主要在集合類中,大多數集合類在System.Collections.Generic和System.Collections.ObjectModel類中。下面簡單的介紹一種泛型集合類:this

     (1).SynchronizedCollection:提供一個線程安全集合,其中包含泛型參數所指定類型的對象做爲元素.編碼

 [ComVisible(false)]
  public class SynchronizedCollection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
  {
    /// <summary>
    /// 初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 類的新實例。
    /// </summary>
    public SynchronizedCollection();
    /// <summary>
    /// 經過用於對線程安全集合的訪問進行同步的對象來初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 類的新實例。
    /// </summary>
    /// <param name="syncRoot">用於對線程安全集合的訪問進行同步的對象。</param><exception cref="T:System.ArgumentNullException"><paramref name="syncRoot"/> 爲 null。</exception>
    public SynchronizedCollection(object syncRoot);
    /// <summary>
    /// 使用指定的可枚舉元素列表和用於對線程安全集合的訪問進行同步的對象來初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 類的新實例。
    /// </summary>
    /// <param name="syncRoot">用於對線程安全集合的訪問進行同步的對象。</param><param name="list">用於初始化線程安全集合的元素的 <see cref="T:System.Collections.Generic.IEnumerable`1"/> 集合。</param><exception cref="T:System.ArgumentNullException"><paramref name="syncRoot"/><paramref name="list"/> 爲 null。</exception>
    public SynchronizedCollection(object syncRoot, IEnumerable<T> list);
    /// <summary>
    /// 使用指定的元素數組和用於對線程安全集合的訪問進行同步的對象來初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 類的新實例。
    /// </summary>
    /// <param name="syncRoot">用於對線程安全集合的訪問進行同步的對象。</param><param name="list">用於初始化線程安全集合的 <paramref name="T"/> 類型元素的 <see cref="T:System.Array"/></param><exception cref="T:System.ArgumentNullException"><paramref name="syncRoot"/><paramref name="list"/> 爲 null。</exception>
    public SynchronizedCollection(object syncRoot, params T[] list);
    /// <summary>
    /// 將項添加到線程安全只讀集合中。
    /// </summary>
    /// <param name="item">要添加到集合的元素。</param><exception cref="T:System.ArgumentException">設置的值爲 null,或者不是集合的正確泛型類型 <paramref name="T"/></exception>
    public void Add(T item);
    /// <summary>
    /// 從集合中移除全部項。
    /// </summary>
    public void Clear();
    /// <summary>
    /// 從特定索引處開始,將集合中的元素複製到指定的數組。
    /// </summary>
    /// <param name="array">從集合中複製的 <paramref name="T "/>類型元素的目標 <see cref="T:System.Array"/></param><param name="index">複製開始時所在的數組中的從零開始的索引。</param>
    public void CopyTo(T[] array, int index);
    /// <summary>
    /// 肯定集合是否包含具備特定值的元素。
    /// </summary>
    /// 
    /// <returns>
    /// 若是在集合中找到元素值,則爲 true;不然爲 false。
    /// </returns>
    /// <param name="item">要在集合中定位的對象。</param><exception cref="T:System.ArgumentException">設置的值爲 null,或者不是集合的正確泛型類型 <paramref name="T"/></exception>
    public bool Contains(T item);
    /// <summary>
    /// 返回一個循環訪問同步集合的枚舉數。
    /// </summary>
    /// 
    /// <returns>
    /// 一個 <see cref="T:System.Collections.Generic.IEnumerator`1"/>,用於訪問集合中存儲的類型的對象。
    /// </returns>
    public IEnumerator<T> GetEnumerator();
    /// <summary>
    /// 返回某個值在集合中的第一個匹配項的索引。
    /// </summary>
    /// 
    /// <returns>
    /// 該值在集合中的第一個匹配項的從零開始的索引。
    /// </returns>
    /// <param name="item">從集合中移除全部項。</param><exception cref="T:System.ArgumentException">設置的值爲 null,或者不是集合的正確泛型類型 <paramref name="T"/></exception>
    public int IndexOf(T item);
    /// <summary>
    /// 將一項插入集合中的指定索引處。
    /// </summary>
    /// <param name="index">要從集合中檢索的元素的從零開始的索引。</param><param name="item">要做爲元素插入到集合中的對象。</param><exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小於零或大於集合中的項數。</exception><exception cref="T:System.ArgumentException">設置的值爲 null,或者不是集合的正確泛型類型 <paramref name="T"/></exception>
    public void Insert(int index, T item);
    /// <summary>
    /// 從集合中移除指定項的第一個匹配項。
    /// </summary>
    /// 
    /// <returns>
    /// 若是從集合中成功移除了項,則爲 true;不然爲 false。
    /// </returns>
    /// <param name="item">要從集合中移除的對象。</param>
    public bool Remove(T item);
    /// <summary>
    /// 從集合中移除指定索引處的項。
    /// </summary>
    /// <param name="index">要從集合中檢索的元素的從零開始的索引。</param><exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小於零或大於集合中的項數。</exception>
    public void RemoveAt(int index);
    /// <summary>
    /// 從集合中移除全部項。
    /// </summary>
    protected virtual void ClearItems();
    /// <summary>
    /// 將一項插入集合中的指定索引處。
    /// </summary>
    /// <param name="index">集合中從零開始的索引,在此處插入對象。</param><param name="item">要插入到集合中的對象。</param><exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小於零或大於集合中的項數。</exception><exception cref="T:System.ArgumentException">設置的值爲 null,或者不是集合的正確泛型類型 <paramref name="T"/></exception>
    protected virtual void InsertItem(int index, T item);
    /// <summary>
    /// 從集合中移除指定 <paramref name="index"/> 處的項。
    /// </summary>
    /// <param name="index">要從集合中檢索的元素的從零開始的索引。</param><exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小於零或大於集合中的項數。</exception>
    protected virtual void RemoveItem(int index);
    /// <summary>
    /// 使用另外一項替換指定索引處的項。
    /// </summary>
    /// <param name="index">要替換的對象的從零開始的索引。</param><param name="item">要替換的對象。</param><exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小於零或大於集合中的項數。</exception>
    protected virtual void SetItem(int index, T item);
    /// <summary>
    /// 返回一個循環訪問同步集合的枚舉數。
    /// </summary>
    /// 
    /// <returns>
    /// 一個 <see cref="T:System.Collections.Generic.IEnumerator`1"/>,用於訪問集合中存儲的類型的對象。
    /// </returns>
    IEnumerator IEnumerable.GetEnumerator();
    /// <summary>
    /// 從特定索引處開始,將集合中的元素複製到指定的數組。
    /// </summary>
    /// <param name="array">從集合中複製的 <paramref name="T"/> 類型元素的目標 <see cref="T:System.Array"/></param><param name="index">複製開始時所在的數組中的從零開始的索引。</param>
    void ICollection.CopyTo(Array array, int index);
    /// <summary>
    /// 向集合中添加一個元素。
    /// </summary>
    /// 
    /// <returns>
    /// 新元素的插入位置。
    /// </returns>
    /// <param name="value">要添加到集合中的對象。</param>
    int IList.Add(object value);
    /// <summary>
    /// 肯定集合是否包含具備特定值的元素。
    /// </summary>
    /// 
    /// <returns>
    /// 若是在集合中找到元素 <paramref name="value"/>,則爲 true;不然爲 false。
    /// </returns>
    /// <param name="value">要在集合中定位的對象。</param><exception cref="T:System.ArgumentException"><paramref name="value"/> 不是集合所含類型的對象。</exception>
    bool IList.Contains(object value);
    /// <summary>
    /// 肯定集合中某個元素的從零開始的索引。
    /// </summary>
    /// 
    /// <returns>
    /// 若是在集合中找到,則爲 <paramref name="value"/> 的索引;不然爲 -1。
    /// </returns>
    /// <param name="value">集合中要肯定其索引的元素。</param>
    int IList.IndexOf(object value);
    /// <summary>
    /// 將某個對象插入到集合中的指定索引處。
    /// </summary>
    /// <param name="index">從零開始的索引,將在該位置插入 <paramref name="value"/></param><param name="value">要在集合中插入的對象。</param><exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小於零或大於集合中的項數。</exception><exception cref="T:System.ArgumentException">設置的 <paramref name="value"/> 爲 null,或者不是集合的正確泛型類型 <paramref name="T"/></exception>
    void IList.Insert(int index, object value);
    /// <summary>
    /// 從集合中移除做爲元素的指定對象的第一個匹配項。
    /// </summary>
    /// <param name="value">要從集合中移除的對象。</param>
    void IList.Remove(object value);
   
  }

   (2).KeyedByTypeCollection:提供一個集合,該集合的項是用做鍵的類型。

 [__DynamicallyInvokable]
  public class KeyedByTypeCollection<TItem> : KeyedCollection<Type, TItem>
  {
    /// <summary>
    /// 初始化 <see cref="T:System.Collections.Generic.KeyedByTypeCollection`1"/> 類的新實例。
    /// </summary>
    public KeyedByTypeCollection();
    /// <summary>
    /// 根據指定的對象枚舉初始化 <see cref="T:System.Collections.Generic.KeyedByTypeCollection`1"/> 類的新實例。
    /// </summary>
    /// <param name="items">泛型類型 <see cref="T:System.Object"/><see cref="T:System.Collections.Generic.IEnumerable`1"/>,用於初始化集合。</param><exception cref="T:System.ArgumentNullException"><paramref name="items"/> 爲 null。</exception>
    public KeyedByTypeCollection(IEnumerable<TItem> items);
    /// <summary>
    /// 返回集合中第一個具備指定類型的項。
    /// </summary>
    /// 
    /// <returns>
    /// 若是爲引用類型,則返回類型 <paramref name="T"/> 的對象;若是爲值類型,則返回類型 <paramref name="T"/> 的值。 若是集合中不包含類型 <paramref name="T"/> 的對象,則返回類型的默認值:若是是引用類型,默認值爲 null;若是是值類型,默認值爲 0。
    /// </returns>
    /// <typeparam name="T">要在集合中查找的項的類型。</typeparam>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public T Find<T>();
    /// <summary>
    /// 從集合中移除具備指定類型的對象。
    /// </summary>
    /// 
    /// <returns>
    /// 從集合中移除的對象。
    /// </returns>
    /// <typeparam name="T">要從集合中移除的項的類型。</typeparam>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public T Remove<T>();
    /// <summary>
    /// 返回 <see cref="T:System.Collections.Generic.KeyedByTypeCollection`1"/> 中包含的類型 <paramref name="T"/> 的對象的集合。
    /// </summary>
    /// 
    /// <returns>
    /// 一個類型 <paramref name="T"/><see cref="T:System.Collections.ObjectModel.Collection`1"/>,包含來自原始集合的類型 <paramref name="T"/> 的對象。
    /// </returns>
    /// <typeparam name="T">要在集合中查找的項的類型。</typeparam>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public Collection<T> FindAll<T>();
    /// <summary>
    /// 從集合中移除全部具備指定類型的元素。
    /// </summary>
    /// 
    /// <returns>
    /// <see cref="T:System.Collections.ObjectModel.Collection`1"/>,包含來自原始集合的類型 <paramref name="T"/> 的對象。
    /// </returns>
    /// <typeparam name="T">要從集合中移除的項的類型。</typeparam>
    [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    public Collection<T> RemoveAll<T>();
    /// <summary>
    /// 獲取集合中包含的某個項的類型。
    /// </summary>
    /// 
    /// <returns>
    /// 集合中指定的 <paramref name="item"/> 的類型。
    /// </returns>
    /// <param name="item">集合中要檢索其類型的項。</param><exception cref="T:System.ArgumentNullException"><paramref name="item"/> 爲 null。</exception>
    [__DynamicallyInvokable]
    protected override Type GetKeyForItem(TItem item);
    /// <summary>
    /// 在集合中的特定位置插入一個元素。
    /// </summary>
    /// <param name="index">從零開始的索引,應在該位置插入 <paramref name="item"/></param><param name="item">要在集合中插入的對象。</param><exception cref="T:System.ArgumentNullException"><paramref name="item"/> 爲 null。</exception>
    [__DynamicallyInvokable]
    protected override void InsertItem(int index, TItem item);
    /// <summary>
    /// 使用一個新對象替換指定索引處的項。
    /// </summary>
    /// <param name="index">要替換的 <paramref name="item"/> 的從零開始的索引。</param><param name="item">要添加到集合中的對象。</param><exception cref="T:System.ArgumentNullException"><paramref name="item"/> 爲 null。</exception>
    [__DynamicallyInvokable]
    protected override void SetItem(int index, TItem item);
  }

   2.泛型接口和泛型委託:

     泛型的主要做用就是定義泛型的引用類型和指類型。一個引用類型或值類型可經過指定類型實參的方式實現泛型接口,也能夠保持類型實參的未指定狀態實現一個泛型接口。

     具體看一下泛型接口IEnumerable:公開枚舉數,該枚舉數支持在非泛型集合上進行簡單迭代。

 [ComVisible(true)]
  [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")]
  [__DynamicallyInvokable]
  public interface IEnumerable
  {
    /// <summary>
    /// 返回一個循環訪問集合的枚舉數。
    /// </summary>
    /// 
    /// <returns>
    /// 一個可用於循環訪問集合的 <see cref="T:System.Collections.IEnumerator"/> 對象。
    /// </returns>
    /// <filterpriority>2</filterpriority>
    [DispId(-4)]
    [__DynamicallyInvokable]
    IEnumerator GetEnumerator();
  }

    CLR支持泛型委託,目的是保證任何類型的對象都能以一種類型安全的方式傳給一個回調方法。泛型委託容許一個孩子類型實例在傳給一個回調方法時不執行任何裝箱處理。委託時機只提供了4個方法:一個構造器,一個Invlke方法,一個BeginInvoke方法和一個EndInvoke方法。若是定義的一個委託類型指定了類型參數,編譯器會定義委託類的方法,用指定的類型參數替換方法的參數類型和值類型。

   以上是對泛型類、泛型接口和泛型委託的簡單瞭解,本文的目的主要是講解泛型方法,下面咱們具體瞭解一些泛型泛型的知識。

三.泛型方法解析:

 1.泛型方法概述:   

    定義泛型類、結構或接口時,類型中定義的任何方法均可引用類型指定的一個類型參數。類型參數能夠做爲方法的參數,做爲方法的返回值,或者做爲方法內部定義的一個局部變量來使用。CLR容許一個方法指定它獨有的類型參數,這些類型參數可用於參數、返回值、或者局部變量。

   C#編譯器支持在調用一個泛型方法時進行類型推斷。執行類型推斷時,C#使用變量的數據類型,而不是由變量引用的對象的實際類型。一個類型能夠定義多個方法,讓其中一個方法接受具體的數據類型,讓另外一個方法接受泛型類型參數。

    泛型方法示例:

List<TOutput> ConverAll<TOutput>(Conver<T,TOutput> conv)

List<TOutput>:返回類型(一個泛型列表)。

ConverAll:方法名。

<TOutput>:類型參數。

Conver<T,TOutput>:參數類型(泛型委託)。

conv:參數名。

    對以上的示例代碼分析,須要掌握:爲每一個類型參數使用一個不一樣的類型,在總體應用這些類型參數。

  (1).首先替換包含方法(List<T>的T部分)的那個類型的類型參數,如將T替換爲string:

List<TOutput> ConverAll<TOutput>(Conver<string,TOutput> conv)

  (2).處理完T後,再須要處理的就是TOutput,能夠看出它是一個方法類型參數,這裏採用guid替換TOutput。

List<Guid> ConverAll(Conver<string,Guid> conv)

  對TOutput賦予類型實參後,能夠移除生命中的類型參數<TOutput>,將方法堪稱非泛型方法,如上。以上的示例能夠處理一個字符串列表,用一個轉換器來生成一個Guid列表。

  將原始列表中的每一個元素都轉換成目標類型,將轉換後的元素添加到一個列表中,最後返回這個列表。以上的處理方式,主要將其泛型方法的參數進行逐一的細化,不管在什麼學科,都須要將複雜的問題進行簡單化,將抽象的問題具體化,這也是一種經常使用的處理方式。

 2.類型約束:

    約束的做用是限制能指定成泛型實參的類型數量。經過限制類型的數量,咱們能夠對那些類型執行更多的操做。約束能夠應用於一個泛型類型的類型參數,也能夠應用於一個泛型方法的類型參數。CLR不容許基於類型參數名稱或約束進行重載,只能基於元數對類型或方法進行重載。不容許爲重寫方法的類型參數指定任何約束,可是類型實參的名稱是能夠改變的。

    泛型約束的操做,約束要放到泛型方法或泛型類型聲明的末尾,並由上下文關鍵where引入。

   (1).引用類型約束:

      引用類型約束:用於確保使用的類型實參是引用類型。(表示爲:T:class,且必須爲類型參數指定的第一個約束。)

   (2).值類型約束:

      值類型約束:用於確保使用的類型參數是指類型。(表示爲:T:struct,可空類型不包含在內)

   (3).構造函數類型約束:

      構造函授類型約束:指定全部類型參數的最後一個約束,它檢查類型實參是否有一個可用於建立實例的無參構造函數。(表示爲:T:new())適用於全部值類型,全部沒有顯示聲明構造函數的非靜態、非抽象類,全部顯示聲明瞭一個公共無參構造函數的非抽象類。

   (4).轉換類型約束:

     轉換類型約束:容許你指定另外一個類型,類型實參必須能夠經過一致性、引用或裝箱轉換隱式地轉換爲該類型。還能夠規定類型實參必須能夠轉換爲另外一個類型實參。(例:class Sample<T> where T:Stream)

   (5).組合約束:

     組合約束:所個約束組合在一塊兒的約束,可是組合約束也有限制條件。由於沒有任何類型便是引用類型,又是值類型。因爲每個值都有一個無參構造函數,因此假如已經有一個值類型約束,就不容許再指定一個構造函數約束。若是存在多個類型約束,而且其中一個爲類,那麼它應該出如今接口的前面,並且咱們不能屢次指定同一個接口。不一樣的類型參數能夠用不一樣的約束,分別由一個where引入。

   備註:類型推斷只適用於泛型方法,不適用於泛型類型。

  以上是對泛型方法的相關概念和約束作了簡單的解析,接下來看一下.NET中一些發行方法的具體實現:

 /// <summary>
  /// 封裝一個方法,該方法具備四個參數而且不返回值。
  /// </summary>
  /// <param name="arg1">此委託封裝的方法的第一個參數。</param><param name="arg2">此委託封裝的方法的第二個參數。</param><param name="arg3">此委託封裝的方法的第三個參數。</param><param name="arg4">此委託封裝的方法的第四個參數。</param><typeparam name="T1">此委託封裝的方法的第一個參數類型。</typeparam><typeparam name="T2">此委託封裝的方法的第二個參數類型。</typeparam><typeparam name="T3">此委託封裝的方法的第三個參數類型。</typeparam><typeparam name="T4">此委託封裝的方法的第四個參數類型。</typeparam><filterpriority>2</filterpriority>
  [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
  [__DynamicallyInvokable]
  public delegate void Action<in T1, in T2, in T3, in T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
  /// <summary>
  /// 表示比較同一類型的兩個對象的方法。
  /// </summary>
  /// 
  /// <returns>
  /// 一個有符號整數,指示 <paramref name="x"/><paramref name="y"/> 的相對值,以下表所示。 值 含義 小於 0 <paramref name="x"/> 小於 <paramref name="y"/>。 0 <paramref name="x"/> 等於 <paramref name="y"/>。 大於 0 <paramref name="x"/> 大於 <paramref name="y"/>/// </returns>
  /// <param name="x">要比較的第一個對象。</param><param name="y">要比較的第二個對象。</param><typeparam name="T">要比較的對象的類型。</typeparam><filterpriority>1</filterpriority>
  [__DynamicallyInvokable]
  public delegate int Comparison<in T>(T x, T y);

四.泛型方法應用代碼示例:

   以上講解的有關泛型方法的內容,這裏提供一個有關泛型方法操做XML的代碼:

  

    /// <summary>
    /// 泛型方法:編譯器可以根據傳入的方法參數推斷類型參數;它沒法僅從約束或返回值推斷類型參數
    /// </summary>
    public class ObjectXmlSerializer
    {
        /// <summary>
        /// 文件的反序列化
        /// </summary>
        /// <typeparam name="T">返回值類型</typeparam>
        /// <param name="fileName"></param>
        /// <returns>
        /// 若是日誌啓用,則發生異常時,異常寫入日誌,若日誌沒有開啓,則直接拋出異常信息
        /// loggingEnabled==true: Null is returned if any error occurs.
        /// loggingEnabled==false: throw exception
        /// </returns>
        public static T LoadFromXml<T>(string fileName) where T : class
        {
            return LoadFromXml<T>(fileName, true);
        }

        /// <summary>
        /// 文件反序列化,若發生異常,異常信息寫入日誌
        /// </summary>
        /// <typeparam name="T">加載類的類型</typeparam>
        /// <param name="fileName">文件名字</param>
        /// <param name="loggingEnabled">啓用日誌記錄</param>
        /// <returns></returns>
        public static T LoadFromXml<T>(string fileName, bool loggingEnabled) where T : class
        {
            FileStream fs = null;
            try
            {
                var serializer = new XmlSerializer(typeof(T));
                fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                //反序列化對象
                return (T)serializer.Deserialize(fs);
            }
            catch (Exception e)
            {
                if (loggingEnabled)
                {
                    //文件異常,寫入日誌
                    LogLoadFileException(fileName, e);
                    return null;
                }
                else
                {

                    throw new Exception(e.Message);
                }
            }
            finally
            {
                if (fs != null) fs.Close();
            }
        }

        /// <summary>
        /// 序列化一個對象到文件中.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fileName">文件名</param>
        /// <param name="data">待序列化的數據</param>
        /// <returns>
        /// 若是日誌啓用,則發生異常時,異常寫入日誌,若日誌沒有開啓,則直接拋出異常信息
        /// loggingEnabled==true: log exception
        /// loggingEnabled==false: throw exception
        /// </returns>
        public static void SaveToXml<T>(string fileName, T data) where T : class
        {
            SaveToXml(fileName, data, true);
        }

        /// <summary>
        /// 文件反序列化,若發生異常,異常信息寫入日誌
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fileName">文件名</param>
        /// <param name="data">發序列化對象</param>
        /// <param name="loggingEnabled">是否啓用日誌</param>
        public static void SaveToXml<T>(string fileName, T data, bool loggingEnabled) where T : class
        {
            FileStream fs = null;
            try
            {
                var serializer = new XmlSerializer(typeof(T));
                fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
                //序列化對象
                serializer.Serialize(fs, data);
            }
            catch (Exception e)
            {
                if (loggingEnabled) LogSaveFileException(fileName, e);
                else
                {
                    throw new Exception(e.Message);
                }
            }
            finally
            {
                if (fs != null) fs.Close();
            }
        }

        /// <summary>
        /// 序列化
        /// XML & Datacontract Serialize & Deserialize Helper
        /// </summary>
        /// <typeparam name="T">T指定必須爲class類型</typeparam>
        /// <param name="serialObject"></param>
        /// <returns></returns>
        public static string XmlSerializer<T>(T serialObject) where T : class
        {
            var ser = new XmlSerializer(typeof(T));
            //MemoryStream實現對內存的讀寫,而不是對持久性存儲器進行讀寫
            //MemoryStream封裝以無符號字節數組形式存儲的數據,該數組在建立MemoryStream對象時被初始化,
            //或者該數組可建立爲空數組。可在內存中直接訪問這些封裝的數據。
            //內存流可下降應用程序中對臨時緩衝區和臨時文件的須要。
            var mem = new MemoryStream();
            var writer = new XmlTextWriter(mem, UTF8);
            ser.Serialize(writer, serialObject);
            writer.Close();
            return UTF8.GetString(mem.ToArray());
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="str"></param>
        /// <returns></returns>
        public static T XmlDeserialize<T>(string str) where T : class
        {
            var mySerializer = new XmlSerializer(typeof(T));
            var mem2 = new StreamReader(new MemoryStream(UTF8.GetBytes(str)), UTF8);
            return (T)mySerializer.Deserialize(mem2);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlData"></param>
        /// <returns>返回值類型爲傳入的類型</returns>
        public static T DataContractDeserializer<T>(string xmlData) where T : class
        {
            var stream = new MemoryStream(UTF8.GetBytes(xmlData));
            var reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
            var ser = new DataContractSerializer(typeof(T));
            var deserializedPerson = (T)ser.ReadObject(reader, true);
            reader.Close();
            stream.Close();
            return deserializedPerson;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="myObject"></param>
        /// <returns></returns>
        public static string DataContractSerializer<T>(T myObject) where T : class
        {
            var stream = new MemoryStream();
            var ser = new DataContractSerializer(typeof(T));
            ser.WriteObject(stream, myObject);
            stream.Close();
            return UTF8.GetString(stream.ToArray());
        }

        /// <summary>
        /// 序列化時異常日誌
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="ex">異常</param>
        [Conditional("TRACE")]
        private static void LogLoadFileException(string fileName, Exception ex)
        {
            var sb = new StringBuilder();
            sb.Append("Fail to load xml file: ");
            sb.Append(fileName + Environment.NewLine);
            sb.Append(ex);
            //寫入日誌記錄中方法
            //  Logger.LogEvent(LogCategory, LogEventLoadFileException, sb.ToString());
        }

        /// <summary>
        /// 反序列化時異常日誌
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="ex">異常</param>
        [Conditional("TRACE")]
        private static void LogSaveFileException(string fileName, Exception ex)
        {
            var sb = new StringBuilder();
            sb.Append("Fail to save xml file: ");
            sb.Append(fileName + Environment.NewLine);
            sb.Append(ex);

        }


        /// <summary>
        /// 將xml字符串序列化爲數據流(數據流編碼爲ASCII,UTF8)
        /// </summary>
        /// <returns>字符串轉換到流</returns>
        public static MemoryStream StringXmlToStream(string strXml,Encoding encod)
        {
            MemoryStream memoryStream = null;
            try
            {
                Encoding encoding;
                if (Equals(encod, ASCII))
                {
                     encoding = new ASCIIEncoding();
                }
                else
                {
                     encoding = new UTF8Encoding();  
                }
                var byteArray = encoding.GetBytes(strXml);
                memoryStream = new MemoryStream(byteArray);
                memoryStream.Seek(0, SeekOrigin.Begin);
                return memoryStream;
            }
            catch (IOException ex)
            {
                throw new IOException(ex.Message);
            }
            finally
            {
                if (memoryStream != null) memoryStream.Close();
            }

         

        }
  
    }

   以上的代碼就不作贅述,須要次代碼的可使用。

五.總結:

    本文講解了C#2.0引入的泛型知識,主要包含泛型類、泛型接口、泛型委託,而且重點講解了泛型方法,已經泛型的約束分類。最後給了一些利用泛型方法操做xml的方法。但願以上的講解能夠幫助到正在想學習的人。

相關文章
相關標籤/搜索