I am having a CA1067 violation on IEquatable(Of T) and can't solve it - vb.net

I have been trying for hours and a lot recode but can get rid of the CA1067 violation.
Using:
Visual Studio 2022, .Net v6.0.13, VB.NET
I will appreciate any help to solve the issue and insights in what I am doing wrong.
So the case is the following:
I have a template class SimNode(Of P,A) where P stands for the data type for parent and A for the data type of the three attributes of the node.
Public Class SimNode(Of P, A)
Implements ISimNode(Of P, A)
Implements IEquatable(Of SimNode(Of P, A))
'[a bunch of properties and methods]
Public Overridable Shadows Function Equals(other As SimNode(Of P, A)) As Boolean Implements IEquatable(Of SimNode(Of P, A)).Equals
If Not Parent.Equals(other.Parent) Then Return False
If Depth <> other.Depth Then Return False
....
Return True
End Function
End Class
I then needed to create another class called SimNode which inherits from SimNode(UShort,UShort) and requires an IEquatable(Of SimNode) because only unique SimNode instances will be added into a template 'container' -> Container(Of T as IEquatable(Of T)).
The word container is generic it could be e.g. a list, a dictionary or a hashset.
This new class is exactly the same as the parent class but with an extra member (list).
Private Class SimNode
Inherits SimNode(Of UShort, UShort)
Implements IEquatable(Of SimNode)
'[a bunch of properties and methods]
Private Shadows Function Equals(other As SimNode) As Boolean Implements IEquatable(Of SimNode).Equals
Return MyBase.Equals(other)
End Function
End Class
My equality criteria is still the same as the one in the parent class despite the extra list.
This approach is leading to a CA1067 violation and I just cannot get this correct.
I will appreciate very much any help!
I have try to follow the suggestions from Visual Studio but all lead to error. The suggestion of override the method Equals in the child class (SimNode) will produce obviously error because it can't override the base class since they have different signatures.
I also worked around this https://stackoverflow.com/questions/2441346/cascading-iequatableof-t
with no success.

After all the great feedback I came up to the answer that solved the violation.
The code is a bit out of how I would code but it seems that this is the correct way to do.
Some feedback on the answer will be great to know if I did this correctly and if this is what you guys were trying to tell me! ;)
Module Program
Sub Main()
Dim storage As New Container(Of Y)
End Sub
Private Class Container(Of T As IEquatable(Of T))
End Class
Private Class X(Of P, A)
Implements IEquatable(Of X(Of P, A))
Public ReadOnly Parent As P
Public ReadOnly Attribute As A
Public Sub New(parent As P, attribute As A)
Dim typ As Type : Dim datTyp As Integer
Dim acceptingTypes As Integer() = {6, 8, 10, 12} '{Byte, USHort, UInteger, ULong}
'check the type of P.
typ = GetType(P) : datTyp = Type.GetTypeCode(typ)
If Not acceptingTypes.Contains(datTyp) Then Throw New ArgumentException("Type 'P' is not acceptable.", NameOf(P))
'check the type of A.
typ = GetType(A) : datTyp = Type.GetTypeCode(typ)
If Not acceptingTypes.Contains(datTyp) Then Throw New ArgumentException("Type 'A' is not acceptable.", NameOf(A))
Me.Parent = parent : Me.Attribute = attribute
End Sub
Public Overridable Function IEquatable_Equals(other As X(Of P, A)) As Boolean Implements IEquatable(Of X(Of P, A)).Equals
If Not Parent.Equals(other.Parent) Then Return False
If Not Attribute.Equals(other.Attribute) Then Return False
Return True
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Return DirectCast(Me, IEquatable(Of X(Of P, A))).Equals(TryCast(obj, X(Of P, A)))
End Function
Public Overrides Function GetHashCode() As Integer
Return Parent.GetHashCode() + Attribute.GetHashCode()
End Function
End Class
Private Class Y
Inherits X(Of UShort, UShort)
Implements IEquatable(Of Y)
Public ReadOnly Lines As List(Of Integer)
Public Sub New(parent As UShort, attribute As UShort)
MyBase.New(parent, attribute)
Lines = New List(Of Integer)
End Sub
Public Overloads Function Equals(other As Y) As Boolean Implements IEquatable(Of Y).Equals
Return MyBase.IEquatable_Equals(other)
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Return DirectCast(Me, IEquatable(Of Y)).Equals(TryCast(obj, Y))
End Function
Public Overrides Function GetHashCode() As Integer
Return Parent + Attribute 'Or Mybase.GetHashCode()?
End Function
End Class
End Module

