Using Polymorphism with incompatible signatures - vb.net

Say I have a class structure like this:
Public class Person1
inherits Person
public function Greeting(ByVal strGreeting As String)
return strGreeting
end function
end class
Public class Person2
inherits Person
public function Greeting()
return "Hello"
end function
end class
I want to be able to use Polymorphism to call: Greeting i.e.
dim P1 As Person = New Person1
dim P2 As Person = New Person2
msgbox(P1.Greeting)
msgbox(P2.Greeting)
However, Person2 accepts an argument, so the signatures are not the same. What is the solution to this?

Your person objects are instances of Types which just happen to inherit from some the same type. As an instance of Person1, the P1 object is not going to have any knowledge of methods contained in Person2 because it is a different Type.
I am not quite sure what you are after, but here is one way to construct it:
Public MustInherit Class Person
Public Property Name As String
Public Sub New(n As String)
Name = n
End Sub
' "I dont care HOW they do it, but child types
' must provide a Greeting() function"
MustOverride Function Greeting() As String
' overload: takes an arg/different sig
Public Overridable Function Greeting(strGreeting As String) As String
Return String.Format("Greetings, {0} {1}", strGreeting, Name)
End Function
End Class
Public Class Person1
Inherits Person
Public Sub New(n As String)
MyBase.New(n)
End Sub
' override with a specific form of address
Public Overrides Function Greeting() As String
Return "Hello, Mr " & Name
End Function
End Class
Public Class Person2
Inherits Person
Public Sub New(n As String)
MyBase.New(n)
End Sub
Public Overrides Function Greeting() As String
Return "Hello, Senorita " & Name
End Function
End Class
Then:
Dim Pa1 As New Person1("Ziggy")
Dim Pa2 As New Person2("Zoey")
Console.WriteLine(Pa1.Greeting)
Console.WriteLine(Pa2.Greeting("Ms")) ' uses base class overload
Console.WriteLine(Pa2.Greeting())
Output:
Hello, Mr Ziggy ' from P1
Greetings, Ms Zoey ' from base class
Hello, Senorita Zoey ' from P2
The base class more commonly might define a default Greeting for all the inherited types, then some base classes might override it and others not depending on the class needed.

Related

Declare Property as diferent Class based on other value

I have: ClassUsser, ClassClient, ClassPerson.
ClassUsser
Public Property Name as String
ClassClient
Public Property Name as String
ClassPerson
Public Property KindPerson as Integer
Public Property Person as (ClassClient or ClassPerson)
I want delare Property Person as diferent type of class based on value of KindPerson.
Enum KindsPerson
{ User=1,
Client=2}
First, I would set value of KindPerson, and after, through set/get methods, obtain the Person
I don't Know If It si posible in VB.Net. It exists any way to do this?
Thanks
You could use the Factory Pattern:
Module Module1
Sub Main()
Dim p1 = Person.GetPerson(Person.PersonKind_ENUM.Client, "Adam")
Dim p2 = Person.GetPerson(Person.PersonKind_ENUM.User, "Barbara")
Dim personList As New List(Of Person)
personList.Add(p1)
personList.Add(p2)
For Each p In personList
Console.WriteLine($"{p.GetType.Name}: {p.name}")
Next
Console.ReadKey()
End Sub
Public Class User
Inherits Person
End Class
Public Class Client
Inherits Person
End Class
Public MustInherit Class Person
Property Name As String
Public Enum PersonKind_ENUM
User
Client
End Enum
Public Shared Function GetPerson(personKind As PersonKind_ENUM, name As String) As Person
Select Case personKind
Case PersonKind_ENUM.Client
Return New Client() With {.Name = name}
Case PersonKind_ENUM.User
Return New User() With {.Name = name}
Case Else
Throw New InvalidOperationException
End Select
End Function
End Class
End Module

How to implement a class when it is defined in an interface?

