提问人:Yola 提问时间:8/25/2022 最后编辑:Yola 更新时间:8/25/2022 访问量:62
如何实现IEnumerable<T的不同比较>
How to implement different comparison for IEnumerable<T>
问:
目前,我以这种方式进行比较(从这里开始):
bool foo<T>(T expected, T actual) {
return EqualityComparer<T>.Default.Equals(expected, actual);
}
它适用于基本类型,但不适用于 .我怎样才能让它为喜欢的人工作?IEnumerable<T>
IEnumerable<T>
SequenceEqual
编辑:我尝试了David L的版本,但它不适用于数组或列表。
答:
2赞
David L
8/25/2022
#1
虽然没有什么可以阻止你直接调用,但你当然可以将该调用包装在帮助程序方法中。请注意,这将逐个索引进行比较。如果要覆盖比较的处理方式,也可以向其传递实例。SequenceEquals
SequenceEquals
IEqualityComparer<T>
bool foo<T>(IEnumerable<T> expected, IEnumerable<T> actual)
{
return expected.SequenceEqual(actual);
}
bool foo<T>(List<T> expected, List<T> actual)
{
return expected.SequenceEqual(actual);
}
bool foo<T>(T[] expected, T[] actual)
{
return expected.SequenceEqual(actual);
}
bool foo<T>(IEnumerable<T> expected, IEnumerable<T> actual,
IEqualityComparer<T> comparer)
{
return expected.SequenceEqual(actual, comparer);
}
使用以下命令进行测试将按预期返回 true:
IEnumerable<int> expected = new List<int> { 1, 2, 3 };
IEnumerable<int> actual = new List<int> { 1, 2, 3 };
List<int> expected2 = new List<int> { 1, 2, 3 };
List<int> actual2 = new List<int> { 1, 2, 3 };
int[] expected3 = new int[] { 1, 2, 3 };
int[] actual3 = new int[] { 1, 2, 3 };
Console.WriteLine(foo(expected, actual));
Console.WriteLine(foo(expected2, actual2));
Console.WriteLine(foo(expected3, actual3));
并返回以下项的 false:
IEnumerable<int> expected = new List<int> { 1, 2, 3 };
IEnumerable<int> actual = new List<int> { 1, 3, 2 };
上述方法的优点是,您可以为要显式支持的每种集合类型获得编译时重载。但是,如果要隐式支持所有集合类型,可以按如下方式扩展当前方法:boo foo<T>
bool foo<T>(T expected, T actual)
{
// check that both T parameters implement IEnumerable
// (meaning they are a collection)
if (expected is IEnumerable expectedEnumerable &&
actual is IEnumerable actualEnumerable)
{
var expectedEnumerator = expectedEnumerable.GetEnumerator();
var actualEnumerator = actualEnumerable.GetEnumerator();
while (true)
{
// Determine if the enumerators have a next element
var hasExpected = expectedEnumerator.MoveNext();
var hasActual = actualEnumerator.MoveNext();
// Either we have no elements or successfully iterated both
if (!hasExpected && !hasActual)
{
return true;
}
// One of the enumerators has a value while the other does not.
if ((hasExpected && !hasActual) || (!hasExpected && hasActual))
{
return false;
}
// check the equality of the two current elements
if (!expectedEnumerator.Current.Equals(actualEnumerator.Current))
{
return false;
}
}
}
// fall back to your original equality comparison because
// one or both parameters do not implement IEnumerable
return EqualityComparer<T>.Default.Equals(expected, actual);
}
对于我上面列出的三个集合用例,这再次返回 true,对于以下测试用例返回 false:
IEnumerable<int> expected4 = new List<int> { 1, 2, 3 };
IEnumerable<int> actual4 = new List<int> { 1, 3, 2 };
List<int> expected5 = new List<int> { 1, 2, 3, 4 };
List<int> actual5 = new List<int> { 1, 2, 3 };
int[] expected6 = new int[] { 2, 3 };
int[] actual6 = new int[] { 1, 2, 3 };
Console.WriteLine(foo(expected4, actual4));
Console.WriteLine(foo(expected5, actual5));
Console.WriteLine(foo(expected6, actual6));
评论
0赞
Yola
8/25/2022
我希望能够调用所有参数。如果我需要超载它,我没关系。foo
0赞
David L
8/25/2022
@Yola没关系。我已经更新了命名。如果你有一个重载,它需要 ,它可以与你当前的方法并存。IEnumerable<T>
foo<T>(T expected, T actual)
0赞
Yola
8/25/2022
我只是尝试了数组和列表,它总是选择.你能提供MWE吗?foo<T>(T expected, T actual)
0赞
David L
8/25/2022
@Yola 由于方法的协定,需要为每个集合类型添加唯一的重载。查看我更新的答案。foo<T>
0赞
Yola
8/25/2022
是的,它是这样工作的。但这样,我需要为我使用的每个集合更新它。似乎不是一个好的设计:( 在 C# 中不可能以更通用的方式做到这一点吗?
评论
Object.Equals
() 的变体,该变体具有 和 具有相同类型的附加约束,并包含特定类型的 的特殊相等规则。正确?bool foo<T>(T expected, T actual)
T
IEnumerable<T2>
public static bool Equals (object objA, object objB)
objA
objB
T