C# 9 记录:ToHashSet() 没有产生预期的结果
C# 9 record: ToHashSet() not producing the desired result
public static class TestRecordTypes
{
public static void RunTest()
{
List<Person> people = new List<Person>()
{
new Person("John", "Doe", "home"),
new Person("John", "Doe", "Away"),
new Person("Billy", "Doe", "home"),
new Person("Billy", "Doe", "home"),
new Person("Batty", "Bo", "home"),
};
var peopleHash = people.ToHashSet();
Debug.WriteLine($"{peopleHash}");
}
}
public record Person(string FirstName, string LastName)
{
string _location;
public Person(string firstName, string lastName, string location):
this(firstName, lastName)
{
_location = location;
}
}
通过这个测试,我曾希望 peopleHash
列表只有 3 条记录,但我得到了 4 条记录,因为相等性似乎包括非初始参数 location
.
有没有办法获取我想要的 3 条记录的列表,其中只对初始属性执行比较并忽略其他位置参数?
像这样使用IEqualityComparer
using System;
using System.Collections.Generic;
using System.Linq;
public static class TestRecordTypes
{
public static void Main()
{
List<Person> people = new List<Person>()
{
new Person("John", "Doe", "home"),
new Person("John", "Doe", "Away"),
new Person("Billy", "Doe", "home"),
new Person("Billy", "Doe", "home"),
new Person("Batty", "Bo", "home"),
};
var peopleHash = people.ToHashSet(new MyEqualityComparer());
Console.WriteLine(peopleHash.Count());
}
}
public record Person(string FirstName, string LastName)
{
string _location;
public Person(string firstName, string lastName, string location):
this(firstName, lastName)
{
_location = location;
}
}
class MyEqualityComparer : IEqualityComparer<Person>
{
public bool Equals(Person p1, Person p2)
{
if (p1 == null && p2 == null)
return true;
else if (p1 == null || p2 == null)
return false;
else if(p1.FirstName == p2.FirstName && p1.LastName == p2.LastName)
return true;
else
return false;
}
public int GetHashCode(Person p)
{
string s = p.FirstName + p.LastName;
return s.GetHashCode();
}
}
您想更改 IEquatable<Person>
实现。为此,您可以在 record
:
中添加 Equal
并覆盖 GetHashCode
public record Person(string FirstName, string LastName)
{
string _location;
public Person(string firstName, string lastName, string location) :
this(firstName, lastName) => _location = location;
public virtual bool Equals(Person other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return FirstName == other.FirstName && LastName == other.LastName;
}
public override int GetHashCode() => HashCode.Combine(FirstName, LastName);
}
然后测试通过:
[TestMethod]
public void HashTest()
{
List<Person> people = new List<Person>()
{
new ("John", "Doe", "home"),
new ("John", "Doe", "Away"),
new ("Billy", "Doe", "home"),
new ("Billy", "Doe", "home"),
new ("Batty", "Bo", "home"),
};
var peopleHash = people.ToHashSet();
Assert.AreEqual(3, peopleHash.Count);
}
public static class TestRecordTypes
{
public static void RunTest()
{
List<Person> people = new List<Person>()
{
new Person("John", "Doe", "home"),
new Person("John", "Doe", "Away"),
new Person("Billy", "Doe", "home"),
new Person("Billy", "Doe", "home"),
new Person("Batty", "Bo", "home"),
};
var peopleHash = people.ToHashSet();
Debug.WriteLine($"{peopleHash}");
}
}
public record Person(string FirstName, string LastName)
{
string _location;
public Person(string firstName, string lastName, string location):
this(firstName, lastName)
{
_location = location;
}
}
通过这个测试,我曾希望 peopleHash
列表只有 3 条记录,但我得到了 4 条记录,因为相等性似乎包括非初始参数 location
.
有没有办法获取我想要的 3 条记录的列表,其中只对初始属性执行比较并忽略其他位置参数?
像这样使用IEqualityComparer
using System;
using System.Collections.Generic;
using System.Linq;
public static class TestRecordTypes
{
public static void Main()
{
List<Person> people = new List<Person>()
{
new Person("John", "Doe", "home"),
new Person("John", "Doe", "Away"),
new Person("Billy", "Doe", "home"),
new Person("Billy", "Doe", "home"),
new Person("Batty", "Bo", "home"),
};
var peopleHash = people.ToHashSet(new MyEqualityComparer());
Console.WriteLine(peopleHash.Count());
}
}
public record Person(string FirstName, string LastName)
{
string _location;
public Person(string firstName, string lastName, string location):
this(firstName, lastName)
{
_location = location;
}
}
class MyEqualityComparer : IEqualityComparer<Person>
{
public bool Equals(Person p1, Person p2)
{
if (p1 == null && p2 == null)
return true;
else if (p1 == null || p2 == null)
return false;
else if(p1.FirstName == p2.FirstName && p1.LastName == p2.LastName)
return true;
else
return false;
}
public int GetHashCode(Person p)
{
string s = p.FirstName + p.LastName;
return s.GetHashCode();
}
}
您想更改 IEquatable<Person>
实现。为此,您可以在 record
:
Equal
并覆盖 GetHashCode
public record Person(string FirstName, string LastName)
{
string _location;
public Person(string firstName, string lastName, string location) :
this(firstName, lastName) => _location = location;
public virtual bool Equals(Person other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return FirstName == other.FirstName && LastName == other.LastName;
}
public override int GetHashCode() => HashCode.Combine(FirstName, LastName);
}
然后测试通过:
[TestMethod]
public void HashTest()
{
List<Person> people = new List<Person>()
{
new ("John", "Doe", "home"),
new ("John", "Doe", "Away"),
new ("Billy", "Doe", "home"),
new ("Billy", "Doe", "home"),
new ("Batty", "Bo", "home"),
};
var peopleHash = people.ToHashSet();
Assert.AreEqual(3, peopleHash.Count);
}