【问题标题】:Why have HashSet but not Set in C#?为什么在 C# 中有 HashSet 而没有 Set?
【发布时间】:2009-06-21 11:21:18
【问题描述】:

老问题

我的理解是 C# 在某种意义上具有 HashSetset 类型。我明白HashSet 是什么。但是为什么set 是一个单独的词呢?为什么不是每个集合都是HashSet<Object>

新问题

为什么C#没有泛型Set类型,类似于Dictionary类型?从我的角度来看,我想要一个具有标准查找/添加/删除性能的集合。我不太关心它是用哈希还是其他东西实现的。那么为什么不创建一个在这个版本的 C# 中实际实现为 HashSet 但在未来版本中可能会有所不同的集合类呢?

或者为什么不至少接口ISet

回答

感谢以下回答的所有人:ICollection 实现了很多您对ISet 的期望。不过,从我的角度来看,ICollection 实现了IEnumerable,而集合不必是可枚举的——例如:1 到 2 之间的实数集合(甚至可以动态生成集合)。我同意这是一个小小的抱怨,因为“普通程序员”很少需要不可数的集合。

好的,我想我明白了。 HashSet 绝对应该被称为Set,但Set 这个词在某种意义上是保留的。更具体地说,.NET 架构的创建者希望为不同的语言提供一致的类集(原文如此!)。这意味着标准类的每个名称都不能与 .NET 语言中的任何关键字重合。然而,Set 这个词在 VB.NET 中使用,它实际上是不区分大小写的(是吗?)所以不幸的是那里没有回旋余地。

谜团解开了:)

结语

Alex Y. 的新答案链接到 MSDN page,它描述了即将到来的 .NET 4.0 接口 ISet,它的行为与我认为的差不多,并由 HashedSet 实现.好结局。

【问题讨论】:

标签: c# set hashset


【解决方案1】:

(您关于set 的原始问题已得到解答。IIRC,“set”是英语中含义最不同的词......显然这对计算也有影响。)

我认为HashSet<T> 具有该名称很好,但我当然欢迎ISet<T> 接口。鉴于 HashSet<T> 仅出现在 .NET 3.5 中(这本身就令人惊讶),我怀疑我们最终可能会获得更完整的基于集合的类型的集合。特别是,在某些情况下,维护插入顺序的 Java 的 LinkedHashSet 等价物会很有用。

公平地说,ICollection<T> 接口实际上涵盖了您在ISet<T> 中想要的大部分内容,所以也许这不是必需的。但是,您可能会争辩说,集合的核心目的(主要是关于包含,并且只是与能够迭代元素无关)与集合并不完全相同。这很棘手。事实上,一个真正的数学集合可能是不可迭代或不可数的——例如,你可以拥有“1 到 2 之间的实数集合”。如果你有一个任意精度的数值类型,计数将是无限的,并且迭代它没有任何意义。

同样,将“添加”到集合中的想法并不总是有意义的。命名集合时,可变性是一件棘手的事情:(

编辑:好的,回复评论:关键字set 绝不是Visual Basic 的遗产。这是设置属性值的操作,而get 检索操作。这与将集合作为操作的想法无关。

想象一下,关键字实际上是 fetchassign,例如

// Not real code!
public int Foo
{
    fetch
    {
        return fooField;
    } 
    assign
    {
        fooField = value;
    } 
}

那里的目的明确吗?现在 real 在 C# 中的等价物只是

public int Foo
{
    get
    {
        return fooField;
    } 
    set
    {
        fooField = value;
    } 
}

所以如果你写:

x = y.Foo;

这将使用属性的get 部分。如果你写:

y.Foo = x;

这将使用set 部分。

这样更清楚吗?

【讨论】:

  • 其实我还是不明白set原来的东西。
  • 从链接的帖子中我得到的最接近的是,有一些来自 Visual Basic 的遗留 Set 字。
  • 对不起,我不清楚。我熟悉 set/get 关键字对,但我知道它们是小写的,而且我相信 C# 区分大小写,所以我认为这与 Set 类无关。但是 Set 是 VB.NET 的保留关键字解释了它(直到现在我才知道 C# 和 VB 是相关的,但现在我猜它们是相关的)
  • 我知道 ICollection,但我想我作为一名数学家,从一开始集合和集合就大不相同了。现在,当我想到它时,我同意 ICollection 类似于人们在编程中实际使用集合的方式。然而,以数学为例,集合有更多有趣的例子。例如,考虑集合 [0; 1] \联合[2; 3)\联合[7; +\infty]。这个集合很容易编程为有序集合,但永远不能编程为集合。
  • 更正:它永远不能被编程为一个列表,但我怀疑 ICollection 包含类似于 ToArray() 的方法。它可以被认为是一个无法迭代的集合,但与人们习惯的相比,我认为这是一个新的想法。
【解决方案2】:

唯一的原因似乎是缺乏在 .NET 3.5 中理想地实现这一点的资源。

.NET 4.0 将包括ISet,以及除了HashSet - SortedSet 之外的新实现。查看提供的 MSDN 库链接 - 它们已在 .NET 4.0 beta1 中可用。

【讨论】:

  • 您发现它的方式太棒了,谢谢!我希望我能接受两个答案。
【解决方案3】:

没有Set<T>。这个BCL team Blog post 有很多关于 HashSet 的详细信息,包括关于在名称中包含 hash 的不完全决定性的讨论。我怀疑不是 BCL 团队中的每个人都喜欢使用名称 HashSet<T> 的决定。

【讨论】:

  • 他们说这是因为 Set 是 get/set 对的上下文关键字——但这不是小写的集合吗?
  • 支持 - 一个指向 BCL 团队博客的链接可能是我的答案,但我刚刚看到了这个问题,你已经回答了。
  • 我个人喜欢将其称为Set<T>,而将实现细节(哈希)省略。
  • 嗯,有一个Set<T>class 是内部的。但它的工作方式类似于HashSet<T>
【解决方案4】:

set 是自 1.0 版以来一直存在的 C# 语言关键字。 is 用于定义属性的赋值部分(get 用于实现属性的值读取部分)。在这种情况下,您应该将“设置”一词理解为动词,就像设置值一样。

HashSet<T> 是集合的数学概念的特殊实现。它最初是在 .NET 3.5 中引入的。 BCL 团队的这篇博文详细解释了其背后的原因,以及为什么名称为HashSet<T> 而不仅仅是Set<T>http://blogs.msdn.com/bclteam/archive/2006/11/09/introducing-hashset-t-kim-hamilton.aspx

对于HashSet<T>,您应该将“set”这个词理解为名词。

【讨论】:

  • 我无法解决线索 :) 我能得到的最好结果是 Set 由于 VB 而被保留。
  • 因为我知道set是动词,但我认为C#是区分大小写的,为什么会和Set混在一起呢?
  • Set确实是VB.NET中的一个关键字。尽管 C# 区分大小写,但 CLS 不区分大小写,因此不区分大小写的语言(例如 VB.NET)存在区分关键字和类型的困难。即使编译器能够弄清楚,开发人员也可能会感到困惑。因此,框架设计指南建议避免将某些关键字作为类型名称。 HashSet<T> 被开发用于任何基于 .NET 的语言,而不仅仅是 C#。
