Yur*_*rii 3 .net c# nullable iequalitycomparer
假设有这个类:
public class Foo
{
public int Id { get; set; }
public int? NullableId { get; set; }
public Foo(int id, int? nullableId)
{
Id = id;
NullableId = nullableId;
}
}
Run Code Online (Sandbox Code Playgroud)
我需要按照以下规则比较这些对象:
为了实现它,我像这样覆盖了 Equals 和 GetHashCode:
public override bool Equals(object obj)
{
var otherFoo = (Foo)obj;
var equalityCondition = Id == otherFoo.Id;
if (NullableId.HasValue && otherFoo.NullableId.HasValue)
equalityCondition &= (NullableId== otherFoo.NullableId);
return equalityCondition;
}
public override int GetHashCode()
{
var hashCode = 806340729;
hashCode = hashCode * -1521134295 + Id.GetHashCode();
return hashCode;
}
Run Code Online (Sandbox Code Playgroud)
再往下,我有两个 Foo 列表:
var first = new List<Foo> { new Foo(1, null) };
var second = new List<Foo> { new Foo(1, 1), new Foo(1, 2), new Foo(1, 3) };
Run Code Online (Sandbox Code Playgroud)
接下来,我想加入这些列表。如果我这样做:
var result = second.Join(first, s => s, f => f, (f, s) => new {f, s}).ToList();
Run Code Online (Sandbox Code Playgroud)
那么结果将如我所料,我将得到 3 个项目。但是,如果我更改顺序并首先加入第二个:
var result = first.Join(second, f => f, s => s, (f, s) => new {f, s}).ToList();
Run Code Online (Sandbox Code Playgroud)
那么结果将只有 1 个项目 - new Foo(1, null)和new Foo(1 ,3)
我不明白我做错了什么。如果尝试在 Equals 方法中放置一个断点,那么我可以看到它尝试比较来自同一列表的项目(例如比较new Foo(1, 1)和new Foo(1 ,2))。对我来说,这看起来是因为在 Join 方法中创建了 Lookup。
有人可以澄清那里发生了什么吗?我应该改变什么来实现所需的行为?
您的 Equals 方法是自反和对称的,但它不是可传递的。
您的实现不符合文档中指定的要求:
如果 (x.Equals(y) && y.Equals(z)) 返回 true,则 x.Equals(z) 返回 true。
来自https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netframework-4.8
例如,假设您有:
var x = new Foo(1, 100);
var y = new Foo(1, null);
var z = new Foo(1, 200);
Run Code Online (Sandbox Code Playgroud)
你有x.Equals(y)和y.Equals(z)这意味着你也应该有x.Equals(z),但你的实现没有这样做。由于您不符合规范,因此您不能期望任何依赖于您的 Equals 方法的算法都能正确运行。
你问你能做什么。这完全取决于您需要做什么。部分问题在于,如果它们确实可以出现,我们还不清楚在极端情况下的意图是什么。如果在一个或两个列表中Id多次出现相同的内容NullableId,会发生什么情况?举个简单的例子,如果new Foo(1, 1)在第一个列表中存在 3 次,在第二个列表中存在 3 次,那么输出中应该是什么?九个项目,每个配对一个?
这是解决您问题的幼稚尝试。这仅加入Id,然后过滤掉任何不兼容的配对NullableId。但是当 aId在每个列表中多次出现时,您可能不会期望重复,如示例输出中所示。
var x = new Foo(1, 100);
var y = new Foo(1, null);
var z = new Foo(1, 200);
Run Code Online (Sandbox Code Playgroud)
输出:
Foo(1, 1)
Foo(1, 2)
Foo(1, 3)
Foo(1, null)
Foo(1, 1)
Foo(1, 2)
Foo(1, 3)
Foo(1, null)
Foo(1, 3)
Foo(1, 3)
Run Code Online (Sandbox Code Playgroud)
如果您有成千上万个具有相同 的项目Id,它对您来说也可能太慢了,因为它会Id在过滤掉它们之前建立每个可能的匹配对。如果每个列表有 10,000 个项目,Id == 1则有 100,000,000 对可供挑选。