C# で抽象静的メソッドを使用できないのはなぜですか?
-
08-06-2019 - |
質問
私は一緒に働いてきました プロバイダー 最近、抽象静的メソッドを持つ抽象クラスが必要になるという興味深い状況に遭遇しました。このトピックに関するいくつかの投稿を読んで、ある程度は理解できましたが、明確な説明はありますか?
解決
静的メソッドはそうではありません インスタンス化された そのため、オブジェクト参照がなくても使用できます。
静的メソッドの呼び出しは、オブジェクト参照ではなくクラス名を介して行われ、静的メソッドを呼び出す中間言語 (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 に対して行われます。これを定義したのは A クラスであり、そのようにコードを記述することはできますが、B.Test ではないからです。
持っていたら クラスタイプ, Delphi のように、オブジェクトではなく型を参照する変数を作成できる場合、仮想的で抽象的な静的メソッド (およびコンストラクター) をより多く使用できますが、それらは利用できないため、静的呼び出しは使用できません。 -.NET の仮想。
IL 設計者は、B.Test を呼び出すようにコードをコンパイルし、実行時に呼び出しを解決できることを理解していますが、それでも何らかのクラス名を記述する必要があるため、仮想ではありません。
仮想メソッド、つまり抽象メソッドは、実行時にさまざまな種類のオブジェクトを含めることができる変数を使用する場合にのみ役立ちます。そのため、変数内にある現在のオブジェクトに対して適切なメソッドを呼び出したい場合にのみ役立ちます。静的メソッドでは、とにかくクラス名を経由する必要があるため、呼び出す正確なメソッドは変更できないし、変更されないため、コンパイル時にわかります。
したがって、仮想/抽象静的メソッドは .NET では使用できません。
他のヒント
静的メソッドは継承またはオーバーライドできないため、抽象メソッドにすることはできません。静的メソッドはクラスのインスタンスではなく型で定義されるため、その型で明示的に呼び出す必要があります。したがって、子クラスのメソッドを呼び出したい場合は、その名前を使用して呼び出す必要があります。これにより、継承は無意味になります。
一時的に、静的メソッドを継承できると仮定します。次のシナリオを想像してください。
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() を呼び出すと、どのメソッドが呼び出されますか?どの値が返されましたか?オブジェクトのインスタンスを作成しないと継承がかなり難しいことがわかります。継承のない抽象メソッドは、本体を持たない単なるメソッドであるため、呼び出すことができません。
別の回答者 (McDowell) は、ポリモーフィズムはオブジェクト インスタンスに対してのみ機能すると述べました。それは修飾されている必要があります。クラスを「クラス」または「メタクラス」型のインスタンスとして扱う言語もあります。これらの言語は、インスタンス メソッドとクラス (静的) メソッドの両方のポリモーフィズムをサポートしています。
C# は、それ以前の Java や C++ と同様、そのような言語ではありません。の static
キーワードは、メソッドが動的/仮想ではなく静的にバインドされていることを示すために明示的に使用されます。
前の説明に追加すると、静的メソッド呼び出しは次の場所で特定のメソッドにバインドされます。 コンパイル時, 、むしろポリモーフィックな動作を除外します。
以下は、静的フィールドとメソッドの継承が確実に必要な状況です。
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"?
実際には (delphi で) 静的メソッドをオーバーライドします。これは少し見苦しいですが、ニーズには問題なく機能します。
これを使用して、クラスがクラス インスタンスなしで利用可能なオブジェクトのリストを持つことができます。たとえば、次のようなメソッドがあります。
class function AvailableObjects: string; override;
begin
Result := 'Object1, Object2';
end;
醜いですが必要です。この方法では、利用可能なオブジェクトを検索するためだけにすべてのクラスをインスタンス化するのではなく、必要なものだけをインスタンス化できます。
これは単純な例ですが、アプリケーション自体はクライアント/サーバー アプリケーションであり、1 台のサーバーで使用できるすべてのクラスと、サーバーが持つすべての機能を必要とせず、オブジェクト インスタンスを必要としない複数の異なるクライアントを備えています。
したがって、これは、クライアントごとに 1 つの異なるサーバー アプリケーションを使用するよりも保守がはるかに簡単です。
例が分かりやすかったと思います。
抽象メソッドは暗黙的に仮想的です。抽象メソッドにはインスタンスが必要ですが、静的メソッドにはインスタンスがありません。したがって、抽象クラス内に静的メソッドを含めることはできますが、それを静的抽象 (または抽象静的) にすることはできません。