質問の見出しは少し混乱しているようですが、ここで質問をクリアしてみます
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();
}
}
}
コード全体を理解しようとしないでください。私はそれを要約しています。
私の質問は、どうすればforcePTSalesPersonに独自のGiveBonus実装を持たせることができますか
あなたはこれについて間違った方法で考えていると思います。言語設計者は、「私たちが本当に必要なのは、メソッドをオーバーライドする必要があるとしてマークする方法です。abstract "と呼ばれるものを発明しましょう。彼らは、「仮想メソッドは、この基本型のすべての派生型がこのメソッドを実行できるはずです。という考えを表すことができます。しかし、賢明なコードなしメソッドの基本クラスバージョンに入れることができますか?その状況の抽象メソッドと呼ばれるものを発明しましょう。」
それが抽象メソッドの解決を意図した問題です。すべての派生クラスに共通のメソッドがありますが、実用的な基本クラスの実装はありません。「派生型に実装を強制する方法が必要」ではありません。派生型は、実装を提供することを強制されます-結果の結果ですが、そもそも解決することを意図した問題ではありません。
C#言語には、「サブメソッドにこのメソッドの独自の実装を提供するよう強制する必要がある」という問題に対するメカニズムがありません。お客様。
あなたへの私の質問は:なぜあなたはこれをしたいのですか?基本クラスの実装が派生クラスにとって正しいかどうかを判断するのは、派生クラスの開発者次第です。それはあなた次第ではありません。そして、あなたがそれをする何らかの方法を持っていたとしても、開発者が単に言うことを止めるもの
override void M() { base.M(); }
?
派生クラスの開発者にこの作業を強制しようとする目的は何ですか?おそらくあなたが望むものを達成するためのより良い方法があります。
しかしより一般的には、あなたの階層がそもそも賢明に設計されているかどうかはわかりません。従業員にメソッドGiveBonusが表示されるとき、これは「従業員がボーナスを受け取ることができる」ではなく、「従業員がボーナスを与えることができる」ことを意味すると想定します。確かにマネージャーはボーナスを与え、従業員受信はボーナスを与えます。従業員の階層をやりすぎているのではないかと思います。
SalesPersonを抽象化するか、階層を変更しない限り、できません。
どうですか:
Employee*
^
|
SalesPersonBase* (have all the code except GiveBonus)
^ ^
| |
SalesPerson PTSalesPerson
EmployeeとSalesPersonBaseの両方が抽象としてマークされるようになりました。
ただし、PTSalesPersonに動作を継承するだけでなく、is-a関係も継承する必要がある場合(PTSalesPersonはSalesPersonでもあります)、これを強制する方法はありません。
上記のテキストは、コンパイル時のチェックのみを考慮する場合にのみ有効です。言い換えると、PTSalesPersonクラスにオーバーライドを追加していない場合にコンパイラーに文句を言わせたい場合、上記で説明したことをしない限り、それを行うことはできません。
ただし、実行時にメソッドを検査するためにリフレクションを使用し、PTSalesPersonのメソッドが明示的にオーバーライドされていない場合は例外をスローすることを妨げるものはありませんが、ハックと見なします。
依存性注入を使用します。 BonusCalculator
クラスを作成します。
public abstract class BonusCalculator
{
public abstract decimal CalculateBonus(Employee e)
}
基本クラスで:
private BonusCalculator Calculator { get; set; }
public void GiveBonus()
{
Bonus = Calculator.CalculateBonus(this)
}
実装のコンストラクターで:
public SomeKindOfEmployee()
{
Calculator = new SomeKindOfEmployeeBonusCalculator();
}
Person
サブクラスを実装している人は、BonusCalculator
のインスタンスを明示的に提供する必要があります(またはNullReferenceException
メソッドでGiveBonus
を取得します)。
追加のボーナスとして、このアプローチにより、Person
のさまざまなサブクラスが適切な場合にボーナス計算方法を共有できます。
編集
もちろん、PTSalesPerson
がSalesPerson
から派生し、そのコンストラクターが基本コンストラクターを呼び出す場合、これも機能しません。
クラスEmployee
を抽象として宣言しますが、"Must be implement by subclasses"のようなメッセージでランタイム例外をスローするGiveBonus()
を提供および実装します。古いSmalltalkの慣習です... C#にとって有用かどうかはわかりません。 Javaコードで使用しました。
WAは「インターフェース」を使用している可能性があるため、IBonusGiver {void GiveBonus(); }次に、抽象メソッドとオーバーライドの代わりに、この新しいインターフェイスをすべてのクラスに実装します。例えばPTSalesPerson:SalesPerson、IBonusGiverは、各クラスで新しい実装を強制します。
これは非常に古いスレッドですが、 この質問 で与えられた答えが役立つ場合があります。派生クラスに、仮想メソッド/プロパティの独自の実装を強制することができます。
public class D
{
public virtual void DoWork(int i)
{
// Original implementation.
}
}
public abstract class E : D
{
public abstract override void DoWork(int i);
}
public class F : E
{
public override void DoWork(int i)
{
// New implementation.
}
}
仮想メソッドが抽象として宣言されている場合、抽象クラスから継承するすべてのクラスに対して仮想メソッドのままです。抽象メソッドを継承するクラスは、メソッドの元の実装にアクセスできません。前の例では、クラスFのDoWorkはクラスDのDoWorkを呼び出すことができません。このように、抽象クラスは派生クラスに仮想メソッドの新しいメソッド実装を強制的に提供できます。
これは、実装に実際に2つの部分があることを示しているように感じます。基本クラスに含まれる部分実装と、サブクラスに必要な実装の完了が欠落している部分です。例:
public abstract class Base
{
public virtual void PartialImplementation()
{
// partial implementation
}
}
public sealed class Sub : Base
{
public override void PartialImplementation()
{
base.PartialImplementation();
// rest of implementation
}
}
初期実装が不完全であるため、オーバーライドを強制する必要があります。できることは、実装を2つの部分に分割することです。実装された部分部分と、実装待ちの欠落部分です。例:
public abstract class Base
{
public void PartialImplementation()
{
// partial implementation
RestOfImplementation();
}
// protected, since it probably wouldn't make sense to call by itself
protected abstract void RestOfImplementation();
}
public sealed class Sub : Base
{
protected override void RestOfImplementation()
{
// rest of implementation
}
}
SalesPerson Abstractを作成できない場合、この作業を行う唯一の方法は次のとおりです。
1)SalesPerson.GiveBonus(...)でリフレクションを使用して、「this」がSalesPerson、または派生クラスであるかどうかを判断しますa)派生クラスではない場合、SalesPerson.GiveBonusで現在のコードを実行します(これを仮想として宣言し、SalesPersonの実装が例外をスローするようにします。)
ここでの欠点は、反射が遅いことです。 GiveBonusDerivedが宣言されていない場合など、コンパイル時エラーはありません。
説明したセットアップを使用することはできません。 PTSalesPersonは、SalesPersonから継承するため、GiveBonusの実装を既に持っています。
SalesPersonインスタンスを直接作成しない場合、最も簡単なことは、SalesPersonを抽象化することです。これにより、子クラスが代わりにそれを実装するよう強制されます(または抽象化されます)。
そのメソッドにすべてのSalesPeopleに共通のロジックがある場合、SalesPersonにGiveBonusを テンプレートメソッド として実装できます。サブクラスで必要な抽象メソッドを呼び出します:
どちらの方法でも、子クラスに実装を強制する唯一の方法は、基本クラスを抽象化することです。
SalesPersonの実装で常にNotImplementedExceptionがスローされるようにすることができます。 :Vしかし、契約上、いいえ、それはできません。
これはかなり古いですが、やや似たような状況があります。基本クラスは構成ファイルをロードし、基本クラスのデフォルトを設定します。ただし、構成ファイルには、継承されたクラスのデフォルト値を含めることもできます。
これが、複合機能を取得する方法です。
基本クラスのメソッド
private void processConfigurationFile()
{
// Load and process the configuration file
// which happens to be an xml file.
var xmlDoc = new XmlDocument();
xmlDoc.Load(configurationPath);
// This method is abstract which will force
// the inherited class to override it.
processConfigurationFile(xmlDoc);
}
protected abstract void processConfigurationFile(XmlDocument document);
さて、この投稿が古いことは知っていますが、最近この回答を調べる必要がありましたので、これを探している他の人のために:(私はVS 2012 .net 4.5を使用していますので、古いバージョンについてはわかりません)
抽象クラスを作成し、両方の子クラスでオーバーライドを使用しました。
public abstract class Person
{
public string Name { get; protected set; }
public abstract void GiveName(string inName);
}
public class Employee : Person
{
public override void GiveName(string inName)
{
Name = inName;
}
}
public class SalesPerson:Employee
{
public override void GiveName(string inName)
{
Name = "Sales: "+inName;
}
}
テスト:
SalesPerson x = new SalesPerson();
x.GiveName("Mark"); //Name="Sales: Mark"
Employee e = x;
e.GiveName("Mark"); //Name="Sales: Mark"
Employee m = new Employee();
m.GiveName("Mark"); //Name="Mark"