VB generics with constraints -- type casting and inheritance? - vb.net

Take this scenario:
Public Interface IMyClass
End Interface
Public mustinherit class MyBaseClass : implements IMyClass
End Class
public class MyClass : inherits MyBaseClass
End Class
public class MyModel(of t as IMyClass)
private Dim _parameter as t
Public Sub New(byval parameter As t)
_parameter As t
End Sub
End class
In my controller, I can do this with no problem:
Dim _myclass as IMyClass = new MyClass()
Can I do something similar with this:
Dim _myModel as MyModel(of IMyClass) = new MyModel(of MyClass)
???
My initial thought was wrong, as I thought the conversion could be done automatically, but it appears it is not done. Any way to achieve the same thing within .NET?
EDIT
I updated the MyModel class to show more of what I was doing. I want to constrain the instance I create, but then do what would be a narrowing conversion with traditional, non-generics code. Basically, my partial Razor views would require the explicit model, and those views end up rendering another view that will take that model and display it. Because the models all implement or inherit a class that implements IMyClass, all the methods should exist on all of the instances and should be callable but the types are not interchangable.

Let’s modify MyModel slightly, shall we?
Public Class MyModel(Of T As IMyClass)
Private _parameter As T
Public Sub Something(parameter As T)
_parameter = parameter
End Sub
End class
Public Class MyClassA : Inherits MyBaseClass
End Class
Public Class MyClassB : Inherits MyBaseClass
End Class
Dim _myModel As MyModel(Of IMyClass) = New MyModel(Of MyClassA)()
_myModel.Something(New MyClassB()) ' Boom!
If the assignment were allowed the last line would pose a problem: MyMode(Of MyClassA)._parameter has type MyClassA but the last line would assign an object of the (unrelated) type MyClassB. This is illegal and so VB forbids it.

Do you need multiple varieties of MyModel, or are you just attempting to require that the stored object be constrained to IMyClass?
Simplest approach (that might not do everything you need):
Public Interface IMyClass
Sub DoIt()
End Interface
Public Class MyModel
Private ReadOnly _parameter As IMyClass
Public Sub New(parameter As IMyClass)
_parameter = parameter
End Sub
Public Sub DoItToIt()
_parameter.DoIt()
End Sub
End Class
Public Class MyClassA
Implements IMyClass
Public Sub DoIt() Implements IMyClass.DoIt
End Sub
End Class
Public Class Tests
Public Sub Main()
Dim model1 As MyModel = New MyModel(New MyClassA)
model1.DoItToIt()
End Sub
End Class
Next step up in complexity is to define an interface IHasMyClass for classes that contain an IMyClass. This supports manipulations based on the allowed type, and the actual type, of the contained object:
Public Interface IMyClass
Sub DoIt()
End Interface
Public Interface IHasMyClass
Function GetIt() As IMyClass
Function GetItsType() As Type
Function GetAllowedType() As Type
End Interface
Public Class MyModel(Of T As IMyClass)
Implements IHasMyClass
Private ReadOnly _parameter As IMyClass
Public Sub New(parameter As IMyClass)
_parameter = parameter
End Sub
Public Sub DoItToIt()
_parameter.DoIt()
End Sub
Public Function GetItAsT() As T
Return _parameter
End Function
Public Function GetIt() As IMyClass Implements IHasMyClass.GetIt
Return _parameter
End Function
Public Function GetItsType() As Type Implements IHasMyClass.GetItsType
Return _parameter.GetType()
End Function
Public Function GetAllowedType() As Type Implements IHasMyClass.GetAllowedType
Return GetType(T)
End Function
End Class
Public Class MyClassA
Implements IMyClass
Public Sub DoIt() Implements IMyClass.DoIt
End Sub
End Class
Public Class Tests
Public Sub Main()
' Allow any IMyClass
Dim model1 As MyModel(Of IMyClass) = New MyModel(Of IMyClass)(New MyClassA)
model1.DoItToIt()
Dim it As IMyClass = model1.GetIt()
Dim allowedT As Type = model1.GetAllowedType()
' Restrict to MyClassA
Dim modelA As MyModel(Of MyClassA) = New MyModel(Of MyClassA)(New MyClassA)
modelA.DoItToIt()
Dim itA1 As IMyClass = modelA.GetIt()
Dim itA2 As MyClassA = modelA.GetItAsT()
Dim allowedTA As Type = modelA.GetAllowedType()
End Sub
End Class
In Tests(), notice that we now need to declare whether we are creating a MyModel that accepts ANY IMyClass MyModel(Of IMyClass), or one that requires a specific sub-class MyModel(Of MyClassA).
If we want to manipulate MyModels, that may be either of the above types, we use the common interface:
Dim model As IHasMyClass
model = model1
...
model = modelA
Or in your case, to support all the functionality of MyModel, rename IHasMyClass as IMyModel, and add the various MyModel functions, but instead of T, use IMyClass:
Public Interface IMyModel
Function GetIt() As IMyClass
Function GetItsType() As Type
Function GetAllowedType() As Type
Sub DoItToIt()
Function CompareIt(other As IMyClass) As Integer
End Interface
And make appropriate changes/additions to IMyClass and MyModel.
Then it becomes possible to do:
Dim model As IMyModel = modelA
If model.CompareIt(model1.GetIt()) > 0 ...