Related

How to override properties in a derived class using generics

I have the following class setup and I don't understand why it won't compile.
I get the following error on "Public Overrides Property F As T"
'Public Overrides Property F As T' cannot override 'Public Overridable Property F As X' because they differ in return types.
This confuses me because I constrained T to be derived from X.
Can someone explain how I can accomplish this goal? In the end I need to have Class A and Class B where B inherits from A. Where A has an overridable property F of type X, and B overrides F with a type that is derived from X. Any suggestions are appreciated. If this cannot be done, I'd be interested to know why (limitation of .NET?) and how I should go about this.
Public Class X
End Class
Public Class Y
Inherits X
End Class
Public Class A
Public Overridable Property F As X
End Class
Public Class A(Of T As X)
Inherits A
Public Overrides Property F As T
End Class
Public Class B
Inherits A(Of Y)
Public Overrides Property F As Y
End Class
Thank-you!
New answer. I don't think it's possible (exactly as you requested it), namely B overrides F with a type that is derived from X, as you saw.
But you could hold Y in a private field in B and expose it through F. Then you'd need to cast F to Y to access whatever functionality Y provides over X. This can be done without changing A.
Public Class X
Public Overridable Function Z() As String
Return "X"
End Function
End Class
Public Class Y
Inherits X
Public Overrides Function Z() As String
Return "Y"
End Function
Public Function Foo() As String
Return "Bar"
End Function
End Class
Public Class A
Public Overridable Property F As X
End Class
Public Class B
Inherits A
Private _f As Y
Public Overrides Property F As X
Get
Return _f
End Get
Set(value As X)
_f = DirectCast(value, X)
End Set
End Property
End Class
Usage:
Dim a As New A()
Dim x As New X()
Dim b As New B()
Dim y As New Y()
a.F = x
Console.WriteLine(a.F.Z)
' Console.WriteLine(DirectCast(a.F, Y).Foo()) ' InvalidCastException
b.F = y
Console.WriteLine(b.F.Z)
Console.WriteLine(DirectCast(b.F, Y).Foo()) ' OK
Output
X
Y
Bar
I finally found a solution that does what I'm after using the Shadows keyword.
Imports System
Public Module Module1
Public Sub Main()
Dim a As New A()
Dim b As New B()
a.F = New X()
b.F = New Y()
Dim c As New Container()
c.Value = a
Console.WriteLine(c)
c.Value = b
Console.WriteLine(c)
End Sub
End Module
Public Class Container
Public Value As A
Public Overrides Function ToString() AS String
Return Value.ToString()
End Function
End Class
Public Class X
Public Overrides Function ToString() AS String
Return "X"
End Function
End Class
Public Class Y
Inherits X
Public Overrides Function ToString() AS String
Return "Y"
End Function
End Class
Public Class A
Public Overridable Property F As X
Public Overrides Function ToString() AS String
Return "A" + F.ToString()
End Function
End Class
Public Class B
Inherits A
Public Shadows Property F As Y
Public Overrides Function ToString() AS String
Return "B" + F.ToString()
End Function
End Class

dotNet iEquatyComparer doesn't get called by HashSet(of T)

