質問
最近、「静的な抽象」メソッドが必要と思われる問題に遭遇しました。なぜ不可能なのかはわかっていますが、この制限を回避するにはどうすればよいですか?
たとえば、説明文字列を持つ抽象クラスがあります。この文字列はすべてのインスタンスに共通であるため、静的としてマークされますが、このクラスから派生したすべてのクラスが独自のDescriptionプロパティを提供することを要求するため、抽象としてマークしました:
abstract class AbstractBase
{
...
public static abstract string Description{get;}
...
}
もちろんコンパイルしません。インターフェイスを使用することを考えましたが、インターフェイスに静的メソッドシグネチャが含まれていない可能性があります。
単に静的ではなく、常にインスタンスを取得してそのクラス固有の情報を取得する必要がありますか?
アイデアはありますか
解決
静的と抽象の組み合わせは、やや無意味です。静的の背後にある考え方は、問題のメンバーを使用するためにクラスのインスタンスを提示する必要がないということです。ただし、抽象では、インスタンスは具体的な実装を提供する派生クラスであると予想されます。
この種の組み合わせが必要な理由はわかりますが、実際には、「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();
}
}
コツは、AbstractBase<T>
の実装方法に関する詳細をDerivedClass
に伝えることです:
-
where T: new()
で新規作成できるため、シングルトンインスタンスを作成できます -
where T : AbstractBase<T>
を使用して自身から派生するため、Description
の実装があることを認識しています。
この方法_instance
には、静的メソッドGetDescription()
で呼び出すことができるDerivedClass.GetDescription()
フィールドが含まれます。
これにより、<=>で<=>を強制的に上書きし、<=>
<!> quot; abstract <!> quot;を作成できます。基本メソッドはException
をスローするため、開発者は<!> quot; warned <!> quot;オーバーライドせずに子クラスでこのメソッドを呼び出そうとした場合。
欠点は、クラスを拡張し、このメソッドを使用しない可能性があることです。次に、提供されている他の回答を参照してください。