Related

VB if base class implements interface, does the derived class also need to implement?

I was analyzing a code. There we have a base class (not abstract) implementing an interface. Then we have a derived class of the base class which also implements the interface.
Interface:
Public Interface MainInterface
Function getMetaThreads(ByVal ThreadCount As Integer) As String()
Property Name() As String
Property TargetDirectory() As String
Property TimeOut() As Long
ReadOnly Property ExecutableAssembly() As String
ReadOnly Property IsVersionValid() As Boolean
End Interface
Base class:
Public Class BaseClass
Implements MainInterface
Public Sub print()
Console.WriteLine("BaseClass printing")
End Sub
Public ReadOnly Property ExecutableAssembly As String Implements MainInterface.ExecutableAssembly
...
End Property
Public ReadOnly Property IsVersionValid As Boolean Implements MainInterface.IsVersionValid
...
End Property
Protected strName As String = ""
Protected strTargetDirectory As String = ""
Protected lngTimeout As Long = 0
Public Property Name As String Implements MainInterface.Name
...
End Property
Public Property TargetDirectory As String Implements MainInterface.TargetDirectory
...
End Property
Public Property TimeOut As Long Implements MainInterface.TimeOut
...
End Property
Public Function getMetaThreads(ThreadCount As Integer) As String() Implements MainInterface.getMetaThreads
...
End Function
Public Overridable Function myOwnFunc() As String
Return ""
End Function
End Class
Derived Class:
Public Class SubClass
Inherits BaseClass
Implements MainInterface
Public Function getMetaThreads(ThreadCount As Integer) As String() Implements MainInterface.getMetaThreads
Return myOwnFunc()
End Function
Overrides Function myOwnFunc() As String()
Dim l As New List (Of String)
l.Add("44")
l.Add("33")
return l.ToArray()
End Function
End Class
Does it make sense to implement the interface in the derived class again? Is there a reason or a case where this becomes necessary? I think that having the base class implement the interface should be enough and implementing it in the interface is redundant.

Inheritance confusion vb.net

I searched over 20 articles and I am still slightly confused with inheritance. I have three classes as such:
Class A
Private _Mode As String
Public Function returnMode() As String
Return _Mode
End Function
Class B
Inherits Class A
Private _Mode As String = "modeb"
Class C
Inherits Class A
Private _Mode As String = "modec"
Now any time I create a B or C class, I would like the object to return the child class _Mode. I can make the New() function _Mode = "modeb" but I wanted to know a better way or more correct way.
How do I properly declare the variable _Mode?
One option would be to make _Mode Protected instead of Private so you can set it from the subclasses, and set the value is the subclass constructors:
Class A
Protected _Mode As String
Public Function returnMode() As String
Return _Mode
End Function
Class B
Inherits Class A
Public Sub New()
_Mode = "modeb"
End Sub
Class C
Inherits Class A
Public Sub New()
_Mode = "modec"
End Sub

Incompatible interface

