我有一段代码,它只是比较两个集合,并返回一个列表中不属于另一个列表的所有项目。
由于这两个列表包含引用不公平的对象,因此我有一个简单的IEquatable
来比较其 ID 上的对象。
我正在运行的代码如下:
private PreferenceDefinition[] FindUserPreferencesToAdd(PreferenceDefinition[] newDefinitions, PreferenceDefinition[] oldDefinitions)
{
//Get the newly selected definitions
var newPreferences = newDefinitions.Where(def => def.IsSelected);
//Get all new definitions that don't exist in the old list
var preferencesToAdd = newPreferences.Where(def => !oldDefinitions.Contains(def)).ToArray();
return preferencesToAdd;
}
preferencesToAdd
的结果给了我完全相同的newPreferences
列表,尽管故意确保newDefinitions
包含已选择的其他项目。如果我传入 7 个新首选项,它将返回 7 个首选项以"添加" - 一个不正确的实现。
返回时遇到断点时,当我在即时窗口中运行完全相同的 LINQ 语句时,它给了我:
newPreferences.Where(def => !oldDefinitions.Contains(def)).ToArray();
{App1Test.PreferenceDefinition[1]}
[0]: {App1Test.PreferenceDefinition}
这包含应添加的单个结果。
为什么即时窗口会给我正确的结果,而运行时代码不会?我尝试在运行时 LINQ 查询运行之前和之后在即时窗口中运行此语句,以确保它不是操作顺序,但它没有区别。
编辑:
我找到了解决问题的方法,将第二个 LINQ 语句替换为:
var preferencesToAdd = newPreferences.Where(d => !oldDefinitions.Any(def => def.Equals(d))).ToArray();
但是我不明白为什么原版不起作用。我有一个非常相似的场景,它与我在这里尝试实现的目标相反(查找要删除的项目),并且工作正常。我错过了什么吗?
编辑 2:
即使没有IEquatable,这段代码也能正常工作:
private PreferenceDefinition[] FindUserPreferencesToDelete(PreferenceDefinition[] newDefinitions, PreferenceDefinition[] oldDefinitions)
{
//Get the newly selected definitions
var newPreferences = newDefinitions.Where(def => def.IsSelected);
//Get all old definitions that don't exist in this new list
var preferencesToDelete = oldDefinitions.Where(def => !newPreferences.Contains(def));
return preferencesToDelete.ToArray();
}
为什么这很好,但第一种方法不能?
看看这里:
https://msdn.microsoft.com/en-us/library/ms131187(v=vs.110).aspx
如果实现 IEquatable,则还应覆盖基础 Object.Equals(Object) 和 GetHashCode 的类实现,以便 它们的行为与 IEquatable.Equals 的行为一致。 方法。
可以明确推断出 == 运算符不受实现 IEquatable 的影响;
因此,Equals 调用使用自定义相等方法,而 Contains 在内部使用 Object.Equals,它不会被重写。
该数组实现 ICollection,因此内部使用的 Include 方法是使用 IndexOf 在数组中实现的,而不使用 EqualityComparer.Default,它尝试使用 IEquatable.Equals(如果有的话)。
尝试添加以下内容:
public override bool Equals(object obj)
{
var test = obj as Test;
return test == null ? obj.Equals(this) : Equals(test);
}
您可以在此处看到一个简单的示例:https://dotnetfiddle.net/C5R4bE