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();
如果Alpha
和Bravo
都从普通类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