c# 扩展方法奇思妙用基础篇五:Dictionary<TKey, TValue> 扩展
Dictionary<TKey, TValue>类是常用的一个基础类,但用起来有时确不是很方便。本文逐一讨论,并使用扩展方法解决。
向字典中添加键和值
添加键和值使用 Add 方法,但很多时候,我们是不敢轻易添加的,因为 Dictionary<TKey, TValue>不允许重复,尝试添加重复的键时 Add 方法引发 ArgumentException。
大多时候,我们都会写成以下的样子:
var dict = new Dictionary<int, string>();
// ...
// 情形一:不存在才添加
if (dict.ContainsKey(2) == false) dict.Add(2, "Banana");
// 情形二:不存在添加,存在则替换
if (dict.ContainsKey(3) == false) dict.Add(3, "Orange");
else dict[3] = "Orange";
其实,第二种情形可以写如下书写(请参见 http://msdn.microsoft.com/zh-cn/library/9tee9ht2.aspx):
dict[3] = "Orange";
不过好多朋友都会对这种方式表示疑虑,不太确定这样会不会出问题。
不管是上面的哪种写法,用字典时最大的感觉就是担心,怕出异常,因此代码会写的很罗嗦。
我每次用字典时都这样,时间长了,实在是厌烦了,索性扩展一下,用以下两个方法来应对上面两种情形:
/// <summary>
/// 尝试将键和值添加到字典中:如果不存在,才添加;存在,不添加也不抛导常
/// </summary>
public static Dictionary<TKey, TValue> TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
{
if (dict.ContainsKey(key) == false) dict.Add(key, value);
return dict;
}
/// <summary>
/// 将键和值添加或替换到字典中:如果不存在,则添加;存在,则替换
/// </summary>
public static Dictionary<TKey, TValue> AddOrReplace<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
{
dict[key] = value;
return dict;
}
TryAdd 和 AddOrReplace 这两个方法具有较强自我描述能力,用起来很省心,而且也简单:
dict.TryAdd(2, "Banana");
dict.AddOrReplace(3, "Orange");
或者像 Linq 或 jQuery 一样连起来写:
dict.TryAdd(1, "A")
.TryAdd(2, "B")
.AddOrReplace(3, "C")
.AddOrReplace(4, "D")
.TryAdd(5, "E");
再来看另外一个问题:
获取值
从字典中获取值通常使用如下方式:
string v = "defaultValue";
// 方式一
if (dict.ContainsKey(3)) v = dict[3];
// 方式二
bool isSuccess = dict.TryGetValue(3, out v);
使用索引的方式获取前一定先判断,否则不存在时会引发 KeyNotFoundException 异常。
我尤其讨厌第二种方式,因为采用 out 要提前声明一个变量,代码至少要两行,不够简洁。
看下 GetValue 扩展:
/// <summary>
/// 获取与指定的键相关联的值,如果没有则返回输入的默认值
/// </summary>
public static TValue GetValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue defaultValue = default(TValue))
{
return dict.ContainsKey(key) ? dict[key] : defaultValue;
}
使用方便:
var v1 = dict.GetValue(2); //不存在则返回 null
var v2 = dict.GetValue(2, "abc"); //不存在返回 ”abc“
一行代码能搞定。
批量添加
List<T> 类有个 AddRange 方法,可以不用 foreach 循环直接向当前集合加入另外一个集合:
List<string> roles = new List<string>();
roles.AddRange(new[] { "role2", "role2" });
roles.AddRange(user.GetRoles());
相当方便,可怜 Dictionary<TKey, TValue>类没有,幸好有扩展方法:
/// <summary>
/// 向字典中批量添加键值对
/// </summary>
/// <param name="replaceExisted">如果已存在,是否替换</param>
public static Dictionary<TKey, TValue> AddRange<TKey, TValue>(this Dictionary<TKey, TValue> dict, IEnumerable<KeyValuePair<TKey, TValue>> values, bool replaceExisted)
{
foreach (var item in values)
{
if (dict.ContainsKey(item.Key) == false || replaceExisted)
dict[item.Key] = item.Value;
}
return dict;
}
使用示例:
var dict1 = new Dictionary<int, int>()
.AddOrReplace(2, 2)
.AddOrReplace(3, 3);
var dict2 = new Dictionary<int, int>()
.AddOrReplace(1, 1)
.AddOrReplace(2, 1)
.AddRange(dict1, false);
线程安全:
为了演示简单,本文中的代码没有考虑线程安全的问题,不宜在实际项目中直接使用!
线程安全请使用 ConcurrentDictionary<TKey, TValue> 类(.Net 4新增),参考以下文章:
http://www.cnblogs.com/ldp615/archive/2011/01/28/dictionary-extensions.html
c# 扩展方法奇思妙用基础篇五:Dictionary<TKey, TValue> 扩展的更多相关文章
- c# 扩展方法奇思妙用基础篇八:Distinct 扩展(转载)
转载地址:http://www.cnblogs.com/ldp615/archive/2011/08/01/distinct-entension.html 刚看了篇文章 <Linq的Distin ...
- c# 扩展方法奇思妙用基础篇八:Distinct 扩展
刚看了篇文章 <Linq的Distinct太不给力了>,文中给出了一个解决办法,略显复杂. 试想如果能写成下面的样子,是不是更简单优雅 var p1 = products.Distinct ...
- c# 扩展方法奇思妙用基础篇九:Expression 扩展
http://www.cnblogs.com/ldp615/archive/2011/09/15/expression-extension-methods.html .net 中创建 Expressi ...
- C# 扩展方法奇思妙用高级篇六:WinForm 控件选择器
在Web开发中,jQuery提供了功能异常强大的$选择器来帮助我们获取页面上的对象.但在WinForm中,.Net似乎没有这样一个使用起来比较方便的选择器.好在我们有扩展方法,可以很方便的打造一个. ...
- c# 扩展方法 奇思妙用 高级篇 九:OrderBy(string propertyName, bool desc)
下面是 Queryable 类 中最常用的两个排序的扩展方法: 1 2 public static IOrderedQueryable<TSource> OrderBy<TSourc ...
- c# 扩展方法奇思妙用
# 扩展方法出来已久,介绍扩展方法的文章也很多,但都是笼统的.本人最近一直在思考扩展方法的应用,也悟出了一些,准备将这最近一段时间对扩展方法的思考,写成一个系列文章.每个文章只介绍一个应用方面,篇幅不 ...
- c# 扩展方法奇思妙用集锦
本文转载:http://www.cnblogs.com/ldp615/archive/2009/08/07/1541404.html 其中本人觉得很经典的:c# 扩展方法奇思妙用基础篇五:Dictio ...
- docker+k8s基础篇五
Docker+K8s基础篇(五) service资源介绍 A:service资源的工作特性 service的使用 A:service字段介绍 B:ClusterIP的简单使用 C:NodePort的简 ...
- C#基础篇五值类型和引用类型
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace P01M ...
随机推荐
- Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2) 一夜回到小学生
我从来没想过自己可以被支配的这么惨,大神讲这个场不容易掉分的啊 A. Carrot Cakes time limit per test 1 second memory limit per test 2 ...
- RHEL7网卡命名规则
systemd 和 udev 引入了一种新的网络设备命名方式:一致网络设备命名(CONSISTENT NETWORK DEVICE NAMING).根据固件.拓扑.位置信息来设置固定名字,带来的好处是 ...
- Luogu【P1130】红牌(DP)
欧拉 本蒟蒻第一个自己想出来的DP题 请移步题目链接 调了半天.i从1到n,j从1到m. f[i][j]表示的是第i道工序在第j个小组办完所花的最短时间. 因为要用到上一个状态,而上一个状态要么是同一 ...
- Java统计程序运行时间
代码如下: 第一种是以毫秒为单位计算的. long startTime = System.currentTimeMillis(); //获取开始时间 doSomething(); //测试 ...
- linux虚拟机无法上网 Network is unreachable
系统centos 安装ftp时报错 Couldn't resolve host 'mirrorlist.centos.org [root@wulihua bin]# yum install vsft ...
- 使用Jackson在Java中处理JSON
在工作中实际使用到Java处理JSON的情况,且有很大部分都使用的是开源工具Jackson实现的. 一.入门 Jackson中有个ObjectMapper类很是实用,用于Java对象与JSON的互换. ...
- 【HDOJ5952】Counting Cliques(团,dfs)
题意:给定一张n点m边的图,求大小为S的团的个数 N ≤ 100,M ≤ 1000,2 ≤ S ≤ 10,保证点的度不超过20 思路:dfs 因为每个点可能不止属于一个极大团,所以不能求出极大团然后计 ...
- 扰动法--*BZOJ3157: 国王奇遇记
求$\sum_{i=1}^ni^mm^i$.$n \leq 1e9,m \leq 200$. 其实我也不知道这东西为啥叫“扰动法”,大概是在黑暗的边缘试探?就是那种,人家再多一点就被您看破了,然后您就 ...
- MVC 上传文件的方法
这两天又开始研究MVC了,期间断断续续已经搞了好久了,可是都没坚持下来.囧!这次一定坚持搞出来一个名堂. 废话少说,直接上代码. 前台引擎采用Razor @model System.Web.HttpP ...
- 标准C程序设计七---15
Linux应用 编程深入 语言编程 标准C程序设计七---经典C11程序设计 以下内容为阅读: <标准C程序设计>(第7版) 作者 ...