0

我正在尝试使用反射来确定在一个类型的两个不同但“相等”的实例上调用 .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. 即使我确实想这样做,也没有真正的捷径可走。重新编辑之前的编辑,无论如何我都应该跳到第 3 步。

感谢大家的意见。

4

3 回答 3

1

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

SO - 内部等于对象

于 2009-12-04T03:38:45.137 回答
1

试穿这个尺寸。

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<>已在该类型上实现。如果有,则返回 true。如果没有,请检查该类型是否覆盖了该Equals(object)方法。如果有,返回true;否则(如果该Equals方法是 中声明的默认方法Object),则返回 false。

于 2009-12-04T04:06:16.307 回答
1

您可以根据这个答案做一些事情,注意这会比较公共属性,而不是字段,这Equals可以做任何它想做的疯狂事情。将其更改为使用字段并不难,但是......老实说,我不确定驱动程序在这里。我只需编写Equals(object)andEquals(MyComplexType)并使用EqualityComparer<T>.Default.Equals(x,y)(它处理IEquatable<T>、 nullNullable<T>等 -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);
}
于 2009-12-04T05:57:12.367 回答