Compiler Error while trying to call overloaded contstructors in VB.NET - 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

Related

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

Class with property that is a List Of items in a subclass

I want a class for a Customer, with a text property name.
Another property CustAddress will be a list of multiple addresses.
Each address will have two string properties.
Here is what I have.
I am not sure if I need something in the constructor of the class address.
And I'm even not sure what the code would look like to exploit this class.
Also, I can't get the F11 Step Into debug feature to step into the class code. If i put a break in the class code it does break and works fine. I have modified the option "Just My Code" to remove checkbox, but it does not help. I have a solution containing one class module and one Windows App together.
<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)>
Public Class ComClass1
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "c8e723b4-f229-4368-9737-97c4c71d490a"
Public Const InterfaceId As String = "16275ddb-5cfe-47c0-995f-84a5f868ad1b"
Public Const EventsId As String = "dad73a5c-8ac4-4384-a5f9-8e2c388b5514"
#End Region
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
'Fields
Private _name As String
Public _CustAddress As List(Of address)
'Constructor for class ComClass
Public Sub New()
_CustAddress = New List(Of address)
End Sub
Public Property CustName() As String
Get
Return _name
End Get
Set(ByVal Value As String)
_name = Value
End Set
End Property
Public Property CustAddress() As List(Of address)
Get
Return _CustAddress
End Get
Set(value As List(Of address))
_CustAddress = value
End Set
End Property
Public Class address
Private _address1 As String
Private _address2 As String
Public Sub New()
'??????
End Sub
Public Property Address1 As String
Get
Return _address1
End Get
Set(value As String)
_address1 = value
End Set
End Property
Public Property Address2 As String
Get
Return _address2
End Get
Set(value As String)
_address2 = value
End Set
End Property
End Class
End Class
I took out the com stuff just to shorten the answer. Since you had no extra code in the Property Procedures I shortened that to automatic Properties. I also moved the address Class out on its own. This class could be useful else where in the program so a nested class is not really necessary.
Public Class ComClass1
Public Property CustName As String
Public Property CustAddress As List(Of address)
Public Sub New(cName As String, cAddresses As List(Of address))
CustName = cName
CustAddress = cAddresses
End Sub
End Class
Public Class address
Public Property Address1 As String 'Street Address
Public Property Address2 As String 'City and State
Public Sub New(a1 As String, a2 As String)
Address1 = a1
Address2 = a2
End Sub
End Class
Private Sub DeclareAComClass1()
Dim addrList As New List(Of address) From {
New address("12 Main Street", "Los Angeles, CA"),
New address("13 Park Avenue", "New York, NY")
}
Dim cc As New ComClass1("Big Company, Inc.", addrList)
End Sub
Here is what I have ended up with. #Mary got me further ahead. But because I am using a COM class, I can't have any public constructors with parameters.
I added a method called AddAddress which gives me the functionality I need.
In my original post I somehow left out MyBase.New which is required for a COM class.
I encourage comments with insights on this approach.
<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)>
Public Class ComClass1
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "c8e723b4-f229-4368-9737-97c4c71d490a"
Public Const InterfaceId As String = "16275ddb-5cfe-47c0-995f-84a5f868ad1b"
Public Const EventsId As String = "dad73a5c-8ac4-4384-a5f9-8e2c388b5514"
#End Region
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
'Fields
Private _name As String
Private _CustAddress As List(Of address)
'Constructor for class ComClass
Public Sub New()
MyBase.New
_CustAddress = New List(Of address)
End Sub
Public Sub AddAddress(a1 As String, a2 As String)
Dim addr As New address(a1, a2)
_CustAddress.Add(addr)
End Sub
Public Property CustName() As String
Get
Return _name
End Get
Set(ByVal Value As String)
_name = Value
End Set
End Property
Public Property CustAddress() As List(Of address)
Get
Return _CustAddress
End Get
Set(value As List(Of address))
_CustAddress = value
End Set
End Property
Public Class address
Private _address1 As String
Private _address2 As String
Public Sub New(a1 As String, a2 As String)
_address1 = a1
_address2 = a2
End Sub
Public Property Address1 As String
Get
Return _address1
End Get
Set(value As String)
_address1 = value
End Set
End Property
Public Property Address2 As String
Get
Return _address2
End Get
Set(value As String)
_address2 = value
End Set
End Property
End Class
End Class
And the code to implement/test is as follows:
Dim TestClass As New ComClass1
Dim myint As Int32
TestClass.CustName = "John Smith"
TestClass.AddAddress("123 Main Street", "Los Angeles")
TestClass.AddAddress("13 Park Avenue", "New York")
Debug.Print(TestClass.CustAddress(0).Address1) '123 Main Stree'
Debug.Print(TestClass.CustAddress(1).Address1) '13 Park Avenue
TestClass.CustAddress.Remove(TestClass.CustAddress(0))
Debug.Print(TestClass.CustAddress(0).Address1) ' 13 Park Avenue

