C# 比较两个序列是否相等 在将其标记为复制品之前,请考虑以下短程序: static void Main() { var expected = new List<long[]> { new[] { Convert.ToInt64(1), Convert.ToInt64(999999) } }; var actual = DoSomething(); if (!actual.SequenceEqual(expected)) throw new Exception(); } static IEnumerable<long[]> DoSomething() { yield return new[] { Convert.ToInt64(1), Convert.ToInt64(999999) }; } static void Main() { var expected=newlist{new[]{Convert.ToInt64(1),Convert.ToInt64(999999)}; var实际值=剂量测量(); 如果(!actual.SequenceEqual(预期))抛出新异常(); } 静态IEnumerable剂量测量法() { 返回新的[]{Convert.ToInt64(1),Convert.ToInt64(999999)}; }
我有一个方法,它返回long类型的数组序列。为了测试它,我在C# 比较两个序列是否相等 在将其标记为复制品之前,请考虑以下短程序: static void Main() { var expected = new List<long[]> { new[] { Convert.ToInt64(1), Convert.ToInt64(999999) } }; var actual = DoSomething(); if (!actual.SequenceEqual(expected)) throw new Exception(); } static IEnumerable<long[]> DoSomething() { yield return new[] { Convert.ToInt64(1), Convert.ToInt64(999999) }; } static void Main() { var expected=newlist{new[]{Convert.ToInt64(1),Convert.ToInt64(999999)}; var实际值=剂量测量(); 如果(!actual.SequenceEqual(预期))抛出新异常(); } 静态IEnumerable剂量测量法() { 返回新的[]{Convert.ToInt64(1),Convert.ToInt64(999999)}; },c#,ienumerable,yield,C#,Ienumerable,Yield,我有一个方法,它返回long类型的数组序列。为了测试它,我在Main中编写了一些类似的测试代码 然而,我得到了例外,但我不知道为什么。预期的序列是否应该与实际返回的序列相比较,或者我是否遗漏了什么 在我看来,方法和执行的epxected都只包含一个元素,其中包含long类型的数组,不是吗 编辑:那么我如何实现不获取异常含义来比较枚举中的元素以返回相等值呢?SequenceEquals测试序列中的元素是否相同。枚举中的元素类型为long[],因此我们实际上比较了两个不同的数组(但是包含相同的元素)
Main
中编写了一些类似的测试代码
然而,我得到了例外,但我不知道为什么。预期的序列是否应该与实际返回的序列相比较,或者我是否遗漏了什么
在我看来,方法和执行的epxected
都只包含一个元素,其中包含long类型的数组,不是吗
编辑:那么我如何实现不获取异常含义来比较枚举中的元素以返回相等值呢?
SequenceEquals
测试序列中的元素是否相同。枚举中的元素类型为long[]
,因此我们实际上比较了两个不同的数组(但是包含相同的元素),这是通过比较它们的引用而不是它们的实际值来完成的
所以我们在这里实际检查的是这个expected[0]==actual[0]
而不是expected[0]。SequqnceEquals(actual[0])
这是由于两个数组共享不同的引用,因此可能返回false
如果我们使用SelectMany
展平层次结构,我们将得到我们想要的:
if (!actual.SelectMany(x => x).SequenceEqual(expected.SelectMany(x => x))) throw new Exception();
编辑:
基于此,我找到了另一种优雅的方法来检查预期的
中的所有元素是否都包含在实际的
中:
if (!expected.All(x => actual.Any(y => y.SequenceEqual(x)))) throw new Exception();
这将搜索预期的
中是否存在与当前列表顺序相同的子列表。这看起来更聪明,因为我们不需要任何定制的EqualityComparer
,也不需要奇怪的hashcode实现 不,你的序列不相等
让我们删除序列位,只取每个项目的第一个元素中的内容
var firstExpected = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
var firstActual = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
Console.WriteLine(firstExpected == firstActual); // writes "false"
上面的代码正在比较两个独立的数组是否相等。相等不检查数组的内容,而是检查引用是否相等
使用
SequenceEquals
的代码本质上是在做同样的事情。它检查可枚举项中每个元素的每种情况下的引用。实际问题是您正在比较两个long[]
,而可枚举项。SequenceEquals
将使用ObjectEqualityComparer
(您可以通过检查EqualityComparer.Default
(可枚举.SequenceEquals)来了解这一点,它将比较这两个数组的引用,而不是数组中存储的实际值,这显然是不同的
为了解决这个问题,您可以编写一个定制的EqualityComparer
:
static void Main()
{
var预期值=新列表
{new[]{Convert.ToInt64(1),Convert.ToInt64(999999)};
var实际值=剂量测量();
如果(!actual.SequenceEqual(应为新的LongArrayComparer()))
抛出新异常();
}
公共类LongArray比较程序:EqualityComparer
{
公共覆盖布尔等于(长[]第一,长[]第二)
{
返回第一个。SequenceEqual(第二个);
}
//@JonSkeet提供的GetHashCode实现
//从http://stackoverflow.com/questions/7244699/gethashcode-on-byte-array
公共覆盖int GetHashCode(长[]arr)
{
未经检查
{
if(数组==null)
{
返回0;
}
int hash=17;
foreach(arr中的长元素)
{
hash=hash*31+元素。GetHashCode();
}
返回散列;
}
}
}
有什么例外?序列中的元素是long[]
。比较将是数组引用的比较,它们确实不同。数组的元素(在序列中)不会被比较。你应该实现你自己的比较器,并将此比较器的实例作为SequenceCompare的第二个参数传递。是的,事实上在一秒钟前就发现了。但是我的解决方案对我来说并不方便,你有更好的解决方案吗?@Yuval的答案包含正确的方法。我没有必要这样写。哟urGetHashCode
不正确。它在这个特殊的用法中可以正常工作,因为SequenceEqual
不使用GetHashCode
,但是如果有人将它用于另一个EqualityComparer
的用法,比如Distinct
,它将是不正确的。您需要生成一个与序列相等相关的哈希代码。@JonHanna你是对的,这是一个快速的破解,只是为了证明可以很容易地实现自定义比较器。我会解决它。真幸运,几个月前我实现了一个通用的EqualityComparer
,而我可以使用lambda表达式来实现这两个方法。不过,我现在基本上就是使用这种方法,谢谢。是的。不作为一种快速但值得指出的方法,它会带来危害,以防有人将其复制粘贴到不起作用的地方。代码是为程序员编写的,而不是为计算机编写的。因此,不寻常的代码应该做一些不寻常的事,否则下一个查看它的人将徒劳地浪费时间试图弄清楚到底发生了什么。在这种情况下,不需要的代码就在其中e未检查的块迫使读卡器扫描整个块以查找原因。后来有人的修改也可能会意外地在该块中放入更多代码。这是关于信噪比。这是关于保持表面
static void Main()
{
var expected = new List<long[]>
{ new[] { Convert.ToInt64(1), Convert.ToInt64(999999) } };
var actual = DoSomething();
if (!actual.SequenceEqual(expected, new LongArrayComparer()))
throw new Exception();
}
public class LongArrayComparer : EqualityComparer<long[]>
{
public override bool Equals(long[] first, long[] second)
{
return first.SequenceEqual(second);
}
// GetHashCode implementation in the courtesy of @JonSkeet
// from http://stackoverflow.com/questions/7244699/gethashcode-on-byte-array
public override int GetHashCode(long[] arr)
{
unchecked
{
if (array == null)
{
return 0;
}
int hash = 17;
foreach (long element in arr)
{
hash = hash * 31 + element.GetHashCode();
}
return hash;
}
}
}