Implement IEquatable Get distinct objects - vb.net

This is not working for me. I couldn't find the answer on MSDN or elsewhere after having spent too much time on it. What am I missing?
Public Class PrinterInfo
Implements IEquatable(Of PrinterInfo)
Public PrinterName As String
Public PrinterDesc As String
'default equality comparer for class vb.net
Public Overloads Function Equals(ByVal other As PrinterInfo) As Boolean _
Implements IEquatable(Of PrinterInfo).Equals
Return other.PrinterName = Me.PrinterName
End Function
End Class
Public ReadOnly Property PrinterInfoList(ByVal Normal As NormalCopier) As List(Of PrinterInfo)
Get
Dim pList1 As List(Of PrinterInfo) = GetList
pList1.Sort()
Return pList1.Distinct.ToList
End Get
End Property
I get the list just fine but I want only distinct items. I tried to implement an equality comparer but it's not working. I'm getting multiple duplicates. What do I need to do to get only distinct values?
MSDN: Enumerable.Distinct(Of TSource)
MSDN: IEqualityComparer(Of T) Interface
This seems similar but I don't understand it
I'd like to avoid Linq GroupBy if I can. That just seems clumsy to me.

The documentation for Enumerable.Distinct(Of Source) says:
The default equality comparer, Default, is used to compare values of the types that implement the IEquatable<T> generic interface. To compare a custom data type, you need to implement this interface and provide your own GetHashCode and Equals methods for the type.
That's the part you're missing. You are expected to provide a GetHashCode() implementation in your class. If you look at the code examples given, you'll see it there too. And when you think about it, it makes sense. The implementation of Distinct uses a hash set internally, so it naturally requires a proper GetHashCode implementation to function properly.
In your case, try adding this to your PrinterInfo class:
Public Overrides Function GetHashCode() As Integer
Return Me.PrinterName.GetHashCode()
End Function

Related

Why am I getting a null reference exception on my IComparer sort?

I have a list of custom object types say
Dim a As New List(Of CustomType)
populated with instances. I have a comparer class that inherits
Public Class CustomTypeComparer
Implements IComparer(Of CustomType)
Public Function Compare(x As CustomType, y As CustomType) As Integer Implements IComparer(Of CustomType).Compare
...
End Function
End Class
that is called using the
a.Sort(New CustomTypeComparer)
method. The comparer's only method Compare() is called automatically, however occasionally the method fails because x is undefined or 'Not set to an instance of an object'.
I have scoured the list being sorted to check none of the elements are Nothing, confirmed with a watch on a.Contains(Nothing) which returns False and checked using other comparers that look at other parts of the object, none of those have problems with the list, only this one.
How can I study the problem any deeper? Is there any insight people can give on this issue?
Update:
Reading the reference source code of the framework, the list sort method uses the underlying Array.Sort() method. Taking a hint from that and I tried using the List.TrimExcess() method on the list, this has changed the behaviour and no Nothings are passed to the IComparer. A commenter discovered that IComparers are expected to compare nulls, which combines with the Array's underlying bound being greater than the array and silently having Nothings in it to generate expected functionality.
If you are just looking for debug help start CustomTypeComparer off like this
Public Class CustomTypeComparer
Implements IComparer(Of CustomType)
Public Function Compare(x As CustomType, y As CustomType) As Integer Implements IComparer(Of CustomType).Compare
If x Is Nothing Then
Stop
ElseIf y Is Nothing Then
Stop

Linqkit Generic Predicates with VB.NET

