C#泛型編程

1.泛型的概念函數

    C#中的泛型與C++中的模板相似,泛型是實例化過程當中提供的類型或類創建的。泛型並不限於類,還能夠建立泛型接口、泛型方法,甚至泛型委託。這將極大提升代碼的靈活性,正確使用泛型能夠顯著縮短開發時間。與C++不一樣的是,C#中全部操做都是在運行期間進行的。this

2.使用泛型spa

  •  可空類型

       值類型必須包含一個值,它們能夠在聲明以後,賦值以前,在未賦值狀態下存在,但不能以任何方式使用,而引用類型能夠爲null。有時讓值類型爲空是頗有用的,泛型提供了使用System.Nullable<T>使值類型爲空的一種方式。以下代碼:code

    private Nullable<int> _nullableInt;對象

    則能夠爲_nullableInt賦爲null,以下:blog

    _nullableInt = null;排序

可空類型很是有用,以至於C#中加入了語法:繼承

int? _nullableIntSecond;接口

  • System.Collections.Generic 名稱空間

    這個名稱空間用於處理集合的泛型類型,使用的很是頻繁。將以List<T>和Dictionary<K,V>爲例介紹這些類,以及和它們配合使用的接口和方法。ci

        1.List<T>

        List<T>泛型集合類更加快捷,更易於使用,建立T類型對象的集合須要一下方法:

        List<string> _myCollection = new List<string>();

        將建立T爲String的List集合。

        能夠在代碼中去查看List<T>所支持的方法,這裏再也不贅述。

       2.對泛型列表進行排序和搜索

        對泛型列表進行排序和搜索與和其它列表進行排序和搜索是同樣的,以下爲實例代碼:

            

public class NumberCollection : List<int>
    {
        public NumberCollection(IEnumerable<int> initialNums)
        {
            foreach (var num in initialNums)
            {
                Add(num);
            }
        }

        public NumberCollection()
        {
            for (int i=0;i < 10;++i)
            {
                Add(i);
            }
        }

        public void Print()
        {
            foreach (var num in this)
            {
                Console.WriteLine(num);
            }

            Console.Read();
        }
    }
public static class NumberCollectionDelegate
    {
        public static int Compare(int i,int j)
        {
            if (i > j)
            {
                return -1;
            }
            else if (i < j)
            {
                return 1;
            }
            return 0;
        }

        public static bool Find(int i)
        {
            if (i %2 == 0)
            {
                return true;
            }

            return false;
        }

         public static Comparison<int> CopmareDelegate = new Comparison<int>(Compare);

 
 

         public static Predicate<int> Predicate = new Predicate<int>(Find);


    }
var numColleciton = new NumberCollection();
numColleciton.Print();
numColleciton.Sort(NumberCollectionDelegate.CopmareDelegate);
numColleciton.Print();
var newNumCollection = new NumberCollection(numColleciton.FindAll(NumberCollectionDelegate.Predicate));
newNumCollection.Print();
Console.ReadLine();

如上代碼,首先定義了NumberCollection繼承自List<int>,定義了Print方法用來輸出集合中全部的值,類NumberCollectionDelegate中定義了Compare方法,以及Find方法,Compare方法用於對集合進行降序排序(爲何這麼寫是降序排序請關注另外一篇文章),Find方法用於選擇集合中爲偶數的值。在實例的使用中,首先對集合中的元素進行了降序排序,後選擇集合中爲偶數的值組成新的集合,固然上述比較與查找用法能夠簡化爲如下用法:

numColleciton.Sort(NumberCollectionDelegate.Compare);

var newNumCollection = new NumberCollection(numColleciton.FindAll(NumberCollectionDelegate.Find));

這樣就不須要顯示引用Comparison<int>類型了,可是在使用時仍然會隱式建立Comparison<int>實例,對於比較也是一樣的。在許多狀況下,均可以使用方法組以這種方式隱式的建立委託,使代碼變的更容易讀取。

3.Dictionary<K,V>

    這個類型能夠定義鍵值對的集合,這個類型須要實例化兩個類型,分別用於鍵和值,以表示集合中的各個項。可使用強類型化的Add方法添加鍵值對,以下。

Dictionary<string, int> stringIntDictionary = new Dictionary<string, int>();
stringIntDictionary.Add("Tom", 1);
stringIntDictionary.Add("Lucy", 2);
stringIntDictionary.Add("Lily", 3);

能夠直接訪問Dicitionary中的keys和Values屬性值:

