- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
问题:
当我使用 Contains()
时针对 IEnumerable<T>
正确实现 IEquatable
的类并覆盖 GetHashCode
它返回错误。如果我将匹配目标包装在列表中并执行 Intersect()
然后比赛正常进行。我更愿意使用 Contains()
.
关于 IEnumerable.Contains()
来自 MSDN :
Elements are compared to the specified value by using the default equality comparer
关于 EqualityComparer<T>.Default
来自 MSDN 的属性(property):
The Default property checks whether type T implements the System.IEquatable generic interface and if so returns an EqualityComparer that uses that implementation. Otherwise it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T.
据我了解,实现 IEquatable<T>
在我的课上应该意味着 Equals
尝试查找匹配项时默认比较器使用方法。我想使用 Equals 是因为我希望两个对象只有一种相同的方式,我不想要开发人员必须记住放入的策略。
我觉得奇怪的是,如果我将匹配目标包装在 List
中然后执行 Intersect
然后正确找到匹配项。
我错过了什么?我是否也必须像 MSDN 文章那样创建一个相等比较器? MSDN 建议有 IEquatable
就足够了,它 会帮我把它包起来。
示例控制台应用
注意:GetHashCode()
来自 Jon Skeet here
using System;
using System.Collections.Generic;
using System.Linq;
namespace ContainsNotDoingWhatIThoughtItWould
{
class Program
{
public class MyEquatable : IEquatable<MyEquatable>
{
string[] tags;
public MyEquatable(params string[] tags)
{
this.tags = tags;
}
public bool Equals(MyEquatable other)
{
if (other == null)
{
return false;
}
if (this.tags.Count() != other.tags.Count())
{
return false;
}
var commonTags = this.tags.Intersect(other.tags);
return commonTags.Count() == this.tags.Count();
}
public override int GetHashCode()
{
int hash = 17;
foreach (string element in this.tags.OrderBy(x => x))
{
hash = unchecked(hash * element.GetHashCode());
}
return hash;
}
}
static void Main(string[] args)
{
// Two objects for the search list
var a = new MyEquatable("A");
var ab = new MyEquatable("A", "B");
IEnumerable<MyEquatable> myList = new MyEquatable[]
{
a,
ab
};
// This is the MyEquatable that we want to find
var target = new MyEquatable("A", "B");
// Check that the equality and hashing works
var isTrue1 = target.GetHashCode() == ab.GetHashCode();
var isTrue2 = target.Equals(ab);
var isFalse1 = target.GetHashCode() == a.GetHashCode();
var isFalse2 = target.Equals(a);
// Why is this false?
var whyIsThisFalse = myList.Contains(target);
// If that is false, why is this true?
var wrappedChildTarget = new List<MyEquatable> { target };
var thisIsTrue = myList.Intersect(wrappedChildTarget).Any();
}
}
}
最佳答案
好的 - 问题实际上出在 ICollection<T>.Contains
的数组实现中.你可以像这样简单地看到:
static void Main(string[] args)
{
var ab = new MyEquatable("A", "B");
var target = new MyEquatable("A", "B");
var array = new[] { ab };
Console.WriteLine(array.Contains(target)); // False
var list = new List<MyEquatable> { ab };
Console.WriteLine(list.Contains(target)); // True
var sequence = array.Select(x => x);
Console.WriteLine(sequence.Contains(target)); // True
}
Enumerable.Contains
代表ICollection<T>.Contains
如果源实现 ICollection<T>
,这就是为什么您获得数组行为而不是 Enumerable.Contains
的原因在您的代码中“手动”实现。
现在ICollection<T>.Contains
是否表示选择使用哪个比较器取决于实现:
Implementations can vary in how they determine equality of objects; for example,
List<T>
usesComparer<T>.Default
, whereasDictionary<TKey, TValue>
allows the user to specify theIComparer<T>
implementation to use for comparing keys.
但是:
EqualityComparer<T>
和 IEqualityComparer<T>
, 不是 Comparer<T>
和 IEqualityComparer<T>
EqualityComparer<T>
我觉得很不自然。解决方案 是覆盖 object.Equals(object)
:
public override bool Equals(object other)
{
return Equals(other as MyEquatable);
}
同时实现这两个 IEquatable<T>
通常是令人愉快的和覆盖object.Equals(object)
,为了一致性。因此,虽然您的代码应该在我看来已经可以工作了
关于c# - 为什么 Contains() 返回 false 但包装在列表中而 Intersect() 返回 true?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25419959/
正在尝试创建一个 python 包。似乎有效,但我收到警告。我的 setup.py 是: #! /usr/bin/env python from distutils.core import setup
我导入了一个数据类型 X ,定义为 data X a = X a 在本地,我定义了一个通用量化的数据类型,Y type Y = forall a. X a 现在我需要定义两个函数, toY 和 fro
我似乎无法让编译器让我包装 Tokio AsyncRead: use std::io::Result; use core::pin::Pin; use core::task::{Context, Po
我有两个函数“a”和“b”。当用户上传文件时,“b”被调用。 “b”重命名文件并返回新文件名。之后应该编辑该文件。像这样: def a(): edits file def b(): r
我使用 Entity Framework 作为我的 ORM,我的每个类都实现了一个接口(interface),该接口(interface)基本上表示表结构(每个字段一个只读属性)。这些接口(inter
有没有办法打开一个程序,通常会打开一个新的jframe,进入一个现有的jframe? 这里是解释,我下载了一个java游戏,其中一个是反射游戏,它在一个jframe中打开,框架内有一堆子面板,我想要做
我想要下面的布局 | AA BBBBBBB | 除非没有足够的空间,在这种情况下 | AA | | BBBBBBB | 在这种情况下,A 是复选框,B 是复选框旁边的 Text
我正在尝试以不同的方式包装我的网站,以便将背景分为 2 部分。灰色部分是主要背景,还有白色部分,它较小并包装主要内容。 基本上我想要this看起来像this . 我不太确定如何添加图像来创建阴影效果,
我正在使用 : 读取整数文件 int len = (int)(new File(file).length()); FileInputStream fis = new FileInputStream(f
我使用 maven 和 OpenJDK 1.8 打包了一个 JavaFX 应用程序我的 pom.xml 中的相关部分: maven-assembly-plugin
我正在使用两个不同的 ItemsControl 来生成一个按钮列表。
我有一个情况,有一个变量会很方便,to , 可以是 TimerOutput或 nothing .我有兴趣提供一个采用与 @timeit 相同参数的宏来自 TimerOutputs(例如 @timeit
我正在尝试包装一个名为 content 的 div与另一个具有不同背景的 div。 但是,当将“margin-top”与 content 一起使用时div,似乎包装 DIV 获得了边距顶部而不是 co
文档不清楚,它似乎允许包装 dll 和 csproj 以在 Asp.Net Core 5 应用程序中使用。它是否允许您在 .Net Core 5 网站中使用针对 .Net Framework 4.6
我被要求开发一个层,该层将充当通用总线,而不直接引用 NServiceBus。到目前为止,由于支持不引人注目的消息,这并不太难。除了现在,我被要求为 IHandleMessages 提供我们自己的定义
我正在尝试包装 getServersideProps使用身份验证处理程序函数,但不断收到此错误:TypeError: getServerSideProps is not a function我的包装看
我有一个项目,它在特定位置(不是/src/resources)包含资源(模板文件)。我希望在运行 package-bin 时将这些资源打包。 我看到了 package-options 和 packag
我正在寻找打印从一系列对象中绘制的 div。我可以通过使用下面的管道语法来实现这一点。 each i, key in faq if (key == 0) |
我在 Meteor.js“main.js - Server”中有这个方法。 Meteor.methods({ messageSent: function (message) { var a
我注意到,如果我的自定义Polymer 1.x元素的宽度比纸张输入元素上的验证错误消息的宽度窄,那么错误将超出自定义元素的右边界。参见下图: 有没有一种机制可以防止溢出,例如在到达自定义元素的边界时自
我是一名优秀的程序员,十分优秀!