如果我实现 IEquatable<T>,我会失去通过引用进行比较的选项吗?
If I implement IEquatable<T>, will I lose the option to compare by reference?
我想将一个对象与另一个对象进行比较,以了解它们是否相等。所以看起来这样做的方法是在我的 class.
中实现 IEquatable 接口
但我不确定这对 class 的行为有何影响。现在,在我的代码中,我用这种方式通过引用比较两个对象:
if(myObject1 == myObject2)
{
// code when both objects are the same.
// Set values in some properties and do some actions according that.
}
else
{
// code when both objects are no the same.
// Set values in some properties and do some actions according that.
}
但在某些特殊情况下,主要是测试,我想比较2个对象,如果所有属性都相等,则考虑相等,但在这种情况下我不知道它是否会影响我的主要代码,其中我比较参考。
另一个选择是实现一个以这种方式进行比较的方法,但我不知道这是个好主意还是实现 IEquatable 接口更好。
谢谢。
这里发生了几件不同的事情。
首先是IEquatable<T>
与==
运算符没有直接相关。如果您实现 IEquatable<T>
,但不重写 ==
运算符,则 ==
将继续执行它当前的操作:通过引用比较您的对象。
IEquatable<T>
给你一个 Equals(T)
方法,仅此而已。就其本身而言,它不会影响 Equals(object)
(您还需要实施),或 ==
和 !=
.
所以让我们假设您确实重载了 ==
运算符,以调用我们的 Equals
方法:
public static bool operator ==(Foo left, Foo right) => Equals(left, right);
public static bool operator !=(Foo left, Foo right) => !Equals(left, right);
这仅更改了两个 Foo
实例之间的 ==
运算符。你仍然可以写:
if ((object)myObject1 == (object)myObject2))
这将回退到使用 object
的 ==
方法,该方法通过引用进行比较。
另一种方法是:
if (ReferenceEquals(myObject1, myObject2))
另请注意,很少为 类 实施 IEquatable<T>
:这真的没有意义。 类 已经有一个 Equals(object)
方法和一个 GetHashCode()
方法,您需要覆盖这些方法,添加 Equals(T)
方法不会给您太多。
IEquatable<T>
然而对结构很有用:它们还有一个 Equals(object)
方法,你需要重写,但如果你真的调用它,那么你将结束装箱,因为它接受object
。如果你在这里实现 IEquatable<T>
那么你 也 得到一个 Equals(T)
方法,你可以调用它而不用装箱任何东西。
综上所述,我会编写您的代码,因为它旨在在您的应用程序中运行,并在您的测试项目中执行任何特定于测试的内容。这意味着如果您的对象应该通过代码中的引用进行比较,我不会向对象本身添加任何新内容。
在您的测试项目中,您可以编写自己的方法来检查对象的两个实例是否具有相同的属性(作为自定义 bool AreFoosEqual(Foo f1, Foo f2)
,或作为完整的 IEqualityComparer<Foo>
实例)。然后,您可以使它完全满足您的测试需要,而不必担心破坏您的应用程序。
你也可以把你的测试方法写成一系列的断言,它告诉你哪个 属性是不正确的,有什么区别。这可以给你更丰富的测试输出:
public static void AssertFoosEquals(Foo f1, Foo f2)
{
Assert.AreEqual(f1.Foo, f2.Foo, "Foo property mismatch");
Assert.AreEqual(f1.Bar, f2.Bar, "Bar property mismtach");
}
当你进行单元测试时 ->
赞:
public void TestSomething()
{
var expectedValue1 = "SomeExpectedValue";
var actualValue = instance.Method();
Assert.Equal(expectedValue1, actualValue);
}
然后你 "simply" 断言你想要查看的属性,如果你 return 一个对象而不是一个值:
public void TestSomething()
{
var expectedValue1 = "SomeExpectedValue";
TestableObject subject = instance.Method();
Assert.Equal(expectedValue1, subject.Somevalue);
}
如果您想要更通用的设置,您可以使用通用流编写一个反射,它查看一个对象的所有属性并尝试将它们与另一个提供的对象匹配。
或者您可以下载已经允许您执行此操作的 nuget 工具包。
我不会覆盖任何功能,只是为了测试。那就是意大利面条代码。
理想情况下,您的代码应该 100% 可通过单元测试进行验证,而无需使用特定的代码部分来增强或辅助您的测试方法。 (除非所述代码仅限于测试项目本身,并且不包含在任何被测试的实际代码中。
如果你想比较相同的对象,但以不同的方式,我建议使用比较器 实现了 IEqualityComparer<T>
:
public class MyClassTestComparer : IEqualityComparer<MyClass> {
public bool Equals(MyClass x, MyClass y) {
if (ReferenceEquals(x, y))
return true;
else if (null == x || null == y)
return false;
return x.Propery1 == y.Property1 &&
x.Propery2 == y.Property2 &&
x.ProperyN == y.PropertyN;
}
public int GetHashCode(MyClass obj) {
return obj == null
? 0
: obj.Propery1.GetHashCode() ^ obj.Propery2.GetHashCode();
}
}
然后你可以选择合适的比较器
public static IEqualityComparer<MyClass> MyClassComparer {
if (we_should_use_test_comparer)
return new MyClassTestComparer();
else
return EqualityComparer<MyClass>.Default;
}
最后if
会
if (MyClassComparer.Equals(myObject1, myObject2)) {
// Equals: by reference or by properties (in test)
}
我想将一个对象与另一个对象进行比较,以了解它们是否相等。所以看起来这样做的方法是在我的 class.
中实现 IEquatable 接口但我不确定这对 class 的行为有何影响。现在,在我的代码中,我用这种方式通过引用比较两个对象:
if(myObject1 == myObject2)
{
// code when both objects are the same.
// Set values in some properties and do some actions according that.
}
else
{
// code when both objects are no the same.
// Set values in some properties and do some actions according that.
}
但在某些特殊情况下,主要是测试,我想比较2个对象,如果所有属性都相等,则考虑相等,但在这种情况下我不知道它是否会影响我的主要代码,其中我比较参考。
另一个选择是实现一个以这种方式进行比较的方法,但我不知道这是个好主意还是实现 IEquatable 接口更好。
谢谢。
这里发生了几件不同的事情。
首先是IEquatable<T>
与==
运算符没有直接相关。如果您实现 IEquatable<T>
,但不重写 ==
运算符,则 ==
将继续执行它当前的操作:通过引用比较您的对象。
IEquatable<T>
给你一个 Equals(T)
方法,仅此而已。就其本身而言,它不会影响 Equals(object)
(您还需要实施),或 ==
和 !=
.
所以让我们假设您确实重载了 ==
运算符,以调用我们的 Equals
方法:
public static bool operator ==(Foo left, Foo right) => Equals(left, right);
public static bool operator !=(Foo left, Foo right) => !Equals(left, right);
这仅更改了两个 Foo
实例之间的 ==
运算符。你仍然可以写:
if ((object)myObject1 == (object)myObject2))
这将回退到使用 object
的 ==
方法,该方法通过引用进行比较。
另一种方法是:
if (ReferenceEquals(myObject1, myObject2))
另请注意,很少为 类 实施 IEquatable<T>
:这真的没有意义。 类 已经有一个 Equals(object)
方法和一个 GetHashCode()
方法,您需要覆盖这些方法,添加 Equals(T)
方法不会给您太多。
IEquatable<T>
然而对结构很有用:它们还有一个 Equals(object)
方法,你需要重写,但如果你真的调用它,那么你将结束装箱,因为它接受object
。如果你在这里实现 IEquatable<T>
那么你 也 得到一个 Equals(T)
方法,你可以调用它而不用装箱任何东西。
综上所述,我会编写您的代码,因为它旨在在您的应用程序中运行,并在您的测试项目中执行任何特定于测试的内容。这意味着如果您的对象应该通过代码中的引用进行比较,我不会向对象本身添加任何新内容。
在您的测试项目中,您可以编写自己的方法来检查对象的两个实例是否具有相同的属性(作为自定义 bool AreFoosEqual(Foo f1, Foo f2)
,或作为完整的 IEqualityComparer<Foo>
实例)。然后,您可以使它完全满足您的测试需要,而不必担心破坏您的应用程序。
你也可以把你的测试方法写成一系列的断言,它告诉你哪个 属性是不正确的,有什么区别。这可以给你更丰富的测试输出:
public static void AssertFoosEquals(Foo f1, Foo f2)
{
Assert.AreEqual(f1.Foo, f2.Foo, "Foo property mismatch");
Assert.AreEqual(f1.Bar, f2.Bar, "Bar property mismtach");
}
当你进行单元测试时 ->
赞:
public void TestSomething()
{
var expectedValue1 = "SomeExpectedValue";
var actualValue = instance.Method();
Assert.Equal(expectedValue1, actualValue);
}
然后你 "simply" 断言你想要查看的属性,如果你 return 一个对象而不是一个值:
public void TestSomething()
{
var expectedValue1 = "SomeExpectedValue";
TestableObject subject = instance.Method();
Assert.Equal(expectedValue1, subject.Somevalue);
}
如果您想要更通用的设置,您可以使用通用流编写一个反射,它查看一个对象的所有属性并尝试将它们与另一个提供的对象匹配。
或者您可以下载已经允许您执行此操作的 nuget 工具包。
我不会覆盖任何功能,只是为了测试。那就是意大利面条代码。 理想情况下,您的代码应该 100% 可通过单元测试进行验证,而无需使用特定的代码部分来增强或辅助您的测试方法。 (除非所述代码仅限于测试项目本身,并且不包含在任何被测试的实际代码中。
如果你想比较相同的对象,但以不同的方式,我建议使用比较器 实现了 IEqualityComparer<T>
:
public class MyClassTestComparer : IEqualityComparer<MyClass> {
public bool Equals(MyClass x, MyClass y) {
if (ReferenceEquals(x, y))
return true;
else if (null == x || null == y)
return false;
return x.Propery1 == y.Property1 &&
x.Propery2 == y.Property2 &&
x.ProperyN == y.PropertyN;
}
public int GetHashCode(MyClass obj) {
return obj == null
? 0
: obj.Propery1.GetHashCode() ^ obj.Propery2.GetHashCode();
}
}
然后你可以选择合适的比较器
public static IEqualityComparer<MyClass> MyClassComparer {
if (we_should_use_test_comparer)
return new MyClassTestComparer();
else
return EqualityComparer<MyClass>.Default;
}
最后if
会
if (MyClassComparer.Equals(myObject1, myObject2)) {
// Equals: by reference or by properties (in test)
}