简体   繁体   中英

How to pass enum value as parameter

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.

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.

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";
}

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

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.

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.

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.

C# virtual reference

robwaminal is correct, setting the title in Partner class only set the title of it's direct parent which is Director .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM