【问题标题】:Why is Distinct not working in this LINQ query?为什么 Distinct 在此 LINQ 查询中不起作用?
【发布时间】:2015-03-19 08:11:31
【问题描述】:

在下面的查询中,Distinct 调用似乎没有做任何事情:

using (var db = new AccountsDbContext())
{
    var uniques = db.AccountMappings
        .Select(m => new CanvasAccount { UserName = m.CanvasUser, Password = m.CanvasPassword })
        .OrderBy(m => m.UserName)
        .ToList()
        .Distinct(new CanvasAccountComparer());
    accounts.AddRange(uniques);
}

此查询返回三个CanvasAccount 对象,但其中两个具有完全相同的用户名和密码。我的比较器如下:

class CanvasAccountComparer : IEqualityComparer<CanvasAccount>
{
    public bool Equals(CanvasAccount x, CanvasAccount y)
    {
        return (x.UserName.ToLower() == y.UserName.ToLower()) && (x.Password == y.Password);
    }

    public int GetHashCode(CanvasAccount obj)
    {
        return obj.GetHashCode();
    }
}

【问题讨论】:

  • 我建议使用ToLowerInvariant 而不是ToLower

标签: c# linq linq-to-objects


【解决方案1】:

你的比较器坏了——两个相等的对象不一定返回相同的哈希码。相等和哈希码生成必须彼此一致。您可以使用以下方法解决此问题:

public int GetHashCode(CanvasAccount obj)
{
    int hash = 23;
    hash = hash * 31 + obj.UserName.ToLower().GetHashCode();
    hash = hash * 31 + obj.Password.GetHashCode();
    return hash;
}

注意:

  • 使用ToLower() 并不是执行不区分大小写比较的好方法。这里的文化有各种各样的奇怪之处。理想情况下,请改用 StringComparer
  • 上面的代码假定PasswordUserName 都是非空的。如果其中一个可以为空,则需要检查。
  • 我希望这段代码并不意味着您使用的是纯文本密码。请注意,如果密码经过哈希处理和加盐处理,则两个相同的纯文本密码可能具有不同的哈希表示。

【讨论】:

  • 谢谢乔恩。不得不承认,我红着脸,其实是在想,“如果他们的字段相同,hashcode应该是一样的。”我一直都知道安全性,密码哈希返回一个不同的值,但有点急于看到概念证明,因为我在大约 3 小时前给出了一个要求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-26
  • 1970-01-01
  • 2012-08-25
  • 2012-11-26
  • 2020-04-05
  • 2022-01-23
相关资源
最近更新 更多