I cant inherit form my parent class - vb.net

I'm having a problem that I cant figure out, I'm trying to code a payroll system with vb.net 2013, I must use a console application.
I'm using classes to calculate the salary depending on the amount of weeks that the employee's worked, but the problem is that I cannot inherit from my parent class, I keep on getting this error and i don't know how to fix it.
Error 2 Class 'Employee_Payment_System.Employee' has no accessible 'Sub New' and cannot be inherited.
Whenever i try to add a 'sub new' I get this
Error 3 'Public Sub New()' has multiple definitions with identical signatures.
Here is my code so far
Public Class Employee
#Region "Private Declarations"
Private EMP_FullName As String
Private EMP_LastName As String
Private EMP_Salary As Double
Private EMP_Number As Integer
Private EMP_Address As String
#End Region
'The values are obtained from the public properties coded below
Private Sub New()
EMP_FullName = ""
EMP_LastName = ""
EMP_Salary = 0.0
EMP_Address = ""
End Sub
Private Sub New(ByVal FullName As String, ByVal LastName As String, ByVal Address As String, ByVal Salary As Double, ByVal Number As Integer)
EMP_FullName = FullName
EMP_LastName = LastName
EMP_Address = Address
EMP_Number = Number
EMP_Salary = Salary
End Sub
' the properties gets their values from the console
Public Property FullName() As String
Get
Return EMP_FullName
End Get
Set(value As String)
EMP_FullName = value
End Set
End Property
Public Property LastName() As String
Get
Return EMP_LastName
End Get
Set(value As String)
EMP_LastName = value
End Set
End Property
Public Property Address() As String
Get
Return EMP_Address
End Get
Set(value As String)
EMP_Address = value
End Set
End Property
Public Property Salary() As Double
Get
Return EMP_Salary
End Get
Set(value As Double)
EMP_Salary = value
End Set
End Property
Public Property Number() As Integer
Get
Return EMP_Number
End Get
Set(value As Integer)
EMP_Number = value
End Set
End Property
Public Overridable Function Payment() As Double
Return EMP_Salary
End Function
End Class
Public Class WeeklySalary : Inherits Employee
'The main problem "Error 2 Class 'Employee_Payment_System.Employee' has no accessible 'Sub New' and cannot be inherited." generates here
Sub New()' I get my second error "Error 3 'Public Sub New()' has multiple definitions with identical signatures. " here
End Sub
Private NumberOfWeeks As Integer
Private Sub New() 'The second Error is related to this sub
NumberOfWeeks = 0
End Sub
Public Sub New()
NumberOfWeeks = Number
End Sub
Public Property Number_Of_Weeks() As Integer 'This is the number of weeks worked
Get
Return NumberOfWeeks
End Get
Set(value As Integer)
NumberOfWeeks = value
End Set
End Property
Public Overrides Function Payment() As Double
Return NumberOfWeeks * Salary 'Calculates Weekly salary here
End Function
End Class
I still have to code one more Class for monthly payments, and I still need to code the module for the console interface but I need my classes to work before I can start the module (For testing purposes).

Okay I have managed to fix it, I have changed my private constructors to public and it worked thank you

As jonrsharpe says: Why are you making your constructors (Sub New) private? When adding a Public Sub New without parameters it clashes with Private Sub New(). You cannot have to methods with the same name and foot print.
But what are you trying to achieve by inheriting from Employee? If you are trying to do some EmployeeWorkRecord class it should probably aggregate Employee and work records and not inherit from it.

I'm not writing this as a criticism, just as a general pointer about inheritance.
The idea of inheritance is that child classes are the same kind of object as the parent class, but with extra functionality.
To have a real world comparison, Somebody's wages aren't the same as the somebody.
However you could have for example a class Human. A child class of that could be an employee while another child class could be a customer. Each with their own properties.
An employee could have a StartOfEmployment property while a customer could have for example a LoyaltyCardPoints property, and they could both have ContactAddress and Gender.
Anyway. To the answer - or one possible one at any rate
I suspect that you're looking at inheritance the wrong way round. The employee could possibly inherit the WeeklySalary class, while a class of Manager could possibly inherit from a MonthlySalary Class. But you'd probably be better setting up some sort of datatable using employee numbers as a key. if you do it the way youre doing at the moment, you'd have a lot of either duplicated or unused data in your program.
The naming of parent and child classes sometimes is counter intuitive as we often think as children as being smaller than the parents, but in programming, the child is the same as the parent but with extra funtionality.