I recently came across the wonderful Linqkit library and I want to make use of Generic Predicates to create a function for mapping users to the data they have access too accross any table that contains our data mapping fields. (H1L1, H1L2, etc)
Based on the tutorial (C# only) I see that this is indeed possible but I'm stuck.
So far I've created an interface:
Public Interface IDataMap
ReadOnly Property H1L1() As String
ReadOnly Property H1L2() As String
ReadOnly Property H1L3() As String
ReadOnly Property H2L1() As String
ReadOnly Property H2L2() As String
ReadOnly Property H2L3() As String
ReadOnly Property H3L1() As String
ReadOnly Property H3L2() As String
ReadOnly Property H3L3() As String
End Interface
Adjusted the Linq class for a table I'd like to operate on by adding
Implements IDataMap
and mapped each of the respective classes properties to the interface. I probably should have extended the linq class but for now i've just hardcoded the changes into the class generated by VS.
<Global.System.Data.Linq.Mapping.ColumnAttribute(Storage:="_H1L1", DbType:="VarChar(30)")> _
Public ReadOnly Property H1L1() As String Implements IDataMap.H1L1
Get
Return Me._H1L1
End Get
End Property
But I'm not sure where to go from here... or where to put this function so it's accessible from anywhere in my project. My test function is basic:
Public Shared Function mapUserToData(Of TEntity As IDataMap)(H1L1 As String) As Expression(Of Func(Of TEntity, Boolean))
Return Function(x) (H1L1 = x.H1L1))
End Function
Evenually I want to be able to say something similar to this:
DB.someTables.Where(someTable.mapUserToData("345BDS"))
The only way intellisense allows me to see that "mapUserToData" is available is if I put the function inside of my Linq Class... but then it's not generic. If I put the function inline in my code behind intellisense doesn't see my "mapUserToData" function as a method on my table. Maybe this is because of language/namespace differences between C# and VB.NET?
I'm a newbie to both .Net and Linq so please forgive me in advance for that.
I can use the linqkit predicate function successfully on an adhoc basis using
Dim predicate = PredicateBuilder.False(Of someTable)()
predicate = predicate.Or(Function(p) p.H1L1 IsNot Nothing)
Dim PgmED = (From x In DB.someTables.Where(predicate) Select x).AsEnumerable()
But can't afford to replicate the data mapping logic each time I need it. If anyone knows how to help I will be forever in their debt!
Try putting the mapUserToData function in a module as an Extension Method. Make it an extension of the IDataMap Interface.
<Extension()> _
Public Function mapUserToData(Of TEntity As IDataMap)(ByVal objTarget As IDataMap, H1L1 As String) As Expression(Of Func(Of TEntity, Boolean))
Return Function(x) (H1L1 = x.H1L1)
End Function

Have implemented IEquatable correctly? Should I always override GetHashCode?

I saw the question posed here: Have I implemented Equals()/GetHashCode() correctly? but my c# is not as strong, and I am unfimiliar with IEquatable enough that I would like to see this in VB.NET if possible please.
My example code (The class will eventually use INotifyPropertyChanged when I get there):
Public Class Car
Implements ICloneable
Implements IEquatable(Of Car)
Public Property Make() As String
Get
Return m_Make
End Get
Set(ByVal value As String)
m_Make = value
End Set
End Property
Private m_Make As String
Public Property Model() As String
Get
Return m_Model
End Get
Set(ByVal value As String)
m_Model = value
End Set
End Property
Private m_Model As String
Public Function Clone() As Object Implements System.ICloneable.Clone
Return New Car() With { _
.Make = Me.Make, _
.Model = Me.Model _
}
End Function
Public Overloads Function Equals(ByVal other As Car) As Boolean Implements System.IEquatable(Of Car).Equals
Return other.Make = Me.Make AndAlso other.Model = Me.Model
End Function
End Class
Thanks,
You really do need to implement Overrides for the object.Equals and object.GetHashCode implementations.
Basically, implementing IEquatable(of T).Equals by itself will only work so long as the caller KNOWS to call IEquatable(of T).Equals instead of regular object.Equals.
Consider if you have an ArrayList of Cars and check if the list Contains(myCar), where myCar's Make and Model are the same as a car in the ArrayList...but the one in the ArrayList isn't actually the exact same instance. Contains would return false.
Worse yet, if you had a Hashtable or Dictionary, which uses GetHashCode to determine where to store entries, equality would never work because two cars with the same Make and Model would return different values for GetHashCode()
Basically, it comes down to you adding the following implementations to car:
Public Overrides Overloads Function Equals(obj As Object) As Boolean
Return TypeOf obj Is Car AndAlso Equals(DirectCast(obj, Car))
End Function
Public Overrides Function GetHashCode() As Int32
Dim hash As Int32 = 179 ' or something intelligent
hash = hash * 27 + Make.GetHashCode()
hash = hash * 27 + Model.GetHashCode()
Return hash
End Function
So the question I have is: why implement IEquatable at all? Why not just override Equals and GetHashCode?
Only implement IEquatable<T> for structs or sealed classes. Any legitimate implementation of IEquatable<T>.Equals(T) needs to have semantics compatible with the class's override of Object.GetHashCode(), which must in turn have semantics compatible with the class's override of Equals(Object). If a type is not sealed, the only way to ensure that derived types' implementation of IEquatable<T>.Equals(T) will be compatible with their override of Object.Equals(Object) will be to have the former method chain to the latter, effectively nullifying any advantage one might have obtained from implementing IEquatable<T> in the first place.
Implementing IEquatable<T> is often a big win for struct types (saves a boxing operation on every comparison), and a somewhat smaller win for other sealed types (saves a typecast on every comparison). Unless performance is critical, I'd probably skip it for most non-struct types, even if they're sealed.

Are generic operator overloads allowed in .NET 4?