I have been trying to implement a HashSet of custom objects but the object specific GetHashCode and Equals implementations never get called. Note - this is NOT a school project but is a database clean up where several people did parts of the work and I need to complete the analysis. Code is below and in VB.Net (same problem occurs in VS 2010, 2013, and 2015)
Imports HashSet_testing
Module Module1
Sub Main()
Const Source As String = "the quick brown fox jumped over the lazy red dog"
Dim stringhash As New HashSet(Of String)(Source.Split(" "c))
stringhash.UnionWith(Source.Split(" "c))
Debug.Print(String.Join(" ", stringhash))
Dim WordHash As New HashSet(Of word)
For Each s As String In Source.Split(" "c)
WordHash.Add(New word(s))
Next s
' Second pass; should load nothing
For Each s As String In Source.Split(" "c)
WordHash.Add(New word(s))
Next s
Debug.Print(String.Join(" ", WordHash))
End Sub
End Module
Class word
Implements IEqualityComparer(Of word), IEqualityComparer
Private _word As String = ""
Public Sub New(word As String)
_word = word
End Sub
Public Overrides Function ToString() As String
Return _word
End Function
Public Function Equals1(x As word, y As word) As Boolean Implements IEqualityComparer(Of word).Equals
Debug.Print("Equals({0}, {1} called", x, y)
Return x._word.Equals(y._word)
End Function
Public Function GetHashCode1(obj As word) As Integer Implements IEqualityComparer(Of word).GetHashCode
Debug.Print("GetHashCode1({0}}", obj)
If TypeOf obj IsNot word Then Return 0
Return _word.GetHashCode()
End Function
Private Function Equals2(x As Object, y As Object) As Boolean Implements IEqualityComparer.Equals
Debug.Print("Equals2({0}, {1})", x, y)
If TypeOf x Is word AndAlso TypeOf y Is word Then
Return (Equals1(CType(x, word), CType(y, word)))
Else
Return x.Equals(y)
End If
End Function
Public Function GetHashCode2(obj As Object) As Integer Implements IEqualityComparer.GetHashCode
Debug.Print("GetHashCode2{{0})", obj)
If TypeOf obj Is word Then Return GetHashCode1(obj) Else Return obj.GetHashCode()
End Function
End Class
If you want to use an IEqualityComparer with a HashSet, you must pass the IEqualityComparer to the constructor of the HashSet. That is why your methods are not being called here.
Dim WordHash As New HashSet(Of word)(New word("X"))
Based on the way your code is written I think you might be confusing IEqualityComparer(Of T) with IEquatable(Of T). The former is typically used when you want to change the way a class is compared for equality without changing that class itself. For example, if the target of the comparison is Word you would have a separate WordEqualityComparer class. That is also why you have to pass it to the constructor of the HashSet.
In your code, it looks like you're really intending to implement the comparison logic in the target class itself. In that case, you should override the base class Equals and GetHashCode methods in your word class, and optionally implement IEquatable(Of word). If you do this, you do not need to pass anything to the constructor of the HashSet and your methods will be called by default as expected.
Class word
Implements IEquatable(Of word)
Private _word As String = ""
Public Sub New(word As String)
_word = word
End Sub
Public Overrides Function ToString() As String
Return _word
End Function
Public Function Equals1(w As word) As Boolean Implements IEquatable(Of word).Equals
Debug.Print(String.Format("Equals1({0}) called on {1}", w, Me))
Return Me._word.Equals(w._word)
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Debug.Print(String.Format("Equals({0}) called on {1}", obj, Me))
If TypeOf obj Is word Then
Return Equals1(CType(obj, word))
Else
Return False
End If
End Function
Public Overrides Function GetHashCode() As Integer
Debug.Print(String.Format("GetHashCode() called on {0}", Me))
Return Me._word.GetHashCode()
End Function
End Class

How can I add a method to an interface with the implementing class as argument type in VB.NET?

