Factory method for generics in VB.NET - vb.net

I want to create a factory for generic classes in VB.NET and I am running into issues.
What I have are two interfaces:
IPersistentObject and IPManagerBase(Of T as IPersistentObject)
The logic is that for each type of peristent object I have a corresponding manager class handling query logic.
Now I have a base class like this:
public class PManagerBase(Of T as IPersistentObject) Implements IPManagerBase(of T)
So, now in the real world I have a persistent type "PUser" and a corresponding manager declared like this:
public class PUserManager implements PManagerBase(Of PUser)
I have about 100 of those persistent objects and corresponding manager classes.
Now I want to have a factory, which I would invoke like this (removing the details):
MyFactory.CreateManager<PUserManager>()
I am creating my Factory like this
public class MyFactory
public shared function CreateManager(Of T as {PManagerBase(Of IPersistentObject), New}) as T
return new T()
end function
end class
Looks great.
Now I want to invoke it:
Dim myManager = MyFactory.CreateManager<PUserManager>()
What happens?
I get a compile error: "PUserManager does not implement/inherit PManagerBase(Of IPersistentObject)". I get the message in German so this is a free tranlation.
What would I need to change to make this running?
It works if I declare my factory like this:
public class MyFactory
public shared function CreateManager(Of T as {PManagerBase(Of PUser), New}) as T
return new T()
end function
end class
But then the benefit is gone, since it works only for Managers of the PUser object.
A better solution is
public class MyFactory
public shared function CreateManager(Of T as {PManagerBase(Of U), New}, U as IPersistentObject) as T
return new T()
end function
end class
This works, but I have to call my factory method like this now:
Dim myManager = MyFactory.CreateManager<PUserManager, PUser>()
I don't like this since this is redundant and I don't need U at all in the function. In it's declaration PUserManager is tied to PUser.
Is there a better way? Why is PUserManager not inheriting from PManagerBase(Of IPersistentObject)?

This is a problem with generics, if you are using VS 2010 you may want to take a look at covariance and contravariance and modify your IPManagerBase definition accordingly.

Related

Named Constructor Idiom in VB.NET?

Is using the Named Constructor Idiom possible in VB.NET? I've found many examples in C#/C++ but can't quite wrap my head around how to use it in vb.net. Seems like a better method of keeping my code readable when involving a lot of constructors with similar argument types.
I've never heard this term before, but after a quick search it sounds vaguely like the Static Factory Pattern. The idea is you make the constructor private and use a shared (static in c#) public function to create the new object.
Public Class Foo
Private Sub New()
End Sub
Public Shared Function CreateNew(param as Object) as Foo
Dim obj as New Foo()
obj.Prop = param
return obj
End Function
End Class
You sure can make Named Constructors in VB. The pattern uses a static (Shared in VB) factory method on the class itself, so that the method can be named. (Other Factory patterns involve using a separate Factory class to provide the static method.)
System.Drawing.Color is a simple example. The pattern is implemented underneath as a static (Shared) property. Since no arguments are necessary, the Get method of a Property works just fine:
Public Shared ReadOnly Property Chartreuse As Color
Usage:
Dim favoriteColor as Color = Color.Chartreuse
Or you can make static factory methods to do the same thing.
Public Class TheClass
Public Sub New()
End Sub
Public Sub New(input As String)
'do something with input
End Sub
Public Shared Function MyNamedConstructor() As TheClass
Return New TheClass
End Function
Public Shared Function AnotherNamedConstructor() As TheClass
Return New TheClass("Another Name")
End Function
End Class
As for whether this pattern is "better" than overloading constructors, that's really an opinion. Personally, I would just overload the constructors. As you can see in the example above, the constructors need to be there anyway.
I suggest using the Named Constructor pattern when you have only a few possible ways to construct your class/struct, but consumers of your class/struct will be using those few constructors often, and with different input values to those constructors (as in the System.Drawing.Color example).
The Name in 'Named Constructor' doesn't represent a name for the constructor itself, but for the object resulting from the constructor. If your named constructor can be used to create two objects that don't feel right to give the same name to, then don't give the constructor that name.

How do I refer to two different classes by one name in vb.net

