第11课:数组与集合(2)
本课继续讨论集合相关类型,包括Dictionary、ConcurrentDictionary类,以及tPair和tPairList类的封装。
Dictionary泛型类
Dictionary泛型类用于处理“键/值”对应的集合,也就是集合中的元素由“键(Key)”和“值(Value)”组成;在使用Dictionary泛型类时,可以指定键和值的类型,如下面的代码演示了Dictionary的基本应用,其中键和值的类型都定义为string类型。
C# |
using System;
using System.Collections.Generic;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("Earth", "地球");
dict.Add("Mars", "火星");
dict.Add("Jupiter", "木星");
foreach(string key in dict.Keys)
{
tWeb.WriteLine(key + " : " + dict[key]);
}
}
}
|
代码执行结果如图1。
图1
使用Dictionary类时,类型结构为<键类型,值类型>。本例中的Add()方法用于添加元素,其中,参数一为键,参数二为值。访问元素时,可以使用Keys属性获取所有键名,然后以键为索引访问元素的值。
同时获取元素的键和值时,可以通过KeyValuePair结构实现,如下面的代码。
C# |
using System;
using System.Collections.Generic;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("Earth", "地球");
dict.Add("Mars", "火星");
dict.Add("Jupiter", "木星");
foreach (KeyValuePair<string, string> item in dict)
{
tWeb.WriteLine(item.Key + " : " + item.Value);
}
}
}
|
代码执行结果与图1相同。
下面是Dictionary泛型类的常用属性。
- Count属性,返回集合中的元素数量。
- Keys属性,返回元素的键组成的集合。
- Values属性,返回元素的值组成的集合。
下面是Dictionary泛型类的常用方法。
- Add(key,value)方法,向集合添加元素。
- Clear()方法,清除集合中的所有元素。
- ContainsKey(key)方法,判断指定的键是否存在,存在时返回true,否则返回false。
- ContainsValue(value)方法,判断指定的值是否存在,存在时返回true,否则返回false。
- Remove(key)方法,删除指定键名的元素,元素存在并删除时返回true,否则返回false。
- TryGetValue(TKey key, out TValue value)方法,尝试获取指定键名的元素的值,参数一指定键名,如果元素存在,则由参数二带出元素的值,方法返回true;如果指定键名的元素不存在,则方法返回false。
此外,还可以使用SortedList或SortedDictionary泛型类处理“键/值”集合,集合中的元素会通过“键”进行排序,对象的操作与Dictionary类型相似。下面的代码演示了SortedList类的基本应用。
C# |
using System;
using System.Collections.Generic;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
SortedList<int,string> lst = new SortedList<int, string>();
lst.Add(2, "ccc");
lst.Add(0, "aaa");
lst.Add(1, "bbb");
foreach(KeyValuePair<int,string> pair in lst)
{
tWeb.WriteLine(pair.Key + " : " + pair.Value);
}
}
}
|
代码中,在向lst对象添加集合元素时,并没有按“键”顺序操作,但在对象的内部会按“键”排列元素;通过foreach语句访问所有元素时可以看到已按“键”排序的结果,如图2。
图2
ConcurrentDictionary泛型类
应用中,特别是有并发操作的应用中,如果需要维护一个全局的集合,就必须考虑并发操作中的线程安全问题。从.NET Framework 4.0开始,新增了System.Collections.Concurrent命名空间,定义了一系列的线程安全集合类型,本节主要讨论如何使用ConcurrentDictionary类操作线程安全的字典集合。
ConcurrentDictionary类中定义了与Dictionary类相同的成员,如:
- Count,返回元素的数量。
- Keys,返回所有“键”组成的集合。
- Values,返回所有“值”组成的集合。
- 索引器,可以使用“键”作为索引访问相应的“值”。
- Clear()方法,清除所有元素。
- ContainsKey(k)方法,当键k存在是返回true,否则返回false。
下面的代码演示了ConcurrentDictionary类的基本应用。
C# |
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ConcurrentDictionary<string, string> dict =
new ConcurrentDictionary<string, string>();
dict["key1"] = "value1";
dict["key2"] = "value2";
dict.AddOrUpdate("key1", "value3", (k, v) => "value3");
//
foreach (KeyValuePair<string, string> pair in dict)
{
tWeb.WriteLine(pair.Key + " : " + pair.Value);
}
}
}
|
代码执行结果如图3。
图3
本例,首先创建了一个ConcurrentDictionary对象,其中“键”和“值”都是定义为string类型;然后通过索引器添加了两个元素,分别是“key1/value1”和“key2/value2”。接下来使用了AddOrUpdate()方法,其功能是对于不存在的键会添加新元素,对于已存在的键则按指定的规则更新元素数据,并返回并的数据。
AddOrUpdate()方法用于更新key1键中的数据,方法使用了三个参数,参数一指定添加或修改数据的键名,参数二指定键不存在时添加的新值,参数三使用了委托类型,指定当键存在时的数据更新规则;代码中,直接将key1元素的数据指定为value3,此外,委托中的参数分别表示已存在元素的键和值,如时更新数据与原数据相关时,可以参考如下代码。
C# |
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ConcurrentDictionary<string, string> dict =
new ConcurrentDictionary<string, string>();
dict["key1"] = "value1";
dict["key2"] = "value2";
dict.AddOrUpdate("key1", "value3", (k, v) => v + ",update");
//
foreach (KeyValuePair<string, string> pair in dict)
{
tWeb.WriteLine(pair.Key + " : " + pair.Value);
}
}
}
|
代码执行结果如图4。
图4
下面再了解一些ConcurrentDictionary类中的常用方法,首先是GetOrAdd()方法,其中,参数一指定“键”,参数二指定“值”;当“键”存在时,返回元素的“值”,如果“键”不存在,则添加新的元素。下面的代码演示了GetOrAdd()方法的应用。
C# |
using System;
using System.Collections.Concurrent;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ConcurrentDictionary<string, string> dict =
new ConcurrentDictionary<string, string>();
string value = dict.GetOrAdd("key1", "value1");
tWeb.WriteLine(value);
value = dict.GetOrAdd("key1", "");
tWeb.WriteLine(value);
}
}
|
本例,第一次调用GetOrAdd()方法时,键key1不存在,会添加“key1/value1”元素到字典;第二次调用GetOrAdd()方法,键key1已存在,会返回其值value1。
ToArray()方法一个KeyValuePair数组,包含了字典中的所有“键/值”对,下面的代码演示了ToArray()方法的应用。
C# |
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ConcurrentDictionary<string, string> dict =
new ConcurrentDictionary<string, string>();
dict["key1"] = "value1";
dict["key2"] = "value2";
dict["key3"] = "value3";
var arr = dict.ToArray();
for (int i = 0; i < arr.Length; i++)
{
tWeb.WriteLine(arr[i].Key + " : " + arr[i].Value);
}
}
}
|
代码执行结果如图5。
图5
ConcurrentDictionary类中还有一些基本的元素操作方法,如:
- TryAdd (TKey key, TValue value)方法,成功添加“key/value”元素时返回true,添加失败或key已存在时返回false。
- TryGetValue (TKey key, out TValue value)方法,当字典中存在键key,则通过输出参数value返回元素的值,方法返回true;如果键key不存在,方法返回false。
- TryRemove (TKey key, out TValue value)方法,
- TryUpdate (TKey key, TValue newValue, TValue comparisonValue)方法,如果字典中的key有对应的comparisonValue,则将其修改newValue。成功修改时返回true,否则返回false。
下面的代码演示了TryRemove()方法的应用。
C# |
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ConcurrentDictionary<string, string> dict =
new ConcurrentDictionary<string, string>();
dict["key1"] = "value1";
dict["key2"] = "value2";
string value;
//
tWeb.WriteLine(dict.TryRemove("key1",out value));
tWeb.WriteLine(value);
//
tWeb.WriteLine(dict.TryRemove("key3", out value));
tWeb.WriteLine(value == null);
}
}
|
代码执行结果如图6。
图6
代码中首先定义了字典对象并添加了两个元素。第一个输出用于删除键为key1的元素,此元素存在方法会返回true,输出参数会带出删除元素的值value1(第二个输出),第三个输出是删除键key3的结果,由于元素不存在则方法返回false,输出参数带出的结果为null,第四个输出显示了方法带出结果与null值的比较结果。
下面的代码演示了TryUpdate()方法的应用。
C# |
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ConcurrentDictionary<string, string> dict =
new ConcurrentDictionary<string, string>();
dict["key1"] = "value1";
dict["key2"] = "value2";
//
tWeb.WriteLine(dict.TryUpdate("key1","valueA","value1"));
tWeb.WriteLine(dict.TryUpdate("key2","valueB","value"));
tWeb.WriteLine(dict.TryUpdate("key3", "valueC", "value"));
}
}
|
执行代码会显示True、False、False。第一个输出,元素“key1/value1”存在,会将其值修改为valueA,方法返回true。第二个输出,键key2存在,但对应的值不是value,更新失败,方法返回false。第三个输出,键key3不存在,方法同样返回false。
tPair和tPairList类
在.NET Framework类库中,System.Collections、System.Collections.Generic和System.Collections.Concurrent等命名空间中包含了大量的集合处理类型,如数组、列表、栈(Stack)、队列(Queue)等;应用开发中,我们还可以根据需要创建自己的集合类型,这也是本节将要完成的工作。
tPair类
首先是tPair类,其功能比较简单,它表示一个“键/值”对象,并定义了常用类型的转换方法,如下面的代码(/app_code/data/base/tPair.cs)。
C# |
using System;
public class tPair
{
public string Name { get; set; }
public object Value { get; set; }
//
public static tPair Get(string sName="",object oValue = null)
{
return new tPair() { Name = sName, Value = oValue };
}
//
public int GetInt() { return tInt.Parse(Value); }
public long GetLng() { return tLng.Parse(Value); }
public float GetSng() { return tSng.Parse(Value); }
public double GetDbl() { return tDbl.Parse(Value); }
public decimal GetDec() { return tDec.Parse(Value); }
public string GetStr() { return tStr.Parse(Value); }
public bool GetBool() { return tBool.Parse(Value); }
public DateTime GetDate() { return tDate.Parse(Value); }
}
|
tPair类中定义了Name和Value属性,分别表示数据名称和数据的值中;构造函数中,数据名称的默认值为空字符串,数据值的默认值为null;此外,在一系列类型转换方法中,调用了封装的对应类型的Parse()方法,将Value属性直接转换为对应的类型,转换失败时会返回相应类型的默认值。
tPairList类
tPairList类用于处理tPair对象组成的集合,实现为List<tPair>的子类,基本定义如下(/app_code/data/base/tPairList.cs)。
C# |
using System;
using System.Collections.Generic;
public class tPairList : List<tPair>
{
public tPairList()
{
}
//
public static tPairList Get(params tPair[] e)
{
tPairList pl = new tPairList();
pl.AddRange(e);
return pl;
}
// 其它代码…
}
|
代码中除了无参数的构造函数,还定义了Get()静态方法,可以通过若干个tPair对象创建tPairList对象。
tPairList类继承于List<tPair>类,除了继承List泛型类的操作成员,还可以根据需要进行扩展,如下面的Add()方法。
C# |
//
public void Add(string sName,object oValue)
{
Add(tPair.Get(sName,oValue));
}
//
public void Add(params tPair[] p)
{
AddRange(p);
}
|
第一个Add()方法,使用数据名称和数据值添加一个列表元素;第二个Add()方法,可以将若干个tPair对象添加为列表对象。
此外,在tPairList类中还定义了如下操作方法。
C# |
public int Find(string sName)
{
for(int i = 0; i < Count; i++)
{
if (this[i].Name == sName)
return i;
}
return -1;
}
//
public bool Exists(string sName)
{
for (int i = 0; i < Count; i++)
{
if (this[i].Name == sName)
return true;
}
return false;
}
//
public tPair GetPair(string sName)
{
for (int i = 0; i < Count; i++)
{
if (this[i].Name == sName)
return this[i];
}
return tPair.Get();
}
|
代码中,Find()方法通过数据名查询列表元素,找到后返回索引值,没有找到时返回-1。Exists()方法判断指定数据名的元素是否存在,存在时返回true,否则返回false。GetPair()方法则通过数据名返回列表元素,没有找到时返回空的tPair对象,而不是null。
tPairList和tPair类的应用特点是,tPair对象表示的数据包含了数据名称和数据的值,并可以方便地转换为各种常用的数据类型;而对于tPairList列表,可以按照数值索引读取元素,方便操作tPair对象的有序集合。