在将其标记为重复之前,请考虑以下简短程序:
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) };
}
我有一个返回long类型数组的方法。为了测试它,我在Main
内写了一些类似于那个的测试代码。
但是我得到了例外,但我不知道为什么。难道预期的序列不应该与实际返回的序列相比,还是我错过了什么?
对我而言,它看起来既是方法又是epxected
只包含一个包含long类型数组的单个元素,不是吗?
编辑:那么如何实现不获取异常意义来比较枚举中的元素以返回相等性?
答案 0 :(得分:5)
实际问题是,您要比较两个long[]
,而Enumerable.SequenceEquals
将使用ObjectEqualityComparer<Int64[]>
(您可以通过检查EqualityComparer<long[]>.Default
来看到这是什么由Enumerable.SequenceEquals
)内部使用,它将比较这两个数组的引用,而不是存储在数组中的实际值,这显然是不一样的。
要解决此问题,您可以编写自定义EqualityComparer<long[]>
:
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;
}
}
}
答案 1 :(得分:4)
不,你的序列不相等!
让我们删除序列位,然后只取每个项目的第一个元素中的内容
var firstExpected = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
var firstActual = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
Console.WriteLine(firstExpected == firstActual); // writes "false"
上面的代码是比较两个单独的数组是否相等。 Equality不检查数组的内容,它检查引用是否相等。
使用SequenceEquals
的代码基本上是做同样的事情。它检查可枚举中每个元素的每种情况下的引用。
答案 2 :(得分:0)
SequenceEquals
测试序列中的元素是否相同。枚举中的元素是long[]
类型,因此我们实际上比较了两个不同的数组(但是包含相同的元素),这是通过比较它们的引用而不是它们的实际值来进行的。
所以我们实际检查的是expected[0] == actual[0]
而不是expected[0].SequqnceEquals(actual[0])
这是obiosuly返回false
,因为两个数组共享不同的引用。
如果我们使用SelectMany
展平层次结构,我们就会得到我们想要的结果:
if (!actual.SelectMany(x => x).SequenceEqual(expected.SelectMany(x => x))) throw new Exception();
编辑:
基于this approach,我找到了另一种优雅的方式来检查expected
中是否还包含actual
中的所有元素:
if (!expected.All(x => actual.Any(y => y.SequenceEqual(x)))) throw new Exception();
这将搜索expected
中的actual
内是否存在与EqualityComparer
内的列表顺序相同的列表。这似乎更聪明,因为我们不需要任何自定义// define the function, and its arguments:
function uniquelyClassed (arr, cName) {
// arr: Array of elements to filter,
// cName: String, the class-name you wish
// to filter by
// checking that the passed Array is in fact
// an Array:
if (arr instanceof Array) {
// filtering the passed Array,
// 'n' is the array-element of the
// Array over which we're iterating:
return arr.filter(function (n) {
// checking that there is one class-name,
// and that the class-list contains the
// passed-in class-name:
return n.classList.length === 1 && n.classList.contains(cName);
});
}
}
// finding the <input> elements in the document:
var elements = document.querySelectorAll('input'),
// converting the HTMLCollection into an Array,
// using Array.prototype.slice():
elementsArray = Array.prototype.slice.call(elements, 0),
// calling the function to find the elements with the
// unique class name:
uniquelyXYZ = uniquelyClassed(elementsArray, 'xyz');
// iterating over the Array using forEach():
uniquelyXYZ.forEach(function (el) {
// adding the 'found' class-name to the
// element (to visibly show the found elements):
el.classList.add('found');
});
并且没有奇怪的哈希码实现。