I have two classes to handle database operations, one for MySQL (DBMySQL), and another for SQLite (DBSQLite). The user chooses which database system to use.
The functions within the classes have the same names, but are obviously slightly different to handle the variations in databases.
I would like to refer to the chosen class by one name throughout the application. I have set a global variable DB.
In a procedure I can: Dim DB as New DBMySQL (or DBSQLite). This works within the procedure, but not globally, but I can see all the functions when coding.
If I instead use: DB = New DBMySQL, this works globally, but no class functions are displayed when coding.
Any alternatives?
Use the concept of inheritance, and create a MustInherit class with MustOverride methods and/or properties.
Public MustInherit Class AbstractDB
Public MustOverride Function MyQuery(input As Object) As Object
Public MustOverride Sub MyUpdateMethod(input As Object)
End Class
Public Class DBMySQL
Inherits AbstractDB
Public Overrides Function MyQuery(input As Object) As Object
End Function
Public Overrides Sub MyUpdateMethod(input As Object)
End Sub
End Class
Public Class DBSQLite
Inherits AbstractDB
Public Overrides Function MyQuery(input As Object) As Object
End Function
Public Overrides Sub MyUpdateMethod(input As Object)
End Sub
End Class
Then, when you want to use your classes, make your DB global variable of type AbstractDB. You could then create either DBMySql or DBSQLite and assign it to your DB variable. The method names will all be the same, because they all inherit the same base class. But each derived class must fill out the content of those methods on its own.
Dim DB as AbstractDB = New DBMySQL
You could also use an interface.
Public Interface IRepository
' common functions of MySQL and SQLLiteclasses
End Interface
Public Class MySQLRepository
Implements IRepository
End Class
Public Class SQLLiteRepository
Implements IRepository
End Class
Public Function GetDB(userChoice As String) As IRepository
If userChoice = "MySQL" Then
Return New MySQLRepository()
Else
Return New SQLLiteRepository
End if
End Function
Dim DB As IRepository = GetDB(userChoice)
This is a basic implementation of the Repository pattern. The example in the link is in C#, but, as you're probably aware, it's not easy finding examples in VB. Fortunately, there are lots of C# to VB converters.
The abstract example Sean Skelly gave should also work. You may want to research the difference between abstract classes and interfaces.

Implementing Inherited Interface with Overloaded Member vb.net

I am trying to implement a derived interface in a class. My interfaces and class are similar to the following. The Namespaces relate to different projects that hold these interfaces and the class:
Namespace ns1
Public Interface IParent
Function myFunction() As Double
End Interface
End ns1
Namespace ns2
Public Interface IDerived
Inherits ns1.IParent
Overloads / Shadows Function myFunction(ByRef myObject as Object) As Double
End Interface
End ns2
Namespace ns3
Public Class myClass
Implements ns2.IDerived
Public Function myFunction(ByRef obj as Object) As Double Implements ns2.IDerived.myFunction
End Function
End ns3
In the derived interface, I am trying to overload the function in a way that when I implement the derived interface, I only have to implement the function as defined therein - as is done with the code above on "myClass". However, I am getting an error saying I have to also implement the function from the parent interface (with the empty argument list). The error exists regardless of my using Overloads or Shadows on the function in the derived interface - both cause the error.
Is there anyway to accomplish what I am trying to do - implement only the derived interface's function in my class - using interfaces? If there is not a way using interfaces, can anyone suggest an alternate way? We really need to use interfaces and are trying to avoid using classes. That said, abstract classes my allow us to do all we need to do with these.
I have read a lot of info on all the topics covered by this question as every concept is pretty basic and well covered in online help. But, I have not found anything that I recognize as a direct solution to my specific issue.
Thanks in advance for any help.
I don't know if this is a typo but you have two distinct methods: one that takes no parameter, and another that takes an object, so the compiler requirement is legitimate.
If this is a typo and that you have only one method, say "myFunction()", then I fear VB.Net does not act like C# by simply hiding the base interface and allowing to only implement the derived one.
But you could easily fix this by forwarding:
Namespace ns1
Public Interface IParent
Function myFunction() As Double
End Interface
End Namespace
Namespace ns2
Public Interface IDerived
Inherits ns1.IParent
Function myFunction() As Double
End Interface
End Namespace
Namespace ns3
Public Class Class1
Implements ns2.IDerived
Public Function myFunction() As Double Implements ns2.IDerived.myFunction
Return 42
End Function
Private Function myFunction1() As Double Implements ns1.IParent.myFunction
Return myFunction()
End Function
End Class
End Namespace
Module Module1
Sub Main()
Dim cp As ns1.IParent = New ns3.Class1
cp.myFunction()
Dim cd As ns2.IDerived = New ns3.Class1
cd.myFunction()
End Sub
End Module
EDIT:
So was not a typo, here is the standard (good/best practice?) fix:
Public Class Class1
Implements ns2.IDerived
Public Function myFunction(ByRef obj As Object) As Double Implements ns2.IDerived.myFunction
End Function
Public Function myFunction() As Double Implements ns1.IParent.myFunction
Throw New NotImplementedException("'ns1.IParent.myFunction' has not been implemented because unicorns can't fly!")
End Function
End Class
I don't believe that what you want to accomplish is possible the way you are trying... As I recall when you inherit an Interface any class that implements your derived Interface is actually being told that it must implement both Interfaces rather allowing the options you have in a full class.
So effectively what you have in myClass is:
Namespace ns3
Public Class myClass
Implements ns2.IDerived
Implements ns1.IParent
Public Function myFunction(ByRef obj as Object) As Double Implements ns2.IDerived.myFunction
End Function
End ns3
So inheriting an interface is really just a way to enforce that a class implementing the derived interface must also implement the base interface.

