[解決済み] C#コンパイラは、異なるベースクラスから派生した型に対して、なぜ「型が統一される可能性がある」と文句を言うのでしょうか?
疑問点
私の現在の非コンパイルコードは以下のようなものです。
public abstract class A { }
public class B { }
public class C : A { }
public interface IFoo<T>
{
void Handle(T item);
}
public class MyFoo<TA> : IFoo<TA>, IFoo<B>
where TA : A
{
public void Handle(TA a) { }
public void Handle(B b) { }
}
C#コンパイラは、以下のルール/エラーを引用して、これをコンパイルすることを拒否します。
'MyProject.MyFoo<TA>' は 'MyProject.IFoo<TA>' と 'MyProject.IFoo<MyProject.B>' の両方を実装できない。なぜなら、これらはいくつかの型パラメータ置換に対して統一される可能性があるからである。
私はこのエラーの意味を理解しています。
TA
が何でもあり得るのであれば、技術的には
B
にもなり得ますが、その場合、2つの異なる
Handle
の実装を曖昧にしてしまいます。
しかし、TA
はできません。
は何でもありです。 型の階層を元に
TA
はできません。
である
B
- 少なくとも、私は
と思う
はできません。
TA
から派生したものでなければなりません。
A
を継承する必要があります。
ではなく
から派生する
B
というように、C#/.NETでは複数のクラスを継承することはできません。
genericパラメータを削除し、代わりに
TA
を
C
あるいは、さらに
A
であっても、コンパイルされます。
では、なぜこのエラーが出るのでしょうか? それはコンパイラのバグ、または一般的な非知性、あるいは私が見逃している他の何かがあるのでしょうか?
何か回避策があるのでしょうか。
MyFoo
ジェネリッククラスを再実装しなければならないのでしょうか?
TA
のような派生型があるのでしょうか?
どのように解決するのですか?
これは、C# 4 の仕様の 13.4.2 項の結果です。
Cから作成される可能性のある構成型が、型引数がLに代入された後、 Lの2つのインターフェースが同一になる場合、Cの宣言は無効である。制約の宣言は、すべての可能な構成された型を決定する際に考慮されません。
そこの2番目の文に注意してください。
したがって、これはコンパイラのバグではなく、コンパイラが正しいのです。言語仕様の欠陥であると主張する人もいるかもしれません。
一般的に言って、制約は、一般的な型について事実を推論しなければならないほとんどすべての状況で無視されます。制約のほとんどは 有効な基底クラス を決定するために使用され、それ以外にはほとんど使用されません。
残念ながら、それは時に、あなたが発見したように、言語が不必要に厳密である状況を引き起こします。
一般的に、一般的な型引数によってのみ区別される何らかの方法で、同じインターフェイスを2回実装することは、悪いコードのにおいです。例えば
class C : IEnumerable<Turtle>, IEnumerable<Giraffe>
-- というのは奇妙なことで、C はカメの列なのです。
と
キリンの列であること。
と同時に
? ここで実際にやろうとしていることを説明できますか?本当の問題を解決するために、もっと良いパターンがあるかもしれません。
実際にあなたのインターフェイスがあなたが説明した通りであるなら。
interface IFoo<T>
{
void Handle(T t);
}
次に、インターフェースの多重継承が別の問題を引き起こします。このインターフェイスをcontravariantにすることを合理的に決定できるかもしれません。
interface IFoo<in T>
{
void Handle(T t);
}
ここで
interface IABC {}
interface IDEF {}
interface IABCDEF : IABC, IDEF {}
そして
class Danger : IFoo<IABC>, IFoo<IDEF>
{
void IFoo<IABC>.Handle(IABC x) {}
void IFoo<IDEF>.Handle(IDEF x) {}
}
そして今、事態は本当におかしくなっています...
IFoo<IABCDEF> crazy = new Danger();
crazy.Handle(null);
どのHandleの実装が呼び出されるのか ???
この問題についての考察は、この記事とコメントをご覧ください。
関連
-
[解決済み】プログラム実行中に1秒待つ
-
[解決済み】Excel "外部テーブルが期待された形式ではありません。"
-
[解決済み】「入力文字列が正しい形式ではありませんでした」エラーの解決方法は?[重複しています]。
-
[解決済み】Visual studio 2019がデバッグ時にフリーズする件
-
[解決済み】2つ(またはそれ以上)のリストを1つに統合する(C# .NETで
-
[解決済み】aspNetCore 2.2.0 - AspNetCoreModuleV2 エラー
-
[解決済み] 関数を終了するには?
-
[解決済み】Nullable型をジェネリックパラメータにすることは可能か?
-
[解決済み] なぜJavaのenumリテラルは汎用型パラメータを持つことができないのですか?
-
[解決済み] C# で Int を Generic Enum にキャストする
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】「未割り当てのローカル変数を使用」とはどういう意味ですか?
-
[解決済み】指定されたキャストが有効でない?
-
[解決済み] エンティティタイプ ApplicationUser は、現在のコンテキストのモデルの一部ではありません。
-
[解決済み】ここで「要求URIに一致するHTTPリソースが見つかりませんでした」となるのはなぜですか?
-
[解決済み] [Entity Framework 4.1でエンティティに関連オブジェクトを追加する際に、エンティティオブジェクトをIEntityChangeTracker.の複数のインスタンスから参照できない。
-
[解決済み】「namespace x already contains a definition for x」エラーの修正方法は?VS2010にコンバートした後に発生しました。
-
[解決済み】EF 5 Enable-Migrations : アセンブリにコンテキストタイプが見つかりませんでした
-
[解決済み] 関数を終了するには?
-
[解決済み】「namespace」なのに「type」のように使われる。
-
[解決済み】名前 'ViewBag' が現在のコンテキストに存在しない - Visual Studio 2015