Create a shared IEqualityComparer - vb.net

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

Related

Get a Field Object, not FieldInfo, from a VB Class Instance

I am trying to iterate through objects (fields) in a class and invoke a method on each object. Each object is of a different type. Here is the parent class:
Public Class MySettings
Public IdentifyByFacType As RadioButtonSetting
Public WtrFacTypes As ListSetting
Public OilFacTypes As ListSetting
Public GroupByRef As CheckboxSetting
Public GroupRefAttr As TxtboxSetting
End Class
Here is part of one of the sub-object classes:
<Serializable>
Public Class TxtboxSetting
<XmlIgnore()>
Public MyControl As Windows.Forms.TextBox
<XmlIgnore()>
Public DefaultSetting As String
Private _SavedSetting As String
Public Property SavedSetting As String
Get
Return _SavedSetting
End Get
Set(value As String)
_SavedSetting = value
CurrentValue = value
End Set
End Property
Public Sub New()
End Sub
Public Sub New(DefaultSetting As String, MyControl As Windows.Forms.TextBox)
Me.DefaultSetting = DefaultSetting
Me.MyControl = MyControl
End Sub
Public Sub RestoreDefault()
CurrentValue = DefaultSetting
End Sub
End Class
All of the sub-objects of the MySettings class, like GroupRefAttr for example, have the same methods and properties, but the internal code is different.
So I will have several classes like the MySettings class, and each one will have different sub-objects. Given an instance of such a class, I want to automatically iterate through the fields and call a method RestoreDefault on each one. I don't want to have to know what objects exist in the MySettings class. Rather, knowing that they all have the RestoreDefaultmethod, I want simply call the method on each object.
Despite much searching, I have not found a way to do this. With reflection, I can only get this far:
Dim Opts as New MySettings
For Each var In Opts.GetType.GetFields
Dim RestoreDefault As System.Reflection.MethodInfo = var.FieldType.GetMethod("RestoreDefault")
RestoreDefault.Invoke(Opts, Nothing)
Next
However, in the line RestoreDefault.Invoke(Opts, Nothing), I can't just pass in Opts, as I am dealing with a field in Opts, not Opts itself. A statement like this would work: RestoreDefault.Invoke(Opts.GroupRefAttr, Nothing), but that requires me to know the objects in the MySettings class ahead of time, and that defeats the purpose. Is there a way to grab field instance objects at runtime and pull this off?
When you invoke the RestoreDefault method you need to invoke it on the setting (i.e., the value of the field), not the class containing the setting. Changing your code to this should fix your problem:
Dim Opts as New MySettings
For Each var In Opts.GetType.GetFields
Dim setting As Object = var.GetValue(Opts)
Dim RestoreDefault As System.Reflection.MethodInfo = var.FieldType.GetMethod("RestoreDefault")
RestoreDefault.Invoke(setting, Nothing)
Next
However, if you introduce either a base class or an interface you should be able to get rid of some or all of the reflection. The container setting class can have a collection of settings that each have a shared base class or interface with a RestoreDefault method. The container setting class will then call this method through the base class or interface without having to use reflection.
The base class:
Public MustInherit Class BaseSetting
Public MustOverride Sub RestoreDefault
End Class
A specific settings class:
Public Class TxtboxSetting
Inherits BaseSetting
Public Overrides Sub RestoreDefault()
' Specific implementation
End Sub
End Class
On any class deriving from BaseSetting you can now call the RestoreDefault method without having to use reflection.
However, considering your design you might still want to use reflection to get the settings containd in the MySettings class. You can do it like this:
Dim settings = From fieldInfo in Opts.GetType.GetFields
Where GetType(BaseSetting).IsAssignableFrom(fieldInfo.FieldType)
Select DirectCast(fieldInfo.GetValue(Opts), BaseSetting)
For Each setting In settings
setting.RestoreDefault()
Next
Reflection is used to find all the fields deriving from BaseSetting and then RestoreDefault is called on each field. This method does not suffer from the "magic string" problem where your code depends on the name of the RestoreDefault method represented in a string.
(Also, calling the MySettings class the parent is a bit misleading because there is nothing inheriting from MySettings. Instead this class contains other settings.)
All of the sub-objects of the MySettings class, like GroupRefAttr for example, have the same methods and properties, but the internal code is different.
In that case, the sub-object types should be defined such that they implement a common interface that demands these same methods and properties exist. For now, I'll name that interface IControlSetting. Then, your For loop looks something like this:
Dim Opts as New MySettings
For Each var In Opts.GetType.GetFields
Dim setting As IControlSetting = TryCast(var.GetValue(Opts), IControlSetting)
If setting Is Nothing Then Continue
setting.RestoreDefault()
Next
Additionally, I'd change your MySettings type to encapsulate a dictionary or IControlSetting objects. Then you can just iterate the dictionary to check each of the objects, rather than needing reflection. That might look like this:
Public Class MySettings
Private allSettings As Dictionary(Of String, IControlSetting)
Public Sub New()
allSettings = new Dictionary(Of String, IControlSetting)()
allSettings.Add("IdentifyByFacType", New RadioButtonSetting())
allSettings.Add("WtrFacTypes", New ListSetting())
allSettings.Add("OilFacTypes", New ListSetting())
'...
End Sub
Public Property IdentifyByFacType As RadioButtonSetting
Get
Return DirectCast(allSettings("IdentifyByFacType"), RadioButtonSetting)
End Get
'The setters may be optional, depending on how you expect to use these
Set(ByVal value As RadioButtonSetting)
allSettings("IdentifyByFacType") = value
End Set
End Property
Public Property WtrFacTypes As ListSetting
Get
Return DirectCast(allSettings("WtrFacTypes"), RadioButtonSetting)
End Get
Set(ByVal value As ListSetting)
allSettings("WtrFacTypes") = value
End Set
End Property
Public Property OilFacTypes As ListSetting
Get
Return DirectCast(allSettings("OilFacTypes"), RadioButtonSetting)
End Get
Set(ByVal value As ListSetting)
allSettings("OilFacTypes") = value
End Set
End Property
'...
Public Sub RestoreAllDefaults()
For Each setting As KeyValuePair(Of String, IControlSetting) In allSettings
setting.Value.RestoreDefault()
Next setting
End Sub
End Class