Find value by MethodName(String) in a LinqToSql result?

Let's say my Person class look like this:
Private Class Person
Public Property Name As String
Public Property Age As Integer
End Class
and I have a result called linqToSqlResult with name = "John" and Age = 30.
Now I want to get the Name of the person as follows:
Dim name As String = CStr(GetValue(linqResult, "Name"))
And I'm looking for some code like this:
Private Function GetValue(ByRef linqToSqlResult As Object, fieldName As String) As Object
'Here's the code I'm looking for??
End Function
Any idea?
Due to the lack of information, I Assume the value passed as LinqToSqlResult is the ouput of the query of the type Person, If not please explain more clearly the contents of LinqToSqlResult
What you could do is the following (Not the most performant piece of code though):
Imports System.Reflection
Module Module1
Sub Main()
Dim i As Object = New Person With {.Name = "TestUser", .Age = 30}
Console.WriteLine(GetValue(Of Person)(i, "Name").ToString())
Console.WriteLine(Convert.ToInt32(GetValue(Of Person)(i, "Age").ToString()))
Console.ReadLine()
End Sub
Private Function GetValue(Of T)(ByRef linqToSqlResult As Object, fieldName As String) As Object
Dim myProp As PropertyInfo = GetType(T).GetProperties().Where(Function(x) x.Name.Equals(fieldName)).FirstOrDefault()
If (myProp IsNot Nothing) Then
Return myProp.GetValue(linqToSqlResult, Nothing)
Else
Throw New ArgumentException(" Some usefull message")
End If
End Function
End Module
Public Class Person
Public Property Name As String
Public Property Age As String
End Class
This outputs:
//TestUser
//30

Using Polymorphism with incompatible signatures

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.

Overloaded Constructor in Abstract Class in vb.NET

I have an abstract class in vb.net with two subclasses. In the abstract class I have a constuctor that looks like this:
Public Sub New(arg1 as String, arg2 as String)
Me.arg1 = arg1
Me.arg2 = arg2
End Sub
I would like to create a second constructor that doesn't take any arguments and just initializes the args to default values. It would look like this:
Public Sub New()
Me.arg1 = "123"
Me.arg2 = "456"
End Sub
When I attempt to create a new subclass using the second constructor the compiler complains that I'm missing two args to the constructor.... Is there a reason I can't overload the constructor in the abstract class?
Thanks
There's no "abstract" in VB. If you mean abstract in the c# sense (MustInherit in VB parlance), then you need to define both constructors in your subclasses, as constructors are not inherited.
Example:
Public MustInherit Class SuperClass
Public Property ValueOne As String = String.Empty
Public Property ValueTwo As String = String.Empty
Public Sub New()
Me.New("123", "456")
End Sub
Public Sub New(ByVal tValueOne As String, ByVal tValueTwo As String)
Me.ValueOne = tValueOne
Me.ValueTwo = tValueTwo
End Sub
End Class
Public Class SubClass
Inherits SuperClass
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal tValueOne As String, ByVal tValueTwo As String)
MyBase.New(tValueOne, tValueTwo)
End Sub
End Class
If your second constructor is in the sub class, it must call the constructor in the base class.
Public Sub New()
MyBase.New("123", "456")
End Sub