使用IEqualityComparer根据C#中的两个属性生成一个不同的列表

时间:2018-04-01 08:12:33

标签: c# linq iequalitycomparer

我正在尝试生成一个项目列表框,它是两个字符串的串联。我创建了一个实现IEqualityComparer的类,我想让这个列表区别开来。

private void PopulateFamily()
    {
        var source = _mfgOrdersData
            .Select(o => new FamilySelector(o.ItemWrapper.ItemClass, o.ItemWrapper.Family))
            .Distinct()
            .OrderBy(f => f.CodeFamily)
            .ToList();

        FamilyFilterListBox.DataSource = source;
        FamilyFilterListBox.ValueMember = "Family";
        FamilyFilterListBox.DisplayMember = "CodeFamily";
    }

class FamilySelector : IEqualityComparer<FamilySelector>
{
    public FamilySelector(string code, string family)
    {
        Code = code;
        Family = family;
    }

    public string Code { get; set; }
    public string Family { get; set; }
    public string CodeFamily { get { return string.Format("{0}\t{1}", Code, Family); } }

    public bool Equals(FamilySelector x, FamilySelector y)
    {
        return x.Code == y.Code && x.Family == y.Family;
    }

    public int GetHashCode(FamilySelector obj)
    {
        return obj.Code.GetHashCode() ^ obj.Family.GetHashCode();
    }
}

问题是我得到的列表不同。同一项目出现多次。 我认为Equals()或GetHashCode()没有正确实现。

2 个答案:

答案 0 :(得分:4)

目前,您在Distinct()个实例的集合上运行FamilySelector,这会导致通过引用相等进行比较。

要做得对,您应该将IEqualityComparer的实例传递给Distinct()来电:

var source = _mfgOrdersData
    .Select(o => new FamilySelector(o.ItemWrapper.ItemClass, o.ItemWrapper.Family))
    .Distinct(new FamilySelector())
    .OrderBy(f => f.CodeFamily)
    .ToList();

您应该将无参数构造函数添加到FamilySelector类,以便可以编译代码。

我还建议对FamilySelector类进行小型重构。目前它保存数据并进行比较。通常IEqualityComparer的实现是一个只执行比较的无数据类:

class FamilyData
{
    public FamilyData(string code, string family)
    {
        Code = code;
        Family = family;
    }

    public string Code { get; set; }
    public string Family { get; set; }
    public string CodeFamily { get { return string.Format("{0}\t{1}", Code, Family); } }
}

class FamilySelector : IEqualityComparer<FamilyData>
{
    public bool Equals(FamilyData x, FamilyData y)
    {
        return x.Code == y.Code && x.Family == y.Family;
    }

    public int GetHashCode(FamilyData obj)
    {
        return obj.Code.GetHashCode() ^ obj.Family.GetHashCode();
    }
}

var source = _mfgOrdersData
    .Select(o => new FamilyData(o.ItemWrapper.ItemClass, o.ItemWrapper.Family))
    .Distinct(new FamilySelector())
    .OrderBy(f => f.CodeFamily)
    .ToList();

答案 1 :(得分:1)

CodeFuller的答案可以正常使用,但作为替代选项,您可以使用MoreLINQ及其DistinctBy方法,这样可以避免需要创建单独的类:

private void PopulateFamily()
{
    var source = _mfgOrdersData
        .Select(o => o.ItemWrapper)
        .DistinctBy(o => new { o.ItemClass, o.Family })
        .OrderBy(f => f.CodeFamily)
        .ToList();

    FamilyFilterListBox.DataSource = source;
    FamilyFilterListBox.ValueMember = "Family";
    FamilyFilterListBox.DisplayMember = "CodeFamily";
}

我认为你想要选择ItemWrapper - 如果没有看到所涉及的类型,很难分辨,但这看起来可能就是你想要的。