An interface can have a class in it but I do not understand how to implement such an interface. I give an example below:
I wrote the following simple code without any interface:
Imports System
Module Program
Sub Main()
Dim n As New name("Mounisha", "Ghosh")
Dim student As New Student(n, 14)
Console.WriteLine("First Name: {0}", student.studentName.firstName)
Console.WriteLine("Last Name: {0}", student.studentName.lastName)
Console.WriteLine("Age: {0}", student.age)
Console.ReadLine()
End Sub
End Module
Class name
Public Property firstName As String
Public Property lastName As String
Sub New(ByVal f As String, ByVal l As String)
firstName = f
lastName = l
End Sub
End Class
Class Student
Private nameValue As name
Public ReadOnly Property studentName() As name
Get
Return nameValue
End Get
End Property
Public Property age As Integer
Sub New(ByVal n As name, ByVal a As Integer)
nameValue = n
age = a
End Sub
End Class
Then I tried to re-organize by putting the class name in an interface and implement it in the class student. But I was not able to construct my code. I give the overall idea of the code I am trying to construct below:
Imports System
Interface IClass
Class name
Public Property firstName As String
Public Property lastName As String
Sub New(ByVal f As String, ByVal l As String)
firstName = f
lastName = l
End Sub
End Class
End Interface
Module Program
Sub Main()
'How to create instances and pass values to constructors?
End Sub
End Module
Class Student : Implements IClass
'The idea is to create a readonly property of type "name"
'But not able to use the Interface to do the same
Public Property age As Integer
End Class
The main idea is to understand how to implement an interface with a class in it. Pls help.
The other point I want to highlight is that in the constructor of the class name I have written End Sub. Now we cannot use the end sub statement in interface - so why am I not getting an error? Also do the statements firstName = f and lastName = l not denote an implementation which should have been flagged as an error by the compiler - but not getting any error. Any explanations for this?
What you're doing is simply adding a nested class to the interface. This isn't seen as something that the implementing class has to implement but instead is just a class available via that interface. Using your structure, in order to require Student to implement a read only name property, you have to add that property to the interface.
Public Interface IClass
ReadOnly Property Fullname As Name
Class Name
Public Property FirstName As String
Public Property LastName As String
Sub New(firstName As String, lastName As String)
Me.FirstName = firstName
Me.LastName = lastName
End Sub
End Class
End Interface
Your Student Class would then look like
Public Class Student : Implements IClass
'Because Name is nested within IClass, it's referenced by IClass.Name
Public ReadOnly Property Fullname As IClass.Name Implements IClass.Fullname
Public Property Age As Integer
Public Sub New(name As IClass.Name, age As Integer)
Fullname = name
Me.Age = age
End Sub
End Class
And creating a student would be
Dim name = New IClass.Name("Mounisha", "Ghosh") 'again we access name via the interface
Dim student = New Student(name, 14)
Usually you would not add a nested Class to the interface but instead do something like
Module Program
Sub Main()
Dim studuent = New Student(New Name("Mounisha", "Ghosh"), 14)
End Sub
End Module
Interface IClass
ReadOnly Property Fullname As Name
End Interface
Public Class Name
Public Property FirstName As String
Public Property LastName As String
Sub New(firstName As String, lastName As String)
Me.FirstName = firstName
Me.LastName = lastName
End Sub
End Class
Class Student : Implements IClass
Public ReadOnly Property Fullname As Name Implements IClass.Fullname
Public Property Age As Integer
Public Sub New(name As Name, age As Integer)
Fullname = name
Me.Age = age
End Sub
End Class

Need Help Initializing a Generic Property in VB.Net

I've created a request class. Here is an abbreviated version of it:
Public Class Request(Of T)
Private _Account As String
Public Property Account() As String
Get
Return _Account
End Get
Set(ByVal value As String)
_Account = value
End Set
End Property
Private _InnerRequest As T
Public Property InnerRequest() As T
Get
Return Me._InnerRequest
End Get
Set(ByVal value As T)
Me._InnerRequest = value
End Set
End Property
End Class
And then I have two other classes that I intend to use with this one - again, abbreviated
Public Class Individual
Public FirstName As String
Public LastName As String
Friend Sub New()
End Sub
End Class
And
Public Class Commercial
Public EntityName As String
Friend Sub New()
End Sub
End Class
Again, both of these are pretty abbreviated. The issue comes in when I attempt to use the properties of individual or commercial:
Dim Req As New Request(Of Individual)()
Req.InnerRequest.FirstName = "Herman" <-- Null Ref Exception
So... how do I get my inner request null ref exception kicked? I tried simply using Me._InnerRequest = New T in the New sub of Request, but no dice. Is there a way to handle this?
Req.InnerRequest must be set to an object instance of Individual first.
Req.InnerRequest = new Individual()
Req.InnerRequest.FirstName = "Herman"
Or create an instance for InnerRequest with the following modifications
Public Class Request(Of T As {New}) 'Classes of type T must have a public new constructor defined
::
Private _InnerRequest As New T() 'Creates a new class of type T when an instance is created of Request
And make the constructors of the other classes Public instead of Friend.
Than you can directly do
Dim Req As New Request(Of Individual)()
Req.InnerRequest.FirstName = "Herman"
#Barry already answered what the main problem is, but here's an alternate syntax if you prefer object initializers:
Req.InnerRequest = new Individual() With { FirstName = "Herman" }
Or, if you prefer, you could overload the constructor for your Individual class:
Dim individual As New Individual("Herman")
Req.InnerRequest = individual
With the Individual class looking like:
Public Class Individual
Public FirstName As String
Public LastName As String
Friend Sub New()
End Sub
Friend Sub New(firstName As String)
Me.FirstName = firstName
End Sub
End Class
You probably should consider restricting the T to some Entity class:
Public Class Request(Of T As Entity)
From which both Individual and Commercial will inherit:
Public Class Individual : Inherits Entity
Then maybe declare an overridable property Name of type String on this Entity class (which can be abstract/MustInherit), this should provide some flexibility. Otherwise you'd be having a hard time consuming your design pattern.

