私は最近、「静的抽象」メソッドが必要であると思われる問題に遭遇しました。なぜそれが不可能なのか知っていますが、この制限を回避するにはどうすればよいですか?
たとえば、説明文字列を持つ抽象クラスがあります。この文字列はすべてのインスタンスに共通なので、静的としてマークされていますが、このクラスから派生したすべてのクラスが独自のDescriptionプロパティを提供することを要求したいので、抽象としてマークしました。
abstract class AbstractBase
{
...
public static abstract string Description{get;}
...
}
もちろんコンパイルされません。インターフェイスの使用を考えましたが、インターフェイスに静的メソッドシグネチャが含まれていない可能性があります。
単に非静的にして、そのクラス固有の情報を取得するためのインスタンスを常に取得する必要がありますか?
何か案は?
静的と抽象を組み合わせても、意味がありません。 staticの背後にある考え方は、問題のメンバーを使用するためにクラスのインスタンスを提示する必要がないということです。ただし、abstractでは、具体的な実装を提供する派生クラスのインスタンスであることが期待されます。
なぜこのような組み合わせが必要なのかはわかりますが、実際には、「this」または非静的メンバーの実装の使用を拒否することが唯一の効果です。つまり、抽象メンバーまたは「静的抽象」メンバーの呼び出しに根本的な違いはありませんが、親クラスは派生クラスの実装に制限を課します(どちらの実装を使用するかを理解するには具体的なインスタンスが必要になるため)
できません。
これを行う場所は属性です。
例えば
[Name("FooClass")]
class Foo
{
}
Descriptionプロパティを賢く実装するために実装を延期することを気にしない場合は、簡単に行うことができます
public abstract string ClassDescription {get; }
// ClassDescription is more intention-revealing than Description
クラスを実装すると、次のようになります。
static string classDescription="My Description for this class";
override string ClassDescription { get { return classDescription; } }
次に、あなたのクラスは説明を持つという契約に従う必要がありますが、あなたはそれを慎重に行うために彼らに任せます。オブジェクト指向の方法で実装を指定する方法はありません(残酷で壊れやすいハックを除く)。
ただし、私の説明では、この説明はクラスメタデータであるため、他の人が説明しているように、属性メカニズムを使用したいと思います。特にリフレクションの複数の使用が心配な場合は、関心のある属性を反映するオブジェクトを作成し、TypeとDescriptionの間にディクショナリを格納します。これにより、反射が最小限に抑えられます(実行時の型検査以外はそれほど悪くありません)。ディクショナリは、通常この情報を必要とするクラスのメンバーとして格納できます。また、ドメイン全体のクライアントが必要とする場合は、シングルトンまたはコンテキストオブジェクトを介して格納できます。
それが静的である場合、変数のインスタンスは1つしかありません。派生クラスで静的変数を使用して実現したいことができる場合、継承がどのように意味をなすかわかりません。個人的には、インスタンス変数を回避しようとするのは遠いと思います。
なぜ古典的な方法だけではないのですか?
abstract class AbstractBase
{
protected string _Description = "I am boring abstract default value";
}
class Foo : AbstractBase {
public Foo() {
_Description = "I am foo!";
}
}
インスタンスで呼び出す必要がある場合、静的ではありません。
インスタンスでそれを呼び出さない場合、多態性はありません(つまり、ChildA.Descriptionは、言語に関する限り、ChildB.Descriptionとはまったく無関係です)。
可能な回避策は、ジェネリックスの助けを借りて、基本クラスで派生クラスのシングルトンを定義することです。
_import System;
public abstract class AbstractBase<T>
where T : AbstractBase<T>, new()
{
private static T _instance = new T();
public abstract string Description { get; }
public static string GetDescription()
{
return _instance.Description;
}
}
public class DerivedClass : AbstractBase<DerivedClass>
{
public override string Description => "This is the derived Class";
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(DerivedClass.GetDescription());
Console.ReadKey();
}
}
_
コツは、DerivedClass
の実装方法について_AbstractBase<T>
_にいくつかの詳細を伝えることです。
where T: new()
で新規作成できるため、シングルトンインスタンスを作成できますwhere T : AbstractBase<T>
_を使ってそれ自体から派生するので、Description
の実装があることがわかりますこのように、__instance
_には、静的メソッドGetDescription()
で呼び出すことができるDescription
フィールドが含まれています。これにより、Description
内のDerivedClass
を強制的に上書きし、DerivedClass.GetDescription()
を使用してその値を呼び出すことができます
「抽象」基本メソッドにException
をスローさせることができるため、開発者がオーバーライドせずに子クラスでこのメソッドを呼び出そうとすると、「警告」が表示されます。
欠点は、クラスを拡張してこのメソッドを使用しない可能性があることです。次に、提供されている他の回答を参照してください。