Related

How to select which object to instantiate without Select Case?

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.

Assigning Private Property values

I'm testing out PetaPoco to determine if it meets our needs. I was under the impression that it would delve into my class and see the private properties that I've marked up as valid columns. Unfortunately, it's not behaving as expected. Can you please take a look and let me know if I'm doing something wrong.
My test class:
Imports PetaPoco
<PetaPoco.TableName("PaulTest")>
<PetaPoco.PrimaryKey("ID")>
Public Class PaulTest
<PetaPoco.Column("ID")>
Private Property pvtID As Integer
Private pvtName As String
Private Sub New()
End Sub
Public Sub New(name As String)
If String.IsNullOrEmpty(name) Then
Throw New ArgumentException("Passed Name is empty")
End If
Me.pvtName = name
End Sub
<PetaPoco.Ignore>
Public ReadOnly Property ID As Integer
Get
Return pvtID
End Get
End Property
<PetaPoco.Column("Name")>
Public Property Name As String
Get
Return pvtName
End Get
Set(value As String)
If String.IsNullOrEmpty(value) Then
Throw New ArgumentException("Passed Name is empty")
End If
Me.pvtName = value
End Set
End Property
End Class
The call to the DB (_db is a PetaPoco database object)
Return (_db.Fetch(Of Peta.Domain.PaulTest)(";EXEC selAllPaulTest")).OrderBy(Function(PaulTest) (PaulTest.ID)).ToList()
What's in the database
ID Name
107 Paul
What's being returned:
PaulTest.ID = 0
PaulTest.pvtID = 0
PaulTest.Name = "Paul"
PaulTest.pvtName = "Paul"
<PetaPoco.Ignore> attribute instructs PetaPoco to ignore the column during mapping. As such, the property Id will always be returning the default value of 0.
If you want to prevent the Id property from being modified, comment our or delete the attribute and add a private setter to the Id property as in the following code snippet.
' <PetaPoco.Ignore>
Public Property Id As Integer
Get
Return pvtID
End Get
Private Set(value As Integer)
pvtID = value
End Set
End Property

VB.Net check for duplicate items in a collection base