Setting Up These Types While Keeping It Properly Structured

I'm completely stuck in a situation and I have no idea on where to go from here. I'm creating a very large project, so my goal is to keep the code itself as clean as possible and keeping as many hacks as possible out of the mix.
Here is the situation.
I have a class called Woo_Type, it is the parent of my many derived classes.
Public MustInherit Class Woo_Type
Private Shared TypeList As New Dictionary(Of String, Woo_Type)
Public MustOverride Sub SetValue(ByVal val As Object)
Public MustOverride Function GetValue() As Object
Public Shared Function GetTypeFromName(ByVal name As String) As Woo_Type
Return TypeList(name)
End Function
Public Shared Sub AddType(ByVal name As String, ByVal def As Woo_Type)
TypeList.Add(name, def)
End Sub
End Class
I have many classes that Inherit from Woo_Type that have similar structures to this:
Public Class Woo_tpInt
Inherits Woo_Type
Private value As Integer = 0
Public Overrides Function GetValue() As Object
Return value
End Function
Public Overrides Sub SetValue(val As Object)
value = val
End Sub
End Class
I want to be able to do things like:
Woo_Type.GetTypeFromName("int")
And have it return something like the class or something...
At this point I'm really confused as to what I want and I didn't know if anybody had any suggestions. To make sure that GetTypeFromName worked correctly, I had in an Initializer sub the following:
Public Sub InitializeTypes()
Woo_Type.AddType("int", Woo_tpInt)
Woo_Type.AddType("String", Woo_tpInt)
End Sub
But I quickly realized that-that obviously doesn't work either.
So this may seem confusing but I'm basically wondering how to better structure this so that everything works...
What do you want to do with the result? Are you sure you don't simply need generics?
Public Class WooType(Of T)
Public Property Value As T
End Class
Public Class Test
Public Sub Foo()
Dim int As New WooType(Of Integer)
int.Value = 42
Dim str As New WooType(Of String)
str.Value = "Forty-Two"
End Sub
End Class
If what you want to do is get the type itself (as opposed to an object), I would recommend using reflection rather than trying to reinvent the wheel. For instance, to get the Woo_tpInt type, you could do this:
Dim a As Assembly = Assembly.GetExecutingAssembly()
Dim t As Type = a.GetType("WindowsApplication1.Woo_tpInt") ' Change WindowsApplication1 to whatever your namespace is
If you want to use a shorter name like "int" to mean "WindowsApplication1.Woo_tpInt", you could create a dictionary to store the translation table, for instance:
Dim typeNames As New Dictionary(Of String, String)
typeNames.Add("int", GetType(Woo_tpInt).FullName)
Dim a As Assembly = Assembly.GetExecutingAssembly()
Dim t As Type = a.GetType(typeNames("int"))

