支持IEquatable的多种比较类型

时间:2015-01-08 11:14:46

标签: vb.net

我重载了现在看起来像的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。所以我所做的就是创建Enum:

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)

整个Part类:

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方法以准备正确删除。不幸的是,当我调用这样的删除时,无论我定义什么,它总是会转到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

1 个答案:

答案 0 :(得分:0)

我会创建一个自定义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))

根据您的评论,您希望通过提供给定的List(Of Part)Part来删除EqualsComparison的一个(或多个)部分。你可以写一个像:

这样的扩展名
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)