Please see the code below:
Public Class clsCar
Implements IVehicle
Public Function getWheels() As Integer Implements IVehicle.getWheels
Return 4
End Function
End Class
Public Interface IVehicle
Function getWheels() As Integer
End Interface
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim list As List(Of IVehicle) = New List(Of IVehicle)
Dim v1 As IVehicle = New clsCar
Dim v2 As IVehicle = New clsBus
list.Add(v1)
list.Add(v2)
Dim IVehicle As IVehicle = New clsCar
Dim IVehicle2 As IVehicle = New clsBus
For Each IVehicle In list
MsgBox(IVehicle.getWheels())
Next
End Sub
End Class
I want to add a new function to the clsBus class:
Public Function getWheels(ByVal strCarType As String) As Integer
If strCarType = "Robin Ryliant" Then
Return 3
Else
Return 4
End If
End Function
How do I call this from the FOR EACH statement? At the moment it will call getWheels with no arguments.
You will have to add the method overload to the interface in order to be able to call it from a IVehicle variable.
Public Interface IVehicle
Function getWheels() As Integer
Function getWheels(ByVal strCarType As String) As Integer
End Interface
But probably it is better to have different, more specialized car types
Public Class clsCar
Implements IVehicle
Public Overridable Function getWheels() As Integer Implements IVehicle.getWheels
Return 4
End Function
End Class
Public Class clsRobinRyliantCar
Inherits clsCar
Public Overrides Function getWheels() As Integer
Return 3
End Function
End Class
This does not break the inheritance hierarchy and is purely polymorphic.
I think I would go for something more like this, with the number of wheels being an instance property (code in LINQPad format):
Sub Main
Dim list As List(Of IVehicle) = New List(Of IVehicle)()
list.Add(New clsCar("Ford Focus", 4))
list.Add(New clsCar("Robin Ryliant", 3))
list.Add(New clsBus())
For Each v In list
Console.WriteLine(String.Format("{0}:{1}", v.GetVehicleType(), v.GetWheels()))
Next
End Sub
' Define other methods and classes here
Public Interface IVehicle
Function GetVehicleType() As String
Function GetWheels() As Integer
End Interface
Public MustInherit Class clsVehicle
Implements IVehicle
Protected Property VehicleType As String
Protected Property Wheels As Integer
Protected Sub New(vehicleType As String, wheels As Integer)
Me.VehicleType = vehicleType
Me.Wheels = wheels
End Sub
Public Function GetVehicleType() As String Implements IVehicle.GetVehicleType
Return Me.VehicleType
End Function
Public Function GetWheels() As Integer Implements IVehicle.GetWheels
Return Me.Wheels
End Function
End Class
Public Class clsCar
Inherits clsVehicle
Public Sub New(vehicleType As String, wheels As Integer)
MyBase.New(vehicleType, wheels)
End Sub
End Class
Public Class clsBus
Inherits clsVehicle
Public Sub New()
MyBase.New("Bus", 4)
End Sub
End Class
If your clsBus and clsCar are meant to refer to a specific car then the type should be a member of that class already, not something you pass in when you want to get information. To this end I'd suggest that you have "type" as something you can pass in the constructor and then the method on the bus would have no parameters and would just refer to its internal type to determine how many wheels it has.
I'm not too fluent with VB.NET so would probably make mistakes in example code but hopefully you get what I mean. If not I'll knock up some code. :)

generic Interface vb

Trying to get my head around generic interfaces and classes. How do I 'get T' when using my class in the new method and call data.method using this type?
Public MustInherit Class RepositoryBase(Of T)
Implements IRepository(Of T)
Private Data As IDAL
Public Sub New()
Data = DTOParserFactory.GetParser(T.GetType().ToString())
End Sub
Public Sub delete(BaseDTO As T) Implements Domain.Business.IRepository(Of T).delete
'Data.delete(Convert.ChangeType(BaseDTO, TypeOf(Type))
End Sub
Public Function getAll() As System.Linq.IQueryable(Of T) Implements Domain.Business.IRepository(Of T).getAll
'Return Data.getAll()()
End Function
End Class
I'm assuming you need to get the Type object for T?
In your constructor
Public Sub New()
Data = DTOParserFactory.GetParser(GetType(T).ToString())
End Sub
I'm not super clear on the question, but perhaps this is what you are looking for.
Assuming you have a common base class BaseDTO then you would define your RepositoryBase class like this:
Public MustInherit Class RepositoryBase(Of T As BaseDTO)
Then you declare an instace of the class like this:
Dim userRepository As New RepositoryBase(Of User)()
What this does is constrain T to be a subclass of BaseDTO, and gives you access to all of BaseDTO's methods.

how to access class from inherited class

I have two classes:
class class2
inherits class1
public sub modify()
'modify property of class1
end sub
end class
How can I modify class1 in a sub in class2?
You just call it. Example:
Public Class class1
Private _Value As String = String.Empty
Property Value() As String
Get
Return _Value
End Get
Set(ByVal value As String)
_Value = value
End Set
End Property
End Class
Public Class class2
Inherits class1
Public Sub modify()
Value = "modified"
End Sub
End Class
And to show it works:
Dim c2 As New class2
c2.modify()
MessageBox.Show(c2.Value)
You are asking about properties, note that only protected and public properties are visible to inherited classes.
You need the MyBase keyword when you are overriding an existing function in the parent class. Other protected or public properties or functions can be accessed regulary without any special keyword.
One tip I wanted to add to the above comments regarding accessing base class info is where you have a base class without a default contructor or want to use a specific constructor This is a good opportunity to use Mybase. You have to call the constructor before any additional actions take place in this scenario.
Public Class MyClass
Inherits baseClass
Public Sub New()
mybase.new("Oranges")
End Sub
End Class
Public Class baseClass
Private _someVariable as String
Public Sub New(byval passedString as string)
_someVariable = passedString
End Sub
End Class