C# 即时窗口和运行时为同一LINQ语句提供不同的结果
我有一段代码,它只是比较两个集合,并返回一个列表中不属于另一个列表的所有项目 由于这两个列表包含引用不公平的对象,因此我有一个简单的IEquatable来比较它们ID上的对象 我正在运行的代码如下所示:C# 即时窗口和运行时为同一LINQ语句提供不同的结果,c#,linq,C#,Linq,我有一段代码,它只是比较两个集合,并返回一个列表中不属于另一个列表的所有项目 由于这两个列表包含引用不公平的对象,因此我有一个简单的IEquatable来比较它们ID上的对象 我正在运行的代码如下所示: private PreferenceDefinition[] FindUserPreferencesToAdd(PreferenceDefinition[] newDefinitions, PreferenceDefinition[] oldDefinitions) { //Get t
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.Whered=>!oldDefinitions.Anydef=>def.Equalsd.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();
}
为什么这样做很好,但第一种方法不行?看看这里:
如果实现IEquatable,还应该覆盖基
类Object.EqualsObject和GetHashCode的实现,以便
他们的行为与等式的行为一致
方法
您可以清楚地推断==运算符不受实现IEquatable的影响
因此,Equals调用使用自定义的相等方法,而Contains内部使用未被重写的Object.Equals
数组实现ICollection,因此内部使用的Contains方法在带有IndexOf的数组中实现,而不使用尝试使用IEquatable.EQUALES(如果有)的EqualityComparer.Default
尝试添加以下内容:
public override bool Equals(object obj)
{
var test = obj as Test;
return test == null ? obj.Equals(this) : Equals(test);
}
您可以在这里看到一个简单的示例:显示您的IEquatabe实现。@HamletHakobyan它只是公共bool EqualsPreferenceDefinition other{返回this.Id==other.Id;}@plusheen:只是一个旁白,但是您的Equals实现应该优雅地处理other为null的可能性。@sstan啊,是的!我真是目光短浅,thanks@sstan不,没有。你自己测试一下,然后去掉毫无意义的否决票。我错了。我刚刚注意到Enumerable.Contains实现确实利用了IEquatable,但前提是IEnumerable不是ICollection。如果它是一个ICollection,那么它将采用一个不同的路径,其行为与您描述的完全相同。@sstan;但我同意这是误导,没问题;基本上,如果在未实现ICollection的集合上使用Contains,那么它很可能会根据集合的实现而工作。看一下这里的评论:我稍后会尝试找到一个例子。同时,请看第1249行: