派生型でオーバーライドできますか?
-
03-07-2019 - |
質問
私が知る限り、C#2.0で次のことを行うことはできません
public class Father
{
public virtual Father SomePropertyName
{
get
{
return this;
}
}
}
public class Child : Father
{
public override Child SomePropertyName
{
get
{
return this;
}
}
}
派生クラスのプロパティを<!> quot; new <!> quot;として作成することで問題を回避しますが、もちろんポリモーフィックではありません。
public new Child SomePropertyName
2.0には解決策はありますか? この問題に対処する3.5の機能についてはどうですか?
解決
これは、型安全性の問題のため、どの.NET言語でも不可能です。タイプセーフ言語では、戻り値の共分散とパラメーターの反分散を指定する必要があります。このコードを使用してください:
class B {
S Get();
Set(S);
}
class D : B {
T Get();
Set(T);
}
Get
メソッドの場合、共分散とは、T
がS
またはD
から派生したタイプでなければならないことを意味します。それ以外の場合、B
型の変数に格納されたB.Get()
型のオブジェクトへの参照があった場合、Set
を呼び出したときに、B.Set(X)
として表現可能なオブジェクトを取得できません-型システムを破壊します。
X
メソッドの場合、反分散とは、D::Set(T)
が<=>または<=>の派生型である必要があることを意味します。それ以外の場合、<=>型の変数に格納された<=>型のオブジェクトへの参照があった場合、<=>を呼び出したときに、<=>は<=>型で、<=>型ではありません、< =>予期しないタイプのオブジェクトを取得します。
C#では、ゲッター/セッターのペアが1つしかない場合でも、プロパティのオーバーロード時に型の変更を許可しないという意識的な決定がありました。つまり、ゲッターを持つもののタイプを変更できますが、ゲッターとセッターの両方を持つタイプは変更できませんか?なぜですか?!<!> quot; -Anonymous Alternate Universe Newbie)。
他のヒント
(新規)再宣言できますが、(同じ名前で)再宣言して上書きすることはできません。 1つのオプションは、保護されたメソッドを使用して詳細を非表示にすることです。これにより、ポリモーフィズムと非表示の両方が同時に可能になります。
public class Father
{
public Father SomePropertyName
{
get {
return SomePropertyImpl();
}
}
protected virtual Father SomePropertyImpl()
{
// base-class version
}
}
public class Child : Father
{
public new Child SomePropertyName
{
get
{ // since we know our local SomePropertyImpl actually returns a Child
return (Child)SomePropertyImpl();
}
}
protected override Father SomePropertyImpl()
{
// do something different, might return a Child
// but typed as Father for the return
}
}
いいえ。ただし、2以上でジェネリックを使用できます:
public class MyClass<T> where T: Person
{
public virtual T SomePropertyName
{
get
{
return ...;
}
}
}
その後、FatherとChildは同じクラスのジェネリックバージョンです
ウィキペディアから:
C#プログラミング言語では、両方のreturn-typeのサポート 共分散とパラメーター デリゲートの反分散が追加されました 言語のバージョン2.0で。 共分散でも反分散でもない メソッドのオーバーライドがサポートされています。
ただし、プロパティの共分散については何も明示していません。
父と子の共通インターフェースを作成し、そのインターフェースのタイプを返すことができます。
いいえ。 C#はこのアイデアをサポートしていません(<!> quot; return type covariance <!> quot;と呼ばれます)。 ただし、これを行うことはできます。
public class FatherProp
{
}
public class ChildProp: FatherProp
{
}
public class Father
{
public virtual FatherProp SomePropertyName
{
get
{
return new FatherProp();
}
}
}
public class Child : Father
{
public override FatherProp SomePropertyName
{
get
{
// override to return a derived type instead
return new ChildProp();
}
}
}
i.e。基本クラスで定義されたコントラクトを使用しますが、派生型を返します。この点を明確にするために、より詳細なサンプルを作成しました-<!> quot; this <!> quot;を返します。再び何も変わりません。
返されたオブジェクトを実際の型(つまり<!> quot; someObjectがChildProp <!> quot;の場合)でテストすることは可能ですが(面倒です)、それに対して仮想メソッドを呼び出すほうがよいそのタイプに合ったもの。
基本クラスの仮想メソッド(この場合、仮想プロパティ)には実装があるだけでなく、コントラクトも定義します。つまり、子クラスはこのコントラクトに適合する場合、SomePropertyNameの異なる実装を提供できます(つまり、SomePropertyNameはオブジェクトを返します)タイプ<!> quot; FatherProp <!> quot;)。タイプ<!> quot; ChildProp <!> quot;のオブジェクトを返す<!> quot; FatherProp <!> quotから派生。この契約を満たしています。ただし、<!> quot; Child <!> quotのコントラクトは変更できません。 -この契約は、<!> quot; Father <!> quot;から派生したすべてのクラスに適用されます。
一歩下がってより広範な設計を検討する場合、C#ツールキットには、ジェネリックまたはインターフェイスなど、代わりに考慮する必要のある他の言語構成要素があります。
いいえ。 C#はこのアイデアをサポートしていません (<!> quot; return typeと呼ばれます 共分散<!> quot;)。
ウィキペディアから:
C#プログラミング言語では、 両方の戻り型のサポート 共分散とパラメーター デリゲートの反分散が追加されました 言語のバージョン2.0で。 共分散でも反分散でもない メソッドのオーバーライドがサポートされています。
(新規)再宣言できますが、 で再宣言してオーバーライドすることはできません 同じ時間(同じ名前)。 1 オプションは、保護されたメソッドを使用して 詳細を非表示-これにより両方が可能になります ポリモーフィズムと非表示 時間:
最善の解決策はジェネリックを使用することです:
public class MyClass<T> where T: Person
{
public virtual T SomePropertyNameA
{
get { return ...; }
}
}//Then the Father and Child are generic versions of the same class
これは私が来ることができる最も近いものです(これまで):
public sealed class JustFather : Father<JustFather> {}
public class Father<T> where T : Father<T>
{ public virtual T SomePropertyName
{ get { return (T) this; }
}
}
public class Child : Father<Child>
{ public override Child SomePropertyName
{ get { return this; }
}
}
JustFather
クラスがないと、他の派生型でない限り、Father<T>
をインスタンス化できませんでした。