【问题标题】:System.Collections.Generic.Dictionary `Add` vs set `Item`System.Collections.Generic.Dictionary `Add` vs set `Item`
【发布时间】:2011-08-29 08:45:41
【问题描述】:

如果我想将项目放入System.Collections.Generic.Dictionary,我可以Add 或设置Item

我知道如果我们执行Add,它会检查密钥是否已经存在,如果不存在则抛出异常。

所以当添加大量项目时,我应该更喜欢设置Item 而不是Add,因为Add 会进行不必要的检查,实际上可能会减慢速度?

【问题讨论】:

    标签: c# .net vb.net generics dictionary


    【解决方案1】:

    设置 Item 时会发生以下情况:

    public void set_Item(TKey key, TValue value)
    {
        this.Insert(key, value, false);
    }
    

    添加项目时会发生以下情况:

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

    最后一个参数last bool add参数只影响这一行:

    if (add)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
    }
    

    因此,如果您希望在添加重复项时出现异常,则需要使用 Add。如果你想覆盖现有的项目,你需要设置项目。

    【讨论】:

    • set_Item 真的是公开的吗?我在智能感知中找不到它。有什么想法吗?
    • nawfal - set_Item 是 CLR 在执行 myArray[1] = x 之类的赋值时调用的方法。换句话说,当您将索引属性public string this[int index] 添加到您的类时,编译器会在后台添加一个方法get_Item 用于索引属性获取器和一个方法set_Item 方法索引属性设置器。它们是否公开取决于您如何准确定义索引属性。每个常规属性下面也有一个或两个方法(getter 和 setter)。
    【解决方案2】:

    这完全取决于您是要处理重复键还是覆盖任何可能存在的项目。要检查重复项,您可以使用:

    例如:

    var dict = new Dictionary<int, string>();
    
    Console.WriteLine(dict.ContainsKey(1)); // false
    dict[1] = "hi";
    dict[1] = "hello"; // "hi" is overwritten
    
    // true: hello
    Console.WriteLine("{0}: {1}", dict.ContainsKey(1), dict[1]);
    
    // TryGetValue if checking by key and interested in the value
    string result;
    if (dict.TryGetValue(1, out result))
    {
        Console.WriteLine("Key 1 exists: " + result);
    }
    else
    {
        Console.WriteLine("Key 1 not found");
    }
    

    【讨论】:

    • Contains 是否更适合检查重复项?
    • @Alex ContainsKeyContainsValueDictionary 类提供的方法将是一个不错的选择。你是说那些还是Enumerable.Contains?如果是后者,则需要先转换 Keys 集合,例如 dict.Keys.Cast&lt;int&gt;().Contains(1),鉴于提供的可用方法,这是不值得的。
    • @Alex 没有问题。是的,如果我们只关心检查现有密钥,ContainsKey 会比TryGetValue 更好。 TryGetValue 在我最初的示例代码中首先浮现在脑海中。
    【解决方案3】:

    抛出异常很便宜,处理它们很昂贵。 try/catch 块的 try 部分正常运行。执行 catch 块时,它必须展开堆栈以填充堆栈跟踪(除其他外)。这就是让异常变得昂贵的原因。如果您有办法通过使用Dictionary&lt;T&gt;.ContainsKey 等方法来避免捕获异常,这就是避免捕获异常的原因@

    您不太可能注意到调用 Add 和设置 Item 之间的性能差异。因此,请使用最适合这种情况的一种。

    更新: 不要优化你的代码,除非它很慢。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-12
      • 2014-06-05
      • 1970-01-01
      • 2022-12-02
      • 1970-01-01
      • 2022-12-04
      • 2013-07-17
      • 2011-12-04
      相关资源
      最近更新 更多