0
我有很多類與往往很多屬性/字段primitive types或array/nullable原始類型。有沒有一種快速有效的方法讓班級公平?
Public Class ClassN
Public P1 As Integer
Public P2 As Byte()
Public P3 As String
Public P4 As Short?
'...
Public P17 As Boolean
Public P18 As Char()
End Class
在這一點上,我想出了使用attributes的解決方案和一個「平等服務類」的執行相等測試。但是有沒有更快,更高效的方法來實現呢?
背後
<AttributeUsage((AttributeTargets.Field Or AttributeTargets.Property), AllowMultiple:=False, Inherited:=False)> _
Public Class EquatableAttribute
Inherits Attribute
End Class
Public Class ClassN
Implements IEquatable(Of ClassN)
<Equatable()> Public P1 As Integer
<Equatable()> Public P2 As Byte()
<Equatable()> Public P3 As String
<Equatable()> Public P4 As Short?
'...
<Equatable()> Public P17 As Boolean
<Equatable()> Public P18 As Char()
Public Overrides Function Equals(obj As Object) As Boolean
Return Me.Equals(TryCast(obj, ClassN))
End Function
Public Overloads Function Equals(obj As ClassN) As Boolean Implements System.IEquatable(Of ClassN).Equals
Return EqualityServices.Equals(Of ClassN)(Me, obj)
End Function
End Class
Public NotInheritable Class EqualityServices
Private Sub New()
End Sub
Public Overloads Shared Function Equals(Of T)(obj1 As T, obj2 As T) As Boolean
If (obj1 Is Nothing) Then
Return obj2 Is Nothing
End If
If (obj2 Is Nothing) Then
Return False
End If
Dim type As Type = GetType(T)
Dim members As MemberInfo() = Nothing
If (Not EqualityServices.EquatableAttributeCache.TryGetValue(type, members)) Then
members = New MemberInfo(-1) {}
For Each info As MemberInfo In type.GetMembers((BindingFlags.Public Or BindingFlags.Instance))
If (info.GetCustomAttributes(EqualityServices.EquatableAttributeType, False).Length > 0) Then
Select Case info.MemberType
Case MemberTypes.Field
Exit Select
Case MemberTypes.Property
With DirectCast(info, PropertyInfo)
If ((Not .CanRead) OrElse (.GetIndexParameters().Length > 0)) Then
Continue For
End If
End With
Exit Select
Case Else
Continue For
End Select
ReDim Preserve members(members.Length)
members(members.Length - 1) = info
End If
Next
EqualityServices.EquatableAttributeCache.Add(type, members)
End If
If (members.Length > 0) Then
Dim value1 As Object = Nothing
Dim value2 As Object = Nothing
For Each info As MemberInfo In members
Select Case info.MemberType
Case MemberTypes.Field
With DirectCast(info, FieldInfo)
type = .FieldType
value1 = .GetValue(obj1)
value2 = .GetValue(obj2)
End With
Exit Select
Case MemberTypes.Property
With DirectCast(info, PropertyInfo)
type = .PropertyType
value1 = .GetValue(obj1, Nothing)
value2 = .GetValue(obj2, Nothing)
End With
Exit Select
Case Else
Continue For
End Select
If (type.BaseType Is EqualityServices.ArrayType) Then
If (Not EqualityServices.SequenceEqual(CType(value1, Array), CType(value2, Array))) Then
Return False
End If
Else
If (Not Object.Equals(value1, value2)) Then
Return False
End If
End If
Next
Return True
End If
Return False
End Function
Private Shared Function SequenceEqual(ByVal array1 As Array, array2 As Array) As Boolean
If (array1 Is Nothing) Then
Return array2 Is Nothing
End If
If (array2 Is Nothing) Then
Return False
End If
If (array1.Rank <> array2.Rank) Then
Return False
End If
If (array1.Length <> array2.Length) Then
Return False
End If
Dim length As Integer = (array1.Length - 1)
If (length > -1) Then
Dim list1 As IList = CType(array1, IList)
Dim list2 As IList = CType(array2, IList)
For index = 0 To length
If (Not Object.Equals(list1.Item(index), list2.Item(index))) Then
Return False
End If
Next
End If
Return True
End Function
Private Shared ReadOnly EquatableAttributeCache As New Dictionary(Of Type, MemberInfo())
Private Shared ReadOnly EquatableAttributeType As Type = GetType(EquatableAttribute)
Private Shared ReadOnly ArrayType As Type = GetType(Array)
End Class
ReSharper的可生成相關的'Equals' ,'GetHashCode'等或您的'IEqualityComparer'代碼。你只需要ReSharper。 – sloth
謝謝@DominicKexel,我會看看它。 –
@DominicKexel由於沒有人回答我的問題,你可以總結你的評論作爲答案,我會接受嗎? –