2012-10-20 23 views
7

मैं नीचे दिए गए कोड जैसे 0 सूचियों को घटाता हूं, assignUsers में 3 रिकॉर्ड और assignedUsers में 2 पंक्तियां हैं। Except विधि के बाद मैं अभी भी 3 पंक्तियों मिलता है, हालांकि मैं 1 रिकॉर्ड मिलना चाहिए क्योंकि assignedUsers में 2 पंक्तियाँ Except विधि काम कर के रूप में उम्मीद बनाने के लिए assignUsersसूची। एक्सेप्ट काम नहीं कर रहा है

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

आपका नक्शाकार शायद संदर्भ खो रहा है, और प्रकार शायद कोई अन्य comparer परिभाषित है। – leppie

+0

आईसीओएमपेयरर का उपयोग करके तुलनात्मक कार्य लिखें। –

+0

@leppie आपको इसे उत्तर के रूप में पोस्ट करना चाहिए :) –

उत्तर

24

आदेश में के समान है, वर्ग AssignUserViewModelGetHashCode और Equals तरीकों होना आवश्यक है सही ढंग से ओवरराइड। अन्यथा,

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

यदि आप नहीं कर सकते हैं/नहीं वर्ग कार्यान्वयन बदलना चाहते हैं:

उदाहरण के लिए, यदि AssignUserViewModel वस्तुओं विशिष्ट उनके Id द्वारा परिभाषित कर रहे हैं, तो आप वर्ग को इस तरह से परिभाषित करना चाहिए , आप IEqualityComparer<> को कार्यान्वित कर सकते हैं और इसे Except विधि पर पास कर सकते हैं, उदाहरण के लिए :

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

फिर अपने अंतिम पंक्ति बन जाएगा:

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

संपादित। समानता तुलनाकर्ता ने थोड़ा सा बदल दिया है जो नल के लिए खाते में बराबर है। – digEmAll

2

क्यों हो रहा? जब आप Set Operations (विशिष्ट, छोड़कर, अंतर, संघ) का उपयोग करते हैं तो लिंक को समानता के लिए अनुक्रमों की तुलना करने की आवश्यकता होती है। डिफ़ॉल्ट रूप से लिंकक तत्वों की तुलना करने के लिए Object.Equals और Object.GetHashCode विधियों का उपयोग करता है। यदि इन विधियों को आपके प्रकार में ओवरराइड नहीं किया गया है, तो बेस क्लास के कार्यान्वयन का उपयोग किया जाता है, जो संदर्भ समानता द्वारा वस्तुओं की तुलना करता है। डिफ़ॉल्ट कार्यान्वयन गारंटी देता है कि एक ही संदर्भ वाले दो ऑब्जेक्ट्स में एक ही हैश कोड होता है (इस प्रकार बराबर माना जाता है)। यह तुम्हारा मामला है। Mapper वर्ग AssignUserViewModel ऑब्जेक्ट्स के नए उदाहरण बनाता है, जिनमें अलग-अलग संदर्भ हैं, और समान के रूप में नहीं माना जा सकता है (भले ही सभी फ़ील्ड मान समान हों)।

तो, हम इसके साथ क्या कर सकते हैं?

  • अवहेलना अपनी कक्षा में Equals और GetHashCode तरीकों। यह आप पर निर्भर करता है कि आप ऑब्जेक्ट समानता का इलाज कैसे करेंगे - सभी फ़ील्ड, या सिर्फ पहचान। लिंक तत्वों की तुलना करने के लिए आपके तरीकों का उपयोग करेंगे। । एक जो डिफ़ॉल्ट comparer का उपयोग करता है, और अन्य, जो तुम्हारा IEqualityComparer<T> स्वीकार करता है -

  • (यह आमतौर पर मामला आप अपने वस्तु संशोधित नहीं कर सकते जब और Equals और GetHashCode ओवरराइड है हाँ, सभी Linq सेट संचालन दो भार के है अपने स्वयं के comparer प्रदान करें।

  • उपयोग गुमनाम प्रकार के। सभी गुमनाम प्रकार पहले से ही तरीकों Equals और GetHashCode है, जो निर्धारित करने के लिए वस्तुओं के बराबर हैं सभी गुण की तुलना का उपयोग हुआ है। इस मामले में आप अपने प्रकार को संशोधित करने और न ही comparer बनाने के लिए न की जरूरत नहीं है

इस प्रकार आप पहले से ही पहले दो तरीकों में से नमूने हैं, तो यहां पिछले एक है:

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(); 
संबंधित मुद्दे