VB.NET Forced Inheritance through multiple generations

I'm trying to wrap my head around inheritance/interfaces/implementation a bit better in .NET.
I have a class that's defined as follows (sort of):
Public Class Sheet
Property Name As String
Property Steps As List(Of [Step])
End Class
The thing is, [Step] is just a virtual, base class. There are 5 different concrete implementations of [Step]. To make matters a bit more complex, there are 3 DIRECT implementations of [Step], 2 of which are virtual. Each of those 2 has 2 subclasses that would concretely implement [Step].
So, here's how it looks:
Step
|-----------------|-----------------|
| | |
SubStepA SubStepB SubStepC
|----|----| |----|----|
| | | |
SubStepAA SubStepAB SubStepCA SubStepCB
So, SubStepB, SubStepAA, SubStepAB, SubStepCA and SubStepCB are the concrete implementations.
There are a couple of things that I'd like ANY Step to do, such as Clone().
So, I tried declaring the following in Step:
Public MustOverride Function Clone() As Step
The problem is that, when I attempt to implement that in SubStepAA, I can't declare the following:
Public Overrides Function Clone() As SubStepAA
If I do that, I get an error that the return types aren't the same.
Is the solution to this to just use a DirectCast call anytime I clone a concrete subclass? That seems odd and unsatisfying. It also just seems wrong. I mean, if I clone a SubStepAA object, I want to get back an object of type SubStepAA.
There's got to be a way to do this, right? I mean, I guess I could just declare each class the way it needs to be, but it also seems wrong to have to write 5 DIFFERENT Clone() methods that just HAPPEN to work in (essentially) the same way (creating a deep copy of the referenced object).
I've looked into using Interface declarations, but that seems to suffer from the same type mismatch error.
Please tell me that I'm just missing something basic!
Thanks!
As an aside, I have been doing some reading and I realize that there may be more optimized ways to do deep copies of object (e.g., through serialization/deserialization), but I'm still interested in this question, even if I choose to clone objects using a different approach.
This may not be exactly what you are hoping for, but you can meet all your requirements by using a generic base type, like this:
Public MustInherit Class [Step](Of T)
Public MustOverride Function Clone() As T
End Class
Public Class StepA
Inherits [Step](Of StepA)
Public Overrides Function Clone() As StepA
' ...
End Function
End Class
However, then, there would be no common Step base class that would be usable for all the derived types. For instance, there would be no way to do something like this:
Dim s As [Step] = New StepA() 'Won't work because there is no Step type, only a generic Step(T) type
Dim c As [Step] = s.Clone()
However, if you need to have a common base type like that, you could still do something like that, albeit with some additional complication:
Public Interface ICloneable(Of T)
Function Clone() As T
End Interface
Public MustInherit Class [Step]
Implements ICloneable(Of [Step])
Public MustOverride Function CloneBase() As [Step] Implements ICloneable(Of [Step]).Clone
End Class
Public MustInherit Class [Step](Of T As [Step])
Inherits [Step]
Implements ICloneable(Of T)
Public Overrides Function CloneBase() As [Step]
Return Clone()
End Function
Public MustOverride Function Clone() As T Implements ICloneable(Of T).Clone
End Class
Public Class StepA
Inherits [Step](Of StepA)
Public Overrides Function Clone() As StepA
' ...
End Function
End Class
If you did it that way, you would have that additional layer of abstraction where you could cast each concrete object as either a Step(T) or as a Step. For instance, you could then do this:
Dim s As [Step] = New StepA()
Dim c As [Step] = s.CloneBase()
But of course, this all begs the question, is it worth all this complication? The two simpler solutions would be to implement the interface independently on each derived class (and thereby forgo the ability to call clone from the base class), or else go with your first idea and just have the Clone method always return the base type.

