How to select which object to instantiate without Select Case? - vb.net

Say I have three classes. A base class Person and two other classes (Employee and Manager) each inherits from Person.
Public Class Person
Public Property Name As String
Public Overridable ReadOnly Property Salary As Decimal
Get
Return 0
End Get
End Property
Public Sub New()
End Sub
End Class
Class Employee:
Public Class Employee
Inherits Person
Overrides ReadOnly Property Salary As Decimal
Get
Return 100
End Get
End Property
Sub New()
MyBase.New()
End Sub
End Class
Class Manager:
Public Class Manager
Inherits Person
Overrides ReadOnly Property Salary As Decimal
Get
Return 1000
End Get
End Property
Sub New()
MyBase.New()
End Sub
End Class
My problem is how to create a new Person(based on a ListBox) that can be either Person/Employeeor Manager and retrieve the Salary Property without going through Select Case or If-else in the ListBox1_SelectedIndexChanged event. To do this selection, I have added another class, named Identify, that takes the selected index of the Listbox and pass it to getProsonType method and return the selected category. Please look at my code below.
The form1 code looks like:
Public Class Form1
Private P As Identify
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles
MyBase.Load
ListBox1.Items.Add("Person")
ListBox1.Items.Add("Employee")
ListBox1.Items.Add("Manager")
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As
EventArgs) Handles ListBox1.SelectedIndexChanged
P = New Identify(CType(ListBox1.SelectedIndex, PersonType))
Dim PGeneral As Person
PGeneral = P.GeneralPerson
Label1.Text = PGeneral.Salary
End Sub
End Class
I have assigned the three types to a public Enum PersonType just to restrict the selection.
Public Enum PersonType
Person = 0
Employee = 1
Manager = 2
End Enum
The Identity Class looks like:
Public Class Identify
Public Property PType As PersonType
Public ReadOnly Property GeneralPerson As Person
Get
Return getProsonType(PType)
End Get
End Property
Private Function getProsonType(ByVal SomeOne As PersonType) As Person
Dim pp As Person
Select Case SomeOne
Case PersonType.Person
pp = New Person()
Case PersonType.Employee
pp = New Employee()
Case PersonType.Manager
pp = New Manager()
End Select
Return GeneralPerson
End Function
Sub New(ByVal PersonType As PersonType)
Me.PType = PersonType
End Sub
End Class
After running the project I get the error System.StackOverflowException. I am not sure if this is the cleanest or the correct way to do this and I looked in many places and reached this dead end!
Please help me to correct this or find a better way.
Thanks in advance.

Related

How to create a new event for my own custom control?

I have a class which inherit from Panel, and below are some member in this class
Public ItemName As String
Public Quantity As Integer
Public Price As Decimal
Public DiscountAmount As Decimal
How can I create a event when Quantity or DiscountAmount changed then run a function?
I try to write in this way but I get error:-
Private Sub info_Changed(sender As Object, e As EventArgs) Handles Quantity.Changed, DiscountAmount.Changed
myFunction()
End Sub
Error:
Handles clause requires a WithEvents variable defined in the
containing type or one of its base types.
You need to declare the events in user control and then consume those. See below code. I have created a user control UserControl1. This control raises events when Price or DiscountAmount is changed. The usercontrol is then used in Form1. You can use the same approach to change the Quantity.
Public Class Form1
Private WithEvents userCntrl As New UserControl1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ChangeValues()
End Sub
Private Sub ChangeValues()
userCntrl.Price = 100
userCntrl.DiscountAmount = 12
End Sub
Private Sub userCntrl_Price_Changed(newValue As Decimal) Handles userCntrl.Price_Changed, userCntrl.DiscountAmount_Changed
MessageBox.Show("New value = " & newValue.ToString)
End Sub
End Class
Public Class UserControl1
Public Event Price_Changed(ByVal newValue As Decimal)
Public Event DiscountAmount_Changed(ByVal newValue As Decimal)
Public ItemName As String
Public Quantity As Integer
Private Price_ As Decimal
Public Property Price() As Decimal
Get
Return Price_
End Get
Set(ByVal value As Decimal)
If value <> Price_ Then
RaiseEvent Price_Changed(value)
End If
Price_ = value
End Set
End Property
Private DiscountAmount_ As Decimal
Public Property DiscountAmount() As Decimal
Get
Return DiscountAmount_
End Get
Set(ByVal value As Decimal)
If value <> DiscountAmount_ Then
RaiseEvent DiscountAmount_Changed(value)
End If
DiscountAmount_ = value
End Set
End Property
End Class

Assign a value to a property depending on initialized Class