I am assuming "No", but I cannot find conclusive proof on Google to back this assumption. Using keywords of 'vb.net "generic operator overload"' yields exactly 1 result, and removing 'overload' gives more, but no direct statement to the issue.
My thinking is given an abstract class, it'd be great to be able to implement a generic operator overload that a derived class can use in such a case when said operator overload has to return a New copy of the derived class, yet the code for each overload is the same. If that makes any sense.
This touches back to my previous questions on my custom Enum class and overloading the bitwise operators (And, Or, Not, & Xor), but, this particular thought was prompted by a mere curiosity of "Can it be done?".
Here's what one of my custom enums basically look like:
The parent, EBase is nothing special, just hosting common Name and Value properties, plus two shared operators, op_Equality and op_Inequality.
Friend NotInheritable Class EExample
Inherits EBase
Private Sub New()
End Sub
Friend Shared Function GetValue(ByVal Name As String) As Enums
Dim tmpOffset As Int32 = Array.IndexOf(_Names, Name)
Return If(HasContent(Name), If(tmpOffset <> -1, Values(tmpOffset), Nothing), Nothing)
End Function
' Num of Enums defined.
Friend Shared ReadOnly MaxEnums As Int32 = 5
' String literals.
Private Shared ReadOnly _Names As String() = New String() _
{"one_adam", "two_boy", "three_charles", "four_david", "five_edward"}
' Enums.
Friend Shared ReadOnly OneA As New Enums(_Names(0), 1)
Friend Shared ReadOnly TwoB As New Enums(_Names(1), 2)
Friend Shared ReadOnly ThreeC As New Enums(_Names(2), 4)
Friend Shared ReadOnly FourD As New Enums(_Names(3), 8)
Friend Shared ReadOnly FiveE As New Enums(_Names(4), 16)
' Enum Values Array.
Friend Shared ReadOnly Values As Enums() = New Enums() _
{OneA, TwoB, ThreeC, FourD, FiveE}
Friend NotInheritable Class Enums
Inherits EBase
Private Sub New()
End Sub
Friend Sub New(ByVal Name As String, ByVal Value As Int32)
MyBase.Name = Name
MyBase.Value = Value
End Sub
End Class
End Class
Here's how the things are used:
Dim Foo As EExample.Enums
Foo = EExample.TwoB
Debug.Print(Foo.Name)
will print two_boy
Now, given that, if I want to do the following:
Dim Foo as EExample.Enums
Foo = EExample.OneA Or EExample.FiveE
I have to define an operator overload for Or inside the EExample.Enums definition. How would this operator overload look?
Public Shared Operator Or(ByVal lhOp As Enums, ByVal rhOp As Enums) As Enums
Return New Enums(String.Concat(lhOp.Name, "|"c, rhOp.Name),
lhOp.Value Or rhOp.Value, True)
End Operator
I have to return a new EEXample.Enums object containing the Bitwise-Or'ed Value property of the parent EExample enums. For the name, I just concatenate the Name properties together with a pipe character until I think of something better.
Assume I have 20 enum classes similar to EExample. I have to duplicate all that operator overload code for each definition even though in the IDE, it looks the exact same. In IL, however, each overload is specific to the containing parent enum class:
.method public specialname static class MyAssembly.EExample/Enums
op_BitwiseOr(class MyAssembly.EExample/Enums lhOp,
class MyAssembly.EExample/Enums rhOp) cil managed
{ ... }
But! A generic operator overload would solve this problem if defined in EBase!
Friend Interface IEnums
Property Name As String
Property Value As Int32
End Interface
Public Shared Operator Or(Of T As IEnums)(ByVal lhOp As T, ByVal rhOp As T) As T
Return New T(String.Concat(lhOp.Name, "|"c, rhOp.Name),
lhOp.Value Or rhOp.Value, True)
End Operator
Then (in theory anyways), calling EExample.OneA Or EExample.FiveE would work because the compiler would know to call the generic operator overload from EBase, know that EExample.Enums matches the IEnums interface constraint, and automatically supply T.
That or I'm just swimming up a certain creek here without a paddle and over-analyzing things. But it's an interesting thought, no? What is StackOverflow's consensus? Do I need to lay off the Spice a little bit?
PS: I know that, in the last example, Return New T( ... ) is invalid, but I can't think of a proper syntax that would articulate the basic idea.
According to what I can see in the language specification, generic operators are not allowed. Section 9.8 says
The type of at least one of the operands or the return value must be the type that contains the operator.
and later when it describes the declaration syntax makes no accounting for a generic specifier as methods do in section 9.2.1.
Found a "workable" solution myself.
For the top-level EBase, I exposed the interface (IEnumBase) as a Friend, then created generic methods in EBase to handle the overload operators:
Protected Shared Function _
op_BitwiseOr(Of T As {IEnumBase, Class})(ByVal lhOp As T, ByVal rhOp As T, ByVal RetEnum As T) As T
RetEnum.Name = String.Concat(lhOp.Name, "|"c, rhOp.Name)
RetEnum.Value = (lhOp.Value Or rhOp.Value)
Return RetEnum
End Function
The trick here, is the generic method simply returns RetEnum back to the caller. In the derived Enums (i.e., EExample), I have:
Public Shared Shadows Operator Or(ByVal lhOp As Enums, ByVal rhOp As Enums) As Enums
Return EBase.op_BitwiseOr(lhOp, rhOp, New Enums)
End Operator
This allows me to keep the bulkier code defined once in EBase, and not replicated each time in my many derived enum classes. Those enum classes simply call on the parent's implementation and use generics to pass-in their sub-defined Enums implementation!
Yeah, not groundbreaking. I could do better, but this works well enough for my needs and doesn't over-inflate the codebase too much. It also reduces code duplication and technically makes maintenance easier, IMHO.
Still leaving Gideon Engelberth's answer as the accepted answer, however. My question initially asked if overloaded operators could be genericized, and he found the snippet on MSDN that says they can't.