Can I have a function with return type of the class itself in inherited classes? VB.NET

I have a parent class that is also a factory. For example:
Public Class Factory
Public Function clone() as Factory
' Some logic here
' return something
End Function
Public Function all() as List (Of Factory)
' Some logic here
' return something
End Function
End Class
And then an inherited one
Public Class BookFactory
inherits Factory
End Class
I can use inflection in the Factory class to generate the proper extended objects when called by the inherited one. myBookFactory.clone() will then return a BookFactory instance and not only a Factory instance.
The problem: this BookFactory instance will be cast as Factory, since the type of the function is Factory and not BookFactory.
I'd like to do something like
Public Class Factory
Public Function clone() as Me.GetType()
' Some logic here
' return something
End Function
Public Function all() as List (Of Me.GetType())
' Some logic here
' return something
End Function
End Class
So the returned value would be correctly cast and avoid having to do this each time:
Dim myBookFactory2 = DirectCast(myBookFactory1.clone(), myBookFactory1.getType())
How can I do this?
This seems to be a variation on asking for covariant return types. As you have noticed, this is not supported by VB.NET (or C# for that matter). Typically this is asked in the context of overriding virtual methods, where it is still not allowed. There are several alternatives, each with their own pros and cons.
Use a generic template argument to specify the derived class
This is similar to the way IComparable<T> is most commonly implemented.
Public Class Factory(Of T As Factory)
Public Function Clone() As T
'use GetType(T) to determine derived type
End Function
End Class
Public Class BookFactory
Inherits Factory(Of BookFactory)
End Class
Additionally, if you can add a New constraint to the Factory (eg: Factory(Of T {New, Factory(Of T)})) base class, you may be able to avoid using reflection.
However, this does not prevent the accidental (or potentially malicious) mistake of declaring a class like this:
Public Class EvilFactory
Inherits Factory(Of BookFactory)
'hmmm, now clone will be making the wrong type
End Class
Also, this approach makes it impossible to create a list of factories of different types without resorting to another base class below Factory(Of T) or declaring the list as being of object.
Make new methods on the derived classes that return the specific type you want.
Public Class Factory
Public Function Clone() As Factory
'create derived class, but return as base
End Function
End Class
Public Class BookFactory
Inherits Factory
Public Function CloneBooks() As BookFactory
Return CType(Me.Clone(), BookFactory)
End Function
End Class
This allows you to hide the cast for those times when you know you have a BookFactory and want to get another BookFactory. It also lets you treat all factory types polymorphically in the normal inheritance sense. However, if you have an object typed as Factory, you will still get back an object type as Factory.
Reconsider the inheritance relationship
Depending on how these classes are used, it may not make sense to use the inheritance relationship here. If you are only concerned with not retyping code, you may want to look into code generation instead.
You could potentially use generics to make the problem easier, but it won't remove the requirement to cast at some point. For example:
Public Class Factory(Of T)
Public Function clone() As Factory(Of T)
' Some logic here
' return something
End Function
Public Function all() As Collections.Generic.List(Of T)
' Some logic here
' return something
End Function
End Class
Public Class BookFactory
Inherits Factory(Of Book)
End Class