Private Variable Instantiation: When Defined or Within Constructor?

I don't know if this has been asked before, but we're having a discussion about it today at my job. Should private variables (that are shared/static) be instantiated when they are dimensioned/defined, or is it a better practice to do this inside of a constructor?
For example, this seems perfectly fine to me...
Public Class IpCam
Private Const HOST As String = "http://test.com/url/example"
Private Shared _Example As New OurClass(HOST)
Public Shared ReadOnly Property Example() As OurClass
Get
Return _Example
End Get
End Property
End Class
But others are telling me that it should be done like this...
Public Class IpCam
Private Const HOST As String = "http://test.com/url/example"
Private Shared _Example As OurClass
Public Sub New()
_Example = New OurClass(HOST)
End Sub
Public Shared ReadOnly Property Example() As OurClass
Get
Return _Example
End Get
End Property
End Class
What is the difference? Is there a common consensus as to which one to use?
It's really a matter of preference. I think what's more important is consistency: if you instantiate a few variables inline, and others in a constructor, it can get harder to maintain, as it's unclear what is instantiated where.
A good idea is to keep variable declarations just above your constructor (so you don't have to jump around to find all the variable instantiations), and instantiate everything inline. For those few objects which require more complex initialization code, you can use a constructor.
I wonder if your second example is a hangover from the old VB6 days when good practise meant generally avoiding As New declarations because it wasn't optimal (auto-instantiation meant a run-time check each time) and you could never reliably test the instance for Is Nothing etc.
Member variables are initialized before the constructor; otherwise everything else is equivalent, so it's entirely up to you. I would go for what's more legible/maintainable/leads to fewer errors.
One benefit to initializing the variables inline is that you do not have to remember to put the initialization in each constructor or make sure each other constructor calls the one with the initialization. Take this code for example:
Public Class Person
Public Sub New()
_name = "asdlfkj"
End Sub
Public Sub New(ByVal age As Integer)
_age = age
End Sub
Private _name As String
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
Private _age As Integer = 17
Public ReadOnly Property Age As Integer
Get
Return _age
End Get
End Property
End Class
Calling the first constructor will put in a default name, but calling the second will not.
Conversely, if you ever need to initialize the variable different ways for different constructors, I would definitely say to initialize in the constructor.

Method to "override" shared Members in child classes

At the moment I'm trying to create a kind of model in vb.net which can be used to create/fetch database entrys.
I created a main class Model with a shared function to fetch the datasets, e.g. Model.find().
Now I'd like to create Classes which inherit the main Model-Class, e.g. a separate one for users: UserModel.find() => "SELECT * FROM users".
What I need now is to find a way to tell the Class which table it should use. I thought about an abstract String "table" which is a constant in each "child-model", but how could this be implemented as it's not possible to override shared members?
Thanks in advance!
Edit: Maybe this will make it a little clearer what I mean:
Public Class Model
Public Shared _controller As Controller
Public Shared table As String
Protected Shared tableFields As String()
Shared reader As Npgsql.NpgsqlDataReader
Public Shared Function find()
Dim a As ArrayList = New ArrayList
'Test if the tablefields are already known to the class, if not, get them
If tableFields Is Nothing Then
getTableFields()
End If
Dim query As String = "SELECT " + String.Join(", ", tableFields) + " FROM " + table
reader = _controller.executeReader(query)
While reader.Read
o = New Model
Dim v As New Hashtable
For Each field In tableFields
v(field) = reader(field)
Next
o.values = v
a.Add(o)
End While
reader.Close()
Return DirectCast(a.ToArray(GetType(Model)), Model())
End Function
Public values As Hashtable
Public Sub New()
End Sub
End Class
So I want a shared method which finds all database entries and gives back an array of instances of its own type, e.g. Model().
That's why I wanted to keep the find-method shared and not bound to an instance.
I think you could use Generics. Here I´ve pasted an example
All the classes in your domain could inherit from Entity class
Public MustInherit Class Entity
'...
End Class
Your Model class, with your method Find
Public Class Model
Public Shared Sub Find(Of T As Entity)()
' You could know the name of T to find the table
Dim tableName As String = GetType(T).Name
'...
End Sub
End Class
One class of your domain, for example: User class
Public Class User
Inherits Entity
' ...
End Class
And finally, an example of how could you instantiate the Find method
Model.Find(Of User)()
'...
I dunno if this is what you mean, do you find this helpfull?
You could make your main class abstract and each subclass will have to return its "own" table name via its own implementation (e.g. getTableName). This way, you would only have to maintain you method logic in the main class.
It is common to use the Singleton design pattern in such cases: create an instance method, overridden by inheriting classes. Each inheriting class should have that instance method return a Singleton object related to that class.
Here is one way of doing it:
MustInherit Class BaseClass
Public MustOverride Function getTableName() As String
End Class
Class Class1
Inherits BaseClass
Private Shared TableName As String = "myTable1"
Public Overrides Function getTableName() As String
Return TableName
End Function
End Class
Class Class2
Inherits BaseClass
Private Shared TableName As String = "myTable2"
Public Overrides Function getTableName() As String
Return TableName
End Function
End Class
EDIT: a whole different approach.
You can have the base class hold some dictionary, which relates class types (or type names) with the correct table:
Class BaseClass
Private Shared myDictionary As New Collections.Generic.Dictionary(Of Type, String)
Friend Shared Sub RegisterType(ByVal childType As Type, ByVal tableName As String)
myDictionary.Add(childType, tableName)
End Sub
Public Shared Function getTableName(ByVal childType As Type) As String
Return myDictionary.Item(childType)
End Function
End Class
Class Class1
Shared Sub New()
BaseClass.RegisterType(GetType(Class1), "table1")
End Sub
End Class
Class Class2
Shared Sub New()
BaseClass.RegisterType(GetType(Class2), "table2")
End Sub
End Class
Shared (static) objects or object members can't be inherited or overrided. Inheritence is for instance of an object. Since you do not have to instantiate a static class you can't inherit from it. The same with the methods. A static method shouldn't be virtual (Overridable in VB) as it defines a method that perform tasks with no instance of the class. Then this makes it impossible to use instance fields or properties within a static (Shared in VB) method. This is a bad design trying so.
In fact, every static (Shared) classes should be marked as NotInheritable in VB, and defining the default empty constructor only. This is a leak from VB in regards of OOP concepts.

How to setup return value for a readonly property using RhinoMocks in VB.NET?

I'm using RhinoMock in VB.NET and I need to set the return value for a readonly list.
Here's what I want to do (but doesn't work):
dim s = Rhino.Mocks.MockRepository.GenerateStub(of IUserDto)()
s.Id = guid.NewGuid
s.Name = "Stubbed name"
s.Posts = new List(of IPost)
It fails on the compile because Posts is a readonly property.
Then I tried a lambda expression, which works fine for Function calls, but not so much for Properties. This fails to compile.
s.Stub(Function(x As IUserDto) x.Posts).Return(New List(Of IPost))
Next (failing) attempt was to use SetupResults, but this failed stating that it cannot be used in Playback mode.
Rhino.Mocks.SetupResult.For(s.Posts).Return(New List(Of IPost))
Which brings me back to my question:
How do I setup a return value for a readonly property using RhinoMocks in VB.NET?
Is IUserDto an interface? If it is then it should just work. If it isn't, then the problem could be that the readonly property in question is not overridable. RhinoMocks can only mock properties/methods which are defined in an interface or can be overridden.
Here is my (clumsy) attempt at proving that the lambda syntax should work:
Imports Rhino.Mocks
Public Class Class1
Public Sub Test()
Dim s = MockRepository.GenerateMock(Of IClass)()
Dim newList As New List(Of Integer)
newList.Add(10)
s.Stub(Function(x As IClass) x.Field).Return(newList)
MsgBox(s.Field(0))
End Sub
End Class
Public Class AnotherClass
Implements IClass
Public ReadOnly Property Field() As List(Of Integer) Implements IClass.Field
Get
Return New List(Of Integer)
End Get
End Property
End Class
Public Interface IClass
ReadOnly Property Field() As List(Of Integer)
End Interface
i.e. I would get a message box with the number 10 displayed on it (I didn't bother to try hooking up a unit-testing framework with this but that shouldn't make a difference) when Class1.Test is invoked.
Hope that helps (it was an interesting exercise trying to work with RhinoMocks in VB.NET in anycase).