Compiler Error while trying to call overloaded contstructors in VB.NET

Could someone explain to me why I get a compiler error when I try to call a base class' constructor from an inherited object? I've included a brief example of what I'm referring to.
Public Class Person
Public name As String
Public Sub New()
name = "John Doe"
End Sub
Public Sub New(Name As String)
name = Name
End Sub
End Class
Public Class NamedPerson
Inherits Person
Public Sub New(FirstName As String, LastName As String)
name = FirstName & " " & LastName
End Sub
'adding this makes it work
Public Sub New(Name As String)
MyBase.New(Name)
End Sub
End Class
'Valid
Dim guy1 As Person = New Person()
'Valid
Dim guy2 As Person = New Person("John Smith")
'Valid
Dim guy3 As NamedPerson = New NamedPerson("John", "Smith")
'Compiler Error
Dim guy4 As NamedPerson = New NamedPerson("John Smith")
Child classes do not inherit constructors from their base types. A child class is responsible for defining it's own constructors. Additionally it must ensure that each constructor it defines either implicitly or explicitly calls into a base class constructor or chains to another constructor in the same type.
For more info See: Instance Constructors
From your sample classes,
Public Class NamedPerson
Inherits Person
Public Sub New(Name As String)
MyBase.New(Name)
End Sub
Public sub New(FirstName As String, LastName As String)
name = FirstName & " " & LastName
End Sub
End Class

Generic Collections, Member Classes, Design Pattern question for VB.NET

I have a class called Person:
Public Class Person
Private PersonID as String
Private Name as String
Private Records as GenericCollection(Of PublicRecord)
Public Sub New(ByVal ID as String)
Me.PersonID = ID
Me.Name = getPersonName(ID)
End Sub
'Get/Sets
End Class
getPersonName is simply a function that does exactly as it is described. GenericCollection class is as follows:
Public Class GenericCollection(Of ItemType)
Inherits CollectionBase
' Purpose: Provides a generic collection class from which all other collections
' classes can be inherited if they wish to extend the functionality below.
#Region "Public Methods"
Public Function Add(ByVal NewObject As ItemType) As Integer
Return MyBase.InnerList.Add(NewObject)
End Function
Public Sub New()
MyBase.New()
End Sub
#End Region
#Region "Public Properties"
Default Public Property Item(ByVal Index As Integer) As ItemType
Get
Return CType(MyBase.InnerList(Index), ItemType)
End Get
Set(ByVal value As ItemType)
MyBase.InnerList(Index) = value
End Set
End Property
#End Region
End Class
PublicRecord class is:
Public Class PublicRecord
Private RecordID As String
Private RecordDataOne As String
Private RecordDataTwo As String
Public Sub New()
MyBase.New()
End Sub
'Get/Sets
End Class
One of the requirements I've been told can be done is that I should be able to grab all Persons in a Collection of Persons, then since all of those Persons will have Collectinos of Records within them... grab a specific set of data from the Collection of Records.
We'll say, I want to: getPersonsOverAge21() from the Collection of Records inside each Person inside the Collection of Persons.
Is this even possible? If so, can someone explain how it would work?
There's no need to implement your own generic collection class. .Net has already done this for you in the System.Collections.Generic namespace. Look at a List(Of Person) or even just a simple IEnumerable(Of Person).
Now you haven't explained how your record objects relate to your person type or what data they contain, so I can only speculate on the next part. But it sounds kind of like you want something like this:
Dim people As List(Of Person) = GetPeopleFromDatabase()
Dim peopleOver21 As IEnumerable(Of Person) = people.Where(Function(p) p.Age >= 21)
Dim peopleOver21Query = From p In people _
Where (p.Age >= 21) _
Select p