【问题标题】:Proper way to JOIN multiple properties on object collection?在对象集合上加入多个属性的正确方法?
【发布时间】:2015-01-05 12:18:19
【问题描述】:

假设我有一个对象,其中以下 3 个属性(其他属性已被省略)构成一个“唯一的”Plan 对象(如果这些属性等于另一个 Plan 对象中的相同值)。

public class Plan
{
    public int ID { get; set; }
    public Plan Parent { get; set; }
    public ID SomeOtherProperty { get; set; }
}

这是我的 Join 代码,其中我省略了 Join 运算符的匿名方法 (我知道默认情况下这段代码不起作用):

oldPlans
    .Join(newPlans, o => o, n => n, (o, n) => new { Old = o, New = n })
    .ForEach(e =>
    {
        ...
    });

我想对两个 Plan 对象集合执行 C#Join。我知道一种方法是对连接属性使用匿名方法,写出这三个属性。

但是有不同的方法吗?我可以覆盖GetHashCode 吗?当我尝试这个时,它似乎并没有把它称为那个方法。我也尝试过覆盖 Equals 但它似乎也没有调用它。我应该覆盖==!= 运算符吗?我可以为键选择器字段显式调用.GetHashCode()(假设我覆盖了它)吗?

是否可以让这个 Join 检查这两个对象的相等性而不使键选择器复杂化?谢谢。

【问题讨论】:

  • 您不必使用匿名对象。您只需要创建一个Func<TOuter, TInner, TResult> resultSelector,它将告诉Enumerable.Join 如何根据两个键选择给定值。

标签: c# .net linq join


【解决方案1】:

您的代码对我来说很好 - 通过 ReferenceSource 进行跟踪,默认比较最终使用的是 ObjectEqualityComparer,它调用 Equals(),所以您的想法是正确的。

所以这取决于你如何实现EqualsGetHashCode。如果你覆盖一个,你应该覆盖两者,如MSDN states:

注意:如果你重写 GetHashCode 方法,你也应该重写 Equals,反之亦然。如果在测试两个对象是否相等时重写的 Equals 方法返回 true,则重写的 GetHashCode 方法必须为这两个对象返回相同的值。

请注意,您的 ID 类还需要正确处理这两种方法,因为 Plan 应该使用它来检查相等性并获取哈希码。

这个程序对我有用,只打印带有ID=2 的第二个条目(请注意,为简单起见,我制作了SomeOtherPropertyint,但这不会影响方法或代码):

class Program
{
    public class Plan
    {
        public int ID { get; set; }
        public Plan Parent { get; set; }
        public int SomeOtherProperty { get; set; }

        // added to show we don't care about this
        public string IgnoreMe { get; set; }

        public Plan(int id, int other, Plan parent, string ignore)
        {
            this.ID = id;
            this.SomeOtherProperty = other;
            this.Parent = parent;
            this.IgnoreMe = ignore;
        }

        public override bool Equals(object obj)
        {
            Plan other = (Plan)obj;
            // just check the relevant properties
            return this.ID == other.ID
                && this.SomeOtherProperty == other.SomeOtherProperty
                && this.Parent == other.Parent;

            // .. or alternatively
            //return (new { ID, SomeOtherProperty, Parent })
            //    .Equals(new { other.ID, other.SomeOtherProperty, other.Parent });
        }

        // nicked from http://stackoverflow.com/a/4630550/1901857
        public override int GetHashCode()
        {
            return new { ID, SomeOtherProperty, Parent }.GetHashCode();
        }

        // just to help debug
        public override string ToString()
        {
            return string.Format("[ID: {0}, Other:{1}, Parent:{2}]", ID, SomeOtherProperty, Parent);
        }
    }

    static void Main(string[] args)
    {
        var parentPlans = new Plan[] {
            new Plan(101, 2, null, "parent1"),
            new Plan(102, 3, null, "parent2"),
            new Plan(103, 4, null, "parent3"),
            new Plan(104, 5, null, "parent4")
        };

        List<Plan> oldPlans = new List<Plan>(new Plan[] {
            new Plan(1, 2, parentPlans[0], "old1"),
            new Plan(2, 3, parentPlans[1], "old2"),
            new Plan(3, 4, parentPlans[2], "old3"),
            new Plan(4, 5, parentPlans[3], "old4")
        });

        List<Plan> newPlans = new List<Plan>(new Plan[] {
            new Plan(11, 2, parentPlans[0], "new1"), // different ID
            new Plan(2, 3, parentPlans[1], "new2"),  // same
            new Plan(3, 14, parentPlans[2], "new3"), // different other ID
            new Plan(4, 5, parentPlans[2], "new4")   // different parent
        });

        foreach (var e in
            oldPlans.Join(newPlans, o => o, n => n, (o, n) => new { Old = o, New = n }))
        {
            Console.WriteLine(e.Old + " / " + e.New);
        };
    }
}

如果您认为 EqualsGetHashCode 的实现应该有效,请在问题中发布它们,也许它们不太正确。

【讨论】:

  • 我没有同时实现 Equals 和 GetHashCode,而是一个,然后尝试另一个(删除另一个)。我会尝试两者,看看它是否有效。
  • 这就是答案。我必须同时实现 Equals 和 GetHashCode(我没有意识到它之前抛出的警告表明这一点)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-16
  • 2011-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-01
  • 1970-01-01
相关资源
最近更新 更多