I want to write an interface that contains a method that has an argument of the same type like the implementing class.
Currently I'm using this:
Public Interface IContent(Of T)
Function ContentEquals(content As IContent(Of T)) As Boolean
End Interface
Public Class SpecificContent
Implements IContent(Of Specific)
Private m_Member As String
Public Function ContentEquals(content As IContent(Of Specific)) As Boolean Implements IContent(Of Specific).ContentEquals
' Actually I need to access content.m_Member here
' Of course this doesn't work
' since not every IContent(Of Specific) has m_Member
' just because SpecificContent does.
Return True
End Function
End Class
The problem is, that this interface definition requires the implementation of ContentEquals to accept any object of any type implementing IContent(Of Specific), not just SpecificContent what I actually want to define.
Is there a way to define a method in the interface I that enforces a method that has an parameter of A for A Implements I and B for B Impements I, i. e. something like content As MyClass?
No, there isn't. And frankly, it's a good thing.
Think about it - how would you be able to use such interface? The point of an interface is that you can call certain method regardless of the type of the object that actually implements the interface. If the interface contained a method bound to its implementor's type, in variable of which type would you store that interface? And if you could store it in a variable, how would you pass it to a method that is not aware about the impelementor, only knowing about the interface? How would that method be able to call the interface, what would it pass as a parameter?
For this kind of equality testing you're supposed to override the Object.Equals method, or introduce another overload of Object.Equals that explicitly accepts your own type. You can still use an interface, too, but the parameter will have to be of type Object, just like it is with Object.Equals.
I found out a proper way to achieve what I want. The solution is interface-inheritance and a second generic for the type you want as parameter type. I knew I had done something similar before, but it was in Java and I couldn't quite remember.
These are my interfaces:
Public Interface IContentFactory(Of T, S As IContent(Of T))
Function CreateFrom(obj As T) As IComparableContent(Of T, S)
End Interface
Public Interface IContent(Of T)
Sub ApplyTo(obj As T)
End Interface
Public Interface IComparableContent(Of T, S As IContent(Of T))
Inherits IContent(Of T)
Function ContentEquals(content As S) As Boolean
End Interface
In my code, I can use these interfaces for a generic content handling class:
Public Class ContentHistory(Of T, S As IContent(Of T))
Private m_Obj As T
Private m_Factory As IContentFactory(Of T, S)
Private m_History As Stack(Of IComparableContent(Of T, S))
Public Sub New(obj As T, factory As IContentFactory(Of T, S))
If obj Is Nothing Then Throw New ArgumentNullException("obj")
If factory Is Nothing Then Throw New ArgumentNullException("factory")
m_Obj = obj
m_Factory = factory
m_History = New Stack(Of IComparableContent(Of T, S))
End Sub
Public Sub Backup()
Dim currentContent = m_Factory.CreateFrom(m_Obj)
If m_History.Count = 0 OrElse Not m_History.Peek().ContentEquals(currentContent) Then
m_History.Push(currentContent)
End If
End Function
Private Sub Restore()
If m_History.Count > 0 Then
m_History.Pop().ApplyTo(m_Obj)
End If
End Function
End Class
Now I can implement specific classes for content-objects and their factories, like so:
Public Class SpecificContentFactory
Implements IContentFactory(Of Specific, SpecificContent)
Public Function CreateFrom(obj As Specific) As IComparableContent(Of Specific, SpecificContent) Implements IContentFactory(Of Specific, SpecificContent).CreateFrom
Return New SpecificContent(obj)
End Function
End Class
Public Class SpecificContent
Implements IComparableContent(Of Specific, SpecificContent)
Private ReadOnly m_Value As String
Friend Sub New(obj As Specific)
m_Value = obj.Value
End Sub
Public Sub ApplyTo(obj As Specific) Implements IContent(Of Specific).ApplyTo
obj.Value = m_Value
End Sub
Public Function ContentEquals(content As SpecificContent) As Boolean Implements IComparableContent(Of Specific, SpecificContent).ContentEquals
Return (content.m_Value = m_Value)
End Function
End Class
To setup this content handler, all I have to do is
Dim obj = New Specific()
Dim history = New ContentHistory(Of Specific, SpecificContent)(obj, New SpecificContentFactory())
and I can use it like
obj.Value = "OldValue"
history.Backup
obj.Value = "OldValue"
history.Backup ' Nothing happens
obj.Value = "NewValue"
history.Backup
obj.Value = "EvenNewerValue"
Dim value = obj.Value ' "EvenNewerValue"
history.Restore
value = obj.Value ' "NewValue"
history.Restore
value = obj.Value ' "OldValue"
history.Restore ' Nothing happens
value = obj.Value ' "OldValue"
As long as I provide the SpecificContent and SpecificContentFactory implementations, I can use the ContentHistory(Of Specific, SpecificContent) for any type as Specific that I like.

Implementing generic IComparer in VB

I am trying to create a class implementing the generic IComparer of my own class "Stellungen" (which translates to positions, like on a chess or checkers board).
This is what I got:
Private Class comparer(Of Stellung)
Implements System.Collections.Generic.IComparer(Of Stellung)
Public Function Compare(x As Stellung, y As Stellung) As Integer Implements System.Collections.Generic.IComparer(Of Stellung).Compare
End Function
End Class
Problem is: inside the function I have no access to any fields of my class. If I start off with x. Intellisense will only give me .Equals, .GetHashCode - the methods you get on a type but not on an instance.
Visual Studio 10 also highights this, in the definition of the function the bits "x as Stellung" and "y as Stellung" are written in light blue, meaning it is a type and not an actual object.
So... what do I do?? How do I access the things I want to compare inside my class??
Thanks!
The fields are probably private and that is why you cant access them.
Make you classes implement the IComparable<T> interface. You can than use that in you comparer class.
Here is an example of a generic comparer class that compares objects that implements IComparable<T>.
Public Class GenericComparer(Of T As IComparable(Of T))
Inherits Comparer(Of T)
Public Overrides Function [Compare](ByVal x As T, ByVal y As T) As Integer
If (Not x Is Nothing) Then
If (Not y Is Nothing) Then
Return x.CompareTo(y)
End If
Return 1
End If
If (Not y Is Nothing) Then
Return -1
End If
Return 0
End Function
Public Overrides Function Equals(ByVal obj As Object) As Boolean
Dim comparer As GenericComparer(Of T) = TryCast(obj,GenericComparer(Of T))
Return (Not comparer Is Nothing)
End Function
Public Overrides Function GetHashCode() As Integer
Return MyBase.GetType.Name.GetHashCode
End Function
End Class
public class Stellung
Implements IComparable(Of Stellung)
Public Function CompareTo(ByVal value As Stellung) As Integer
'Here you should be able to access all fields.
End Function
End class
If you declare Private Class comparer(Of Stellung) then "Stellung" is just a placeholder for the type to use (like "T" in the tutorials).
Declare Private Class comparer, and Implements System.Collections.Generic.IComparer(Of Stellung) tells the compiler that you want to compare objects of type "Stellung", which btw makes the properties of Stellung visible in the editor.

