支持 IEquatable 的多种比较类型
Support multiple comparison-types for IEquatable
我重载了现在看起来像这样的 Equals 方法:
Public Overloads Function Equals(other As Part) As Boolean _
Implements IEquatable(Of Part).Equals
If other Is Nothing Then
Return False
End If
Return (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
End Function
如您所见,我正在根据 PartName 和 PartId 进行比较。并像下面这样使用它:
Console.WriteLine(vbLf & "Contains(""1734""): {0}", parts.Contains(New Part() With { _
.PartId = 1334, _
.PartName = "chain rin8g" _
}))
除此之外,我还希望能够单独比较 PartId 或 partName。所以我所做的是创建枚举:
Public Enum EqualsComparmission
PartId
PartName
PartId_and_PartName
End Enum
所以我所做的是添加额外的方法:
Public Overloads Function Equals(other As Part, compParameter As EqualsComparmission) As Boolean
If other Is Nothing Then
Return False
End If
Dim result As Boolean
Select Case compParameter
Case EqualsComparmission.PartId
result = (Me.PartId.Equals(other.PartId))
Case EqualsComparmission.PartName
result = (Me.PartName.Equals(other.PartName))
Case EqualsComparmission.PartId_and_PartName
result = (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
Case Else
End Select
Return result
End Function
但在那之后我无法使用例如:
Console.WriteLine(vbLf & "Contains(""1734""): {0}",
parts.Contains(New Part() With { _
.PartId = 1334, _
.PartName = "chain rin8g" _
}), EqualsComparmission.PartId)
整个零件类:
Imports System.Collections.Generic
' Simple business object. A PartId is used to identify the type of part
' but the part name can change.
Public Class Part
Implements IEquatable(Of Part)
Public Property PartName() As String
Get
Return m_PartName
End Get
Set(value As String)
m_PartName = Value
End Set
End Property
Private m_PartName As String
Public Property PartId() As Integer
Get
Return m_PartId
End Get
Set(value As Integer)
m_PartId = Value
End Set
End Property
Private m_PartId As Integer
Public Overrides Function ToString() As String
Return "ID: " & PartId & " Name: " & PartName
End Function
Public Overrides Function Equals(obj As Object) As Boolean
If obj Is Nothing Then
Return False
End If
Dim objAsPart As Part = TryCast(obj, Part)
If objAsPart Is Nothing Then
Return False
Else
Return Equals(objAsPart)
End If
End Function
Public Overrides Function GetHashCode() As Integer
Return PartId
End Function
Public Overloads Function Equals(other As Part) As Boolean _
Implements IEquatable(Of Part).Equals
If other Is Nothing Then
Return False
End If
Return (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
End Function
Public Overloads Function Equals(other As Part, compParameter As EqualsComparmission) As Boolean
If other Is Nothing Then
Return False
End If
Dim result As Boolean
Select Case compParameter
Case EqualsComparmission.PartId
result = (Me.PartId.Equals(other.PartId))
Case EqualsComparmission.PartName
result = (Me.PartName.Equals(other.PartName))
Case EqualsComparmission.PartId_and_PartName
result = (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
Case Else
End Select
Return result
End Function
' Should also override == and != operators.
End Class
编辑进一步讨论:
我想测试一些东西,因为如果 'Remove' 方法指的是 IEqutable 的 Equals 方法(根据 MSDN),我再次实现 Equtable 并修改了 Equals 方法以便为正确删除做好准备。不幸的是,当我像下面这样调用 remove 时,无论我定义什么,它总是会出现 EqualsComparmission.PartId 情况 - 这种情况:EqualsComparmission.PartId_and_PartName
它转到 Equal 方法的这一部分:
Case EqualsComparmission.PartId
Return Me.PartId.Equals(other.PartId)
我是这样使用它的:
Dim deleted As Boolean = parts.Remove(New Part(EqualsComparmission.PartId_and_PartName) With { _
.PartId = 11, _
.PartName = "al7a" _
})
Console.WriteLine("Found and deleted: true/false: : " & deleted )
全班:
Imports System.Collections.Generic
Public Class Part
Implements IEqualityComparer(Of Part), IEquatable(Of Part)
Public Property ComparisonType As EqualsComparmission
Public Sub New(comparisonType As EqualsComparmission)
Me.ComparisonType = comparisonType
End Sub
Public Sub New()
End Sub
Public Property PartName() As String
Get
Return m_PartName
End Get
Set(value As String)
m_PartName = value
End Set
End Property
Private m_PartName As String
Public Property PartId() As Integer
Get
Return m_PartId
End Get
Set(value As Integer)
m_PartId = value
End Set
End Property
Private m_PartId As Integer
Public Overrides Function ToString() As String
Return "ID: " & PartId & " Name: " & PartName
End Function
Public Function Equals1(x As Part, y As Part) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Part).Equals
If x Is Nothing AndAlso y Is Nothing Then Return True
If x Is Nothing OrElse y Is Nothing Then Return False
Select Case ComparisonType
Case EqualsComparmission.PartId
Return x.PartId = y.PartId
Case EqualsComparmission.PartName
Return String.Equals(x.PartName, y.PartName)
Case EqualsComparmission.PartId_and_PartName
Return x.PartId = y.PartId AndAlso String.Equals(x.PartName, y.PartName)
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
End Function
Public Function GetHashCode1(obj As Part) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Part).GetHashCode
Select Case ComparisonType
Case EqualsComparmission.PartId
Return obj.PartId
Case EqualsComparmission.PartName
Return If(obj.PartName Is Nothing, 0, obj.PartName.GetHashCode())
Case EqualsComparmission.PartId_and_PartName
Dim hash = 17
hash = hash * 23 + obj.PartId
hash = hash * 23 + If(obj.PartName Is Nothing, 0, obj.PartName.GetHashCode())
Return hash
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
End Function
Public Overloads Function Equals(other As Part) As Boolean Implements IEquatable(Of Part).Equals
If other Is Nothing Then
Return False
End If
Select Case ComparisonType
Case EqualsComparmission.PartId
Return Me.PartId.Equals(other.PartId)
Case EqualsComparmission.PartName
Return Me.PartName.Equals(other.PartName)
Case EqualsComparmission.PartId_and_PartName
Return (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
Return (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
End Function
End Class
我会创建一个自定义的 IEqualityComparer(Of Part)
,它将枚举作为 属性 并作为构造函数参数。然后您可以将它用于大多数 LINQ 方法,例如 Contains
.
我的想法是:
Public Class PartComparer
Implements IEqualityComparer(Of Part)
Public Sub New(comparisonType As EqualsComparison)
Me.ComparisonType = comparisonType
End Sub
Public Property ComparisonType As EqualsComparison = EqualsComparison.PartId
Public Function Equals1(x As Part, y As Part) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Part).Equals
If x Is Nothing AndAlso y Is Nothing Then Return True
If x Is Nothing OrElse y Is Nothing Then Return False
Select Case ComparisonType
Case EqualsComparison.PartId
Return x.PartId = y.PartId
Case EqualsComparison.PartName
Return String.Equals(x.PartName, y.PartName)
Case EqualsComparison.PartId_and_PartName
Return x.PartId = y.PartId AndAlso String.Equals(x.PartName, y.PartName)
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
End Function
Public Function GetHashCode1(obj As Part) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Part).GetHashCode
Select Case ComparisonType
Case EqualsComparison.PartId
Return obj.PartId
Case EqualsComparison.PartName
Return If(obj.PartName Is Nothing, 0, obj.PartName.GetHashCode())
Case EqualsComparison.PartId_and_PartName
Dim hash = 17
hash = hash * 23 + obj.PartId
hash = hash * 23 + If(obj.PartName Is Nothing, 0, obj.PartName.GetHashCode())
Return hash
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
End Function
End Class
您可以这样使用它(与 Enumerable.Contains
一起使用,但也可以与其他 LINQ 方法一起使用):
Dim contains As Boolean = parts.Contains(New Part() With { _
.PartId = 1334, _
.PartName = "chain rin8g" _
}, New PartComparer(EqualsComparison.PartId_and_PartName))
根据您的评论,您希望通过提供给定的 Part
和 EqualsComparison
来删除 List(Of Part)
的一个(或多个)部分。你可以写一个像这样的扩展:
Module Extensions
<Extension()>
Public Sub Remove(partList As List(Of Part), partToDelete As Part, comparisonType As EqualsComparison, Optional onlyOne As Boolean = True)
Dim comparer = New PartComparer(comparisonType)
For i As Int32 = partList.Count - 1 To 0 Step -1
If comparer.Equals(partList(i), partToDelete) Then
partList.RemoveAt(i)
If onlyOne Then Return
End If
Next
End Sub
End Module
现在可以了:
Dim partToDelete = New Part With {.PartId = 4711}
parts.Remove(partToDelete, EqualsComparison.PartId)
我重载了现在看起来像这样的 Equals 方法:
Public Overloads Function Equals(other As Part) As Boolean _
Implements IEquatable(Of Part).Equals
If other Is Nothing Then
Return False
End If
Return (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
End Function
如您所见,我正在根据 PartName 和 PartId 进行比较。并像下面这样使用它:
Console.WriteLine(vbLf & "Contains(""1734""): {0}", parts.Contains(New Part() With { _
.PartId = 1334, _
.PartName = "chain rin8g" _
}))
除此之外,我还希望能够单独比较 PartId 或 partName。所以我所做的是创建枚举:
Public Enum EqualsComparmission
PartId
PartName
PartId_and_PartName
End Enum
所以我所做的是添加额外的方法:
Public Overloads Function Equals(other As Part, compParameter As EqualsComparmission) As Boolean
If other Is Nothing Then
Return False
End If
Dim result As Boolean
Select Case compParameter
Case EqualsComparmission.PartId
result = (Me.PartId.Equals(other.PartId))
Case EqualsComparmission.PartName
result = (Me.PartName.Equals(other.PartName))
Case EqualsComparmission.PartId_and_PartName
result = (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
Case Else
End Select
Return result
End Function
但在那之后我无法使用例如:
Console.WriteLine(vbLf & "Contains(""1734""): {0}",
parts.Contains(New Part() With { _
.PartId = 1334, _
.PartName = "chain rin8g" _
}), EqualsComparmission.PartId)
整个零件类:
Imports System.Collections.Generic
' Simple business object. A PartId is used to identify the type of part
' but the part name can change.
Public Class Part
Implements IEquatable(Of Part)
Public Property PartName() As String
Get
Return m_PartName
End Get
Set(value As String)
m_PartName = Value
End Set
End Property
Private m_PartName As String
Public Property PartId() As Integer
Get
Return m_PartId
End Get
Set(value As Integer)
m_PartId = Value
End Set
End Property
Private m_PartId As Integer
Public Overrides Function ToString() As String
Return "ID: " & PartId & " Name: " & PartName
End Function
Public Overrides Function Equals(obj As Object) As Boolean
If obj Is Nothing Then
Return False
End If
Dim objAsPart As Part = TryCast(obj, Part)
If objAsPart Is Nothing Then
Return False
Else
Return Equals(objAsPart)
End If
End Function
Public Overrides Function GetHashCode() As Integer
Return PartId
End Function
Public Overloads Function Equals(other As Part) As Boolean _
Implements IEquatable(Of Part).Equals
If other Is Nothing Then
Return False
End If
Return (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
End Function
Public Overloads Function Equals(other As Part, compParameter As EqualsComparmission) As Boolean
If other Is Nothing Then
Return False
End If
Dim result As Boolean
Select Case compParameter
Case EqualsComparmission.PartId
result = (Me.PartId.Equals(other.PartId))
Case EqualsComparmission.PartName
result = (Me.PartName.Equals(other.PartName))
Case EqualsComparmission.PartId_and_PartName
result = (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
Case Else
End Select
Return result
End Function
' Should also override == and != operators.
End Class
编辑进一步讨论:
我想测试一些东西,因为如果 'Remove' 方法指的是 IEqutable 的 Equals 方法(根据 MSDN),我再次实现 Equtable 并修改了 Equals 方法以便为正确删除做好准备。不幸的是,当我像下面这样调用 remove 时,无论我定义什么,它总是会出现 EqualsComparmission.PartId 情况 - 这种情况:EqualsComparmission.PartId_and_PartName
它转到 Equal 方法的这一部分:
Case EqualsComparmission.PartId
Return Me.PartId.Equals(other.PartId)
我是这样使用它的:
Dim deleted As Boolean = parts.Remove(New Part(EqualsComparmission.PartId_and_PartName) With { _
.PartId = 11, _
.PartName = "al7a" _
})
Console.WriteLine("Found and deleted: true/false: : " & deleted )
全班:
Imports System.Collections.Generic
Public Class Part
Implements IEqualityComparer(Of Part), IEquatable(Of Part)
Public Property ComparisonType As EqualsComparmission
Public Sub New(comparisonType As EqualsComparmission)
Me.ComparisonType = comparisonType
End Sub
Public Sub New()
End Sub
Public Property PartName() As String
Get
Return m_PartName
End Get
Set(value As String)
m_PartName = value
End Set
End Property
Private m_PartName As String
Public Property PartId() As Integer
Get
Return m_PartId
End Get
Set(value As Integer)
m_PartId = value
End Set
End Property
Private m_PartId As Integer
Public Overrides Function ToString() As String
Return "ID: " & PartId & " Name: " & PartName
End Function
Public Function Equals1(x As Part, y As Part) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Part).Equals
If x Is Nothing AndAlso y Is Nothing Then Return True
If x Is Nothing OrElse y Is Nothing Then Return False
Select Case ComparisonType
Case EqualsComparmission.PartId
Return x.PartId = y.PartId
Case EqualsComparmission.PartName
Return String.Equals(x.PartName, y.PartName)
Case EqualsComparmission.PartId_and_PartName
Return x.PartId = y.PartId AndAlso String.Equals(x.PartName, y.PartName)
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
End Function
Public Function GetHashCode1(obj As Part) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Part).GetHashCode
Select Case ComparisonType
Case EqualsComparmission.PartId
Return obj.PartId
Case EqualsComparmission.PartName
Return If(obj.PartName Is Nothing, 0, obj.PartName.GetHashCode())
Case EqualsComparmission.PartId_and_PartName
Dim hash = 17
hash = hash * 23 + obj.PartId
hash = hash * 23 + If(obj.PartName Is Nothing, 0, obj.PartName.GetHashCode())
Return hash
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
End Function
Public Overloads Function Equals(other As Part) As Boolean Implements IEquatable(Of Part).Equals
If other Is Nothing Then
Return False
End If
Select Case ComparisonType
Case EqualsComparmission.PartId
Return Me.PartId.Equals(other.PartId)
Case EqualsComparmission.PartName
Return Me.PartName.Equals(other.PartName)
Case EqualsComparmission.PartId_and_PartName
Return (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
Return (Me.PartId.Equals(other.PartId) And Me.PartName.Equals(other.PartName))
End Function
End Class
我会创建一个自定义的 IEqualityComparer(Of Part)
,它将枚举作为 属性 并作为构造函数参数。然后您可以将它用于大多数 LINQ 方法,例如 Contains
.
我的想法是:
Public Class PartComparer
Implements IEqualityComparer(Of Part)
Public Sub New(comparisonType As EqualsComparison)
Me.ComparisonType = comparisonType
End Sub
Public Property ComparisonType As EqualsComparison = EqualsComparison.PartId
Public Function Equals1(x As Part, y As Part) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Part).Equals
If x Is Nothing AndAlso y Is Nothing Then Return True
If x Is Nothing OrElse y Is Nothing Then Return False
Select Case ComparisonType
Case EqualsComparison.PartId
Return x.PartId = y.PartId
Case EqualsComparison.PartName
Return String.Equals(x.PartName, y.PartName)
Case EqualsComparison.PartId_and_PartName
Return x.PartId = y.PartId AndAlso String.Equals(x.PartName, y.PartName)
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
End Function
Public Function GetHashCode1(obj As Part) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Part).GetHashCode
Select Case ComparisonType
Case EqualsComparison.PartId
Return obj.PartId
Case EqualsComparison.PartName
Return If(obj.PartName Is Nothing, 0, obj.PartName.GetHashCode())
Case EqualsComparison.PartId_and_PartName
Dim hash = 17
hash = hash * 23 + obj.PartId
hash = hash * 23 + If(obj.PartName Is Nothing, 0, obj.PartName.GetHashCode())
Return hash
Case Else
Throw New NotSupportedException("Unknown comparison type for parts: " & ComparisonType.ToString())
End Select
End Function
End Class
您可以这样使用它(与 Enumerable.Contains
一起使用,但也可以与其他 LINQ 方法一起使用):
Dim contains As Boolean = parts.Contains(New Part() With { _
.PartId = 1334, _
.PartName = "chain rin8g" _
}, New PartComparer(EqualsComparison.PartId_and_PartName))
根据您的评论,您希望通过提供给定的 Part
和 EqualsComparison
来删除 List(Of Part)
的一个(或多个)部分。你可以写一个像这样的扩展:
Module Extensions
<Extension()>
Public Sub Remove(partList As List(Of Part), partToDelete As Part, comparisonType As EqualsComparison, Optional onlyOne As Boolean = True)
Dim comparer = New PartComparer(comparisonType)
For i As Int32 = partList.Count - 1 To 0 Step -1
If comparer.Equals(partList(i), partToDelete) Then
partList.RemoveAt(i)
If onlyOne Then Return
End If
Next
End Sub
End Module
现在可以了:
Dim partToDelete = New Part With {.PartId = 4711}
parts.Remove(partToDelete, EqualsComparison.PartId)