回答:
ここからの引用:
これは実際には仕様によるものです。静的クラスを継承する正当な理由はないようです。クラス名自体を介していつでもアクセスできるパブリック静的メンバーがあります。静的なものを継承するために私が見た唯一の理由は、タイピングのいくつかの文字を保存するなど、悪いものでした。
静的メンバーを直接スコープに入れるメカニズムを検討する理由があるかもしれません(実際、Orcas製品サイクルの後でこれを検討します)が、静的クラスの継承は進むべき道ではありません。静的クラスにたまたま存在する静的メンバーのみ。
(Mads Torgersen、C#言語PM)
チャンネル9からの他の意見
.NETでの継承は、インスタンスベースでのみ機能します。静的メソッドは、インスタンスレベルではなく、タイプレベルで定義されます。そのため、静的メソッド/プロパティ/イベントではオーバーライドが機能しません...
静的メソッドはメモリに1回だけ保持されます。それらのために作成された仮想テーブルなどはありません。
.NETでインスタンスメソッドを呼び出す場合は、常に現在のインスタンスを指定します。これは.NETランタイムによって隠されていますが、発生します。各インスタンスメソッドは、最初の引数として、メソッドが実行されるオブジェクトへのポインタ(参照)を持っています。これは静的メソッドでは発生しません(型レベルで定義されているため)。コンパイラーは、呼び出すメソッドを選択することをどのように決定する必要がありますか?
(リトルグル)
そして貴重なアイデアとして、littleguruにはこの問題に対する部分的な「回避策」があります。それはシングルトンパターンです。
object
、誰もがそれを知っていると予想されます。したがって、静的クラスは、明示的に指定するかどうかにかかわらず、常にから継承しobject
ます。
静的クラスを継承できない主な理由は、静的クラスが抽象的であり、シールされているためです(これにより、インスタンスの作成も防止されます)。
したがって、この:
static class Foo { }
このILにコンパイルします。
.class private abstract auto ansi sealed beforefieldinit Foo
extends [mscorlib]System.Object
{
}
このように考えてみましょう。次のように、型名を介して静的メンバーにアクセスします。
MyStaticType.MyStaticMember();
そのクラスから継承する場合は、新しいタイプ名でアクセスする必要があります。
MyNewType.MyStaticMember();
したがって、コードで使用した場合、新しいアイテムは元のアイテムとは関係がありません。多態性などの継承関係を利用する方法はありません。
おそらく、元のクラスの一部のアイテムを拡張したいだけだと思っているかもしれません。その場合、元のメンバーをまったく新しい型で使用することを妨げるものは何もありません。
おそらく、既存の静的型にメソッドを追加したいでしょう。あなたはすでに拡張メソッドを介してそれを行うことができます。
おそらくType
、メソッドの実行内容を正確に知らなくても、実行時にstatic を関数に渡し、その型のメソッドを呼び出すことができるようにしたいでしょう。その場合、インターフェースを使用できます。
つまり、最終的には静的クラスを継承しても何も得られません。
SomeClass<T> where T:Foo
アクセスできるように、静的タイプと仮想静的メンバーとの継承関係を定義できますFoo
。また、のT
一部の仮想静的メンバーをFoo
オーバーライドするクラスの場合、ジェネリッククラスはそれらのオーバーライドを使用します。おそらく、言語が現在のCLRと互換性のある方法でそれを行うことができる規則を定義することも可能です(たとえば、そのようなメンバーを持つクラスは、静的なフィールドとともに、そのようなインスタンスメンバーを含む保護された非静的クラスを定義する必要がありますそのタイプのインスタンスを保持します)。
クラス階層を使用して実現したいことは、名前空間を介してのみ実現できます。したがって、名前空間をサポートする言語(C#など)では、静的クラスのクラス階層を実装する必要はありません。クラスをインスタンス化することはできないので、必要なのは、名前空間を使用して取得できるクラス定義の階層構造だけです。
継承されたクラス名を通じて「継承された」静的メンバーにアクセスできますが、静的メンバーは実際には継承されません。これが、仮想または抽象にできず、オーバーライドできない理由の一部です。あなたの例では、Base.Method()を宣言した場合、コンパイラはInherited.Method()への呼び出しをとにかくBase.Method()にマッピングします。明示的にBase.Method()を呼び出すこともできます。小さなテストを作成して、Reflectorで結果を確認できます。
静的メンバーを継承できず、静的クラスに静的メンバーのみを含めることができる場合、静的クラスを継承するとどのようなメリットがありますか?
うーん...静的メソッドで満たされた非静的クラスがあるだけなら、それははるかに異なりますか?
できる回避策は、静的クラスを使用せず、コンストラクターを非表示にすることです。これにより、クラスの静的メンバーのみがクラスの外部からアクセスできるようになります。結果は本質的に継承可能な「静的」クラスです:
public class TestClass<T>
{
protected TestClass()
{ }
public static T Add(T x, T y)
{
return (dynamic)x + (dynamic)y;
}
}
public class TestClass : TestClass<double>
{
// Inherited classes will also need to have protected constructors to prevent people from creating instances of them.
protected TestClass()
{ }
}
TestClass.Add(3.0, 4.0)
TestClass<int>.Add(3, 4)
// Creating a class instance is not allowed because the constructors are inaccessible.
// new TestClass();
// new TestClass<int>();
残念ながら、「設計による」言語の制限により、次のことはできません。
public static class TestClass<T>
{
public static T Add(T x, T y)
{
return (dynamic)x + (dynamic)y;
}
}
public static class TestClass : TestClass<double>
{
}
静的継承のように見えることができます。
ここにトリックがあります:
public abstract class StaticBase<TSuccessor>
where TSuccessor : StaticBase<TSuccessor>, new()
{
protected static readonly TSuccessor Instance = new TSuccessor();
}
次に、これを行うことができます:
public class Base : StaticBase<Base>
{
public Base()
{
}
public void MethodA()
{
}
}
public class Inherited : Base
{
private Inherited()
{
}
public new static void MethodA()
{
Instance.MethodA();
}
}
Inherited
クラスには、静的そのものではないが、我々はそれを作成することはできません。実際にはBase
、を構築する静的コンストラクタを継承し、すべてのプロパティとメソッドをBase
静的として使用可能なています。これで、静的コンテキストに公開する必要がある各メソッドおよびプロパティの静的ラッパーを作成するために残された唯一のことです。
静的ラッパーメソッドを手動で作成する必要があるなどの欠点があり、 new
キーワード。しかし、このアプローチは、静的継承に本当に似たものをサポートするのに役立ちます。
PSコンパイルされたクエリを作成するためにこれを使用しましたが、これは実際にはConcurrentDictionaryで置き換えることができますが、スレッドセーフの静的な読み取り専用フィールドで十分でした。
私の答え:デザインの選択が悪い。;-)
これは、構文の影響に焦点を当てた興味深い議論です。私の見解では、議論の核心は、設計の決定が封印された静的クラスにつながったということです。子の名前の後ろに隠れる(「混乱させる」)のではなく、最上位に表示される静的クラスの名前の透明性に焦点を当てていますか?ベースまたは子に直接アクセスして混乱を招く可能性のある言語実装を想像することができます。
静的な継承が何らかの方法で定義されていると想定した疑似例。
public static class MyStaticBase
{
SomeType AttributeBase;
}
public static class MyStaticChild : MyStaticBase
{
SomeType AttributeChild;
}
につながる:
// ...
DoSomethingTo(MyStaticBase.AttributeBase);
// ...
同じストレージに影響を与える可能性があります(?)
// ...
DoSomethingTo(MyStaticChild.AttributeBase);
// ...
とても紛らわしい!
ちょっと待って!コンパイラは、両方で同じシグネチャが定義されているMyStaticBaseとMyStaticChildをどのように処理しますか?子が上記の例よりもオーバーライドすると同じストレージが変更されない場合、おそらく?これはさらに混乱を招きます。
静的な継承を制限するための強力な情報スペースの正当化があると思います。制限の詳細についてはまもなく説明します。この疑似コードは値を示しています。
public static class MyStaticBase<T>
{
public static T Payload;
public static void Load(StorageSpecs);
public static void Save(StorageSpecs);
public static SomeType AttributeBase
public static SomeType MethodBase(){/*...*/};
}
それからあなたは得る:
public static class MyStaticChild : MyStaticBase<MyChildPlayloadType>
{
public static SomeType AttributeChild;
public static SomeType SomeChildMethod(){/*...*/};
// No need to create the PlayLoad, Load(), and Save().
// You, 'should' be prevented from creating them, more on this in a sec...
}
使用法は次のようになります。
// ...
MyStaticChild.Load(FileNamePath);
MyStaticChild.Save(FileNamePath);
doSomeThing(MyStaticChild.Payload.Attribute);
doSomething(MyStaticChild.AttributeBase);
doSomeThing(MyStaticChild.AttributeChild);
// ...
静的な子を作成する人は、プラットフォームまたは環境のシリアル化エンジンに課される可能性のある制限を理解している限り、シリアル化プロセスについて考える必要はありません。
静的(シングルトンや他の形式の「グローバル」)は、多くの場合、構成ストレージの周辺で発生します。静的な継承により、この種の責任の割り当てを構文で明確に表現して、構成の階層を一致させることができます。ただし、先に示したように、基本的な静的継承の概念が実装されている場合は、非常にあいまいになる可能性がたくさんあります。
適切な設計の選択は、特定の制限付きで静的継承を許可することだと思います。
それでも、ジェネリックリファレンスを介して同じストアを変更できますMyStaticBase<ChildPayload>.SomeBaseField
。ただし、ジェネリック型を指定する必要があるため、お勧めできません。子参照はよりクリーンになりMyStaticChild.SomeBaseField
ますが、
私はコンパイラの作成者ではないので、これらの制限をコンパイラに実装することの難しさについて何か欠けているのかどうかはわかりません。とは言っても、静的な継承を制限するには情報スペースが必要であり、基本的な答えは、デザインの選択が悪い(または単純すぎる)ためにできないということです。
静的クラスとクラスメンバーは、クラスのインスタンスを作成せずにアクセスできるデータと関数を作成するために使用されます。静的クラスメンバーを使用すると、オブジェクトのアイデンティティに依存しないデータと動作を分離できます。データと関数は、オブジェクトに何が発生しても変化しません。静的クラスは、オブジェクトIDに依存するクラスにデータまたは動作がない場合に使用できます。
クラスは静的に宣言できます。これは、クラスに静的メンバーのみが含まれることを示します。staticキーワードのインスタンスを作成するためにnewキーワードを使用することはできません。静的クラスは、クラスを含むプログラムまたは名前空間が読み込まれるときに、.NET Framework共通言語ランタイム(CLR)によって自動的に読み込まれます。
静的クラスを使用して、特定のオブジェクトに関連付けられていないメソッドを含めます。たとえば、インスタンスデータに作用せず、コード内の特定のオブジェクトに関連付けられていない一連のメソッドを作成することは、一般的な要件です。静的クラスを使用して、これらのメソッドを保持できます。
静的クラスの主な機能は次のとおりです。
静的メンバーのみが含まれます。
それらはインスタンス化できません。
彼らは封印されています。
インスタンスコンストラクターを含めることはできません(C#プログラミングガイド)。
したがって、静的クラスの作成は、静的メンバーとプライベートコンストラクタのみを含むクラスの作成と基本的に同じです。プライベートコンストラクターは、クラスがインスタンス化されるのを防ぎます。
静的クラスを使用する利点は、コンパイラがインスタンスメンバーが誤って追加されていないことを確認できることです。コンパイラーは、このクラスのインスタンスが作成できないことを保証します。
静的クラスはシールされているため、継承できません。Object以外のクラスから継承することはできません。静的クラスにインスタンスコンストラクタを含めることはできません。ただし、静的コンストラクタを持つことができます。詳細については、「静的コンストラクター(C#プログラミングガイド)」を参照してください。
静的メンバーとプライベートコンストラクターのみを含む静的クラスを作成する場合、唯一の理由は、静的コンストラクターがクラスをインスタンス化できないため、静的クラスを継承できないためです。クラス名自体を使用して静的クラスを作成します。静的クラスを継承しようとすることはお勧めできません。