添加到词典的不同方式

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

我注意到,当插入一个重复的键时,最后一个版本不会引发ArgumentException ,但有没有理由更喜欢第一个版本?

编辑 :有没有人有关于此的权威信息来源? 我试过MSDN,但它是一如既往的一个疯狂的追逐:(

性能几乎是100%相同的。 您可以通过在Reflector.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); } } 

这是添加方法:

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

我不会发布整个插入方法,因为它相当长,但方法声明是这样的:

 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,则抛出exception。

所以对于所有目的和意图,性能是相同的。

像其他一些提到的一样,这是关于你是否需要检查,试图添加相同的密钥两次。

对不起,冗长的post,我希望没关系。

第一个版本会向字典中添加一个新的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 

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

  • 使用Add方法添加新的键/值对,现有键不会被replace(引发ArgumentException )。
  • 如果您不关心字典中是否已经存在该键,则使用索引器,换句话说:如果键不在字典中,则添加键/值对,或者如果键已经存在,则replace指定键的值在字典里。

要首先回答这个问题,我们需要看一下字典和底层技术的目的。

DictionaryKeyValuePair<Tkey, Tvalue>的列表,其中每个值由其唯一键表示。 比方说,我们有一个你最喜欢的食物清单。 每个值(食物名称)都由其独特的键(一个位置=你喜欢这个食物多less)来表示。

示例代码:

 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"; 

但是不要忘记你是程序员,从现在开始,你完成了你的句子; 你拒绝使用表情符号,因为他们会抛出编译错误,所有的collections夹列表是基于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"); 

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

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

现在我们要看看引擎盖下。 编译字典时,编译器会为该存储区预留空间(存储空间以存储您的logging)。 存储桶不按照您定义的方式存储密钥。 每个密钥在去存储桶(由微软定义)之前都被散列,值得一提的是值部分保持不变。

我将使用CRC32哈希algorithm来简化我的例子。 当你定义:

 myDietFavorites[0] = "Pizza"; 

什么是桶db2dc565 “比萨”(简化)。

当你用下面的方法改变值时:

 myDietFavorites[0] = "Spaghetti"; 

你再次散列你的0,这又是db2dc565,然后你在这个桶里查找这个值,看看它是否在那里。 如果在那里你只是重写分配给该键的值。 如果它不在那里,你会把你的价值放在桶里。

当你在你的字典中调用Add函数就像:

 myDietFavorite.Add(0, "Chocolate"); 

你哈希你的0来比较它的值与桶中的值。 只有在不存在的情况下,才可以将其放置在存储桶中。

了解它是如何工作的,尤其是如果您使用string或字符types的键的字典是至关重要的。 由于正在进行哈希,因此区分大小写。 例如“name”!=“Name”。 我们用我们的CRC32来描述这个。

“name”的值是: e04112b1 “Name”的值是: 1107fb5b

是的,这是不同的,如果密钥已经存在,则Add方法会引发exception。

使用Add方法的原因正是这个。 如果字典不应该包含密钥,您通常需要例外,以便您意识到问题。

鉴于性能上可能的相似之处,可以使用任何更正确和可读的代码。

我觉得一个操作,描述了一个额外的,作为密钥的存在已经是一个非常罕见的例外最好用代表。 在语义上它更有意义。

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

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