foreach (var key in stringIntDictionary.Keys)
{
Console.WriteLine(key);
}

foreach (var value in stringIntDictionary.Values)
{
Console.WriteLine(value);
}

一樣能夠迭代集合中每一項,以下:

foreach (KeyValuePair<string,int> item in stringIntDictionary)
{
Console.WriteLine("{0} = {1}", item.Key, item.Value);
}

對於Dictionary<K,V>須要注意的一點是,每一個項的鍵都必須式惟一的。若是要添加的項與已存在的項的鍵值相同,則會拋出異常。

3.定義泛型

    1.定義泛型類

         要建立泛型類,只需在類定義中包括尖括號:

class MyGenericClass<T>
{
}

其中T能夠是任意標識符,只須要遵循C#命名規則便可,但通常只使用T。

泛型類能夠在其定義中包含任意多個類型,它們用逗號分開,例如:

class MyGenericClass<T1,T2,T3>
{
}

定義了這些類型以後,就能夠在類定義中像使用其它類型那樣使用它們,以下

class MyGenericClass<T1,T2,T3>
    {
        private T1 _object;

        public MyGenericClass(T1 item)
        {
              _object = item;
        }

        public T1 InnerT1Object
        {
            get
            {
                return _object;
            }
        }
    }

注意不能假定使用了什麼類型,例如:

_object = new T1();

由於此刻不知道T1是什麼,也就不能使用它的構造函數,可能T1就沒有構造函數,或者沒有可公共訪問的構造函數。所以要對泛型進行實際的操做須要更多瞭解其使用的類型。

  • default關鍵字

    要肯定用於建立泛型類型的實例,須要瞭解一個最基本的狀況,它是引用類型仍是值類型,若不瞭解這個狀況就不能直接對變量賦予null值。此時default關鍵字就派上了用場:

_object = default(T1);

若是_object是引用類型就給引用類型賦爲null值,若是爲值類型就給它賦爲默認值。對於數字類型默認值爲0,對於結構,按照相同的規則對它們進行賦值。default關鍵字容許對必須使用的類型進行更多的操做,爲了進行更多的操做,必須對使用的類型進行更多的約束。

  • 約束類型

    前面使用的類型稱爲無綁定類型,由於沒有對它們進行任何約束,而經過約束能夠限定用於泛型的類型。在類定義中,可使用where關鍵字,來限定用於泛型的類型,以下:

class MyGenericClass<T1,T2,T3> where T1 : constraint

其中constraint定義了約束,能夠用這種能方式定義不少約束,每一個約束之間用逗號分開。還可使用多個where語句,定義泛型類型須要的任意類型或全部類型上的約束,約束必須出如今類型說明符的後面。

  • 從泛型類中繼承

    類能夠從泛型中繼承,如

class Farm<T> : IEnumerable<T> where T : Animal
{
}

如上代碼Farm<T>是一個接口類型,一樣對於T的約束也會在IEnumerable中使用的T上添加一個額外的約束,這能夠用於限制用於約束的類型,可是須要遵照一些規則。

    首先,若是某個類型所繼承的基類型中受到了約束,該類型就不能接觸約束,即類型T在基類中使用時所受到的約束,必須擴展到子類中,至少於基類的約束相同。

  • 泛型運算符

    泛型類也支持運算符的重寫。

  • 泛型結構

    結構與類相同,只是有一些細微的差異,並且結構是值類型,不是引用類型,因此能夠建立泛型結構,如:

struct MyGenericStruct<T1, T2>
{
}

2.定義泛型接口

定義泛型接口於定義泛型類所用的技術相同,例如:

  interface IGeneric<T> where T : Object
    {
        void Sum(T x, T y);
    }

3.定義泛型方法

    可使用泛型方法以達到泛型方法的更通常形式,在泛型方法中,參數類型或返回類型由泛型類型參數所決定。

,例如:

  T GetDefault<T>()
           {
               return default(T);
           }

可使用非泛型類,實現泛型方法:

   public class Defaulter
    {
        public T GetDefault<T>()
        {
            return default(T);
        }
    }

 若是類是泛型的,那麼須要爲類中的泛型方法提供不一樣的標示符。以下代碼會提示泛型方法:

  public class Defaulter<T>
    {
        public T GetDefault<T>()
        {
            return default(T);
        }
    }

會提示內部泛型參數與外部泛型參數相同,此時應該更改泛型標示符。

 

本篇內容參考C#入門經典。

相關文章
相關標籤/搜索