似乎许多人已经遇到过这个问题:
所以我看到了答案,并试图实现Equals和GetHashCode的重写,但似乎我编写了错误的代码。
这种情况:我有一个Users(Class)列表,每个用户都有一个List和一个Name属性,list属性包含许可证。我正在尝试做一个
if (!users.Contains(currentUser))
但它没有按预期工作。这是我用来覆盖Equals和GetHashCode的代码:
public override bool Equals(object obj)
{
return Equals(obj as User);
}
public bool Equals(User otherUser)
{
if (ReferenceEquals(otherUser, null))
return false;
if (ReferenceEquals(this, otherUser))
return true;
return this._userName.Equals(otherUser.UserName) &&
this._licenses.SequenceEqual<string>(otherUser.Licenses);
}
public override int GetHashCode()
{
int hash = 13;
if (!_licenses.Any() && !_userName.Equals(""))
{
unchecked
{
foreach (string str in Licenses)
{
hash *= 7;
if (str != null) hash = hash + str.GetHashCode();
}
hash = (hash * 7) + _userName.GetHashCode();
}
}
return hash;
}
提前感谢您的建议和帮助!
编辑1:
这是我在做List.Contains的代码,我试图查看列表是否已包含某个用户,如果没有,则添加不存在的用户。包含仅在第一次工作时,当currentUser更改时,列表中的用户更改为当前用户可能这是一个与equals,any ideas无关的问题?
if (isIn)
{
if (!listOfLicenses.Contains(items[3]))
listOfLicenses.Add(items[3]);
if (!users.Contains(currentUser))
{
User user2Add = new User();
user2Add.UserName = currentUser.UserName;
users.Add(user2Add);
userIndexer++;
}
if (users[userIndexer - 1].UserName.Equals(currentUser.UserName))
{
users[userIndexer - 1].Licenses.Add(items[3]);
}
result.Rows.Add();
}
答案 0 :(得分:2)
好吧,您的哈希码有一个问题 - 如果 没有许可证或用户名为空,则忽略其他组件。我把它重写为:
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 31 + _userName.GetHashCode();
foreach (string licence in Licences)
{
hash = hash * 31 + licences.GetHashCode();
}
return hash;
}
}
更短更简单。如果使用空字符串的哈希码,或者迭代空集合,则无关紧要。
那就是说,无论如何我都希望以前的代码可以工作。请注意,许可证的订单敏感 ...哦,List<T>
无论如何都不会使用GetHashCode
。 (你应该绝对适当地覆盖它,但它不会是错误的原因。)
如果你能展示一个简短但完整的程序来证明这个问题,那将非常有帮助 - 我强烈怀疑你会发现它实际上是你的测试数据的问题。
答案 1 :(得分:1)
users[userIndexer - 1].Licenses.Add(items[3])
之后,users[userIndexer - 1]
不再是同一个用户。您已更改了在等式比较中使用的许可证(in User.Equals
)。
- 编辑 见下面的代码
public class Class
{
static void Main(string[] args)
{
User u1 = new User("1");
User u2 = new User("1");
Console.WriteLine(u1.Equals(u2));
u2.Lic = "2";
Console.WriteLine(u1.Equals(u2));
}
}
public class User
{
public string Lic;
public User(string lic)
{
this.Lic = lic;
}
public override bool Equals(object obj)
{
return (obj as User).Lic == Lic;
}
}
答案 2 :(得分:0)
您需要为License
类实现Equals和GetHashcode,否则SequenceEqual将无效。
答案 3 :(得分:0)
您的班级是否实施IEquatable<User>
?从你的平等方法看来它只是检查。
List.Contains
的文档指出:
此方法使用默认相等性确定相等性 比较器,由对象的实现定义 用于T的IEquatable(T).Equals方法(列表中值的类型)
答案 4 :(得分:0)
确保GetHashCode
返回的值永远不会因对象的特定实例而发生变化,这一点非常重要。如果值更改,则列表和词典将无法正常工作。
将GetHashCode
视为“GetPrimaryKey”。如果有人向用户添加了新许可证,则不会更改数据库中用户记录的主键。同样,您不得更改GetHashCode
。
从您的代码中可以看出,您正在更改许可证集合,并且您正在使用它来计算哈希代码。所以这可能会导致你的问题。
现在,为您生成的每个哈希代码使用常量值是完全合法的 - 例如,您可以为每个实例返回42
。这将强制调用Equals
来确定两个对象是否相等。具有不同哈希码的所有操作都需要调用Equals
。
如果_userName
字段没有改变,那么只需返回其哈希码,看看它是否有效。