【Clr in c#】泛型

  使用泛型的好處是「代碼重用」,極大的提升了開發效率,泛型爲開發者提供瞭如下優點:c++

    1,源代碼保護  算法的源代碼不須要提供給使用泛型算法的開發人員,使用c++模板的泛型技術須要提供。(目前c++模板的泛型技術瞭解較少)算法

    2,類型安全    給泛型算法指定類型時,編譯器能理解開發者意圖,只有兼容類型能經過,不兼容的時候編譯時候會報錯。安全

    3,更清晰的代碼  因爲編譯器強制類型的安全性,減小源代碼中必須進行的轉型次數,使得代碼容易維護和編寫。例如:DateTime dt=dtList[0];從DateTime的集合中按照索引取出來的值能夠直接賦值給DateTime類型,不須要轉型。ide

    4,更佳的性能 在操做值類型時候,非泛型集合會形成裝箱、拆箱操做,會形成託管堆上的內存分配,會形成頻繁的垃圾回收,影響性能。性能

    補充:對於泛型方法,約束父類類型,與參數直接傳遞父類,在沒有返回值的狀況下是沒有區別的,假若有須要返回傳入的類型,則用泛型方法比較合適,由於經過泛型方法返回的類型不須要通過類型轉換  http://bbs.csdn.net/topics/380050195優化

 1 public class AA{}
 2 public class BB:AA{}
 3 
 4 
 5 public void GetText<T>(T t) where T:AA
 6 {
 7 }
 8  9 public void GetText(AA x)
10 {}之間是等效的,沒有區別。
11 
12 
13 public T GetText<T>(T t) where T:AA
14 {
15 }
16 public AA GetText(AA x)
17 在調用的地方是有區別的
18 
19 BB b=new BB();
20 var rtGetText=GetText<BB>(b);
21 var rtGetText2=(BB)GetText(B);//須要進行一次類型轉換
View Code

 

1.泛型基礎結構

  1.1 開放類型和封閉類型

      具備泛型類型參數的類型稱爲開放類型。ui

        不能建立實例。例如Dictionary<,>,沒有指定參數,目前尚不清楚這個開放類型有什麼用。this

      全部類型實參傳遞的都是實際數據類型爲封閉類型。spa

        使用約束沒法將類型實參限制爲某一類型,能夠用一個靜態構造器來保證類型。以下.net

      

internal sealed class GenericTypeThatRequiresAnEnum<T>{
  static   GenericTypeThatRequiresAnEnum(){
    if(!typeof(T).IsEnum){
      throw new ArgumentException("T must be an enumerated type");
    }
  }
}

  1.2泛型類型的繼承

    泛型類型仍然是類型,它能從其餘任何類型派生。

    public class Node1<T>
    {
        public T m_data;
        public Node1<T> m_next;
        public Node1(T data) : this(data, null) { }
        public Node1(T data, Node1<T> next)
        {
            m_data = data;
            m_next = next;
        }
        public override string ToString()
        {
            // ABC
            return m_data.ToString()+((m_next!=null)?m_next.ToString():null);
        }
    }

  上面例子必須是相同數據類型下使用,加入鏈表須要多個m_data爲多種類型的時候這種結構將沒法知足,這時候咱們能夠考慮抽出一個非泛型的基類,這樣繼承的泛型就能夠指定多種類型。這是一個泛型應用的技巧。

public class Node2
    {
        protected Node2 m_next;

        public Node2(Node2 next)
        {
            m_next = next;
        }
    }

   public class TypeNode<T> : Node2 {
        public T m_data;
        public TypeNode(T data,Node2 next):base(next){
            m_data = data;
        }
        public TypeNode(T data):this(data,null){
        }
        public override string ToString()
        {
            // Tody is 時間。
            return m_data.ToString() + ((m_next != null) ? m_next.ToString() : null);
        }
    }

1.3泛型類型的同一性

  這種性質不常常用,這裏簡單記一下只當瞭解。

  簡化泛型的寫法多封裝一層去除"<"">"。

  class DateTimeList:List<DateTime>{

  //這裏不須要放入任何代碼。

}

這樣使用的時候就沒有<,>符號了。

DateTimeList dt=new DateTimeList();

這只是表面方便了,絕對不要單純出於加強代碼可讀性目的定義一個新類,事實上也不會這麼作,可是這樣寫會喪失同一性和相等性,以下代碼爲Flase