I try to assign a value (Test1) to a Property (Wealth) dynamically so that depending on the initialized Class the calculated value is different. But all I get as a result is 0. Could anyone explain me why and how I can solve the problem.
Public Class Class1
Private _test1 As Integer
Overridable ReadOnly Property Test1 As Integer
Get
Return _test1
End Get
End Property
Public ReadOnly Property Wealth As Integer
Get
Dim rnd As New Random
Dim val As Integer = rnd.Next(1, 6)
Return val * _test1
End Get
End Property
End Class
Public Class Class2
Inherits Class1
Public Overrides ReadOnly Property Test1 As Integer
Get
Return 3
End Get
End Property
End Class
Initialisation:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim t As New Class2
MsgBox(t.Wealth.ToString)
End Sub
End Class
Don't use the private variable, you need to reference the property itself.
Public Class Form1
Public Class Class1
Overridable ReadOnly Property Test1 As Integer
Get
Return 0 'Default value'
End Get
End Property
Public ReadOnly Property Wealth As Integer
Get
Dim rnd As New Random
Dim val As Integer = rnd.Next(1, 6)
Return val * Test1 'Changed! Uses the Property name, so that if it is overridden it uses the new version'
End Get
End Property
End Class
Public Class Class2
Inherits Class1
Public Overrides ReadOnly Property Test1 As Integer
Get
Return 3
End Get
End Property
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim t As New Class2
MsgBox(t.Wealth.ToString)
End Sub
End Class
Sounds like you need a constructor.
Public Class Class1
Public Sub New(int As Integer)
Me.test1 = int
End sub
...
Then when you declare it
Dim t As New Class1(5)
MsgBox(t.Wealth.ToString)

Hiding function on nested class

Public Class Class1
Private names As List(Of String)
Private _class2 As New Class2
Public Sub AddName(ByVal name As String)
names.Add(name)
_class2.Add()
End Sub
Public ReadOnly Property AddAge(ByVal name As String) As Class2
Get
_class2.index = names.IndexOf(name)
Return _class2
End Get
End Property
Public Sub Clear()
names.Clear()
_class2.Clear()
End Sub
Public Class Class2
Private _age As List(Of Integer)
Protected Friend index As Integer
Public Property Age() As Integer
Get
Return _age(index)
End Get
Set(ByVal value As Integer)
_age(index) = value
End Set
End Property
Public Sub Add()
_age.Add(0)
End Sub
Public Sub Clear()
_age.Clear()
End Sub
End Class
End Class
How can I hide ,Sub Clear and Sub Add on class2, so they'll only be visible on class1, like;
Public Sub Clear()
names.Clear()
_class2.Clear() '<<<<<<<
End Sub
I want they do not be visible on Sub Main(), like they are below.
Sub Main()
Dim person As New Class1
person.AddAge("kid").Clear() '<<<<<<
person.AddAge("kid").Add() '<<<<<<
End Sub
If I put Protected, I class1 cannot access it. If I put Protected Friend, Sub Main() can still access them. Thanks for your help and time.
Used -Hans Passant- comment.
"Trust in .NET follows assembly boundaries. If you get two classes in one assembly then there are two programmers that know how to find each other if there's a problem. The only way to get what you want is to put these classes in a separate class library project. Which then lets you use Friend. And whomever writes that Main method doesn't have to be friendly."

One table many classes

Say I have a database structure like this:
create table Product(id int not null identity,Name varchar(30))
INSERT INTO Product VALUES ('ProductA')
INSERT INTO Product VALUES ('ProductB')
and a class structure like this:
Imports System.Data.SqlClient
Public Class Product
Protected ProductName As String
Public Overridable Sub Display()
End Sub
End Class
Public Class ProductA
Inherits Product
Public Sub New(ByVal product As String)
ProductName = product
End Sub
Public Overrides Sub Display()
'Specific logic to display product A
End Sub
End Class
Public Class ProductB
Inherits Product
Public Sub New(ByVal product As String)
ProductName = product
End Sub
Public Overrides Sub Display()
'Specific logic to display product B
End Sub
End Class
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim p1 As Product
Dim p2 As Product
p1 = New ProductA("ProductA")
p2 = New ProductB("ProductB")
p1.Display()
p2.Display()
End Sub
End Class
There is a Property (Product) that identifies, which product the class relates to. This does not look correct to me. Is there a better way of modelling it? This is similar to the NHibernate concept of a Discriminator (I am not using NHibernate in this case).
With you latest change, you should move your constructor to the base class. Aside from that, the design is fine.
Public Class Product
Protected ProductName As String
Public Sub New(ByVal product As String)
ProductName = product
End Sub
Public Overridable Sub Display()
End Sub
End Class
Public Class ProductA
Inherits Product
Public Overrides Sub Display()
'Specific logic to display product A
End Sub
End Class
Also, in your declarations you can use the inherited class:
Dim p1 As ProductA
Dim p2 As ProductB

Accessing a list from another class vb.net

I have these two classes class FootballAdmin makes use of the import Football from the projects references, what i need to do is in class MainForm is for the updateView method to access the list held by FootballAdmin and display it in the teamSheetListBox, i am unsure how access the list as indicated by ?????
Imports Football
Public Class FootballAdmin
Private fTeam As List(Of FootballTeams)
Public Sub New()
fTeam = New List(Of FootballTeams)
End Sub
Public ReadOnly Property Teams() As List(Of FootballTeams)
Get
Return fTeams
End Get
End Property
End Class
Public Class MainForm
Private fFootballAdmin As FootballAdmin
Public Sub New()
InitializeComponent()
fFootballAdmin = New FootballAdmin
updateView()
End Sub
Private sub updateView()
For each team As String In ????????
teamSheetListBox.Items.Add(team)
Next
End Sub
End Class
Help please!
The big hint I am going to give you is that team in your loop:
For each team As String In ????????
teamSheetListBox.Items.Add(team)
Next
Isn't going to be a String. It will be the same type: FootballTeam as in your FootballAdmin Class. Consider what you have access to in your MainForm that can get you to those types.