2012-10-20 17 views
7

Kodun altında 2 liste çıkarmayı deniyorum, assignUsers 3 kayıt var ve assignedUsers 2 satır var. Ben 1 kayıt almalısınız rağmen assignedUsers 2 satır Except yöntem beklendiği gibi çalışma yapmak için assignUsers amacıylaList.Except çalışmıyor

var users = accountApp.GetUsersByAccountId(context.GetUserData().AccountId); 
List<AssignUserViewModel> assignUsers = Mapper.Map<List<AssignUserViewModel>>(users).ToList(); 
var mailUsers = mailApp.GetMailAssignedByMailId(id).Select(m => new { m.UserId, m.User.Name }).ToList(); 
List<AssignUserViewModel> assignedUsers = mailUsers.Select(Mapper.DynamicMap<AssignUserViewModel>).ToList(); 
assignUsers = assignUsers.Except(assignedUsers).ToList(); 
+2

Kişisel mapper muhtemelen referanslar kaybediyor ve tipi muhtemelen tanımlanmış başka hiçbir karşılaştırıcısı vardır. – leppie

+0

IComparerer kullanarak bir karşılaştırma işlevi yazın. –

+0

@leppie cevap olarak göndermelisiniz :) –

cevap

24

benzer çünkü Except yöntemin ardından hala, 3 satır olsun, sınıf AssignUserViewModelGetHashCode ve Equals yöntemleri olmalıdır doğru şekilde geçersiz kılınmış. Örneğin

, AssignUserViewModel nesneler benzersiz onların Id tarafından tanımlanırsa, bu şekilde sınıfını tanımlamak gerekir:

class AssignUserViewModel 
{ 
    // other methods... 


    public override int GetHashCode() 
    { 
     return this.Id.GetHashCode(); 
    } 
    public override bool Equals(object obj) 
    { 
     if (!(obj is AssignUserViewModel)) 
      throw new ArgumentException("obj is not an AssignUserViewModel"); 
     var usr = obj as AssignUserViewModel; 
     if (usr == null) 
      return false; 
     return this.Id.Equals(usr.Id); 
    } 
} 

Aksi takdirde,/sınıf uygulaması değiştirmek istemiyorsanız olamazsa IEqualityComparer<>'u uygulayabilir ve Except yöntemine iletebilirsiniz, örn. :

class AssignUserViewModelEqualityComparer : IEqualityComparer<AssignUserViewModel> 
{ 
    public bool Equals(AssignUserViewModel x, AssignUserViewModel y) 
    { 
     if (object.ReferenceEquals(x, y)) 
      return true; 
     if(x == null || y == null) 
      return false; 
     return x.Id.Equals(y.Id); 
    } 

    public int GetHashCode(AssignUserViewModel obj) 
    { 
     return obj.Id.GetHashCode(); 
    } 
} 

sonra son çizgi haline gelmeli

assignUsers = assignUsers.Except(assignedUsers, new AssignUserViewModelEqualityComparer()).ToList(); 
+1

Düzenlendi. Boşlukları eşitlemek için eşitlik karşılaştırması eşittir. – digEmAll

2

neden oluyor? Set Operations (Farklı, Hariç, Kesiştir, Birleşim) kullandığınızda, Linq'in eşitlik için sıralama (dizileri) öğelerini karşılaştırması gerekir. Linq, varsayılan olarak elemanları karşılaştırmak için Object.Equals ve Object.GetHashCode yöntemlerini kullanır. Bu yöntemler türünüzde geçersiz kılmıyorsa, temel sınıfın uygulaması kullanılır, bu da nesneleri referans eşitliği ile karşılaştırır. Varsayılan uygulama, aynı referansı olan iki nesnenin aynı karma kodu (bu nedenle eşit kabul edilir) olduğunu garanti eder. Bu senin durumun. Mapper sınıfı, farklı başvuruları olan ve eşit olarak kabul edilemeyen (tüm alan değerleri aynı olsa bile) AssignUserViewModel nesnelerinin yeni örneklerini oluşturur.

Peki, bununla ne yapabilirdik?

  • geçersiz kılma Sınıfındaki Equals ve GetHashCode yöntemleri. Nesnelerin eşitliğini nasıl ele alacağınız size kalmış - tüm alanlar ya da sadece kimlik. Linq, öğeleri karşılaştırmak için yöntemlerinizi kullanacaktır. . Sizindir IEqualityComparer<T> kabul ettiği varsayılan comparer kullanır birini ve diğer -

  • (bu genellikle size nesneyi değiştirmek ve Equals ve GetHashCode geçersiz kılamaz durumda Evet, tüm Linq Küme İşlemleri iki aşırı yükleri var kendi karşılaştırıcısı sağlayın.

  • kullanın anonim türleri. Tüm anonim türleri zaten nesneleri eşit olup olmadığını belirlemek için tüm özelliklerinin karşılaştırılması kullanmak yöntemleri Equals ve GetHashCode, yarattı. Bu durumda size türünü değiştirmek için ne karşılaştırıcısı oluşturmak için ne gerekmez

Böylece zaten ilk iki yaklaşımın örnekleri var, burada sonuncusu:

var assignUsers = accountApp.GetUsersByAccountId(context.GetUserData().AccountId) 
          .Select(u => new { u.UserId, u.Name }); 

var assignedUsers = mailApp.GetMailAssignedByMailId(id) 
          .Select(m => new { m.UserId, m.User.Name }); 

var assignUsers = assignUser.Except(assignedUsers); 
// do not map until here 
List<AssignUserViewModel> result = 
      assignUsers.Select(Mapper.DynamicMap<AssignUserViewModel>).ToList();