Есть ли эффективный способ определить, будет ли .Equals для двух разных, но "равных" экземпляров возвращать true? - PullRequest
0 голосов
/ 04 декабря 2009

Я пытаюсь использовать отражение, чтобы определить результат вызова .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> в своем классе следующим образом, я бы получил значение true:

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));
    }
}

Я полагаю, что, вероятно, я могу сделать это, создав два экземпляра с помощью отражения, а затем установив для всех свойств значения, заданные по умолчанию. Хотя это много работы и много накладных расходов, и я думаю, что я столкнулся бы с проблемами, если бы в типе не было пустого конструктора.

Есть еще идеи?


Edit:

Кажется, люди смущены моими намерениями. Я приношу извинения. Надеюсь, это уточнит:

У меня есть метод, который должен сравнивать два объекта в меру своих возможностей. Простого вызова .Equals () будет недостаточно, потому что либо:

  1. Объекты будут типами значений или будут хорошо реализовывать IEquatable, и я получу истинный ответ. Отлично!
  2. Объекты могут иметь все одинаковые свойства и быть "равными", но, поскольку они являются разными экземплярами, я получу ложный ответ. Я не могу сказать, является ли это ложным, потому что объекты не "равны", или потому что они просто разные экземпляры .

Так что, на мой взгляд, метод сравнения должен:

  1. Проверьте тип объекта, чтобы увидеть, будет ли метод Equals возвращать true для двух разных экземпляров с одинаковыми общими свойствами.
  2. Если это так, вызовите метод Equals и верните результат
  3. Если нет, посмотрите на все свойства и поля и сравните их, насколько я могу, чтобы определить, равны ли они

Теперь я понимаю, что могу просто перейти к шагу 3, но если есть способ заранее определить, необходимо ли это, это сэкономит время.


Редактировать 2:

Я собираюсь закрыть это по нескольким причинам:

  1. Чем больше я об этом говорю, тем больше понимаю, что то, что я спрашивал, не то, что я действительно хотел сделать
  2. Даже если бы я действительно хотел это сделать, реального ярлыка нет вообще. RE ранее отредактируйте, я все равно должен просто перейти к шагу 3.

Спасибо всем за ваш вклад.

Ответы [ 3 ]

1 голос
/ 04 декабря 2009

Попробуйте это для размера.

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.

1 голос
/ 04 декабря 2009

Вы могли бы сделать что-то на основе этого ответа , отметив, что это сравнивает публичные свойства , а не поля, и что Equals может делать все, что захочет.Было бы нетрудно изменить его на использование полей вместо этого, но ... если честно, я не уверен, какой здесь драйвер.Я бы просто написал Equals(object) и Equals(MyComplexType) и использовал бы EqualityComparer<T>.Default.Equals(x,y) (который обрабатывает IEquatable<T>, нули, Nullable<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);
}
1 голос
/ 04 декабря 2009

Честно говоря, если вы сравниваете значения типов, по умолчанию должно быть в порядке. Однако при использовании стандартной реализации equals на ссылочных типах она работает по-другому, в большей степени, чем равенство ссылочных указателей. Чтобы заставить действующие операции Equals на уровне объекта работать, вы должны реализовать IEquatable, переопределить метод Equals для каждого класса или использовать отражение для сравнения каждого открытого свойства. Посмотрите на эту ссылку, и она может или не может помочь:

SO - Внутренний Объект Равных

...