C# 泛型

來源:互聯網
上載者:User

標籤:

一、前言

首先談談泛型,包括Java, C++都有自己的泛型(模版),這種機制大大的減少了代碼的數量,是一種類型的抽象。集合就我瞭解C++的 STL 中的vector<T>, list<T>, map<T,T> 等, .net 中的List<T>, HashTable<T,T>等,都是對基本資料結構的實現,如鏈表,隊列,棧,等。但是在具體使用中,不同的語言,如果使用不當,我造成嚴重的效能影響,合格的程式員應該瞭解這些效能陷阱。

 

二、.net 泛型

在.net中通過使用泛型,我們可以達到以下兩個目的:

1.Type safe  2. No Boxing.

這個比較好理解,舉個例子ArrayList, 其源碼如下:

public class ArrayList : IEnumerable, ICollection, IList    {        private object[] items;        private int size;        public ArrayList(int initalCapacity)        {            items = new object[initalCapacity];        }        public void Add(object item)        {            if (size < items.Length - 1)            {                items[size] = item;                ++size;            }            else {                //Allocate a larger array, copy the elements to there.            }        }        public object this[int index]        {            get            {                if (index < 0 || index >= size) throw new IndexOutOfRangeException();                return items[index];            }            set            {                if (index < 0 || index >= size) throw new IndexOutOfRangeException();            }        }        // ommit other details    }

可見在Add的時候會有裝箱操作發生,如果存放的是1,000,000的Point, 將會有大量的記憶體被浪費掉(8M (extra)+ 8M(data) + 4M(reference)), 除了因為裝箱引起記憶體浪費外,因為我們相關的操作時基於System.Object,型別安全也是一個大問題。

 

泛型可以完美的解決這個問題,原理看簡化的源碼:

public class List<T> : IEnumerable<T>, ICollection<T>, IList<T>    {        private T[] items;        private int size;        public List(int initalCapacity)        {            // does this work?            items = new T[initalCapacity];        }        public void Add(T item)        {            if (size < items.Length - 1)            {                items[size] = item;                ++size;            }            else            {                //Allocate a larger array, copy the elements to there.            }        }        public T this[int index]        {            get            {                if (index < 0 || index >= size) throw new IndexOutOfRangeException();                return items[index];            }            set            {                if (index < 0 || index >= size) throw new IndexOutOfRangeException();                items[index] = value;            }        }        // ommit other details    }

不用擔心型別安全和裝箱拆箱的問題了。但是如果我增加一些比較的功能呢?

 public static int BinarySearch<T>(T[] array, T element) {

//At some point in the algorithm, we need to compare:

if (array[x] < array[y]) {

...

}

System.Object沒有實現 static operator <, 對於上面這個函數,大部分都會類型都會編譯錯誤。我們可以使用模版函數的限制功能,來保證T實現了 比較的 , .NET一種有5種限制:

public class Widget{        public void Display(int i, int j) { }    }    public class GenericDemo    {        // T must implement an interface        public string Format<T>(T instance) where T: IFormattable        {            return instance.ToString("N", CultureInfo.CurrentCulture);            // OK, T must have IFormattable.ToString(...)        }        // T must based on a base class        public void Display<T>(T widget) where T : Widget        {            widget.Display(1, 2);        }        // T must a parameterless cosntructor        public T Create<T>() where T : new()        {            return new T();        }        // T must be a reference type:        public void ReferencesOnly<T>(T reference) where T : class { }        // T must be a value type:        public void ValueType<T>(T valueType) where T : struct { } }

這樣我們可以這樣寫BinarySearch了: 

public static int BinarySearch<T>(T[] array, T element) where T : IComparable<T> {

        //At some point in the algorithm, we need to compare:

             int x = 1; int y = 2;

        if (array[x].CompareTo(array[y]) < 0) {

        //...

        }

        }

 

接下來我們再討論 IEquatable<T>,先看下面這個函數:

public static void CallEquals<T>(T instance) {instance.Equals(instance);}

Equals將會調用基類的虛函數Equals,它的參數是System.Object,會產生裝箱。但是我們實現了IEquatable<T>,使用在模版限定中, 就可以避免裝箱了

//From the .NET Framework:public interface IEquatable<T> {bool Equals(T other);}public static void CallEquals<T>(T instance) where T : IEquatable<T> {instance.Equals(instance);}

這個函數將不再調用虛函數的Equals, 這樣就避免了裝箱。我們在前一篇文章中,提到valueType的最佳實務中,要現實IEquatable<T> 就是這個原因。 那麼按理說所有的集合最好都限制為IEquatable<T>類型,但是為了擴充性的考慮,我們用組合的形式,委託給GenericEqualityComparer, 舉個例子List<T>.Contains, 前看簡化源碼:

public bool Contains(T item)        {            if (item == null)            {                for (int i = 0; i < this._size; i++)                {                    if (this._items[i] == null)                    {                        return true;                    }                }                return false;            }            EqualityComparer<T> @default = EqualityComparer<T>.Default;            for (int j = 0; j < this._size; j++)            {                if (@default.Equals(this._items[j], item))                {                    return true;                }            }            return false;        }

把比較委託給了EqualityComaprer<T>, 如果我們替換了它,就可以改變我們的比較策略了。除了equals,這裡還有別的實現數學的泛型知識。請看參考連結

 

三、參考

<<Pro .NET Performance>>

http://www.codeproject.com/Articles/8531/Using-generics-for-calculations

 

C# 泛型

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.