Linq / Enumerable任何Vs包含

时间:2013-08-05 12:52:31

标签: c# linq enumerable

我已经解决了我遇到的问题但是虽然我已经发现某些事情是如何起作用的(或者不是)但我并不清楚为什么会这样。

我喜欢那种喜欢"为什么"我希望有人可以解释一下:

我有项目列表和相关评论,我想区分管理员评论和用户评论,所以我尝试了以下代码:

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
}

我对此感到高兴,因为它的代码较少,而且我认为更干净,但我不明白包含什么不起作用。

希望有人能为我解决这个问题。

4 个答案:

答案 0 :(得分:9)

这可能是 ,因为您没有覆盖Equals课程上的相等比较(GetHashCodeoperator==Role)。因此,它正在进行参考比较,这实际上并不是最好的主意,好像它们不是同一个对象,它让它认为它是不同的。您需要覆盖这些相等运算符以提供值相等。

答案 1 :(得分:4)

如果您要使用Equals,则必须覆盖GetHashCode(并始终Contains)。否则Equals只会比较参考文献。

例如:

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

另一种选择是为Enumerable.Contains的重载实现自定义IEqualityComparer<Role>

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))
{
    // ...
}

答案 2 :(得分:1)

这将是您对角色的平等比较。

commentUserRole中的对象与您要查找的对象commentUser.Roles不同。

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

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

答案 3 :(得分:1)

使用Contains - 方法时,检查用户对象的数组Roles是否包含您事先从数据库中检索到的对象。虽然数组包含角色“admin”的对象,但它不包含您之前获取的确切对象。

使用Any - 方法时,您可以检查是否有任何名称为“admin”的角色 - 并提供预期结果。

要使用Contains - 方法获得相同的结果,请在角色类上实现IEquatable<Role> - 接口,并比较名称以检查两个实例是否实际上具有相同的值。