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

可能是因为您没有覆盖类上的相等比较 ( Equals, GetHashCode, operator==) 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

当您从中选择并使用新角色集合填充角色属性时,您的上下文对象将创建一个新对象。如果您的上下文没有跟踪对象以便在请求第二个副本时返回相同的对象,那么即使所有属性可能相同,它将是一个不同的对象。因此,Contains 的失败

您的Any子句明确检查 Name 属性,这就是它起作用的原因

尝试制作角色实现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实现- 接口并比较名称以检查两个实例实际上是否具有相同的值。IEquatable<Role>

于 2013-08-05T12:56:19.363 回答