Custom Generic.IEqualityComparer(Of T) - Compiler Errors - vb.net

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.

Related

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.

Can I override and overload the same function in vb.net?

Is it possible to override and overload the same function at the same time in vb.net?
Something like this:
Public Overrides overloads Function Delete(ByVal code As Integer) As Boolean
You can use overloads keyword if your class contains more than one method with same name and different signature. Please see the below code and mark the answer if it's useful
Public Class Base
Public Overridable Function Delete(code As Integer) As Boolean
Return True
End Function
End Class
Public Class Derived
Inherits Base
Public Overloads Overrides Function Delete(code As Integer) As Boolean
Return MyBase.Delete(code)
End Function
Public Overloads Function Delete(code As Integer, id As Integer) As Boolean
Return MyBase.Delete(code)
End Function
End Class
No, you can't do that, because once you change the signature of the method (which would be the only reason you would want to do this), Overrides will fail to find the underlying method that you want to override.
However, you can have your override or overload call the appropriate internal method or throw an exception if the overridden version is not to be used.
Public Overrides Function Delete(ByVal code As Integer) As Boolean
Throw New Exception("Please use the two parameter version")
End Function
Public Overloads Function Delete(ByVal code As Integer, param2 As Boolean) As Boolean
MessageBox.Show("This is the right one")
Return True
End Function
It might help to think of it this way. You're asking the function to do 2 different things.
Overload calls basically the same function with a different set of parameters.
Override calls the same function with the same parameters to do something different.

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.

Create a shared IEqualityComparer

I'm doing some LINQ which requires a custom comparer, so I created a new class implementing IEqualityComparer. However, when I use it, I have to create an instance of it each time.
Dim oldListOnly = oldList.Except(newList, New MyEqualityComparer)
Dim newListOnly = newList.Except(oldList, New MyEqualityComparer)
I may be misunderstanding how .NET works, but it seems wasteful to create a new comparer each time. I really just want one instance (the equivalent of static in C++/C#).
So I tried creating a "static" class, which in vb.net is a module. But got an 'Implements' not valid in Modules error.
I then tried making the Equals and GetHashCode function shared methods on my class, but got this error: Methods that implement interface members cannot be declared 'Shared'.
Any ideas how to accomplish my goal here? Or am I simply misunderstanding what's going behind the scenes?
Your understanding is correct, although the waste is unlikely to be noticeable. For your situation, you could use the singleton pattern, which usually goes something like this:
Public Class MyEqualityComparer
Implements IEqualityComparer(Of whatever)
Private Sub New()
'no outsider creation
End Sub
Private Shared ReadOnly _instance As New MyEqualityComparer()
Public Shared ReadOnly Property Instance As MyEqualityComparer
Get
Return _instance
End Get
End Property
'other code
End Class
Why not simply do
Dim comparer = New MyEqualityComparer
Dim oldListOnly = oldList.Except(newList, comparer )
Dim newListOnly = newList.Except(oldList, comparer )
There needs to be an instance of a concrete type that implements IEqualityComparer. What you can do with a module, however, is define a public instance which is initialized to "New EqualityComparer". You can then pass that default instance to the Except method.
Something like:
Public Module MyComparer
Public acmeComparer As acmeCompareType
Public Class acmeCompareType
Implements IEqualityComparer(Of System.Drawing.Point)
Public Function Equals1(x As System.Drawing.Point, y As System.Drawing.Point) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of System.Drawing.Point).Equals
Return Math.Abs(x.X) = Math.Abs(y.X) AndAlso Math.Abs(x.Y) = Math.Abs(y.Y)
End Function
Public Function GetHashCode1(obj As System.Drawing.Point) As Integer Implements System.Collections.Generic.IEqualityComparer(Of System.Drawing.Point).GetHashCode
' Note that obj is a struct passed by value, so we can safely modify it here
' (without affecting the caller's instance)
obj.X = Math.Abs(obj.X)
obj.Y = Math.Abs(obj.Y)
Return obj.GetHashCode
End Function
End Class
End Module

Generic List Equivalent of DataTable.Rows.Find using VB.NET?

I am converting DataTables to a generic list and need a quick and easy way to implement a Find function. It seems I am going to have to use a Predicate. Upon further investigation, I still can't seem to re-create the functionality. I have this predicate...
Private Function ByKey(ByVal Instance As MyClass) As Boolean
Return Instance.Key = "I NEED THIS COMPARISON TO BE DYNAMIC!"
End Function
And then calling it like this...
Dim Blah As MyClass = MyList.Find(AddressOf ByKey)
But I have no way to pass in a key variable to this predicate to do the comparison, as I used to do with DataTable...
Dim MyRow as DataRow = MyTable.Rows.Find(KeyVariable)
How can I setup a predicate delegate function in VB.NET to accomplish this?
Do not recommend LINQ or lambdas because this is question is regarding .NET version 2.0.
Just put your predicate in a class instance:
Public Class KeyMatcher
Public Sub New(ByVal KeyToMatch As String)
Me.KeyToMatch = KeyToMatch
End Sub
Private KeyToMatch As String
Public Function Predicate(ByVal Instance As MyClass) As Boolean
Return Instance.Key = KeyToMatch
End Function
End Class
and then:
Dim Blah As MyClass = MyList.Find(AddressOf New KeyMatcher("testKey").Predicate)
We can even get a little fancy and make this generic:
Public Interface IKeyed(Of KeyType)
Public Key As KeyType
End Interface
Public Class KeyMatcher(Of KeyType)
Public Sub New(ByVal KeyToMatch As KeyType)
Me.KeyToMatch = KeyToMatch
End Sub
Private KeyToMatch As KeyType
Public Function Predicate(ByVal Instance As IKeyed(Of KeyType)) As Boolean
Return Instance.Key = KeyToMatch
End Function
End Class
And then make your MyClass type implement the new IKeyed interface