【解决方案5】:

Set 是 VB.NET 中的保留关键字(相当于 C# 中的 set)。 VB.NET 可以使用与关键字同名的类/方法/等,但它们必须写在方括号之间,这很丑:

Imports Wintellect.PowerCollections 'PowerCollections contains a class called Set'
Public Class Test
    Private _myValue As Integer  

    Public Property MyValue() As Integer
        Get
            Return _myValue
        End Get
        Set ' Set as keyword'
            _myValue = value
        End Set
    End Property

    Public Function X As [Set](Of Integer)
        Dim a As New [Set](Of Integer) ' Set as class'
        Return a
    End Function

End Class

【讨论】:

  • 不,抱歉,我不明白。 C# 和 VB/.NET 有什么关系?
  • VB.NET 和 C# 是 .NET 的主要语言,它们在功能上几乎是相当的,它们编译成几乎相同的 IL 并且微软承诺将来会使它们更接近。 VB.NET 社区相当大,但你看不到很多关于 VB.NET 的问题,因为他们中的许多人都可以毫无问题地理解 C#。
【解决方案6】:

嗯,我现在明白你的问题了
不确定我能否 100% 看到ISet<T> 的需求。
我想问题是您认为哪个是集合的基本行为?
是添加、删除、包含等吗?如果是这样,那么ICollection<T> 已经为此提供了一个接口。
如果它是联合、相交等集合操作,那么您认为这些操作是否足够通用以抽象为合同样式执行?

我不得不说我不知道​​这个问题的正确答案 - 我认为这是有争议的,我怀疑 BCL 团队最终可能会在未来的版本中加入类似的东西,但这取决于他们。我个人不认为这是大量缺失的功能

原帖

BCL 根本没有 Set 集合,至少据我所知没有。
在 .NET 3.5 中引入了一些 3rd 方集合库,例如 Iesi.Collections
HashSet<T>,以创建快速集合集合,即您想要一个没有重复的集合。它还具有典型的集合操作,例如 Union 和 Join。 在 HashSet 上查看 BCL 团队的 this link

您通常会在以前必须使用 List<T> 并在添加时检查重复项的地方使用它。
将项目添加到 HashSet<T> 也可以是 significantly faster 而不是 List

更多细节:
HashSet 的另一个不错的功能是,如果您尝试添加重复项,它不会引发异常,它只是无法添加重复项,这使您不必在每个添加项周围放置大量 try.catch 块 - 很好:)

【讨论】:

  • 好的,但是为什么不使用具有所有这些属性的接口 ISet 和实现它的 HashSet 呢?这就是字典的工作原理。
【解决方案7】:

我很确定 BCL 中没有 Set<T> 类,至少在 .NET 3.5 中(看起来也不是 .NET 4.0)。无论如何,你会期望这样一个类的需求是什么?

HashSet<T> 本身只是一个普通的集合数据结构,它使用哈希码(对象的GetHashCode 方法)来比较元素。这只是实现集合类型的一种有效方式。 (其他检查相等性的方法可能会降低性能。)

【讨论】:

  • HashSet 使用 GetHashCode 来定位其存储桶内的元素。它仍然使用 Equals 比较元素,以防两个元素具有相同的 HashCode 并最终在同一个桶中。
  • @Noam:确实如此。我的意思是 GetHashCode 是主要的比较方法。 Equals 几乎被用作“备份”。
猜你喜欢
  • 2016-06-28
  • 2018-10-31
  • 1970-01-01
  • 2011-01-31
  • 2011-07-05
  • 1970-01-01
  • 2015-09-25
  • 2012-08-04
  • 1970-01-01
相关资源
最近更新 更多