包含二维对象数组的对象数组的序列相等性



我想编写一个函数,用输入object[,]做一些事情,并返回一个元素object[,]object[]。我只是一开始就编写了一些愚蠢的东西,没有输入来首先设置测试,然后我将正确编码函数:

public static class TestData
{
public static object[,] Island1()
{
object[,] res = new object[3, 2];
res[0, 0] = 1;
res[0, 1] = 0;
res[1, 0] = 1;
res[1, 1] = 1;
res[2, 0] = 1;
res[2, 1] = 0;
return res;
}
}
public class ComponentsFinder
{
public object[] GetIslands()
{
return  new object[]{TestData.Island1()};
}
}

和测试:

[TestClass]
public class TestCompomentsFinder
{
[TestMethod]
public void FirstTest()
{
object[,] island1 = TestData.Island1();
object[] expected = new object[] {island1};
object[] actual = new ComponentsFinder().GetIslands();
bool res = actual.SequenceEqual(expected);
Assert.IsTrue(res);
}
}

这个测试失败了,我知道为什么:即使两个object[]都只包含一个object代表代表相同"矩阵"的object[,],它们也不指向同一个数组,因此测试失败。

我会有一个真正的类C而不是object[,]这不会有问题,因为我会C正确地实现IEquatable,然后SequenceEquals调用Equals覆盖,测试就可以了。

但是这里我没有课,那我该怎么办?我真的应该将所有内容包装在类中,还是有另一种方法来测试我的object[]的相等性(这相当于知道在具有相同维度和相同各自系数的意义上测试object[,]的相等性,我的object[,]的系数是类型实现IEquatable)?

你对SequenceEqual()失败的原因是正确的。C# 中的数组是引用类型,这意味着当您比较它们时,您将获得引用相等性,这意味着 CLR 会检查它们是否实际上是内存中的相同对象(两个object[,]是内存中的不同对象)。

此外,SequenceEqual()正在遍历最外层的object[]元素,但它不会进入这些数组的内容来迭代内部object[,]

您需要值相等,以便可以比较对象的而不是它们的引用。

但是,由于您将object用于所有内容,因此即使对象实际上是ints的,您也不会获得值相等。从 C# 交互窗口查看此示例:

> object object1 = 1;
> object object2 = 1;
> object1 == object2
false
> (int)object1 == (int)object2
true

您需要将各个值转换回ints,然后才能对它们进行适当的比较。无论如何,我都建议使用int数组,只是为了更好的类型安全性(并且由于不执行一堆装箱转换可能会有更好的性能)。

话虽如此,一般方法是遍历每个单独的项目并单独比较它们。如果它们intobject[,]数组中,请确保先投射它们((int))。至于如何实现这种比较,您有几种选择。

正如你已经提到的,你可以实现自己的包含类。在这种情况下,您可以覆盖/实现接口以提供所需的功能。您还可以实现独立的帮助程序方法(例如public void ArrayCompare(object[,] arr1, object[,] arr2))。

我实现了一个示例作为扩展方法,它将允许您使用ArrayExtension.ArrayCompare(actual, expected)actual.ArrayCompare(expected)来使用它。

public static class ArrayExtension
{
public static bool ArrayCompare(this object[,] arr1, object[,] arr2)
{
if (arr1.Rank != arr2.Rank) return false;
var numDims = arr1.Rank;
for(var i = 0; i < numDims; i++)
if (arr1.GetLength(i) != arr2.GetLength(i))
return false;
for(var j = 0; j < numDims; j++)
{
var dimLength = arr1.GetLength(j);
for(var k = 0; k < dimLength; k++)
if ((int)arr1[j, k] != (int)arr2[j, k])
return false;
}
return true;
}
}

最新更新