C#学习笔记(二十九)-- List<T>与Dictionary<K, V>

    System.Collections.Generic名称空间包含用于处理集合的泛型类型,常与using语句一起使用。

1  List<T>

    List<T>泛型集合类型更快捷、更便于使用:不必再从CollectionBase中派生一个类,然后实现需要的方法。它的另一个好处是正常情况下需要实现的许多方法(例如,Add())已经自动实现了。

    创建T类型对象的集合需要如下代码:

List<T> myCollection = new List<T>;

    这样就足够了。未必要定义类、实现方法或执行其他操作。还可以把List<T>对象传递给构造函数,在集合中设置项的起始列表。List<T>还有一个Item属性,允许进行类似数组的访问,如下所示:

T itemIndex2 = myCollectionOfT[2];

2  对泛型列表进行排序和搜索

    对泛型列表进行排序与对其他列表进行排序是一样的。之前介绍了如何使用IComparer和IComparable接口比较两个对象,然后对该类型的对象列表排序。这里唯一的区别在于,可以使用泛型接口IComparer<T>和IComparable<T>,它们提供了略有区别的、针对特定类型的方法。下表列出了它们之间的区别:

泛型方法非泛型方法区别
int IComparable<T>.CompareTo(T otherObj)int IComparable.CompareTo(object otherObj)在泛型版本中是强类型化的
bool IComparable<T>.Equals(T otherObj)N/A在非泛型接口中不存在,可以改用继承的object.Equals()
int IComparer<T>.Compare(T objectA, T objectB)int IComparer.Compare(object objectA, object objectB)在泛型版本中是强类型化的
bool IComparer<T>.Equals(T objectA, T objectB)N/A在非泛型接口中不存在,可以改用继承的object.Equals()
int IComparer<T>.GetHashCode(T objectA)N/A在非泛型接口中不存在,可以改用继承的object.GetHashCode()

    要对List<T>排序,可以在要排序的类型上提供IComparable<T>接口,或者提供IComparer<T>接口。另外,还可以提供泛型委托,作为排序方法。这些排序方法较非泛型更加简单。

    一般情况下,给列表排序需要有一个方法来比较两个T类型的对象。要在列表中搜索,只需要一个方法来检查T类型的对象,看它是否满足某个条件。定义这样的方法很简单,这里给出两个可以使用的泛型委托类型:

    1)Comparison<T>:这个委托类型用于排序方法,其返回类型和参数如下:

int method(T objectA, T objectB)

    2)Predicate<T>:这个委托类型用于搜索方法,其返回类型和参数如下:

bool method(T targetObject)

3  Dictionary<K, V>

    Dictionary<K, V>类型可定义键/值对的集合。与前面介绍的其他泛型集合类型不同,这个类需要实例化两个类型,分别用于键和值,以表示集合中的各个项。

    实例化Dictionary<K, V>对象后,就可以像在继承自DictionaryBase的类上那样,对他执行相同的操作,但是要使用已有的类型安全的方法和属性。例如,使用强类型化的Add()方法添加键/值对。

Dictionary<string, int>things = new Dictionary<string, int>()
things.Add("Green Things", 29);
things.Add("Red Things", 34);

    不使用Add()方法也可以添加键/值对,但代码看起来并不优雅:

Dictionary<string, int>things = new Dictionary<string, int>()
{
  things.Add("Green Things", 29),
  things.Add("Red Things", 34)
};

    可使用Keys和Values属性迭代集合中的键和值:

foreach(string key in things.Keys)
{
  WriteLine(key);
}
foreach(int value in things.Values)
{
  WriteLine(value);
}

    还可以迭代集合中的各个项,把每个项作为一个KeyValuePair<K, V>实例来获取,这与第11章介绍DictionaryEntry对象十分相似:

foreach (KeyValuePair<string, int> thing in things)
{
   WriteLine($"{thing.Key} = {thing.Value}");
}

    对于Dictionary<K, V>要注意的一点是,每个项的键都必须是唯一的。如果要添加的项的键与已有项的键相同,就会抛出ArgumentException异常。所以,Dictionary<K, V>允许把IComparer<K>接口传递给其构造函数。如果要把自己的类用作键,且它们不支持IComparable或IComparable<K>接口,或者要使用非默认的过程比较对象,就必须把IComparer<K>接口传递给其构造函数。例如,在上例中,可以使用不区分大小写的方法来比较字符串键:

Dictionary<string, int>things = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);

    若不使用Add()方法或更优雅的方法来填充Dictionary<K, V>类型,则可以考虑使用索引初始化器,它支持在对象初始化器内部初始化索引:

var things = new Dictionary<string, int>()
{
  ["Green Things"] = 29,
  ["Blue Things"] = 34
};

    索引初始化器的使用很方便,因为在许多情况下都不需要通过var things显式临时变量。使用表达式方法,上例会级联简化的作用并使Dictionary<K,V>类型的初始化最终变得优雅:

public Dictionary<string, int>SomeThings() => new Dictionary<string, int>{["Green Things"] = 29, ["Blue Things"] = 94};

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值