Boolean sameType=(typeof(List<DateTime>)==typeof(DateTimeList));

能夠經過使用using指令彌補相等性,添加以下結果爲True;

using DateTimeList=System.Collections.Generic.List<System.DateTime>;

 

1.4代碼爆炸

  使用泛型類型參數的一個方法在JIT(即時編譯)編譯時,Clr獲取方法的IL,用指定的實參進行替換,建立恰當的本地代碼,缺點是CLR要爲每種不一樣的方法、類型組合生成本地代碼,可能形成應用程序集顯著增大,損壞性能,稱之爲 代碼爆炸。

  可是CRL內建了一些優化措施,緩解代碼爆炸。全部程序集使用List<DateTime>時候,只會生成一次,認爲全部引用類型實參都是徹底相同,List<String>和List<Stream>能夠公用,之因此會這樣,是由於全部引用類型的實參或者變量實際都是指向堆上的對象指針,而指針所有都是以相同的方式來操做。

2,泛型接口

  泛型接口的一個例子是IComparable接口,在接口裏詳細寫

3,泛型委託

  建議使用泛型的Action和Func委託,會在之後的委託中細說

4,委託和接口的逆變和協變泛型類型實參

  不變量(invariant)表示泛型類型不可變。

  逆變量(contravariant)表示泛型類型參數能夠從一個基類更改成該類的派生類,用in關鍵字標記,只出如今輸入位置。

  協變量(covariant) 表示泛型類型能夠從一個派生類更改成它的基類型,用out關鍵字標記,只出如今輸出位置。

  public delegate TResult Func<in T,out TResult>(T arg);

  Func<object,ArgumentException> fn1=null;

  func<string,Exception> fn2=fn1;//這裏不須要顯示轉換,由於逆變量,協變量

  調用委託Exception e=fn2("");

  

  使用要獲取泛型參數和返回值的委託時,建議儘可能使用in和out關鍵字,由於不會有不良反應。

  泛型接口和泛型委託同樣也能夠用out和in。

5,泛型方法

   用一個例子介紹下泛型的定義,下面一個類型定義了一個類型參數,一個方法定義了它本身的專用類型參數。

  

class GenericType<T>{
  private T m_value;
  public GenericType(T value){m_value=value;}
  public TOutput Coverter(TOutput)(){
        TOutput  result=(TOutput)Convert.ChangeType(m_value,typeof(TOutput ));
      return   result;
  }  
}

  下面寫一個比較經典經常使用的泛型方法,2個參數互換

private static void Swap<T>(ref T o1,ref T o2){
  T temp=o1;
  o1=o2;
  o2=temp;    
}

 

6泛型約束

  確保使用當前泛型是本身想要的類型。

 例如以下方法,在類型沒有提供CompareTo方法時候會報錯。

 private static T Min<T>(T o1,To2){

    if(o1.CompareTo(o2)<0)

      return o1;

    return o2;

  }

   這個時候咱們就須要在該泛型方法添加泛型約束。

 private static T Min<T>(T o1,To2) where T:IComparable<T>{

    if(o1.CompareTo(o2)<0)

      return o1;

    return o2;

  }

泛型約束主要分爲3種。

1,主要約束   主要約束能夠是一個引用類型,實參必須與約束相同或者派生,

例如where T:Stream ,使用該泛型方法必須是Stream 類型或者其派生類型。

where T:Class,使用該泛型方法必須是引用類型。

2,次要約束   次要約束表明的是一個藉口類型,指定的參數必須實現全部接口約束例如 where T:IComparable<T>

3,構造器約束    指定的實參必須實現公共無參構造器的一個非抽象類型where T:New()

 

  

 下面是項目中用到的一個泛型方法,模板反序列化。使用了Newtonsoft.Json

        public T GetTemplateData<T>() where T : TemplateData
        {
            if (!string.IsNullOrEmpty(TemplateDataJsonStr))
            {
                T obj = (T)JsonConvert.DeserializeObject(TemplateDataJsonStr, typeof(T));
                obj.CheckField();
                return obj;
            }
            else return null;
            
        }
        public void SetTemplateData(TemplateData templateData) 
        {
           TemplateDataJsonStr= JsonConvert.SerializeObject(templateData);
        }
相關文章
相關標籤/搜索