I have a class that inherits from CollectionBase. I tried to use the contains method to detect whether the Key already exists before inserting a new one. Here is what I have tried.
<Serializable()> Public Class validationList
Inherits CollectionBase
Public Function Add(ByVal Item As validationItem) As Integer
Return Me.List.Add(Item)
End Function
Default Public ReadOnly Property Item(ByVal index As Integer) As validationItem
Get
Return CType(List.Item(index), validationItem)
End Get
End Property
Public Sub Remove(ByVal index As Integer)
Me.List.RemoveAt(index)
End Sub
Protected Overrides Sub OnInsert(ByVal index As Integer, ByVal value As Object)
If Me.List.Contains(value) Then MsgBox("Already exist")
MyBase.OnInsert(index, value)
End Sub
Public Function IndexOf(ByVal key As validationItem)
Return List.IndexOf(key)
End Function
Public Sub AddRange(ByVal item() As validationItem)
For counter As Integer = 0 To item.GetLength(0) - 1
List.Add(item(counter))
Next
End Sub
End Class
<Serializable()> Public Class validationItem
Implements IEquatable(Of validationItem)
Private _key As validationTypes
Private _value As String
Public Sub New()
' Empty constructor is needed for serialization
End Sub
Public Sub New(ByVal k As validationTypes, ByVal v As String)
_key = k
_value = v
End Sub
Public Enum validationTypes
Madatory = 0
[Integer] = 1
Numeric = 2
[Decimal] = 3
MaxValue = 4
MinValue = 5
MinLength = 6
Email = 7
End Enum
Public Property Value As String
Get
Return _value
End Get
Set(ByVal Value As String)
_value = Value
End Set
End Property
Public Property Key As validationTypes
Get
Return _key
End Get
Set(ByVal value As validationTypes)
_key = value
End Set
End Property
Protected Overloads Function Equals(ByVal eqItem As validationItem) As Boolean Implements IEquatable(Of Testing_Project.validationItem).Equals
If eqItem Is Nothing Then Return False
Return Me._key = eqItem.Key
End Function
Public Overrides Function Equals(ByVal eqItem As Object) As Boolean
If eqItem Is Nothing Then Return False
Dim eqItemObj As validationItem = TryCast(eqItem, validationItem)
If eqItemObj Is Nothing Then Return False
Return Equals(eqItemObj)
End Function
Public Overrides Function GetHashCode() As Integer
Return Me._key.GetHashCode()
End Function
End Class
The validationList will be exposed from a usercontrol as a property, so that items could be added from the designer. When adding items I need to detect whether they already exist. I tried overriding the OnInsert but this sometime return that duplicates exists even when their aren't and doesn't report that duplicate exist when I try to add existing keys.
This indirectly answers the question after dealing with the issue which emerged in comments about Collection(Of T):
Add a reference to System.Collections.ObjectModel if needed, then
Imports System.Collections.ObjectModel
' a ValidationItem collection class
Public Class ValidationItems
Inherits Collection(Of ValidationItem)
Public Shadows Sub Add(NewItem As ValidationItem)
' test for existence
' do not add if it is not unique
Dim dupe As Boolean = False
For n As Int32 = 0 To Items.Count - 1
If Items(n).Key = NewItem.Key Then
dupe = True
Exit For
End If
Next
If dupe = False then
items.Add(newitem)
End if
' I would actually use an IndexOfKey function which might
' be useful elsewhere and only add if the return is -1
If IndexOfKey(NewItem.Key) <> -1 Then
Items.Add(newItem)
End If
End Sub
Some NET collection types implement Add as a function and return the item added. This sounds weird since you pass it the item to add. But returning Nothing if the item cannot be added is a neat semaphore for "I cant/wont do that". I cant recall if the std NET Collection Editor recognizes that or not.
One problem with using Contains is that it will test if item passed as param is the same object as one in the list. They never will be the same object, even if they have the same values. Testing the key in a loop is simpler than calling a method which implements an interface. (That previous answer was totally valid in the context presented, but the context has changed).
Even if you stay with CollectionBase, you want to handle it in the Add. If you try to remove it in OnInsert, VS will have problems deserializing the collection.
Also, your validationitem needs a Name property or the Collection Editor will display "Myassembly+MyType" as the Name (or a ToString override).
Other issues:
I am not sure your IndexOf will work. The list contains ValidationItems (objects), but you check it for _key (string). This will not matter if you change to Collection(Of T) which implements it for you.
The simple ctor is needed by the Collection Editor, not serialization. But the important thing is that it is there.
As for the comment about all Zeroes coming back - that is because your ValidationItem is not yet decorated for designer serialization. Maybe not the Collection Property either, that isnt shown.

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

Generic Collections

