2015-01-05 33 views
3

假设我有这个对象,其中以下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 => 
    { 
     ... 
    }); 

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

但是有没有不同的方法?我可以覆盖GetHashCode吗?当我尝试这种方式时,似乎并没有将它称为该方法。我也试图压倒Equals,但它似乎并没有这么说。我应该覆盖==!=运营商吗?我可以明确地调用.GetHashCode()作为关键选择器字段(假设我忽略它)?

是否有可能让这个连接检查这两个对象的相等性而不会使关键字选择器复杂化?谢谢。

+0

您不必使用匿名对象。您只需创建一个'Func resultSelector',它将告诉'Enumerable.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的实现应该已经工作了,那么请将它们发布在问题中,也许它们不太正确。

+0

我没有实现BOTH Equals和GetHashCode,只有一个,然后尝试另一个(移除另一个)。我会试一试,看看它是否有效。 –

+1

这就是答案。我必须实现Equals和GetHashCode(我没有意识到它提前发出的警告表明这一点)。 –

相关问题