Reputation: 1833
I'm learning C# on my own from a book and don't understand what I'm doing wrong here. I have a base abstract class, Employee
, that the class Director
inherits from, and the class Partner
inherits from that. I want to set the job title in the Partner
class based on an enum type with job titles. Assume the following (MWE) code:
public abstract class Employee
{
protected string title = "Employee"; // underlying field
public string Title { get { return title; } } // read-only property
public Employee() { // do some stuff all children need } // constructor
public virtual void Display()
{
Console.WriteLine("Title: {0}", Title);
}
}
public class Director : Employee
{
protected new string title = "Director"; // shadowing field works here
public int NumberOfProjectsManaged { get; set; } // additional property
public Director() : base() { NumberOfProjectsManaged = 0; } // constructor
public override void Display()
{
base.Display();
Console.WriteLine("Number of Projects Managed: {0}", NumberOfProjectsManaged);
}
}
public class Partner : Director
{
// there are more than two in the actual code, but this is a MWE
public enum SpecificTitle
{
Principal,
Partner
};
public Partner() : base()
{
this._setTitle(SpecificTitle.Partner); // defaults to Partner
}
public Partner(SpecificTitle jobTitle)
{
this._setTitle(jobTitle); // overloaded ctor allows user to specify
}
private void _setTitle(SpecificTitle jobTitle)
{
switch (jobTitle)
{
case SpecificTitle.Principal:
this.title = "Principal";
break;
case SpecificTitle.Partner:
default:
this.title = "Partner";
break;
}
}
}
The Director
class works fine and the title is always "Director" as desired. However, the Partner
class always has the title "Employee" rather than "Partner" or "Principal". It doesn't matter if I simply use the default constructor:
Partner DefaultTitle = new Partner(); // title = "Employee"
Or if I specify one:
Partner PrincipalTitle = new Partner(Partner.SpecificTitle.Principal);
To output the value, I use the inherited Display()
method:
DefaultTitle.Display();
Please help me understand what I am doing wrong.
Upvotes: 2
Views: 388
Reputation: 18419
To cater your need not to define title in all of the constructors in your Director class
public Director() : base() {
// other stuffs
this.title = "Director";
}
// other constuctors
public Director(object someparam) : this() {
// do some stuff
}
So every time a constructor is called, it bubbles up to the base constructor.
Upvotes: 1
Reputation: 4595
The problem is your use of this line:
protected new string title = "Director";
The new
keyword is hiding the Employee
definition of title
.
Not really a problem if that is what you are wanting. The problem comes in when you are calling Partner.Display
the path of execution traces back to the Employee
definition of that method. Which in the Employee
definition it is using the hidden title
field.
When you are setting the title
in the Partner
class you are only setting the new
title
field in the Director
class and not the base class Employee
's title
field.
To fix this issue remove the line in question mentioned above. Then you will want to make your Director
constructor look like this.
public Director() : base()
{
NumberOfProjectsManaged = 0;
title = "Director";
}
Upvotes: 2
Reputation: 2978
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Partner DefaultTitle = new Partner(); // title = "Employee"
DefaultTitle.Display();
Console.ReadLine();
}
}
public abstract class Employee
{
public virtual string title { get; set; } // underlying field
public string Title
{
get { return title; }
} // read-only property
public Employee() { // do some stuff all children need
this.title = "Employee";
} // constructor
public virtual void Display()
{
Console.WriteLine("Title: {0}", Title);
}
}
public class Director : Employee
{
public override string title { get; set; } // shadowing field works here
public int NumberOfProjectsManaged { get; set; } // additional property
public Director() : base() {
this.title = "Director";
} // constructor
public override void Display()
{
base.Display();
}
}
public class Partner : Director
{
// there are more than two in the actual code, but this is a MWE
public override string title { get; set; }
public enum SpecificTitle
{
Principal,
Partner
};
public Partner() : base()
{
this._setTitle(SpecificTitle.Partner); // defaults to Partner
}
public Partner(SpecificTitle jobTitle)
{
this._setTitle(jobTitle); // overloaded ctor allows user to specify
}
private void _setTitle(SpecificTitle jobTitle)
{
switch (jobTitle)
{
case SpecificTitle.Principal:
this.title = "Principal";
break;
case SpecificTitle.Partner:
default:
this.title = "Partner";
break;
}
}
}
}
Finally got it working! sorry for my last answer. I set the base class to virtual so any child classes can overwrite its value.
robwaminal is correct, setting the title in Partner
class only set the title of it's direct parent which is Director
.
Upvotes: 0
Reputation: 81
You can set the enum 'SpecificTitle' ouside from Partner class.
public enum SpecificTitle
{
Principal,
Partner
};
and use the type of title in both Employee and Director classes as 'SpecificTitle' enum
public abstract class Employee
{
protected SpecificTitle title = "Employee";
//others
}
public class Director : Employee
{
protected SpecificTitle title = "Director";
//others
}
and replace the switch case as the following:
switch (jobTitle)
{
case SpecificTitle.Principal:
this.title = SpecificTitle.Principal;
break;
case SpecificTitle.Partner:
default:
this.title = SpecificTitle.Partner;
break;
}
or sure you should replace the switch case with this line
private void _setTitle(SpecificTitle jobTitle)
{
this.title = jobTitle;
}
I did not tested this, but this logic will work with you.
Upvotes: 0
Reputation: 1733
The base Employee.Display()
method prints the value of its title
field. The Director
class defines a new title
field, which shadows (not overrides) the base Employee.title
field. The Partner
and Director
class work with Director.title
, which has nothing to do with the base Employee.title
field. Refactor your Director
class to remove the new title
field.
Upvotes: 3
Reputation: 505
It would appear as if you problem is in the Director class, in particular the following line:
protected new string title = "Director"; // shadowing field works here
You don't really need it, and you may also want to change your constructor as well. Heres the Director class
public class Director : Employee
{
//protected string title = "Director"; // shadowing field works here
public int NumberOfProjectsManaged { get; set; } // additional property
public Director() : base() {
NumberOfProjectsManaged = 0;
title = "Director";
} // constructor
public override void Display()
{
base.Display();
Console.WriteLine("Number of Projects Managed: {0}", NumberOfProjectsManaged);
}
}
For testing I used this:
Partner DefaultTitle = new Partner();
DefaultTitle.Display();
Partner PrincipalTitle = new Partner(Partner.SpecificTitle.Principal);
PrincipalTitle.Display();
Director director = new Director();
director.Display();
and got the following output:
Title: Partner
Number of Projects Managed: 0
Title: Principal
Number of Projects Managed: 0
Title: Director
Number of Projects Managed: 0
Upvotes: 1