添加到 Dictionary 的不同方法

Dictionary.add(key, value)Dictionary[key] = value有什么区别?

我已经注意到最后一个版本在插入重复的键时没有抛出 ArgumentException,但是有什么理由更喜欢第一个版本吗?

编辑 : 是否有人拥有关于这方面的权威信息来源?我试过 MSDN,但总是徒劳无功: (

211004 次浏览

考虑到性能方面的大多数相似之处,请使用任何对您正在使用的代码片段感觉更正确和更易读的代码。

我觉得一个操作,描述了一个加法,作为关键的存在已经是一个真正罕见的例外是最好的表示与添加。从语义上讲更合理。

dict[key] = value代表更好的替换。如果我看到这段代码,我希望这个键已经在字典中了。

第一个版本将向字典中添加一个新的 KeyValuePair,如果 key 已经在字典中,则抛出。第二种方法是使用索引器,如果键不存在,则添加一个新对,但如果键已经存在于字典中,则覆盖该键的值。

IDictionary<string, string> strings = new Dictionary<string, string>();


strings["foo"] = "bar";          //strings["foo"] == "bar"
strings["foo"] = string.Empty;   //strings["foo"] == string.empty
strings.Add("foo", "bar");       //throws

是的,这就是区别所在,如果键已经存在,Add 方法将引发异常。

使用 Add 方法的原因正是如此。如果字典不应该已经包含键,那么通常需要异常,以便让您意识到问题。

Dictionary.Add(key, value)Dictionary[key] = value有不同的用途:

  • 使用 Add方法对 新的键/值对,现有的键将不会被替换(抛出一个 ArgumentException)。
  • 如果你不关心这个键是否已经存在于字典中,那么使用索引器,换句话说: 如果这个键不在字典中,那么添加键/值对; 如果这个键已经在字典中,那么替换指定键的值。

性能几乎是100% 相同的。您可以通过在 Refector.net 中打开类来检查这一点

这是这个索引器:

public TValue this[TKey key]
{
get
{
int index = this.FindEntry(key);
if (index >= 0)
{
return this.entries[index].value;
}
ThrowHelper.ThrowKeyNotFoundException();
return default(TValue);
}
set
{
this.Insert(key, value, false);
}
}

这就是 Add 方法:

public void Add(TKey key, TValue value)
{
this.Insert(key, value, true);
}

我不会发布整个 Insert 方法,因为它太长了,但是方法声明是这样的:

private void Insert(TKey key, TValue value, bool add)

在函数的下面,会发生这样的情况:

if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key))
{
if (add)
{
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
}

它检查键是否已经存在,如果存在且参数 add 为 true,则引发异常。

因此,无论出于何种目的和意图,性能都是相同的。

像其他一些提到的一样,这完全是关于您是否需要检查,是否需要尝试将同一个键添加两次。

抱歉这么长的文章,希望你不介意。

一个是分配一个值,而另一个是添加到字典一个新的关键字和值。

为了首先回答这个问题,我们需要了解一下字典的用途和底层技术。

DictionaryKeyValuePair<Tkey, Tvalue>的列表,其中每个值由其唯一的键表示。假设我们有一张你最喜欢的食物清单。每个值(食物名称)都由其唯一的键(一个位置 = 你有多喜欢这种食物)表示。

示例代码:

Dictionary<int, string> myDietFavorites = new Dictionary<int, string>()
{
{ 1, "Burger"},
{ 2, "Fries"},
{ 3, "Donuts"}
};

假设你想保持健康,你改变了主意,你想用沙拉代替你最喜欢的“汉堡”。你的列表仍然是你最喜欢的列表,你不会改变列表的性质。你的最爱仍然是名单上的第一名,只是它的价值会改变。这就是你所谓的:

/*your key stays 1, you only replace the value assigned to this key
you alter existing record in your dictionary*/
myDietFavorites[1] = "Salad";

但是不要忘记你是程序员,从现在开始,你要用表情符号结束你的句子; 你拒绝使用表情符号,因为它们会抛出编译错误,并且所有的收藏夹列表都是基于0索引的。

你的饮食也改变了! 所以你再次改变了你的清单:

/*you don't want to replace Salad, you want to add this new fancy 0
position to your list. It wasn't there before so you can either define it*/
myDietFavorites[0] = "Pizza";


/*or Add it*/
myDietFavorites.Add(0, "Pizza");

定义有两种可能性,你要么想给以前不存在的东西定义一个新的定义,要么想改变已经存在的定义。

Add 方法允许您添加记录,但只有在一个条件下: 此定义的键可能不存在于字典中。

现在我们来看看引擎盖下面。编写字典时,编译器为 bucket (存储记录的内存空间)预订。Bucket 不按照您定义的方式存储密钥。每个键在进入 bucket (由 Microsoft 定义)之前都进行了散列,值得一提的是值部分保持不变。

我将使用 CRC32散列算法来简化我的示例:

myDietFavorites[0] = "Pizza";

什么是去桶是 Db2dc565“披萨”(简化)。

当您用以下方法更改值时:

myDietFavorites[0] = "Spaghetti";

你散列你的0,也就是 Db2dc565然后你在你的桶里查找这个值,看看它是否存在。如果它在那里,您只需重写分配给键的值。如果它不在那里,你会把你的价值放在桶。

在字典上调用 Add 函数时,如下所示:

myDietFavorite.Add(0, "Chocolate");

您对0进行散列以将其值与桶中的值进行比较。你可以把它放在桶 除非它不在那里

了解它是如何工作的是至关重要的,特别是当您使用字符串或字符类型的键的字典时。因为经历了散列,所以它是区分大小写的。比如“名字”!= “姓名”。让我们用我们的 CRC32来描述这个。

“ name”的值为: < strong > e04112b1 “ Name”的值是: < strong > 1107fb5b

将 Value 插入到 Dictionary 中

 Dictionary<string, string> dDS1 = new Dictionary<string, string>();//Declaration
dDS1.Add("VEqpt", "aaaa");//adding key and value into the dictionary
string Count = dDS1["VEqpt"];//assigning the value of dictionary key to Count variable
dDS1["VEqpt"] = Count + "bbbb";//assigning the value to key