我有以下
Dim query = From city In myCountry.Cities
From street In city.Streets
Select New StreetInfo With {.Name = street.Name, .Index = street.Index}
Distinct
现在。我再次指出,如果我有多个相同的街道(具有相同的Name
和 Index
),则StreetInfo列表包含所有重复的...
我应该如何为生成的StreetInfo值集合指定真正不同的值?
说,StreetInfo
类的定义如下:
Public Class StreetInfo
Public Property Name As String
Public Property Index As Integer
End Class
答案 0 :(得分:5)
Distinct
使用默认的相等比较器,这意味着您必须覆盖Equals
上的GetHashCode
和StreetInfo
才能使其正常工作。
答案 1 :(得分:1)
你可以覆盖GetHashCode
中的Equals
和StreetInfo
- 但鉴于它是可变的,它在现有形式中不会非常好。 (您可以创建两个等于一分钟然后不等于下一个的实例。这通常会导致令人困惑的调试体验。)或者,您可以使用匿名类型,确保使用只读“键”属性:
Dim query = From city In myCountry.Cities
From street In city.Streets
Select New With { Key .Name = street.Name, Key .Index = street.Index}
Distinct
此处,编译器将自动提供相等和哈希码。这相当于:
Dim query = From city In myCountry.Cities
From street In city.Streets
Select street.Name, street.Index
Distinct
有关详细信息,请参阅MSDN article on anonymous types。
如果您之后肯定需要StreetInfo
值并且您不想使其成为不可变的,那么您可以在之后添加另一个投影(选择)。我不知道是否可以在单个查询中在一个Distinct子句后附加另一个Select子句,但是你可以使用第二个表达式:
Dim query = From city In myCountry.Cities
From street In city.Streets
Select street.Name, street.Index
Distinct
Dim query2 = From street in query
Select New StreetInfo With {.Name = street.Name, _
.Index = street.Index}
答案 2 :(得分:1)
正如其他人所提到的,使用匿名类型是一个很好的解决方案,因为编译器会为您创建Equals
和GetHashCode
方法。但是,问题是您丢失了对原始对象(StreetInfo
)的引用,而是获得了一个不同的匿名类型列表。
相反,您可以使用自定义IEqualityComparer
根据所需的任何自定义字段比较原始对象。以下是可重复使用的CustomComparer
,可根据任何自定义条件比较任何对象。
Public Class CustomComparer(Of TSource As Class, TCompareType)
Implements IEqualityComparer(Of TSource)
Private getComparisonObject As Func(Of TSource, TCompareType)
Public Sub New(ByVal getComparisonObject As Func(Of TSource, TCompareType))
If (getComparisonObject Is Nothing) Then
Throw New ArgumentNullException("getComparisonObject")
End If
Me.getComparisonObject = getComparisonObject
End Sub
Public Function Equals(ByVal x As TSource, ByVal y As TSource) As Boolean
If (x Is Nothing) Then
Return (y Is Nothing)
ElseIf (y Is Nothing) Then
Return false
End If
Return EqualityComparer.Default.Equals(getComparisonObject(x), getComparisonObject(y))
End Function
Public Function GetHashCode(ByVal obj As TSource) As Integer
Return EqualityComparer.Default.GetHashCode(getComparisonObject(obj))
End Function
End Class
这允许您编写以下代码:
Dim query = From city In myCountry.Cities
From street In city.Streets
Select New StreetInfo With {.Name = street.Name, .Index = street.Index}
query = query.Distinct(new CustomComparer(function (street) New With {Key.Name = street.Name, Key.Index = street.Index}))
这将返回所有不同的StreetInfo
,而不是返回不同的匿名类型。
(注意:请原谅任何VB.NET语法问题......我在lambdas和anon类型之前切换到C#)