3

抱えていた問題を解決しましたが、何かがどのように機能するか (または機能しないか) はわかりましたが、その理由は明確ではありません。

私は「なぜ」を知るのが好きなタイプの人なので、誰かが説明できることを願っています:

アイテムのリストと関連するコメントがあり、管理者のコメントとユーザーのコメントを区別したかったので、次のコードを試しました。

User commentUser = userRepository.GetUserById(comment.userId);
Role commentUserRole = context.Roles.Single(x=>x.Name == "admin");
if(commentUser.Roles.Contains(commentUserRole)
 {
   //do stuff
 }
else
{
 // do other stuff
}

コードをステップ実行すると、正しい Role オブジェクトがあるにもかかわらず、commentUser.Roles の役割が認識されないことがわかりました。

最終的に機能したコードは次のとおりです。

if(commentUser.Roles.Any(x=>x.Name == "admin"))
{
  //do stuff
}

コードが少なくなり、私の意見ではよりきれいになったので、私はこれに満足していますが、contains がどのように機能しなかったのか理解できません。

誰かが私のためにそれを片付けてくれることを願っています。

4

4 に答える 4

9

これはおそらく、クラスで等値比較 ( EqualsGetHashCodeoperator==) をオーバーライドしなかったためです。Roleしたがって、参照比較を行っていましたが、これは実際には最良のアイデアではありません。まるでそれらが同じオブジェクトではないかのように、別のものであると考えさせます。値の等価性を提供するには、これらの等価演算子をオーバーライドする必要があります。

于 2013-08-05T12:55:45.143 に答える
4

を使用する場合は、オーバーライドする必要がありますEquals(常に オーバーライドする必要があります) 。それ以外の場合は、参照を比較するだけです。GetHashCodeContainsEquals

たとえば、次のようになります。

public class Role
{
    public string RoleName{ get; set; }
    public int RoleID{ get; set; }
    // ...

    public override bool Equals(object obj)
    {
        Role r2 = obj as Role;
        if (r2 == null) return false;
        return RoleID == r2.RoleID;
    }
    public override int GetHashCode()
    {
        return RoleID;
    }
    public override string ToString()
    {
        return RoleName;
    } 
}

IEqualityComparer<Role>別のオプションは、次のオーバーロードのカスタムを実装することEnumerable.Containsです。

public class RoleComparer : IEqualityComparer<Role>
{
    public bool Equals(Role x, Role y)
    {
        return x.RoleID.Equals(y.RoleID);
    }

    public int GetHashCode(Role obj)
    {
        return obj.RoleID;
    }
}

次のように使用します。

var comparer = new RoleComparer();
User commentUser = userRepository.GetUserById(comment.userId);
Role commentUserRole = context.Roles.Single(x=>x.Name == "admin");
if(commentUser.Roles.Contains(commentUserRole, comparer))
{
    // ...
}
于 2013-08-05T12:58:01.700 に答える
1

これは、ロールの等価比較になります。

のオブジェクトはcommentUserRole、探しているオブジェクトと同じではありませんcommentUser.Roles

コンテキスト オブジェクトから選択すると、新しいオブジェクトが作成され、Roles プロパティに新しい Roles のコレクションが入力されます。2 番目のコピーが要求されたときに同じオブジェクトを返すためにコンテキストがオブジェクトを追跡していない場合、すべてのプロパティが同じであっても、別のオブジェクトになります。したがって、Contains の失敗

あなたのAny句は Name プロパティを明示的にチェックしているため、機能します

Role を実装してみるIEquatable<Role>

public class Role : IEquatable<Role> {
  public bool Equals(Role compare) {
    return compare != null && this.Name == compare.Name;
  }
}

MSDNは、実際にオーバーライドしてこれを機能させるために必要な場合にのみこれが必要であることを示していますが、List<T>EqualsGetHashCode

その場合:

public class Role : IEquatable<Role> {
  public bool Equals(Role compare) {
    return compare != null && this.Name == compare.Name;
  }

  public override bool Equals(object compare) {
     return this.Equals(compare as Role); // this will call the above equals method
  }

  public override int GetHashCode() {
     return this.Name == null ? 0 : this.Name.GetHashCode();
  }
}
于 2013-08-05T12:56:04.923 に答える
1

-メソッドを使用する場合、ユーザー オブジェクトContainsの配列Rolesに、事前にデータベースから取得したオブジェクトが含まれているかどうかを確認します。配列にはロール「admin」のオブジェクトが含まれていますが、以前にフェッチした正確なオブジェクトは含まれていません。

-メソッドを使用Anyする場合、「admin」という名前のロールがあるかどうかを確認すると、期待される結果が得られます。

Contains-methodで同じ結果を得るにはIEquatable<Role>、役割クラスに -interface を実装し、名前を比較して、2 つのインスタンスが実際に同じ値を持つかどうかを確認します。

于 2013-08-05T12:56:19.363 に答える