【问题标题】:Best Practice - Removing item from generic collection in C#最佳实践 - 从 C# 中的通用集合中删除项目
【发布时间】:2010-10-13 06:45:37
【问题描述】:

我在带有 .NET 3.5 的 Visual Studio 2008 中使用 C#。

我有一个通用字典,可以将事件类型映射到通用订阅者列表。一个订阅者可以订阅多个事件。

private static Dictionary<EventType, List<ISubscriber>> _subscriptions;

要从订阅列表中删除订阅者,我可以使用这两个选项之一。

选项 1:

ISubscriber subscriber;  // defined elsewhere
foreach (EventType event in _subscriptions.Keys) {
    if (_subscriptions[event].Contains(subscriber)) {
        _subscriptions[event].Remove(subscriber);
    }
}

选项 2:

ISubscriber subscriber;  // defined elsewhere
foreach (EventType event in _subscriptions.Keys) {
    _subscriptions[event].Remove(subscriber);
}

我有两个问题。

首先,请注意选项 1 在删除项目之前检查是否存在,而选项 2 使用暴力删除,因为 Remove() 不会引发异常。在这两种方法中,哪一种是首选的“最佳实践”方法?

其次,是否有另一种“更简洁”的更优雅的方式来执行此操作,可能使用 lambda 表达式或使用 LINQ 扩展?我还在适应这两个功能。

谢谢。

编辑

澄清一下,我意识到选项 1 和 2 之间的选择是速度(选项 2)与可维护性(选项 1)的选择。在这种特殊情况下,我不一定要尝试优化代码,尽管这当然是值得考虑的。我想了解的是,是否有一个普遍成熟的做法来做到这一点。如果不是,您会在自己的代码中使用哪个选项?

【问题讨论】:

    标签: c# generics .net-3.5


    【解决方案1】:

    选项 1 会比选项 2 慢。Lambda 表达式和 LINQ 会更慢。我会使用HashSet&lt;&gt; 而不是List&lt;&gt;

    如果您需要确认删除项目,则必须使用Contains

    编辑: 由于在lock 语句中使用您的代码的可能性很高,最佳做法是减少lock 中的执行时间,因此应用选项 2 可能很有用。看起来没有最佳做法可以使用或不要将ContainsRemove 一起使用。

    【讨论】:

    • 已经有一个字典:用 HashSet 替换 List(值)有什么好处?
    • @LicenseQ:你是对的。我认为选项 1 和 2 之间的选择是速度与可维护性的选择。我正在寻找普遍接受的方法,如果它存在的话。您能否详细说明为什么要使用 HashSet 而不是 List?
    • 字典>
    • HashSet 将加快包含和删除操作——速度将等于字典的速度。参见msdn.microsoft.com/en-us/library/bb359438.aspx
    • @LicenseQ:是的,刚刚看到。 List 的 Remove() 为 O(n),而 HashSet 的 Remove() 为 O(1)。谢谢!
    【解决方案2】:

    Remove() 方法 'approches O(1)' 并且当键不存在时是可以的。

    但除此之外:如有疑问,请测量。获得一些时间并不难......

    【讨论】:

      【解决方案3】:

      既然您只关心值,为什么还要枚举键?

      foreach (List<ISubscriber> list in _subscriptions.Values)
      {
          list.Remove(subscriber);
      }
      

      也就是说,Eric P 建议的 LINQ 解决方案肯定更简洁。不过,性能可能是个问题。

      【讨论】:

      • 好点。令人惊讶的是,有时您无法只见树木不见森林。谢谢。
      【解决方案4】:

      我会选择第二个选项。 Contains() 和 Remove() 都是 O(n) 方法,没有理由同时调用这两个方法,因为 Remove 不会抛出。至少对于方法 2,您只调用了一个昂贵的操作而不是两个。

      我不知道有什么更快的处理方法。

      【讨论】:

        【解决方案5】:

        如果您想使用 Linq 来执行此操作,我认为这可行(未经测试):

        _subscriptions.Values.All(x => x.Remove(subscriber));
        

        可能想检查一下它的性能。

        【讨论】:

          猜你喜欢
          • 2018-10-18
          • 1970-01-01
          • 2010-09-17
          • 2016-11-12
          • 2010-10-19
          • 2016-09-03
          • 1970-01-01
          • 1970-01-01
          • 2010-09-06
          相关资源
          最近更新 更多