<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

      .NET 中的泛型 101

      1.1.1 摘要

      generic0

      圖1 C# 泛型介紹

            在接觸泛型之前,我們編程一般都是使用具體類型(char, int, string等)或自定義類型來定義我們變量,如果我們有一個功能很強的接口,而且我們想把它提取或重構成一個通用的接口,使得該接口不僅僅適用于已定義數據類型,而是適用于更多數據類型,從而方便以后的擴展。

           泛型提供上述功能的實現,泛型其實就是提供一個數據類型的抽象層,因為它泛所以抽象,方便了我們代碼的重構和提取,我們無需hard-code接口中的數據類型,而是通過一個抽象泛型類型來指定數據類型,所以泛型可以提取出一個通用的接口。接下來讓我們通過具體的例子說明什么是泛型。

      1.1.2 正文

      1.1.1.1 沒有泛型的C# 1.0

            相信許多人都使用過棧或者其他經典數據結構,而且對于棧的FILO都是嫻熟于心了。假設現在要我們定義一個棧,用來存放具體數據類型,例如:int 數據,OK讓我們來實現自定義棧。

      /// <summary>
      /// A custom stack1.
      /// </summary>
      public class CustomStack1
      {
          private int _stackPointer = 0;
          private int[] _stackArray;
      
          public void Push(int item)
          {
              ////Concrete implemention.
          }
      
          public int Pop()
          {
              ////Concrete implemention.
          }
      }

            為了簡潔沒有完全遵守OOP的原則,這里沒有使用屬性和給出方法的具體實現,現在我們有了第一版可以存放int數據類型的棧。但如果需求改變保存數據類型增加string。那么我們可以怎樣實現呢?沒錯我們只要增加一個類型為string的棧就OK了。

      /// <summary>
      /// A custom stack2.
      /// </summary>
      public class CustomStack2
      {
          private int _stackPointer = 0;
          private string[] _stackArray;
      
          public void Push(int item)
          {
              ////Concrete implemention.
          }
      
          public string Pop()
          {
              ////Concrete implemention.
          }
      }

            很快我們就完成了第二版本的棧了,這看上去的確很簡單而且實現起來很快只不過是ctrl + c和ctrl + v,但我們的代碼真的那么簡單好維護嗎?想想其實危機四伏。我們能不能一開始就把保存的數據類型定義成為一個通用的類型呢(抽象數據類型)?----邪惡的object。

      /// <summary>
      /// A custom stack.
      /// </summary>
      public class CustomStack
      {
          private int _stackPointer = 0;
          private object[] _stackArray;
      
          public void Push(object item)
          {
              ////Concrete implemention.
          }
      
          public object Pop()
          {
              ////Concrete implemention.
          }
      }

            現在我們實現了第三版的棧了,看上去我們好像找到了通用的解決方法,想想我們要注意一點是如果我們保存和取出數據類型為值類型時,值類型要進行boxing和unboxing操作(《.NET值類型和引用類型101》),而且還有進行數據類型檢測。如果數據量不大我們可能察覺不到性能變化,但數據量大hehehe…。這就是為什么我們要使用泛型的原因之一,但更重要的原因是在進行boxing和unboxing時,我們需要提供更多信息給編譯器,編譯時再根據我們提供的信息進行類型檢測。

      1.1.1.2 C#中的泛型

            現在我們知道了.NET為什么要提供泛型,現在讓我們學習什么是泛型和怎樣實現吧!在C# 2.0中提供了泛型這一機制,但這可不是什么新奇的技術,因為早在C++和Java都提供泛型機制。

      C#中提供五種泛型分別是:classes, structs, interfaces, delegates, and methods

      • 泛型類

           也許有人說沒有使用過C++的模板或Java的泛型,而且不了解C#中的泛型,真的是這樣嗎?其實我們經常都在使用泛型,相信很多人都使用過Dictionary<TKey,TValue>,沒錯這就是C#中提供的泛型字典,接下來我們將介紹自定義泛型類CustomStack。

      generic2圖2泛型類 

      /// <summary>
      /// A custom generic stack.
      /// </summary>
      public class CustomStack<T>
      {
          private int _stackPointer = 0;
          private T[] _stackArray;
      
          public void Push(T item)
          {
              ////Concrete implemention.
          }
      
          public T Pop()
          {
              ////Concrete implemention.
          }
      }

            前面給出了泛型類CustomStack實現,我們發現只需在類名后添加<T>,并且把具體數據類型改為抽象的泛型類型T,現在我們就定義了一個簡單泛型類,我們可以通過以下對比一下非泛型和泛型實現的區別。

      generic1

      圖3非泛型和泛型類定義

            通過上圖我們發現泛型類CustomStack和非泛型類CustomStack在實現上沒有太大的區別,我們只需把具體類型換成T就OK了,接下來我們將進入泛型的進階學習。

      • 泛型委托

           關于委托大家可以閱讀《.NET 中的委托》和《.NET中的委托和事件(續)》,現在讓我們學習一下泛型委托。

      generic4

      圖4泛型委托的定義

            上圖給出了泛型委托的定義,我們要注意Type parameters包括泛型參數和返回類型。隨著C#3.0 Linq特性的引用,泛型委托的使用得到了極大地擴展,讓我們通過具體代碼講講如何使用泛型委托。

            首先我們定義一個泛型委托,然后再定義一個Calc類,接著在Calc里定義兩個方法分別是Add() 和Divide() 如下:

      /// <summary>
      /// Define generic delegate.
      /// </summary>
      public delegate TR CalcMethod<T1, T2, TR>(T1 x, T2 y);
      
      
      public class Calc
      {
          static private double sum;
      
          /// <summary>
          /// Gets or sets the sum.
          /// </summary>
          /// <value>
          /// The sum.
          /// </value>
          static public double Sum
          {
              get { return sum; }
              set { sum = value; }
          }
      
          /// <summary>
          /// Adds the specified x.
          /// </summary>
          /// <param name="x">The x.</param>
          /// <param name="y">The y.</param>
          /// <returns></returns>
          static public string Add(int x , int y)
          {
              Sum = x + y;
              return Sum.ToString();
          }
      
          /// <summary>
          /// Divides the specified x.
          /// </summary>
          /// <param name="x">The x.</param>
          /// <param name="y">The y.</param>
          /// <returns></returns>
          static public string Divide(int x, int y)
          {
              if (y == 0)
              {
                  return "除數不能為零";
              }
              Sum = x * 1.0 / y;
              return Sum.ToString();
          }
      
      } 

          接下來我們需要定義一個委托變量,而后將委托變量和具體調用方法綁定就OK了。

      ////Initialize engeric delegate instance to Add method.
      CalcMethod<int, int, string> calcMethod =
          new CalcMethod<int, int, string>(Calc.Add);
      • 類型約束

          前面例子我們并沒有對泛型類型進行限制,由于T是一個抽象類型,有時我們必須限制T是哪種類型,例如我們可以定義CustomStack<int>,CustomStack<double>或CustomStack<string>類型的棧,但有時我們必須限制泛型類型。這時我們需要使用類型約束,引入關鍵字----where

          C#中提供五種類型約束(類名,接口名,引用類型,值類型和構造函數),我們可以通過使用不同的類型約束來限定泛型類型。

      類型約束

      約束描述

      ClassName

      T只能是該類或繼承該類的子類

      InterfaceName

      T只能是該接口或實行該接口的類型

      struct

      T是任意值類型

      class

      T是任意引用類型(如classes, arrays, delegates, and interfaces等)

      new()

      T是包含公有無參構成函數的任意類型

      表1類型約束

       

            通過表1我們初步地了解不同類型約束之間的區別,現在讓我們通過具體的例子來看看它們使用范圍和區別。

            假設我們定義了一個泛型結構體struct RefSample<T> where T : class,現在考考大家以下例子符合類約束的有(提示值類型和引用類型區別):

       

      A. ? RefSample<IDisposable>

      B. ? RefSample<string>

      C.? RefSample<int[]>

      D.? RefSample<Guid>

      E. ? RefSample<int>

           激動人心的時刻又到了現在讓我們快快公布答案吧!答案是ABC,因為該泛型的約束是引用類型約束,如果大家還不清楚請看一下引用類型約束的定義。

           通過類約束例子,我們舉一反三值類型約束就是約束類型為值類型。

           OK接下來讓我們介紹構造函數約束。在介紹構造函數約束之前,讓我們回顧一下符合構造函數約束的條件:任意值類型,任意非靜態非抽象無明確定義構造函數的類和任意非抽象有明確定義無參構造函數的類。這句話很別扭,讓我們通過具體例子講解一下。

      //// Define generic method
      //// Which has constructor type constraints
      public T CreateInstance<T>() where T : new() 
      {
      return new T(); 
      }
      
      CreateInstance<int>();
      CreateInstance<object>();
      CreateInstance<string>();

            現在我們定義了一個泛型方法并且添加構造函數約束,調用CreateInstance<int>() 和 CreateInstance<object>() 成功,但調用CreateInstance<string>() 失敗,這由于String類沒有提供無參構造函數。也許有人會問:“我們很難判斷每種類型是否包含默認構無參造函數”,確確是這樣但我們可以記住的是C#規定值類型提供默認無參構造函數

       

      • 組合約束

           前面的泛型例子都是只使用一種類型約束,但有時候我們要使用多種類型約束,這時我們就可以使用組合約束,在使用約束的時我們要注意約束的先后次序,約束次序如下:

      generic3

      圖5約束次序

           通過上圖我們發現ClassName,class和struct是主要約束,接口名是第二約束,最后是構造函數約束。OK現在我們對組合約束有了初步地了解,那么讓我們通過以下例子加深理解。

      A. class Sample<T> where T : class, struct

      B. class Sample<T> where T : Stream, class

      C. class Sample<T> where T : new(), Stream

      D. class Sample<T> where T : IDisposable, Stream

      E. class Sample<T> where T : XmlReader, IComparable, IComparable

      F. class Sample<T,U> where T : struct where U : class, T

      G. class Sample<T,U> where T : Stream, U : IDisposable

           上面給出錯誤使用組合約束的例子(注:A~E單類型組合約束,FG多類型組合約束),請大家指出約束錯誤的原因,如果不清楚錯誤的原因大家回憶一下約束定義。

      1.1.3 總結

           本文注意介紹了C# 中泛型的基礎知識給出自己的總結,而且這不是C# 泛型的全部,如果大家在看完本文之后希望進一步學習泛型這才是我的目的。

      泛型的優點:

      • 編譯時進行類型檢測,減少運行時異常InvalidCastException。
      • 泛型使用強數據類型。如我們實例一個CustomStack<CustomStruct>對象objStack,通過調用Push()方法成功把CustomStruct壓入棧中,而objStack.Push(“Stack”)失敗。
      • 值類型無需進行boxing和unboxing操作。例如前面的泛型Push()和Pop()方法存放和取出值類型時無需進行boxing和unboxing操作。
      • 減少代碼量。如:我們定義一個泛型棧,就不用像前面例子那樣分別定義int和string類型的棧。
      • 程序性能提高,因為無需類型轉換,從而減少類型檢測。
      • 使用泛型減少內存消耗。因為無需進行boxing操作,不用重新分配堆空間。
      • 代碼可讀性更強。

            很多人喜歡將C# ,C++ 和Java中的泛型進行對比,而且也有很多相關的討論,在這里我也給出自己的想法,我覺得C++ 的泛型功能的確比C# 和Java都要強大。

      posted @ 2011-06-11 18:00  JK_Rush  閱讀(4380)  評論(5)    收藏  舉報
      主站蜘蛛池模板: 又大又硬又爽免费视频| 国产午夜亚洲精品国产成人| 成熟了的熟妇毛茸茸| 国产久爱免费精品视频| 国产中文字幕精品视频| 欧美高清精品一区二区| 午夜福利国产精品小视频| 阳山县| 韩国三级网一区二区三区| 国产精品国产三级国快看| 午夜免费无码福利视频麻豆| 亚洲欧美日韩人成在线播放| 神马视频| 亚洲精品国产av成拍色拍个| 国产女同疯狂作爱系列| 色吊丝一区二区中文字幕| 日韩V欧美V中文在线 | 国产一区二区不卡视频在线| 91精品91久久久久久| 无码精品人妻一区二区三区中| 亚洲精品日韩中文字幕| 我要看亚洲黄色太黄一级黄| 亚洲国产欧美一区二区好看电影| 亚洲伊人精品久视频国产| 久久月本道色综合久久| 亚洲高清国产成人精品久久| 一本色道婷婷久久欧美| 色94色欧美sute亚洲线路二| 中国老妇xxxx性开放| 国产超碰无码最新上传| 亚洲各类熟女们中文字幕| 欧美牲交a免费| 精品久久久bbbb人妻| 亚洲精品一区二区天堂| 神农架林区| 亚洲AV成人片在线观看| 久久亚洲av午夜福利精品一区| 18av千部影片| 人妻中文字幕av资源站| 99中文字幕精品国产| 久久国产成人午夜av影院|