【问题标题】:Is there an effective way to determine whether .Equals on two different but "equal" instances will return true?有没有一种有效的方法来确定两个不同但“相等”的实例上的 .Equals 是否会返回 true?
【发布时间】:2009-12-04 00:33:24
【问题描述】:

我正在尝试使用反射来确定在一个类型的两个不同但“相等”的实例上调用 .Equals 的结果。

我的方法是这样的:

public static bool TypeComparesProperties(Type t)
{
    // return true if (an instance of t).Equals(a different instance of t)
    //  will be true if all publicly accessible properties of the instances
    //  are the same
}

举例:

string a = "Test";
string b = "Test";
bool areEqual = a.Equals(b);   // areEqual will be true
// so:
TypeComparesProperties(typeof(string));   // should return true

但是,鉴于:

public class MyComplexType
{
    public int Id { get; set; }
    public string MyString { get; set; }
}

MyComplexType a = new MyComplexType {Id = 1, MyString = "Test"};
MyComplexType b = new MyComplexType { Id = 1, MyString = "Test" };
bool areEqual = a.Equals(b);   // areEqual will be false
// so:
TypeComparesProperties(typeof(MyComplexType));   // should return false

如果我按如下方式在我的班级上实现IEquatable<MyComplexType>,我会得到正确的:

public class MyComplexType : IEquatable<MyComplexType>
{
    public int Id { get; set; }
    public string MyString { get; set; }

    public bool Equals(MyComplexType other)
    {
        return (Id.Equals(other.Id) && MyString.Equals(other.MyString));
    }
}

我想我可以通过使用反射实例化两个实例来实现,然后将所有属性设置为适当类型的默认值。虽然这需要大量工作和大量开销,而且我认为如果该类型上没有空构造函数,我会遇到问题。

还有其他想法吗?


编辑:

似乎人们对我的意图感到困惑。我道歉。希望这会澄清:

我有一个方法可以最大程度地比较两个对象。简单地调用 .Equals() 是不够的,因为:

  1. 这些对象将是值类型或将以一种很好的方式实现 IEquatable,我会得到一个真实的响应。太好了!
  2. 对象可能具有所有相同的属性并且是“相等的”,但由于它们是不同的实例,我会得到错误的响应。 我不知道这是因为对象不“相等”,还是因为它们只是不同的实例

所以在我看来,比较方法应该是:

  1. 检查对象类型以查看其Equals 方法是否会为具有相同公共属性的两个不同实例返回true。
  2. 如果是,调用Equals方法并返回结果
  3. 如果不是,请查看所有属性和字段并尽可能比较它们以确定它们是否相等

现在,我知道我可以直接跳到第 3 步,但如果有办法提前确定是否有必要,那将节省时间。


编辑 2:

我要关闭它有几个原因:

  1. 我越是谈论它,我就越意识到我问的并不是我真正想做的事情
  2. 即使我确实想这样做,也没有真正的捷径可走。 RE 之前的编辑,无论如何我都应该跳到第 3 步。

感谢大家的意见。

【问题讨论】:

  • 这个问题相当于The Halting Problem;一般无法解决。你能解释一下为什么要这样做吗?
  • RE 停止问题,您的意思是如果我要在每个属性上递归调用此方法以寻找相等性?否则我看不出它是如何等价的......
  • 在回答您的问题时,基本上是尝试确定给定类型是否“简单”到足以使用 .Equals 进行比较。我从相对不同的系统(共享类型程序集)接收两个对象,我想尽我所能比较它们。如果我不能使用 Equals,我想检查属性并尽力进行比较。
  • 您实际上想在这里完成什么?这将有助于确定如何解决这个问题。
  • 我不确定你试图对空构造函数等做出什么意义......你能澄清你的意思吗?

标签: c# reflection comparison equality


【解决方案1】:

您可以基于this answer 做一些事情,注意这是比较公共属性,而不是字段,Equals 可以做任何它想做的疯狂事情。将其更改为使用字段并不难,但是......老实说,我不确定驱动程序在这里。我只需编写Equals(object)Equals(MyComplexType) 并使用EqualityComparer&lt;T&gt;.Default.Equals(x,y)(处理IEquatable&lt;T&gt;、空值、Nullable&lt;T&gt; 等 - 使用object.Equals(x,y) 作为后备策略)。

对于我认为满足您更新需求的东西:

public static bool AreEqual<T>(T x, T y) {
    if(ReferenceEquals(x,y)) return true;
    if(x==null || y == null) return false;
    IEquatable<T> eq = x as IEquatable<T>;
    if(eq == null) return PropertyCompare.Equal(x,y);
    return eq.Equals(y);
}

【讨论】:

  • 这实际上更接近我真正想做的事情。我的错。我已经更新了我的问题以澄清。
【解决方案2】:

老实说,如果您比较值类型,默认等于应该没问题。但是,当在引用类型上使用 equals 的默认实现时,它的操作方式不同,更多的是引用指针相等。要获得真正的对象级 Equals 操作,您必须实现 IEquatable,覆盖每个类的 Equals 方法,或者使用反射来比较每个公共属性。看看这个链接,它可能有帮助,也可能没有帮助:

SO - Internal Equals Object

【讨论】:

  • 感谢 Joshua,我明白这一点,但我需要知道,对于特定的引用类型,我是否可以在其上使用 Equals 来获得“平等”。如果我只是在两个未知对象上调用 Equals 并且它返回 false,那么我一点也不聪明。
  • 有两种方法可以在运行时进行检查。这两项检查都可以存在于您的 TypesComparesProperties 方法中 1) 检查 Type 是否实现了 IEquatable 接口,如果是,您可以使用它。 2) 查看该类是否覆盖了对象的 Equals 方法。要做到这一点,请参阅帖子stackoverflow.com/questions/1760388/… 这应该允许您在尝试运行 equals 命令之前进行类型检查,这样您就知道是否需要执行更多涉及基于反射的相等操作而不是简单的 objA.Equals(objB) 命令。
  • 刚看到马克的回答。该解决方案看起来很不错。考虑到我有一个项目,我们现在需要在一堆对象上实现相等性,我想我可能不得不试一试他的解决方案,看看它对我的应用程序的效果如何。
【解决方案3】:

试穿一下这个尺寸。

public static bool TypeComparesProperties(Type t)
{
    Type equatableInterface = typeof(IEquatable<>);

    if (t.GetInterface(equatableInterface.Name) != null)
    {
        return true;
    }
    else
    {
        Type objectClass = typeof(Object);
        MethodInfo equalsMethod = t.GetMethod("Equals", new Type[] { typeof(object) });

        return equalsMethod.DeclaringType != objectClass;
    }
}

首先,该方法检查IEquatable&lt;&gt; 是否已在该类型上实现。如果有,则返回 true。如果没有,请检查该类型是否覆盖了Equals(object) 方法。如果有,返回true;否则(如果Equals方法是Object中声明的默认方法),返回false。

【讨论】:

  • 为什么不直接使用EqualityComparer&lt;T&gt;.Default.Equals(x,y),它支持IEquatable&lt;T&gt;,回退到object.Equals,还可以处理空值,Nullable&lt;T&gt;
  • 我想我可能只是在某种程度上重新发明了轮子。不熟悉 EqualityComparer&lt;T&gt; 类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-24
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多