泛型的總結

泛型最常見的用途是泛型集合,命名空間System.Collections.Generic 中包含了一些基於泛型的集合類,使用泛型集合類可以提供更高的類型安全性,還有更高的性能,避免了非泛型集合的重複的裝箱和拆箱。 
    很多非泛型集合類都有對應的泛型集合類,下面是常用的非泛型集合類以及對應的泛型集合類:
非泛型集合類 泛型集合類
ArrayList List<T>
HashTable DIctionary<T>
Queue Queue<T>
Stack Stack<T>
SortedList SortedList<T>


    我們用的比較多的非泛型集合類主要有 ArrayList類 和 HashTable類。我們經常用HashTable 來存儲將要寫入到數據庫或者返回的信息,在這之間要不斷的進行類型的轉化,增加了系統裝箱和拆箱的負擔,如果我們操縱的數據類型相對確定的化  用 Dictionary<TKey,TValue> 集合類來存儲數據就方便多了,例如我們需要在電子商務網站中存儲用戶的購物車信息( 商品名,對應的商品個數)時,完全可以用 Dictionary<string, int> 來存儲購物車信息,而不需要任何的類型轉化。

List類
注意:此類在 .NET Framework 2.0 版中是新增的。表示可通過索引訪問的對象的強類型列表。提供用於對列表進行搜索、排序和操作的方法。命名空間: System.Collections.Generic,程序集:mscorlib(在 mscorlib.dll 中),List 類是 ArrayList 類的泛型等效類。

   //聲明一個泛型類  
    class TestGenericList
    ...{
        static void Main()
        ...{
            //聲明一個List對象,只加入string參數
            List<string> names = new List<string>();
            names.Add("喬峯");
            names.Add("歐陽峯");
            names.Add("馬蜂");
            //遍歷List
            foreach (string name in names)
            ...{
                Console.WriteLine(name);
            }
            //向List中插入元素
            names.Insert(2, "張三峯");
            //移除指定元素
            names.Remove("馬蜂");           
        }
    }
在決定使用 List 還是使用 ArrayList 類(兩者具有類似的功能)時,記住 List 類在大多數情況下執行得更好並且是類型安全的。如果對 List 類的類型 T 使用引用類型,則兩個類的行爲是完全相同的。但是,如果對類型 T 使用值類型,則需要考慮實現和裝箱問題。

如果對類型 T 使用值類型,則編譯器將特別針對該值類型生成 List 類的實現。這意味着不必對 List 對象的列表元素進行裝箱就可以使用該元素,並且在創建大約 500 個列表元素之後,不對列表元素裝箱所節省的內存將大於生成該類實現所使用的內存。

其實我們也可以自己定義一個泛型類,如下所示:
   //聲明一個泛型類
    public class ItemList<T>
    ...{
        void Add(T item) ...{ }
    }
    class TestGenericList
    ...{
        private class ExampleClass ...{ }
        static void Main()
        ...{
            // 聲明一個對象,只能加入int型
            ItemList<int> list1 = new ItemList<int>();

            //聲明一個對象,只能加入Student類型,Student類爲自定義類
            ItemList<Student> list2 = new ItemList<Student>();

        }
    }

泛型的用法還有很多種,如泛型方法,泛型委託,泛型接口等。

 

List 和 IList的區別 IList <Class1> IList11 =new List <Class1>(); 
List <Class1> List11 =new List <Class1>();

這兩行代碼,從操作上來看,實際上都是創建了一個List<Class1>對象的實例,也就是說,他們的操作沒有區別。

只是用於保存這個操作的返回值變量類型不一樣而已。

那麼,我們可以這麼理解,這兩行代碼的目的不一樣。 
List <Class1> List11 =new List <Class1>(); 
是想創建一個List<Class1>,而且需要使用到List<T>的功能,進行相關操作。 
而 
IList <Class1> IList11 =new List <Class1>(); 
只是想創建一個基於接口IList<Class1>的對象的實例,只是這個接口是由List<T>實現的。
所以它只是希望使用到IList<T>接口規定的功能而已。
C#裏List的用法
主程序代碼:

 


