使用匿名类型选择独立

我有一个对象集合。确切的类型并不重要。我想从中提取出一对特定属性的所有唯一对,如下所示:

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

因此,我的问题是: 在这种情况下,“清晰”会使用默认的对象等于(这对我来说毫无用处,因为每个对象都是新的) ,还是可以告诉它执行不同的等于(在这种情况下,等于 Alpha 和 Bravo = > 等于实例的值) ?如果这个不起作用,有什么办法能达到这个结果吗?

101927 次浏览

点击这里阅读 K · 斯科特 · 艾伦(K. Scott Allen)的精彩文章:

人人平等... 匿名类型

简短的回答(我引用) :

结果 C # 编译器覆盖了 用于匿名的 Equals 和 GetHashCode 类型的实现 重写的方法使用所有公共 类型上的属性,以计算 对象的哈希代码和测试 如果两个相同的对象 匿名类型都是一样的 属性的值 物体是相等的。

因此,在返回匿名类型的查询上使用 District ()方法是完全安全的。

如果 AlphaBravo都继承自一个公共类,那么您就可以通过实现 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];
}
}

我运行了一个小测试,发现如果属性是值类型,那么它似乎可以正常工作。如果它们不是值类型,那么该类型需要提供自己的 Equals 和 GetHashCode 实现才能工作。我觉得弦乐会奏效的。

您可以创建您自己的独特扩展方法,该方法采用 lambda 表达式

创建一个从 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();
}
}

然后创建“显著扩展”方法

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();
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();

抱歉之前的格式错误

有趣的是,它可以在 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()

嘿,我也遇到了同样的问题,我找到了解决办法。 您必须实现 IEqutable 接口,或者只是重写 (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();
}

正如你所看到的,我得到了一个名为 Person 的类,它有3个属性(Name,Age,IsEdgar“ Because I am”)。在 GetHashCode 中,我返回了 Name 属性的 hash 值,而不是 Person 对象。

试试看,它会工作 ISA。 谢谢, Sadik 院长

为了让它在 VB.NET 中工作,您需要在匿名类型的每个属性之前指定 Key关键字,就像这样:

myObjectCollection.Select(Function(item) New With
{
Key .Alpha = item.propOne,
Key .Bravo = item.propTwo
}).Distinct()

我一直在纠结这个问题,我以为 VB.NET 不支持这种类型的特性,但实际上它支持。