Custom Generic.IEqualityComparer(Of T) - Compiler Errors

I am trying to implement a simple IEqulityComparer to use with LINQ collections. I have written the following code which is reduced to its simplest form for discussion purposes...
Public Structure bob
Dim SiteID As Integer
Dim fred As String
End Structure
Public Class insCompare
Implements System.Collections.Generic.IEqualityComparer(Of bob)
Public Function Equals(ByVal x As bob, ByVal y As bob) As Boolean
Return IIf(x.SiteID = y.SiteID, True, False)
End Function
Public Function GetHashCode(ByVal x As bob) As Integer
Return x.SiteID.GetHashCode()
End Function
End Class
The problem that I have is that both functions throw the compiler warning "function 'getHashCode' (or 'Equals') shadows an overridable method in the base class 'Object'. To override the base class method, this method must be declared 'Overrides'."
However, if I declare them as Overrides, I get the error "function 'GetHashCode' cannot be declared Overrides because it does not override a function in the base class."!!
I am also getting a compiler error on the "Implements" line to the effect that I must implement "getHashCode" but I presume that is a result of the first problem.
All my research indicates that I should be ok - anyone got any clues please?
This is a late answer to the question but as per the documentation you can do use the following. Notice the inclusion of the Overloads keyword.
Public Class MyModelComparer
Implements Generic.IEqualityComparer(Of MyModel)
Public Overloads Function Equals(x As MyModel, y As MyModel) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of MyModel).Equals
' do compare
End Function
Public Overloads Function GetHashCode(obj As MyModel) As Integer Implements System.Collections.Generic.IEqualityComparer(Of MyModel).GetHashCode
' do hashcode
End Function
End Class
Ok, it seems to get sorted by renaming the functions and declaring them as "Implements", although I have seen dozens of examples on the Web where this has not been the case.
However I now get a runtime exception which I will post separately.
Public Class insCompare
Implements System.Collections.Generic.IEqualityComparer(Of Object)
Public Function Equals1(ByVal x As Object, ByVal y As Object) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Object).Equals
Return IIf(x.SiteID = y.SiteID, True, False)
End Function
Public Function GetHashCode1(ByVal x As Object) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Object).GetHashCode
Return x.SiteID.ToString.ToLower.GetHashCode()
End Function
End Class
I am getting same problem. I am converting my C# code to VB.Net; Even Adding the Implements didn't help;
Using a shadow or overload removes all warning and errors. I wonder what is difference in behavior in both cases.
If I specify Overrides, I get an error.
Not specifying any of (overrides, overloads, shadows) gives a warning.
' <summary>
' Pair Comparator for maintaining uniquness in results.
' </summary>
Public Class PairComparer
Implements IEqualityComparer(Of Pair)
Public Shadows Function Equals(ByVal x As Pair, ByVal y As Pair) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Pair).Equals
If x.first = y.first AndAlso x.second = y.second Then
Equals = True
ElseIf x.first = y.second AndAlso x.second = y.first Then
Equals = True
Else
Equals = False
End If
End Function
Public Overloads Function GetHashCode(ByVal obj As Pair) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Pair).GetHashCode
GetHashCode = obj.first + obj.second
End Function
End Class
You're getting the compiler error because you are in VB.NET, not C#. In C#, having a method with the same signature as an interface method you need to implement makes the compiler wire it up for you automatically.
VB.NET requires that you explicitly implement say what method is being implemented. You can use the same name (it's encouraged), you just have to have that 'implements' clause.