2014-02-04 4 views
1

У меня есть сценарий, чтобы проверитьСравнить два пользовательских LIST объектов

1), если какой-либо опоры (EmployeeObject), из empDb появляются в empXml, вернитесь true. Иначе вернуть false

public class EmployeeObject 
{ 
    public Int32 Id { get; set; } 
    public string Title { get; set; } 
    public string Desc { get; set; } 
    ..... 
} 

IList<EmployeeObject> empDb = PopulateFromDb(); //calling ado.net 
IList<EmployeeObject> empXml = PopulateFromXml(); //deserializing xml 

Итак, позвольте мне получить это прямо, я пытаюсь определить, если список empXml является подмножеством списка empDb?

Пробовал до сих пор; но он возвращает false, даже думал, что я проверяю данные в обоих списках, и он должен иметь true, если я не делаю что-то не так в моем выражении.

//at least one MATCH 
empDb.Any(a => empXml.Contains(a)); 

или

//at least one EXACT match 
empDb.Any(x => empXml.Contains(y => x.Equals(y))); 
+1

ли вы '' Equals' и GetHashCode' реализованного в классе 'EmployeeObject'? Если нет, то что, если у вас будет два объекта с одинаковым идентификатором, но с другим заголовком? –

ответ

3

Если вы не имеете Equals и GetHashCode реализованы в EmployeeObject классе, то сотрудники будут сравниваться по ссылке. И у вас обязательно будут разные экземпляры здесь, потому что первый список создается при чтении данных из базы данных, а второй список создается при десериализации xml. Таким образом, даже сотрудники с одинаковыми значениями всех полей будут считаться разными.

Если вы хотите проверить матчи только идентификатор сотрудника, то вы можете проецировать последовательности идентификаторов, а затем использовать Intersect, чтобы проверить соответствие существует

// at least one employee with equal Id 
empDb.Select(e => e.Id).Intersect(empXml.Select(e => e.Id)).Any() 

Если вы хотите сравнить сотрудник по стоимости их поля вместо их ссылок, у вас есть несколько вариантов. Если вы не можете или не хотите, чтобы изменить реализацию класса EmployeeObject и переопределить его Equals и методы GetHashCode, то вы можете создать собственный компаратор для сотрудников:

public class EmployeeComparer : IEqualityComparer<EmployeeObject> 
{ 
    public bool Equals(EmployeeObject x, EmployeeObject y) 
    { 
     return x.Id == y.Id 
      && x.Title == y.Title 
      && x.Desc == y.Desc; 
    } 

    public int GetHashCode(EmployeeObject obj) 
    { 
     int code = 19; 
     code = code * 23 + obj.Id.GetHashCode(); 
     code = code * 23 + obj.Title.GetHashCode(); 
     code = code * 23 + obj.Desc.GetHashCode(); 
     return code; 
    } 
} 

Затем вы можете использовать этот компаратор:

empDb.Intersect(empXml, new EmployeeComparer()).Any() 

Или вы можете проецировать ваши сотрудник анонимных объектов (которые по умолчанию реализация Equals и GetHashCode):

empDb.Select(e => new { e.Id, e.Title, e.Desc }) 
    .Intersect(empXml.Select(e => new { e.Id, e.Title, e.Desc })).Any() 

Или переопределение эти методы:

public class EmployeeObject 
{ 
    public Int32 Id { get; set; } 
    public string Title { get; set; } 
    public string Desc { get; set; } 

    public override int GetHashCode() 
    { 
     int code = 19; 
     code = code * 23 + Id.GetHashCode(); 
     code = code * 23 + Title.GetHashCode(); 
     code = code * 23 + Desc.GetHashCode(); 
     return code; 
    } 

    public override bool Equals(object obj) 
    { 
     EmployeeObject other = obj as EmployeeObject; 
     if (other == null) 
      return false; 

     if (ReferenceEquals(this, other)) 
      return true; 

     return Id == other.Id && 
       Title == other.Title && Desc == other.Desc;     
    } 
} 

И ваш код будет работать. Или вы можете использовать Intersect:

empDb.Intersect(empXml).Any() 
+0

Что делать; если мне нужно сравнить с «Title или Desc или Id», есть ли способ создать один метод вместо создания трех? а также что не так с моим кодом, который у меня есть в моем вопросе, почему это не сработает? –

+0

@AbuHamzah Я уже объяснил в первом абзаце, почему ваш код не работает. Если вы хотите сравнить несколько свойств, то либо переопределите 'Equals' и' GetHashCode' вашего класса, либо создайте собственный сопоставитель и передайте его в 'Intersect' –

+0

okay, я получил его; я должен сравнивать с Title или Desc или Id, есть ли способ создать один метод вместо создания трех? один способ, который я могу сделать, это добавить 'if else statement', но есть ли другой лучший способ обработки. –

2

Если Id является первичным ключом сущности вы можете написать:

var set = new HashSet<int>(empXml.Select(x => x.Id)); //For faster lookup 
empDb.Any(a => set.Contains(a.Id)); 

Но если вам нужно, чтобы соответствовать на все свойства, нужно переопределить Equals и GetHashCode.
(эта реализация также совпадают с нулевыми значениями свойств)

public class EmployeeObject : IEquatable<EmployeeObject> 
{ 
     public bool Equals(EmployeeObject other) 
     { 
      return Id == other.Id && 
        string.Equals(Title, other.Title) && 
        string.Equals(Desc, other.Desc); 
     } 

     public override bool Equals(object obj) 
     { 
      if (ReferenceEquals(null, obj)) return false; 
      if (ReferenceEquals(this, obj)) return true; 
      if (obj.GetType() != this.GetType()) return false; 
      return Equals((EmployeeObject) obj); 
     } 

     public override int GetHashCode() 
     { 
      unchecked 
      { 
       var hashCode = Id; 
       hashCode = (hashCode*397)^(Title != null ? Title.GetHashCode() : 0); 
       hashCode = (hashCode*397)^(Desc != null ? Desc.GetHashCode() : 0); 
       return hashCode; 
      } 
     } 

     public Int32 Id { get; set; } 
     public string Title { get; set; } 
     public string Desc { get; set; } 
    } 

, а запись:

var set = new HashSet<EmployeeObject>(empXml); //For faster lookup 
empDb.Any(a => set.Contains(a)); 
+0

см. мой ответ Сергею –

+0

@AbuHamzah Да, я обновил ответ – Magnus

Смежные вопросы