例えば:
public class A : A.B
{
public class B { }
}
コンパイラからこのエラーが生成されます。
'A' と 'AB' を含む循環基底クラスの依存関係
ネストされたクラスは、外部クラスのプライベート メンバーへのアクセスに関する特別な規則を除いて、通常のクラスと同じように動作すると常に考えていましたが、2 つのクラス間で暗黙の継承が発生していると思いますか?
例えば:
public class A : A.B
{
public class B { }
}
コンパイラからこのエラーが生成されます。
'A' と 'AB' を含む循環基底クラスの依存関係
ネストされたクラスは、外部クラスのプライベート メンバーへのアクセスに関する特別な規則を除いて、通常のクラスと同じように動作すると常に考えていましたが、2 つのクラス間で暗黙の継承が発生していると思いますか?
私が知る限り、暗黙の継承はありません。A と B が一般的であるとすれば奇妙に思えるかもしれませんが、これで問題ないと思っていました。
仕様のセクション 10.1.4 で指定されています。
クラス B がクラス A から派生する場合、A が B に依存するのはコンパイル時エラーです。クラスは直接の基本クラス (存在する場合) に 直接依存し、すぐにネストされているクラスに直接依存します(もしあれば)。この定義を考えると、クラスが依存するクラスの完全なセットは、直接依存関係の推移閉包です。
関連するセクションを強調表示しました。
これは、コンパイラがそれを拒否している理由を説明していますが、言語がそれを禁止している理由ではありません。CLI制限とかあるのかな…
編集: わかりました、Eric Lippert から応答がありました。基本的には、技術的には可能です (CLI にはそれを禁止するものは何もありません) が、次のようになります。
また、電子メールのスレッドでは、この種のことが有効になることも指摘されていました。
A.B x = new A.B.B.B.B.B.B.B.B.B.B.B.B();
...しかし、BがAから派生した場合、それはすでに(Tinisterが指摘したように)有効です。
入れ子 + 継承 = 奇妙さ...
これは、C# の問題ではなく、コンパイラの問題です。コンパイラの仕事の 1 つは、メモリ内にクラスを配置することです。これは、一連の基本的なデータ型、ポインター、関数ポインター、およびその他のクラスです。
クラス B のレイアウトが何であるかを知るまで、クラス A のレイアウトを構築することはできません。クラス A のレイアウトが完了するまで、クラス B のレイアウトが何であるかを知ることはできません。循環依存。
私がやろうとしていたことについての質問について:
基本的には、それ自体と構成関係のあるクラスを作成したかったのですが、含まれているオブジェクトに他のオブジェクトを含めたくなかったので、「A has-a A has-aAhas-」が多いチェーンを作成しました。 a Ahas-a...」の関係。ですから、当時の私の考えは次のようなことでした。
public class A : A.AA
{
public class AA
{
// All of the class's logic
}
private AA _containedObject;
}
当時はかなり滑らかに見えましたが、振り返ってみると、私にはよくわかりません...
私はグーグルを調べたが、それについて良い議論が見つからなかったので、ここに投稿しようと思った。
ただし、Eric Lippertのブログの投稿のコメントの中で、彼はネストされたインターフェイスを実装するクラスと、型引数としてネストされたクラスを使用するジェネリックインターフェイスを実装するクラスの例を示しています(コンパイルせず、「現在のコンパイラの「バグ」)。これらの例はどちらもインターフェイスに関するものなので、ネストされたクラスに特別なルールがあるかどうか疑問に思いました。そして、あるようです。
ネストされたインターフェイスを含む別のクラスから継承することで、これを(少なくともインターフェイスで)回避できました。(私のシナリオでは、これらのインターフェイスへの参照も返しています。)
それ以外の:
public class MyClass<T1, T2, T3> :
MyClass<T1, T2, T3>.Interface
where T1 : ...
where T2 : ...
where T3 : ... {
public interface Interface { Interface SomeMethod(); }
Interface Interface.SomeMethod() {
...
}
}
// compile error: Circular base class dependency
次のようにします。
public sealed class MyClassInterfaces<T1, T2, T3>
where T1 : ...
where T2 : ...
where T3 : ... {
public interface Interface { Interface SomeMethod(); }
}
sealed class MyClass<T1, T2, T3> :
MyClassInterfaces<T1, T2, T3>.Interface
where T1 : ...
where T2 : ...
where T3 : ... {
MyClassInterfaces<T1, T2, T3>.Interface
MyClassInterfaces<T1, T2, T3>.Interface.SomeMethod() {
...
}
}
明示的なインターフェース実装の見苦しさを避けるために、他のクラスから継承することもできますが、ネストされたクラスから継承しようとしても、両方のクラスから継承することはできないため、うまくいきません。
public abstract class MyClassInterfaces<T1, T2, T3>
where T1 : ...
where T2 : ...
where T3 : ... {
public interface Interface { Interface SomeMethod(); }
}
sealed class MyClass<T1, T2, T3> :
MyClassInterfaces<T1, T2, T3>,
MyClassInterfaces<T1, T2, T3>.Interface
where T1 : ...
where T2 : ...
where T3 : ... {
Interface Interface.SomeMethod() {
...
}
}
入れ子は、入れ子になった型が入れ子型の定義の一部であることを表すためのものだと思います。その解釈では、コンパイラが A の定義にヒットした時点で AB はまだ定義されておらず、A の最後でも AB に関して既に定義されているため、この制限は理にかなっています。
これは私には意味がありません...あなたは存在しない何かを拡張しようとしています!!! クラスBはクラスAのスコープ内にのみ存在するため、何らかの継承があると思います。