泛型的总结

泛型最常见的用途是泛型集合,命名空间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的用法
主程序代码:

 

Code

 

 

Code

 

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 慢就沒用呀,他能容易的對多屬性做排序,而速度差異也不大
比較糟的是,如果我的物件裏有子物件,我要對依子物件的屬性做排序,他就辦不到了。

posted on 2008-09-10 14:40  小顾问  阅读(689)  评论(0编辑  收藏  举报