How to force overriding a method in a descendant, without having an abstract base class?

Question Heading seems to be little confusing, But I will Try to clear my question here.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    public abstract class Employee
    {
        private string name;
        private int empid;
        BenefitPackage _BenefitPackage = new BenefitPackage();
        public string Name
         {
             get { return this.name; }
             set { this.name = value; }
            }
        public int EmpId
        {
            get { return this.empid; }
            set
            {
                if (value == 1)
                    return;
                this.empid = value; }
        }
        public Employee(string Name, int EmpId)
        {
            this.Name = Name;
            this.EmpId = EmpId;
        }
        public Employee()
        { }

        public abstract void GiveBonus();

    }

    public class Manager : Employee
    {
        private int noofstockoptions;
        public override void GiveBonus()
        {
            Console.WriteLine("Manger GiveBonus Override");
        }
        public int NoOfStockOptions
        {
            get { return this.noofstockoptions; }
            set { this.noofstockoptions = value; }
        }

        public Manager(string Name,int EmpId, int NoOfStockOptions):base(Name,EmpId)
        {
            this.NoOfStockOptions=NoOfStockOptions;
        }

    }
    public class SalesPerson:Employee
    {
        private int noofsales;
        public int NoOfSales
        {
            get { return this.noofsales; }
            set { this.noofsales = value; }
        }

        public SalesPerson(string Name, int EmpId, int NoOfSales):base(Name,EmpId)
        {
            this.NoOfSales = NoOfSales;
        }
        public override void GiveBonus()
        {
            Console.WriteLine("Hi from salesperson");
        }
    }
    public sealed class PTSalesPerson : SalesPerson
    {
        private int noofhrworked;
        public int NoOfHrWorked
        {
            get { return this.noofhrworked; }
            set { this.noofhrworked = value; }

        }
        public PTSalesPerson(string Name, int EmpId, int NoOfSales,int NoOfHrWorked):base(Name,EmpId,NoOfSales)
        {
            this.NoOfHrWorked = NoOfHrWorked;

        }
        //public new void GiveBonus()
        //{
        //    Console.WriteLine("hi from ptsalesperson");
        //} 
    }

    class BenefitPackage
    {
        public int Bonus;
        public int GiveBonus()
        {
            int i = 200;
            return i;
        }

        private class innerPublic
        {
            public int innerBonus;

        }


    }

    class MainClass
    {
        public static void Main()
        { 
        Manager _Manager=new Manager("Vaibhav",1,50);
        PTSalesPerson _PTSalesPerson = new PTSalesPerson("Shantanu", 1, 4, 6);
        _Manager.GiveBonus();

        Employee _emp;
        //_emp = new Employee("new emp",4);
        //_emp.GiveBonus();
        _PTSalesPerson.GiveBonus();
        ((SalesPerson)_PTSalesPerson).GiveBonus();
        Console.ReadLine();    
        }

    }
}

Please do not try to understand the whole code. I am summarising it.

  1. Employee is a Abstract class, which have an abstract method GiveBonus
  2. SalesPerson is a deriving from Employee. SalesPerson has to give definition to abstract Method GiveBonus.(SalesPerson can not be Abstract)
  3. PTSalesPerson is deriving from SalesPerson.

Now my question is, How can I force PTSalesPerson to have its own implementation of GiveBonus.


I think you're thinking about this the wrong way. The language designers did not say to themselves "what we really need is a way to mark a method as must be overridden, let's invent this thing called abstract". They said "A virtual method lets us represent the idea that every derived type of this base type should be able to do this method. But what if there is no sensible code that can possibly go in the base class version of the method? I know, let's invent this thing called an abstract method for that circumstance."

That's the problem that abstract methods were intended to solve: you have a method common to all derived classes but no sensible base class implementation, NOT "I need a way to force my derived types to provide an implementation". That derived types are forced to provide an implementation is a consequence of the solution, but not the problem intended to be solved in the first place.

The C# language does not have a mechanism for the problem "I must force my subtype to provide their own implementation of this method" because that's not a problem that the language designers, to my knowledge, ever considered would be a problem for the majority of our customers.

So my question to you is: why do you want to do this? Surely it is up to the developer of the derived class to determine whether or not the base class implementation is correct for the derived class or not. That's not up to you. And even if you did have some way to do that, what would stop the developer from simply saying

override void M() { base.M(); }

?

Can you explain what purpose you have for attempting to force this work upon the developers of your derived classes? Perhaps there is a better way to achieve what you want.

But more generally: I am not sure that your hierarchy is sensibly designed in the first place. When I see a method GiveBonus on an Employee, I assume that this means that "an employee can give a bonus", not "an employee can receive a bonus". Surely a manager gives a bonus and an employee receives a bonus. I think you might be making the employee hierarchy do too much.


You can not, unless you make SalesPerson abstract or change the hierarchy.

How about:

                       Employee*
                           ^
                           |
                       SalesPersonBase* (have all the code except GiveBonus)
                        ^           ^
                        |           |
                 SalesPerson      PTSalesPerson

Both Employee and SalesPersonBase are now marked as abstract.

However, if you require a PTSalesPerson to not only inherit behavior, but also inherit the is-a relationship (a PTSalesPerson is also a SalesPerson), then you have no way of forcing this.

Note, the above text is only valid if you only consider compile-time checks. In other words, if you want the compiler to complain if you haven't added an override to the PTSalesPerson class, you cannot do that, unless you do what I outlined above.

However, there's nothing stopping you from using reflection to examine the methods at runtime, and throw an exception if the method in PTSalesPerson is not explicitly overridden there, however I would consider that a hack.


Declare the class Employee as abstract, the class SalesPerson as concrete (non-abstract), and provide an implementation of GiveBonus() that throws a runtime exception with a message like "Must be implemented by subclasses" for any types or cases which the provided code is not supposed to cover. It's an old Smalltalk practice. I have used it in Java code.

if (GetType() != typeof(SalesPerson)) 
{
    throw new NotImplementedException("Please override in subclasses");
}

// ...proceed with giving SalesPerson a bonus

Use dependency injection. Create a BonusCalculator class:

public abstract class BonusCalculator
{
   public abstract decimal CalculateBonus(Employee e)
}

In your base class:

private BonusCalculator Calculator { get; set; }

public void GiveBonus()
{
   Bonus = Calculator.CalculateBonus(this)
}

In your implementation's constructor:

public SomeKindOfEmployee()
{
    Calculator = new SomeKindOfEmployeeBonusCalculator();
}

Someone implementing a Person subclass now has to explicitly provide it with an instance of a BonusCalculator (or get a NullReferenceException in the GiveBonus method).

As an added, er, bonus, this approach allows different subclasses of Person to share a bonus-calculation method if that's appropriate.

Edit

Of course, if PTSalesPerson derives from SalesPerson and its constructor calls the base constructor, this won't work either.