很多非泛型集合类都有对应的泛型集合类,下面是常用的非泛型集合类以及对应的泛型集合类:
非泛型集合类 | 泛型集合类 |
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 慢就沒用呀,他能容易的對多屬性做排序,而速度差異也不大
比較糟的是,如果我的物件裏有子物件,我要對依子物件的屬性做排序,他就辦不到了。