In VB6, there used to be a Collection data type that would allow retrieval of an item in the collection by either its key or its ordinal. However, it wasn't strongly typed.
Now, with VB.Net, I am looking for a suitable replacement that is strongly type and could be used with a generic collection.
This is a simple example of what I want to do. The only problem is that the underlying collection class, BindingList, does not support efficient retrieval of an item by an alpha key, so I have to loop through the elements to get the item I am looking for. For large collections, this is not efficient.
I have looked though the various Collection type classes and have found no suitable replacement.
This is what I want to do, except for the looping that is done with the Item property.
Rather than just saying "Use Hash tables" or something like that, if you could, please include the detailed out as I have done for the short example below.
Public Class Car
Public Sub New(ByVal keyName As String, ByVal property1 As String)
_KeyName = keyName
_Property1 = property1
End Sub
Dim _KeyName As String
Public Property KeyName() As String
Get
Return _KeyName
End Get
Set(ByVal value As String)
_KeyName = value
End Set
End Property
Public _Property1 As String
Public Property Property1() As String
Get
Return _Property1
End Get
Set(ByVal value As String)
_Property1 = value
End Set
End Property
End Class
Public Class Cars
Inherits System.ComponentModel.BindingList(Of Car)
Public Overloads ReadOnly Property Item(ByVal key As String) As Car
Get
For Each CurrentCar As Car In Me.Items
If CurrentCar.KeyName = key Then
Return CurrentCar
End If
Next
Return Nothing
End Get
End Property
End Class
I believe you're looking for Dictionary<TKey, TValue>. In fact, if you do want your own collection class that's strongly typed and isn't (itself) generic, if you change your parent class to Dictionary<string, Car>, you should be all set. This all does, of course, assume that you add the cars to the collection with an explicit string key. If you want the lookup to be based on the value of a property in the collection, you'd do better either using or inheriting from List<Car> and using LINQ to query the list. You could then have...
Public Overloads ReadOnly Property Item(ByVal key As String) As Car
Get
Return (from c in Me where c.KeyName = key select c).SingleOrDefault()
End Get
End Property
Do you really need both access by key AND index?
If you do not, then use a Dictionary(Of String, Car), and use
- MyCol.Items("XXX") to retrieve an item by key (or the shorthand MyCol("XXX"))
- MyCol.ContainsKey("XXX") to test if a key exists in the collection
- For Each Entry as KeyValuePair(Of String, Car) in MyCol if you want to enumerate all objects AND their key
- For Each Entry as Car in MyCol.Values if you want to enumerate the entries without consideration for the key
If you need both access by index and key, I'm afraid your best bet is to use a List(of Car) and a Dictionary(of Car) rolled into one custom collection class, because I believe they went away from that kind of collection which is not really all that useful for most problems.
This is what I am thinking is my best solution. I welcome comments for a better way!
Imports Microsoft.VisualBasic
Public Class Car
Implements Xs(Of Car).IKeyName
Private _KeyName As String
Public Sub New(ByVal keyName As String, ByVal property1 As String)
_KeyName = keyName
_Property1 = property1
End Sub
Public Property KeyName() As String Implements Xs(Of Car).IKeyName.KeyName
Get
Return _KeyName
End Get
Set(ByVal value As String)
_KeyName = value
End Set
End Property
Public _Property1 As String
Public Property Property1() As String
Get
Return _Property1
End Get
Set(ByVal value As String)
_Property1 = value
End Set
End Property
End Class
Public Class Cars
Inherits System.ComponentModel.BindingList(Of Car)
Public Overloads ReadOnly Property Item(ByVal key As String) As Car
Get
For Each CurrentCar As Car In Me.Items
If CurrentCar.KeyName = key Then
Return CurrentCar
End If
Next
Return Nothing
End Get
End Property
End Class
Public Class X
Private _KeyName As String
Public Property KeyName() As String
Get
Return _Keyname
End Get
Set(ByVal value As String)
_Keyname = value
End Set
End Property
End Class
Public Class Xs(Of X)
Inherits Hashtable
Interface IKeyName
Property KeyName() As String
End Interface
Public Shadows Sub Add(ByVal item As IKeyName)
MyBase.Add(item.KeyName, item)
End Sub
Public Shadows ReadOnly Property Item(ByVal key As String) As x
Get
If Me.ContainsKey(key) Then
Return MyBase.Item(key)
Else
'If I mispell a key, I don't want to end up creating a new mispelled version, I want an error
Throw New Exception("Element with key " & key & " is not found")
End If
End Get
End Property
End Class
Public Class Cars2
Inherits Xs(Of Car)
End Class
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim MyCar As New Car("key1", "prop1")
'First approach
Dim MyCars As New Cars
MyCars.Add(MyCar)
Dim RetrievedCar As Car = MyCars.Item("key1") 'Inefficient retrieval by key (uses looping)
'Second approach
Dim Cars2 As New Cars2
Cars2.Add(MyCar)
Dim RetrievedCar2 As Car = Cars2.Item("key1") 'Can now efficiently retreive an item by its key
End Sub
The OrderedDictionary in the System.Collections.Specialized namespace can be accessed by index and by key, if you ever need that. But looking at your solution, it looks like a standard Dictionary, but less efficient because it forces a string type for keys.
Is there any reason you can't use the Dictionary .NET provides you, or another collection type that's already in .NET like OrderedDictionary?