HashSet允许重复项目插入 - C#

jpi*_*s14 38 .net c# hashset

这种看起来像是一个菜鸟问题,但我没有特别找到这个问题的答案.

我有这门课:

public class Quotes{ 
    public string symbol; 
    public string extension
}
Run Code Online (Sandbox Code Playgroud)

我正在使用这个:

HashSet<Quotes> values = new HashSet<Quotes>();
Run Code Online (Sandbox Code Playgroud)

但是我可以多次添加相同的Quotes对象.例如,我的Quotes对象可能具有等于'A'的'symbol'和'= n'的'extension',并且此Quotes对象在HashSet中出现多次(通过调试模式查看Hashset).打电话时我曾想过

values.Add(new Quotes(symb, ext));
Run Code Online (Sandbox Code Playgroud)

使用相同的symb和ext,将返回'false'并且不会添加元素.我感觉它与HashSet添加新对象时比较Quotes对象有关.任何帮助将不胜感激!

Ken*_*rey 50

我猜你正在Quotes用相同的值创建一个新的.在这种情况下,他们是不平等的.如果它们应被视为相等,则覆盖Equals和GetHashCode方法.

public class Quotes{ 
    public string symbol; 
    public string extension

    public override bool Equals(object obj)
    {
        Quotes q = obj as Quotes;
        return q != null && q.symbol == this.symbol && q.extension == this.Extension;
    }

    public override int GetHashCode()
    {
        return this.symbol.GetHashCode() ^ this.extension.GetHashCode();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果符号或扩展名可能为null,则GetHashCode必须处理该问题而不是崩溃. (18认同)
  • 请注意,对于除`string`s,`int`s或其他值类型或密封类以外的字段类型,您应该使用`q!= null && q.symbol.Equals(this.symbol)&& q.extension.Equals( `.extension)`而不是使用`==`,因为`==`不是多态的(即如果子类定义了`operator ==`,基类'`orperator ==`仍将被使用,而子类可以*覆盖*.Equals()`方法,因此将使用子类'.Equals()`.另外,`hash1 ^ hash2`是一个糟糕的哈希实现,因为`"a","b"`和`"b","a"`,具有相同的散列.喜欢`(hash1 + 7*13)^ hash2`之类的东西. (4认同)

Ree*_*sey 19

我曾经想过,当values.Add(new Quotes(symb, ext));使用相同的symb和ext 调用时,将返回'false'并且不会添加元素.

不是这种情况.

HashSet将使用GetHashCodeEquals确定对象的相等性.现在,由于您没有覆盖这些方法Quotes,因此System.Object将使用默认的引用相等性.每次添加新的Quote时,它都是唯一的对象实例,因此HashSet将其视为唯一对象.

如果重写Object.EqualsObject.GetHashCode,因为你希望它会工作.


Mat*_*ias 6

HashSets首先根据其计算的哈希值来比较条目GetHashCode.
默认实现返回基于对象本身的哈希码(每个实例之间不同).

只有当哈希值相同时(基于实例的哈希值非常不可能),才会调用Equals方法并用于明确比较两个对象.

你必须选择:

  • 将引号更改为结构
  • 在引号中覆盖GetHashCode和Equals

例:

 public override int GetHashCode()
 {
    return (this.symbol == null ? 0 : this.symbol.GetHashCode())
       ^ (this.extension == null ? 0 : this.extension.GetHashCode());
 }
 public override bool Equals(object obj)
 {
    if (Object.ReferenceEquals(this, obj))
      return true;

    Quotes other = obj as Quotes;
    if (Object.ReferenceEquals(other, null))
      return false;

    return String.Equals(obj.symbol, this.symbol)
        && String.Equals(obj.extension, this.extension);
 }
Run Code Online (Sandbox Code Playgroud)

  • 你还需要覆盖`Object.Equals` - 不保证哈希是唯一的,所以使用两种方法...... (2认同)

小智 6

只是想在 Kendall 的回答中解决一些问题(由于某些奇怪的原因无法发表评论)。

return this.symbol.GetHashCode() ^ this.extension.GetHashCode();
Run Code Online (Sandbox Code Playgroud)

请注意,xor 函数是一种非常容易发生冲突的组合两个散列的方法,尤其是当它们都是相同类型时(因为每个符号 == 扩展名的对象都会散列为 0)。即使它们不是同一类型或不太可能彼此相等,这也是不好的做法,习惯它可能会导致不同设备出现问题。

相反,将一个散列乘以一个小的素数,然后添加第二个,例如:

return 3 * this.symbol.GetHashCode() + this.extension.GetHashCode();
Run Code Online (Sandbox Code Playgroud)