Storing an object that implements multiple interfaces and derives from a certain base (.net)

In .net, it's possible to use generics so that a function can accept arguments which support one or more interfaces and derive from a base type, even if there does not exist any single type from which all valid argument types derive. For example, one could say:
Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(Param as T)
and be allowed to pass any derivative of SomeBaseType which implements both IInterface1 and IInterface2. This will work even if SomeBaseType does not support Interface1 and Interface2, and classes which do implement those interfaces don't share any common ancestor that also implements them.
This can be very convenient if one won't need to keep the parameter anywhere after the function has exited. Unfortunately, I can't figure out a way to persist the passed-in parameter in such a way that it can later be passed to a similar function, except perhaps by using Reflection. Is there any nice way of doing that?
The closest I've been able to come up with is to define an interface INest (perhaps not the best name--can anyone improve it?) thus:
Interface INest(Of Out T)
Function Nest() As T
End Interface
And for any interface that will be used in combination with others or with base-class "constraint", define a generic version as illustrated below
Interface IFun1
' Any members of the interface go here, e.g. ...'
Sub DoFun1()
End Interface
Interface IFun1(Of Out T)
' This one does nothing but inherit'
Inherits IFun1, INest(Of T)
End Interface
A class which will support multiple interfaces should declare itself as implementing the generic ones, with itself as the type argument.
Class test123a
Inherits sampleBase
Implements IFun1(Of test123a), IFun2(Of test123a), IFun3(Of test123a)
End Class
If that is done, one can define a function argument or class variable that supports multiple constraints thusly:
Dim SomeField as IFun1(Of IFun2(Of IFun3(Of sampleBase)))
and then assign to it any class derived from sampleBase, which implements those interfaces. SomeField will implement IFun1; SomeField.Nest will implement IFun2; SomeField.Nest.Nest will implement IFun3. Note that there's no requirement that IFun1, IFun2, IFun3, or sampleBase share any common derivation other than the generic interfaces inheriting from INest(Of T). Note also that, no matter how many INest-derived interfaces a class implements, it only needs to define one implementation of INest(Of T).Nest.
Not exactly beautiful, but there are two nice things about it: (1) any concrete class which in fact implements the necessary interfaces can be assigned directly to a field declared as above, without a typecast; (2) while fields which chain the types in a different order are not assignment compatible, they may be typecast to each other.
Is there any better way to store something in such a way that it's "known" to support multiple interfaces and derive from a certain base type? Given that one can write such code in a type-safe manner, it would seem like the .net 2.0 CLR could probably support such a thing quite nicely if compilers offered a little assistance. I'm unaware of any particularly nice approach with present compilers, though.
The best way I can think of is to make an abstract storage and generic implementation of this storage. For example (excuse my VB.NET):
MustInherit Class Storage
Public MustOverride Sub DoSomething()
End Class
Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
Inherits Storage
Public Overrides Sub DoSomething()
' do something with Value.
End Sub
Public Value As T
End Class
And usage
Dim S As Storage
Sub Foo(Of T As {IInterface1, IInterface2, SomeBaseType})(ByVal Param As T)
S = New Storage(Of T) With {.Value = Param}
End Sub
Sub UseS()
S.DoSomething();
End Sub
Update: Ok, because we may not be able identify in advance all of the actions:
MustInherit Class Storage
MustOverride ReadOnly Property SomeBaseType As SomeBaseType
MustOverride ReadOnly Property IInterface1 As IInterface1
MustOverride ReadOnly Property IInterface2 As IInterface2
End Class
Class Storage(Of T As {IInterface1, IInterface2, SomeBaseType})
Inherits Storage
Public Value As T
Public Overrides ReadOnly Property IInterface1 As IInterface1
Get
Return Value
End Get
End Property
Public Overrides ReadOnly Property IInterface2 As IInterface2
Get
Return Value
End Get
End Property
Public Overrides ReadOnly Property SomeBaseType As SomeBaseType
Get
Return Value
End Get
End Property
End Class