LINQselect不同于匿名types

所以我有一个对象的集合。 确切的types并不重要。 从中我想提取一对特定属性的所有唯一对,因此:

myObjectCollection.Select(item=>new { Alpha = item.propOne, Bravo = item.propTwo } ).Distinct(); 

所以我的问题是:在这种情况下,将不同的使用默认对象等于(这将是无用的,因为每个对象是新的),或可以告诉做一个不同的等于(在这种情况下,相等值的阿尔法和布拉沃=>等于实例)? 有什么办法可以达到这个效果吗?

请阅读K. Scott Allen在这里的优秀post:

和所有平等…匿名types

简短的回答(我引用):

原来,C#编译器覆盖了匿名types的Equals和GetHashCode。 两个重写方法的实现使用该types上的所有公共属性来计算对象的哈希码并testing是否相等。 如果两个具有相同匿名types的对象具有相同的属性值 – 对象相等。

所以在返回匿名types的查询中使用Distinct()方法是完全安全的。

 public class DelegateComparer<T> : IEqualityComparer<T> { private Func<T, T, bool> _equals; private Func<T, int> _hashCode; public DelegateComparer(Func<T, T, bool> equals, Func<T, int> hashCode) { _equals= equals; _hashCode = hashCode; } public bool Equals(T x, T y) { return _equals(x, y); } public int GetHashCode(T obj) { if(_hashCode!=null) return _hashCode(obj); return obj.GetHashCode(); } } public static class Extensions { public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals, Func<T,int> hashCode) { return items.Distinct(new DelegateComparer<T>(equals, hashCode)); } public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals) { return items.Distinct(new DelegateComparer<T>(equals,null)); } } var uniqueItems=students.Select(s=> new {FirstName=s.FirstName, LastName=s.LastName}) .Distinct((a,b) => a.FirstName==b.FirstName, c => c.FirstName.GetHashCode()).ToList(); 

对不起,早些时候搞乱了格式化

我跑了一个小testing,发现如果属性是值types,它似乎工作正常。 如果它们不是值types,那么types需要提供自己的Equals和GetHashCode实现。 我想,弦乐会奏效。

有趣的是,它在C#中工作,但不在VB中

返回26个字母:

 var MyBet = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"; MyBet.ToCharArray() .Select(x => new {lower = x.ToString().ToLower(), upper = x.ToString().ToUpper()}) .Distinct() .Dump(); 

退货52 …

 Dim MyBet = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ" MyBet.ToCharArray() _ .Select(Function(x) New With {.lower = x.ToString.ToLower(), .upper = x.ToString.ToUpper()}) _ .Distinct() _ .Dump() 

你可以创build你自己的Distinct扩展方法,它采用lambdaexpression式。 这是一个例子

创build一个从IEqualityComparer接口派生的类

 public class DelegateComparer<T> : IEqualityComparer<T> { private Func<T, T, bool> _equals; private Func<T, int> _hashCode; public DelegateComparer(Func<T, T, bool> equals, Func<T, int> hashCode) { _equals= equals; _hashCode = hashCode; } public bool Equals(T x, T y) { return _equals(x, y); } public int GetHashCode(T obj) { if(_hashCode!=null) return _hashCode(obj); return obj.GetHashCode(); } } 

然后创build你的Distinct Extension方法

 public static class Extensions { public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals, Func<T,int> hashCode) { return items.Distinct(new DelegateComparer<T>(equals, hashCode)); } public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals) { return items.Distinct(new DelegateComparer<T>(equals,null)); } } 

你可以用这个方法find不同的项目

 var uniqueItems=students.Select(s=> new {FirstName=s.FirstName, LastName=s.LastName}) .Distinct((a,b) => a.FirstName==b.FirstName, c => c.FirstName.GetHashCode()).ToList(); 

如果AlphaBravo都从普通类inheritance,那么通过实现IEquatable<T> ,您将能够在父类中规定相等性检查。

例如:

 public class CommonClass : IEquatable<CommonClass> { // needed for Distinct() public override int GetHashCode() { return base.GetHashCode(); } public bool Equals(CommonClass other) { if (other == null) return false; return [equality test]; } } 

嘿,我有同样的问题,我find了解决办法。 你必须实现IEquatable接口或者简单地覆盖(Equals&GetHashCode)方法。 但是,这不是诀窍,GetHashCode方法中的技巧。 你不应该返回你的类的对象的哈希码,但你应该返回你想要比较的属性的哈希。

 public override bool Equals(object obj) { Person p = obj as Person; if ( obj == null ) return false; if ( object.ReferenceEquals( p , this ) ) return true; if ( p.Age == this.Age && p.Name == this.Name && p.IsEgyptian == this.IsEgyptian ) return true; return false; //return base.Equals( obj ); } public override int GetHashCode() { return Name.GetHashCode(); } 

正如你看到我有一个类叫有人有3个属性(名称,年龄,IsEgyptian“因为我”)在GetHashCode我返回的名称属性,而不是个人对象的散列。

试试看,它将工作ISA。 谢谢,Modather Sadik