2009-12-11 3 views
3

У меня есть два сложных объекта одного типа. Я хочу сравнить оба объекта, чтобы определить, имеют ли они одинаковые значения. Каков эффективный способ сделать это? Классовая структураСложное сравнение объектов в C#

образец приведен ниже:

class Package 
{ 
    public List<GroupList> groupList; 
} 
class GroupList 
{ 
    public List<Feature> featurelist; 
} 
class Feature 
{ 
    public int qty; 
} 
+11

Зависит от вашего определения, имеющие те же значения. –

+1

И какой из объектов вы хотите сравнить. –

+0

с классом образцов выше: сравнить два объекта пакета, чтобы они имели одинаковые списки групп, и каждый список групп имеет одинаковый набор списков функций, и каждая функция имеет такое же значение для qty. – jbagavathi

ответ

5

Хорошо, так что вы хотите глубоко неупорядоченный структурное сравнение. «Неупорядоченная» часть сложна, и на самом деле это сильный намек на то, что ваши классы не разработаны правильно: List<T> по своей сути упорядочен, поэтому, возможно, вы предпочтете использовать там HashSet<T> (если вы не ожидаете каких-либо дубликаты). Это позволило бы сделать сравнение и проще в реализации, и быстрее (хотя Вставки будет медленнее):

class Package 
{ 
    public HashSet<GroupList> groupList; 

    public override bool Equals(object o) 
    { 
     Package p = o as Package; 
     if (p == null) return false; 
     return groupList.SetEquals(p.groupList); 
    } 

    public override int GetHashCode() 
    { 
     return groupList.Aggregate(0, (hash, g) => hash^g.GetHashCode()); 
    } 
} 

class GroupList 
{ 
    public HashSet<Feature> featureList; 

    public override bool Equals(object o) 
    { 
     GroupList g = o as GroupList; 
     if (g == null) return false; 
     return featureList.SetEquals(g.featureList); 
    } 

    public override int GetHashCode() 
    { 
     return featureList.Aggregate(0, (hash, f) => hash^f.GetHashCode()); 
    } 
} 

class Feature 
{ 
    public int qty; 

    public override bool Equals(object o) 
    { 
     Feature f = o as Feature; 
     if (f == null) return false; 
     return qty == f.qty; 
    } 

    public override int GetHashCode() 
    { 
     return qty.GetHashCode(); 
    } 
} 

Если вы хотите продолжать использовать List<T>, вы должны будете использовать LINQ набор операций - внимание, однако, что те, значительно медленнее:

class Package 
{ 
    public List<GroupList> groupList; 

    public override bool Equals(object o) 
    { 
     Package p = o as Package; 
     if (p == null) return false; 
     return !groupList.Except(p.groupList).Any(); 
    } 
} 

class GroupList 
{ 
    public List<Feature> featureList; 

    public override bool Equals(object o) 
    { 
     GroupList g = o as GroupList; 
     if (g == null) return false; 
     return !featureList.Except(f.featureList).Any(); 
    } 
} 
+0

В качестве дополнительной заметки вы, вероятно, можете упростить первый пример дальше, используя 'HashSet .CreateSetComparer()' - вы получите 'GetHashCode()' наборы бесплатно таким образом. Оставленный как упражнение для читателя. –

+0

Я считаю, что вы должны заменить первый пример на 'HashSet .CreateSetComparer()', так как лучше использовать встроенное решение здесь. Также всегда следует переопределять «GetHashCode» при переопределении Equals, поэтому код или слово на нем было бы лучше (во втором примере). – nawfal

1

Если бы я тебя, я бы реализовать IComparable интерфейс на два типа:

http://msdn.microsoft.com/en-us/library/system.icomparable.aspx

Оттуда вы можете использовать .CompareTo, и выполнять точные сопоставления, требуемые в соответствии с вашими обстоятельствами. Это общая передовая практика в .NET, и я думаю, что это хорошо относится к вашему делу.

+4

'IComparable' предназначен для использования, когда на типах существует определенная _ordering_ (т. Е. Когда вы можете сказать, что' A меньше B', а 'B больше A'). Это не всегда так, и это даже не требуется в большинстве случаев - обычно вы просто хотите знать, равен ли A A B. Для этого нет необходимости в интерфейсе - 'Object.Equals()' обрабатывает этот случай уже (хотя есть также 'IEquatable '). –

+1

... процитировать самое первое предложение в документации для «IComparable»: «Определяет обобщенный метод сравнения типов, который тип или класс значения реализует для __order или sort__ его экземпляры». –

2

Мы всегда просто в конечном итоге написание метода на классе, который проходит через все, и сравнивает его. Вы можете реализовать это как IComparable или переопределить Equals.

2

Как говорится в комментарии, зависит от того, как «точный» вы хотите измерить.

Вы можете просто переопределить равенство и реализовать метод GetHashCode, однако это не гарантирует, что они являются точными совпадениями. Тем не менее, они гарантируют, что они «очень вероятны» в точном матче.

Следующее, что вы могли бы сделать, - это пройти через каждое свойство/поле в классе и сравнить эти значения хэша. Это было бы «очень вероятным» точным совпадением.

И чтобы действительно получить точное соответствие, вам нужно сравнить каждое поле и член в рекурсивном цикле ... не рекомендуется.

+0

Я хочу удостовериться, что оба объекта точно соответствуют только – jbagavathi

+0

+1 для GetHashCode –

1

Зависит от того, что вы хотите, чтобы сравнить. Как и другие, IComparer - хороший выбор. Если вы планируете использовать лямбды и LINQ, я бы с IEqualityComparer

http://msdn.microsoft.com/en-us/library/system.collections.iequalitycomparer.aspx

+0

+1 для упоминания IEqualityComparer. Вы можете просто извлечь из EqualityComparer и переопределить методы Equals & GethashCode. – Sunit

1

в общем, вам нужен способ, чтобы проверить два, независимо от того, перегружать ли вы или нет равных, или использовать IComparer.

Вы спросили, как сделать это наиболее эффективно, вот несколько советов:

  • Ваш метод равенства должны попытаться отказаться быстро, например, убедитесь, что размер списков один и тот же, если они не являются, а затем возвращают false сразу
  • Если бы вы могли реализовать эффективный хэш-код, вы могли бы сначала сравнить хэши, если они не равны, то объекты не равны, если они равны, то вам нужно сравнить объекты, чтобы узнать, равны ли объекты.

Так что сначала выполните самые быстрые сравнения, чтобы попытаться вернуть false.

0

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

void Mymethod(){ 

Class1 class1 = new Class1(); 

//define properties for class1 

Class1 class2 = new Class1(); 
//define properties for class2 

PropertyInfo[] properties = class1.GetType().GetProperties(); 

bool bClassesEqual = true; 

foreach (PropertyInfo property in properties) 
{ 
    Console.WriteLine(property.Name.ToString()); 

    if (property.GetValue(class1, null) != property.GetValue(class2, null)) 
    { 
     bClassesEqual = false; 
     break; 

    } 

} 

}