2012-10-20 16 views
7

私はassignUsersは3レコードを持っており、assignedUsersは2行を持っている2つのリストを減算しようとします。 Except方法の後、私はまだassignedUsersで2行が期待どおりに動作しExcept方法を行うためにassignUsersList.Exceptは動作していません

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

あなたのマッパーは、おそらく参照を失っている、とタイプは、おそらく他の比較演算子が定義されていません。 – leppie

+0

IComparererを使用して比較機能を作成します。 –

+0

@leppie回答として投稿する必要があります:) –

答えて

24

に似ているので、私は1つのレコードを取得する必要がありますが、クラスAssignUserViewModelGetHashCodeEqualsメソッドを持っている必要があり、3行を取得します正しく上書きされます。

AssignUserViewModelオブジェクトは一意にIdによって定義されている場合たとえば、あなたがこの方法でクラスを定義する必要があります。

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

そうでない場合、あなたは/クラスの実装を変更したくないことができない場合は、 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(Distinct、Except、Intersect、Union)を使用する場合、Linqはシーケンス要素を比較する必要があります。デフォルトでは、Linqは要素を比較するのにObject.EqualsObject.GetHashCodeのメソッドを使用します。これらのメソッドがあなたの型でオーバーライドされない場合は、参照クラスが等しいかどうかでオブジェクトを比較する基本クラスの実装が使用されます。デフォルトの実装では、同じ参照である2つのオブジェクトが同じハッシュコード(つまり等しいとみなされます)を持つことが保証されます。これはあなたの場合です。 Mapperクラスは、参照が異なるAssignUserViewModelオブジェクトの新しいインスタンスを作成します(すべてのフィールド値が同じ場合でも同じ)として扱うことはできません。

私たちはこれで何ができますか?あなたのクラスの

  • オーバーライドEqualsGetHashCode方法。すべてのフィールドやアイデンティティーだけで、オブジェクトの平等性をどのように扱うかは、あなた次第です。 Linqはメソッドを使用して要素を比較します。

  • は独自の比較演算を提供する(これは通常、あなたのオブジェクトを変更し、EqualsGetHashCodeを上書きすることはできません場合ですはい、すべてのLINQのSet操作は2つのオーバーロードがある - 。既定の比較を使用して1、そして他の、あなたIEqualityComparer<T>受け付けます。

  • 使用匿名型。すべての匿名型は、すでにオブジェクトが等しいかどうかを判断するために、すべての特性の比較を使用する方法EqualsGetHashCodeを、生成している。この場合は、あなたがあなたのタイプを変更するどちらを必要としないでも比較子を作成します。

したがってすでにここに、最初の2つのアプローチのサンプルを持っているが、最後のものである:

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(); 
関連する問題