JOIN 对象集合的多个属性的正确方法?

Proper way to JOIN multiple properties on object collection?

假设我有一个对象,其中以下 3 个属性(其他已省略)构成了一个 "unique" 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 检查这两个对象的相等性而不会使键选择器复杂化?谢谢。

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

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

CAUTION: If you override the GetHashCode method, you should also override Equals, and vice versa. If your overridden Equals method returns true when two objects are tested for equality, your overridden GetHashCode method must return the same value for the two objects.

请注意,您的 ID class 也需要正确处理这两种方法,因为 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 
        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 的实现应该有效,那么请 post 他们在问题中,也许他们不太正确。