static void Main(string[] args)
        {
            ClassList listClass 
= new ClassList();
            Console.WriteLine(
"請輸入第個字符串");
            
string a = Console.ReadLine();
            Console.WriteLine(
"請輸入第二個字符串");
            
string b = Console.ReadLine();

            
foreach (string n in listClass.strList(a, b))
            {
                Console.WriteLine(n);
            }
類:
class ClassList
    {
        
public List<string> strList(string str1,string str2)
        {
            
string stra = str1 + str2;
            
string strb = str2 + str1;
            
string strc = str1 + str1;
            List
<string> listStr = new List<string>();
            listStr.Add(stra);
            listStr.Add(strb);
            listStr.Add(strc);
            
return listStr;
        }
    }

 

 


 public class Person
    {
       
private string _name;
       
private string _like;
       
public string Name
       {
           
get
           {
               
return this._name;
           }
           
set
           {
               
this._name = value;
           }
       }
       
public string Like
       {
           
get
           {
               
return this._like;
           }
           
set
           {
               
this._like = value;
           }
       }
    }
IList
<Person> myPerson = new List<Person>();
            Person person 
= new Person();
            person.Like 
= "pingpong";
            person.Name 
= "panjun";
            myPerson.Add(person);
            
foreach (Person person1 in myPerson)
            {
                
this.label1.Text += person1.Name + person1.Like;
            }

 

Dictionary 
此類在 .NET Framework 2.0 版中是新增的。表示鍵和值的集合。命名空間:System.Collections.Generic,程序集:mscorlib(在 mscorlib.dll 中)
    class TestGenericList
    ...{
         static void Main()
        ...{
 //聲明對象,參數表示,鍵是int類型,值是string類型
            Dictionary<int, string> fruit = new Dictionary<int, string>();
            try...{
             //加入重複鍵會引發異常
                fruit.Add(1, "蘋果");
                fruit.Add(2, "桔子");
                fruit.Add(3, "香蕉");
                fruit.Add(4, "菠蘿");            
  //參數錯誤將引發異常,如下所示
  //fruit.Add("5", "aa");
            }
            catch (ArgumentException)
            ...{
                Console.WriteLine("添加錯誤!!!");
            }
 //因爲引入了泛型,所以鍵取出後不需要進行Object到int的轉換,值的集合也一樣
            foreach (int i in fruit.Keys)
            ...{
                Console.WriteLine("鍵是:{0}  值是:{1}",i,fruit[i]);
            }
      //刪除指定鍵,值
            fruit.Remove(1);
             //判斷是否包含指定鍵
            if (fruit.ContainsKey(1))
            ...{
                Console.WriteLine("包含此鍵");
            }
            //清除集合中所有對象
            fruit.Clear();
        }
    }
Dictionary遍歷輸出的順序,就是加入的順序,這點與Hashtable不同,其它方法如:ContainsKey ,ContainsValue ,Remove 等,使用方法基本一致。

======================================================================================
.NET(C#) Hashtable Dictionary 探索
先看下面的代碼

using System;
using System.Collections;

namespace NoSortHashtable
{
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    class Class1
     {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
         [STAThread]
        static void Main(string[] args)
         {
             Hashtable hashTable = new Hashtable();

             hashTable.Add("hunan","changsha");
             hashTable.Add("beijing","beijing");
             hashTable.Add("anhui","hefei");
             hashTable.Add("sichuan","chengdu");
            foreach(string str in hashTable.Keys)
             {
                 Console.WriteLine(str + " : " + hashTable[str]);
             }

         }
     }
}

打印的結果是:
     anhui : hefei
     hunan : changsha
     sichuan : chengdu
     beijing : beijing
爲何產生這樣的結果? 我查了MSDN後發現----------------------------------------------------------------------------------------------------Hashtable 對象由包含集合元素的存儲桶組成。存儲桶是 Hashtable 中各元素的虛擬子組,與大多數集合中進行的搜索和檢索相比,存儲桶可令搜索和檢索更爲便捷。每一存儲桶都與一個哈希代碼關聯,該哈希代碼是使用哈希函數生成的並基於該元素的鍵。

哈希函數是基於鍵返回數值哈希代碼的算法。鍵是正被存儲的對象的某一屬性的值。哈希函數必須始終爲相同的鍵返回相同的哈希代碼。一個哈希函數能夠爲兩個不同的鍵生成相同的哈希代碼,但從哈希表檢索元素時,爲每一唯一鍵生成唯一哈希代碼的哈希函數將令性能更佳。

在 Hashtable 中用作元素的每一對象必須能夠使用 GetHashCode 方法的實現爲其自身生成哈希代碼。但是,還可以通過使用接受 IHashCodeProvider 實現作爲參數之一的 Hashtable 構造函數,爲 Hashtable 中的所有元素指定一個哈希函數。

在將一個對象添加到 Hashtable 時,它被存儲在存儲桶中,該存儲桶與匹配該對象的哈希代碼的哈希代碼關聯。在 Hashtable 內搜索一個值時,將爲該值生成哈希代碼,並且搜索與該哈希代碼關聯的存儲桶。

例如,一個字符串的哈希函數可以採用該字符串中每一字符的 ASCII 代碼並它們添加到一起來生成一個哈希代碼。字符串“picnic”將具有與字符串“basket”的哈希代碼不同的哈希代碼;因此,字符串“picnic”和“basket”將處於不同的存儲桶中。與之相比,“stressed”和“desserts”將具有相同的哈希代碼並將處於相同的存儲桶中。

Dictionary 類與 Hashtable 類的功能相同。對於值類型,特定類型(不包括 Object)的 Dictionary 的性能優於 Hashtable,這是因爲 Hashtable 的元素屬於 Object 類型,所以在存儲或檢索值類型時通常發生裝箱和取消裝箱操作。

----------------------------------------------------------------------------------------------------
產生這個結果的原因就是Hashtable內部的排序機制使然,但我現在就是不想排序,我按什麼順序輸入的,就想它再怎麼給我輸出,怎麼辦?google後發現幾個可以解決的辦法,不過都需要自己寫代碼實現比如,繼承hashtable,使用不自動排序的arraylist做中間橋
using System;
using System.Collections;

namespace NoSortHashtable
{
    public class NoSortHashtable : Hashtable
   {
        private ArrayList keys = new ArrayList();

        public NoSortHashtable()
        {
        }

        public override void Add(object key, object value)
        {
            base.Add (key, value);
            keys.Add (key);
        }

        public override ICollection Keys
        {
            get
            {
                return keys;
            }
        }

        public override void Clear()
        {
            base.Clear ();
            keys.Clear ();
        }

        public override void Remove(object key)
        {
            base.Remove (key);
            keys.Remove (key);
        }
        public override IDictionaryEnumerator GetEnumerator()
        {
            return base.GetEnumerator ();
        }

     }
}
或者只要Compare函數的返回結果不等於0就可以添加相同的Key,這樣可以實現既可以排序,又可以有相同的Key值,可能在某些情況下會用得到。 using System;
using System.Collections;

namespace testSortedList
{
    class Class1
     {
         [STAThread]
         static void Main(string[] args)
         {
             SortedList sl = new SortedList(new MySort());        //不排序
             sl.Add(333,333);
             sl.Add(111,111);
             sl.Add(222,222);
             sl.Add(111,112);

             PrintList(sl);

             Console.ReadLine();
         }

        private static void PrintList(SortedList sl)
         {
            for(int i=0;i<sl.Count ;i++)
             {
                 Console.WriteLine("{0}\t{1}",sl.GetKey(i),sl.GetByIndex(i));
             }//end for
         }//end fn()

     }
    public class MySort:IComparer
     {
        #region IComparer 成員
        public int Compare(object x, object y)
         {
            return -1;

            //排序
//             int iResult = (int)x - (int)y;
//             if(iResult == 0) iResult = -1;
//             return iResult;

         }
        #endregion
     }

}

 

使用單鏈接列表實現 IDictionary。建議用於通常包含 10 個或 10 個以下項的集合。


最後我測試了使用泛類型的Dictionary<T,T>, 儘管msdn上說hashtable和Dictionary的實現是一樣的,不過同樣的數據,返回的結果卻是不同的,我沒有找到更多的解釋,測試代碼如下


using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;

namespace NoSortHashtable
{
     /// <summary>
     /// Summary description for Class1.
     /// </summary>
     public class Class1
     {
         /// <summary>
         /// The main entry point for the application.
         /// </summary>
         [STAThread]
         static void Main(string[] args)
         {
             Hashtable ht = new Hashtable();
             ht.Add("hunan","changsha");
             ht.Add("beijing","beijing");
             ht.Add("anhui","hefei");
             ht.Add("sichuan","chengdu");
             foreach(string str in ht.Keys)
             {
                 Console.WriteLine(str + " : " + ht[str]);
             }    
            
             Console.WriteLine("------------------------------------");
               
             Dictionary<String,String> dic = new Dictionary<String,String>();
             dic.Add("hunan","changsha");
             dic.Add("beijing","beijing");
             dic.Add("anhui","hefei");
             dic.Add("sichuan","chengdu");
             foreach(string str in dic.Keys)
             {
                 Console.WriteLine(str + " : " + dic[str]);
             }
            
             Console.WriteLine("------------------------------------");
               
             ListDictionary lsdic = new ListDictionary();
             lsdic.Add("hunan","changsha");
             lsdic.Add("beijing","beijing");
             lsdic.Add("anhui","hefei");
             lsdic.Add("sichuan","chengdu");
             foreach(string str in lsdic.Keys)
             {
                 Console.WriteLine(str + " : " + lsdic[str]);
             }
        }
   }
}

另外,System.Collections.Specialized.ListDictionary也是可以完成該要求的,不過。。。
========================================================================================
3個對泛型 List 排序的方法

方式1:


    List<SoftDrink> list = manager.SoftDrink.ListSoftDrink();
    list.Sort(new MyComp().Compare);
    list.Sort(new MyCompDesc().Compare);


        public class MyComp : IComparer<SoftDrink> {
            public int Compare(SoftDrink x, SoftDrink y) {
                return String.Compare(x.SerialId, y.SerialId);
            }
        }

        public class MyCompDesc : IComparer<SoftDrink> {
            public int Compare(SoftDrink x, SoftDrink y) {
                return String.Compare(y.SerialId, x.SerialId);
            }
        }


 

方式2:


list.Sort(
    new Comparison<SoftDrink>(
        delegate(SoftDrink x, SoftDrink y) { 
            return String.Compare(x.SerialId, y.SerialId);
        }));
list.Sort(
    new Comparison<SoftDrink>(
        delegate(SoftDrink x, SoftDrink y) {
            return String.Compare(y.SerialId, x.SerialId);
        }));


 

方式3: 使用 Dynamic Reflection Library


DynamicComparer<SoftDrink> comparer = new DynamicComparer<SoftDrink>("SerialId");
DynamicComparer<SoftDrink> comparerDesc = new DynamicComparer<SoftDrink>("SerialId DESC");
list.Sort(comparer);
list.Sort(comparerDesc);


 

在List有90筆 SoftDrink的情況下,對List正排倒排連續做1000次

方法1: 0.424 秒
方法2: 0.393 秒
方法3: 1.859 秒 
方法3: 0.527 秒 (如果new Comparer()放在迴圈外)

 

不要覺得 Dynamic Reflection Library 慢就沒用呀,他能容易的對多屬性做排序,而速度差異也不大
比較糟的是,如果我的物件裏有子物件,我要對依子物件的屬性做排序,他就辦不到了。

發佈了2 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章