私は最近、かなり多くのプロバイダーと連携しており、抽象静的メソッドを持つ抽象クラスが必要な興味深い状況に遭遇しました。このトピックに関するいくつかの投稿を読みましたが、それは理にかなっていますが、わかりやすい説明はありますか?
私は最近、かなり多くのプロバイダーと連携しており、抽象静的メソッドを持つ抽象クラスが必要な興味深い状況に遭遇しました。このトピックに関するいくつかの投稿を読みましたが、それは理にかなっていますが、わかりやすい説明はありますか?
回答:
静的メソッドはインスタンス化されないため、オブジェクト参照がなくても使用できます。
静的メソッドの呼び出しは、オブジェクト参照ではなくクラス名を介して行われ、それを呼び出す中間言語(IL)コードは、それを定義したクラスの名前(必ずしも使用したクラス。
例を示しましょう。
次のコードで:
public class A
{
public static void Test()
{
}
}
public class B : A
{
}
次のようにB.Testを呼び出すと、
class Program
{
static void Main(string[] args)
{
B.Test();
}
}
次に、Mainメソッド内の実際のコードは次のとおりです。
.entrypoint
.maxstack 8
L0000: nop
L0001: call void ConsoleApplication1.A::Test()
L0006: nop
L0007: ret
ご覧のとおり、コードはそのように記述できますが、それを定義したのはA.Testであり、B.Testではなく、A.Testが呼び出されます。
あなたが持っていた場合は、クラスの種類、あなたがタイプしていないオブジェクトを参照する変数を作ることができますデルファイのように、、、あなたは仮想ので、抽象静的メソッド(ともコンストラクタ)のためのより多くの使用を持っているでしょうが、彼らは利用できませんし、したがって、静的呼び出しは.NETでは非仮想です。
ILの設計者は、コードをコンパイルしてB.Testを呼び出し、実行時に呼び出しを解決できることを理解していますが、そこに何らかのクラス名を記述する必要があるため、仮想化はできません。
仮想メソッド、つまり抽象メソッドは、実行時に多くの異なるタイプのオブジェクトを含むことができる変数を使用している場合にのみ有用であり、したがって、変数内にある現在のオブジェクトに対して適切なメソッドを呼び出す必要があります。静的メソッドでは、とにかくクラス名を調べる必要があるので、呼び出すことができる正確なメソッドは変更できないため、コンパイル時に既知です。
したがって、仮想/抽象静的メソッドは.NETでは使用できません。
Car
、仮想静的CreateFromDescription
ファクトリメソッドを持つ型がある場合、Car
制約付きのジェネリック型を受け入れるコードは、型の自動車を生成するためにT
呼び出すことができます。このような構造は、そのようなメソッドを定義する各型が、仮想「静的」メソッドを保持するネストされたクラスジェネリックの静的シングルトンインスタンスを保持する場合、CLR内でかなりよくサポートされます。T.CreateFromDescription
T
静的メソッドは継承またはオーバーライドできません。そのため、抽象メソッドにすることはできません。静的メソッドは、クラスのインスタンスではなく型で定義されるため、その型で明示的に呼び出す必要があります。したがって、子クラスのメソッドを呼び出す場合は、その名前を使用して呼び出す必要があります。これは継承を無意味にします。
しばらくの間、静的メソッドを継承できると仮定します。このシナリオを想像してください:
public static class Base
{
public static virtual int GetNumber() { return 5; }
}
public static class Child1 : Base
{
public static override int GetNumber() { return 1; }
}
public static class Child2 : Base
{
public static override int GetNumber() { return 2; }
}
Base.GetNumber()を呼び出す場合、どのメソッドが呼び出されますか?どの値が返されましたか?オブジェクトのインスタンスを作成しないと、継承はかなり難しいことが簡単にわかります。継承のない抽象メソッドは、本体を持たないメソッドなので、呼び出すことができません。
int DoSomething<T>() where T:Base {return T.GetNumber();}
。DoSomething<Base>()
5 DoSomething<Child2>()
を返し、2 を返すと便利です。このような機能は、おもちゃの例だけでなく、のようなものにも役立ちます。この場合class Car {public static virtual Car Build(PurchaseOrder PO);}
、から派生するすべてのクラスCar
は、注文書を指定してインスタンスを作成できるメソッドを定義する必要があります。
静的フィールドとメソッドの継承が確実に必要な状況は次のとおりです。
abstract class Animal
{
protected static string[] legs;
static Animal() {
legs=new string[0];
}
public static void printLegs()
{
foreach (string leg in legs) {
print(leg);
}
}
}
class Human: Animal
{
static Human() {
legs=new string[] {"left leg", "right leg"};
}
}
class Dog: Animal
{
static Dog() {
legs=new string[] {"left foreleg", "right foreleg", "left hindleg", "right hindleg"};
}
}
public static void main() {
Dog.printLegs();
Human.printLegs();
}
//what is the output?
//does each subclass get its own copy of the array "legs"?
legs
静的抽象プロパティである必要があります。
前の説明に加えて、静的メソッド呼び出しはcompile-timeで特定のメソッドにバインドされます。これにより、ポリモーフィックな動作が除外されます。
(delphiの)静的メソッドを実際にオーバーライドしますが、少し見苦しいですが、私たちのニーズには問題なく動作します。
これを使用して、クラスがクラスインスタンスなしで使用可能なオブジェクトのリストを持つことができるようにします。たとえば、次のようなメソッドがあります。
class function AvailableObjects: string; override;
begin
Result := 'Object1, Object2';
end;
醜いですが必要です。これにより、使用可能なオブジェクトを検索するためだけにすべてのクラスをインスタンス化する代わりに、必要なものだけをインスタンス化できます。
これは簡単な例ですが、アプリケーション自体は、1つのサーバーですべてのクラスを使用できるクライアントサーバーアプリケーションであり、サーバーが持つすべてのものを必要とせず、オブジェクトインスタンスを必要としない複数の異なるクライアントです。
そのため、クライアントごとに1つの異なるサーバーアプリケーションを用意するよりも、保守がはるかに簡単です。
例が明確であることを願っています。
抽象メソッドは暗黙的に仮想です。抽象メソッドにはインスタンスが必要ですが、静的メソッドにはインスタンスがありません。したがって、抽象クラスに静的メソッドを含めることができますが、静的抽象(または抽象静的)にすることはできません。