他の答えは正しいですが、それらが真実で関連性のあるステートメントを作成しているという意味では、ここにはまだ表現されていない言語設計の微妙な点がいくつかあります。現在の条件演算子の設計には、さまざまな要因が影響しています。
まず、できるだけ多くの式が、式の内容のみから判別できる明確な型を持つことが望ましいです。これは、いくつかの理由から望ましいことです。たとえば、IntelliSense エンジンの構築がはるかに簡単になります。入力すると、IntelliSense はsome-expressionx.M(some-expression.
を分析し、その型を決定し、xM が参照するメソッドを IntelliSense が認識する前にドロップダウンを生成できる必要があります。IntelliSense は、すべての引数を確認するまで M がオーバーロードされている場合、xM が何を参照しているのかを確実に知ることができませんが、最初の引数さえまだ入力していません。
2 つ目は、型情報が「内側から外側」に流れることを好みます。これは、まさに先ほど述べたシナリオ、つまりオーバーロード解決のためです。次の点を考慮してください。
void M(object x) {}
void M(int x) {}
void M(string x) {}
...
M(b ? 1 : "hello");
これは何をすべきですか?オブジェクトのオーバーロードを呼び出す必要がありますか? 時には文字列のオーバーロードを呼び出し、時には int のオーバーロードを呼び出す必要がありますか? たとえば、別のオーバーロードがあったM(IComparable x)
場合はどうしますか? いつそれを選択しますか?
型情報が「双方向に流れる」場合、事態は非常に複雑になります。「これを object 型の変数に割り当てているので、コンパイラーは object を型として選択しても問題ないことを認識しているはずです」と言っても意味がありません。多くの場合、割り当て先の変数の型がわからないことがあります。オーバーロードの解決は、まさに引数の型から、引数を割り当てる変数であるパラメーターの型を解決するプロセスです。引数の型が割り当てられている型に依存する場合、推論に循環性があります。
ラムダ式の場合、型情報は「双方向に流れます」。それを効率的に実装するのに、1 年の大半を費やしました。私は、式が使用される可能性のあるコンテキストに基づいて、型情報が複雑な式に流れ込む場所を分析できるコンパイラを設計および実装する際のいくつかの困難について説明する長い一連の記事を書きました。パート1はここにあります:
http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx
あなたは、「そうですね、私がオブジェクトに代入しているという事実がコンパイラによって安全に使用できない理由を理解しています。また、式が明確な型を持つ必要がある理由も理解していますが、型がそうでないのはなぜですか? int と string の両方がオブジェクトに変換可能であるため、式オブジェクトの?" これは私の 3 番目のポイントにつながります。
第 3 に、微妙ではあるが一貫して適用されている C# の設計原則の 1 つは、「魔法によって型を生成しない」ことです。型を決定する必要がある式のリストが与えられた場合、決定する型は常にリストのどこかにあります。新しいタイプを作成して選択することは決してありません。あなたが得るタイプは常にあなたが私たちに選んだものです。型のセットから最適な型を見つけると言う場合、その型のセットで最適な型を見つけます。セット {int, string} には、たとえば「動物、カメ、哺乳類、ワラビー」のように、最も一般的な型はありません。この設計上の決定は、条件演算子、型推論の統合シナリオ、暗黙的に型指定された配列型の推論などに適用されます。
この設計上の決定の理由は、通常の人間が、最適な型を決定する必要がある特定の状況でコンパイラが何をしようとしているのかを理解しやすくするためです。すぐそこにいて、あなたの顔をじっと見つめているタイプが選択されることがわかっている場合、何が起こるかを理解するのははるかに簡単です.
また、競合が発生した場合に、一連の型の中で最も一般的な型は何かについて、多くの複雑なルールを作成する必要がなくなります。タイプ {Foo, Bar} があり、両方のクラスが IBlah を実装し、両方のクラスが Baz を継承しているとします。両方が実装されている IBlah と、両方が拡張されている Baz のどちらが最も一般的な型ですか? この質問に答える必要はありません。私たちはそれを完全に避けたいと思っています。
最後に、C# コンパイラは実際には型の決定を微妙に間違っていることに注意してください。それについての私の最初の記事はここにあります:
http://blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx
実際には、コンパイラが正しく実行し、仕様が間違っていることは議論の余地があります。私の意見では、実装設計は仕様設計よりも優れています。
とにかく、これは、三項演算子のこの特定の側面を設計する理由のほんの一部です。ここには他にも微妙な点があります。たとえば、特定の分岐パスのセットがスタック上のすべての可能なパスで正しい型を残すことが保証されているかどうかを CLR ベリファイアが判断する方法などです。それを詳細に議論することは、私をかなり遠ざけるでしょう.