我有HashSet<MyCustomClass> mySet = new HashSet<MyCustomClass>();
,我希望删除包含相同值的所有MyCustomClass。
让我们说MyCustomClass看起来像这样:
public class MyCustomClass
{
Point point;
public MyCustomClass(int x, int y)
{
point.X = x;
point.Y = y;
}
// Other methods...
}
我尝试像MSDN建议的那样实现IEqualityComparer
,并将其传递给HashSet<MyCustomClass>();
的构造函数,但最终失败了。
什么是正确的方法?
修改
这是我的Chain
课程和我的ChainEqualityComparer
:
public class Chain
{
HashSet<Mark> chain;
HashSet<Mark> marks;
public Chain(HashSet<Mark> marks)
{
chain = new HashSet<Mark>();
this.marks = marks;
}
// Other methods...
}
public class ChainEqualityComparer : IEqualityComparer<Chain>
{
#region IEqualityComparer<Chain> Members
public bool Equals(Chain x, Chain y)
{
if (x.ChainWithMarks.Count == y.ChainWithMarks.Count)
{
foreach (Mark mark in x.ChainWithMarks)
{
if (!y.ChainWithMarks.Contains(mark))
return false;
}
return true;
}
return false;
}
public int GetHashCode(Chain obj)
{
return obj.GetHashCode() ^ obj.GetType().GetHashCode();
}
#endregion
}
这是我的Mark
课程:
public class Mark
{
int x;
int y;
public Mark(int x, int y)
{
this.x = x;
this.y = y;
}
public int X
{
get { return x; }
set { x = value; }
}
public int Y
{
get { return y; }
set { y = value; }
}
}
public class MarkEqualityComparer : IEqualityComparer<Mark>
{
#region IEqualityComparer<Mark> Members
public bool Equals(Mark x, Mark y)
{
return (x.X == y.X) && (x.Y == y.Y);
}
public int GetHashCode(Mark obj)
{
return obj.GetHashCode() ^ obj.GetType().GetHashCode();
}
#endregion
}
(如果代码太多,我可以将代码粘贴到代码中......)
答案 0 :(得分:5)
您可以使用EqualityComparer或仅覆盖Equals和GetHashCode。
您必须确保您认为是重复的任何内容都被标识为具有等效的哈希码,并在测试相等时返回true。
我的猜测是你没有返回相同的哈希码。你可以发布相等比较器的代码吗?
作为测试,你可以这样做:
var set = new HashSet<MyCustomClass>();
var a = new MyCustomClass(1,2);
var b = new MyCustomClass(1,2);
set.Add(a);
set.Add(b);
Assert.IsTrue(a.Equals(b));
Assert.IsTrue(b.Equals(a));
Assert.AreEqual(a.GetHashCode(), b.GetHashCode());
Assert.AreEqual(1, set.Count);
一组类似的测试也适用于相等比较器。
修改强>
是的,怀疑它是哈希码函数。您需要根据类型本身的值来计算它。一个常见的错误。
public int GetHashCode(Mark obj)
{
return ((MyCustomClass)obj).point.GetHashCode();
}
假设point
是您类型中唯一的州字段。
答案 1 :(得分:2)
我认为你被绊倒了因为两个Mark
实例具有相同的值,在ChainEqualityComparer
类中将不相等。似乎没有使用过MarkEqualityComparer
。
该行:
if (!y.ChainWithMarks.Contains(mark))
除非您在Equals
课程上覆盖GetHashCode
和Mark
,否则始终为false。 (除非你在链x和链y中都有两个相同标记的引用,我认为这不是你想要的)。
如果y.ChainWithMarks
是HashSet并且您想使用MarkEqualityComparer
,请确保使用包含MarkEqualityComparer
实例的正确构造函数创建该HashSet。
由于Mark
是值类型,因此您可以考虑使用结构来表示它,因为.Net运行时在比较时使用值相等而不是引用相等。我认为这实际上是你的想法最正确的实现。