3

重複の可能性:
条件演算子は暗黙的にキャストできませんか?

私は奇妙な状況に遭遇しました、そしてなぜ私がそれをしなければならないのか知りたいです。.NET3.5を使用しています。

これは機能します:

short foo;

if (isValid)
    foo = -1;
else
    foo = getFoo();

これは動作しません:

short foo;
foo = isValid ? -1 : getFoo();

-1を型キャストする必要があります。

short foo;
foo = isValid ? (short)-1 : getFoo();

三項式の違いは何ですか?-1は、shortにキャストする必要があるintであると見なされます。しかし、なぜ?

4

4 に答える 4

11

いくつかのこと。

まず、条件演算子は三項演算子であり、三項演算子ではありません。

次に、コードサンプルでは、​​同等であることが意図されている2つのコードサンプルは次のようになっていないことに注意してください。

short foo;
if (isValid)
    foo = -1;
else
   getFoo();

と同じではありません

short foo = isValid ? (short)-1 : getFoo();

isValidがfalseの場合、前者はfooを未割り当てのままにします。後者は、isValidの値に関係なくfooを割り当てます。

私はあなたが意味したと思います

short foo;
if (isValid)
    foo = -1;
else
    foo = getFoo();

さらに、getFoo()はshortを返します。

問題は、型キャストなしの条件演算子での変換が違法であるのに、ifステートメントの結果が合法である理由です。

仕様のセクション6.1.9には次のように記載されているため、ifステートメントでは合法です。

int型の定数式は、定数式の値が宛先型の範囲内であれば、sbyte、byte、short、ushort、uint、またはulong型に変換できます。

-1は、shortの範囲にあるint型の定数式であるため、暗黙的にshortに変換できます。

では、なぜ条件式は偽物なのですか?

最初に明確に確立する必要があるのは、条件式のタイプは、コンテキストからではなく、その内容から決定されるという規則です。割り当ての右側にある式のタイプは、割り当てられているものに依存しません。あなたが持っていたとしましょう

short M(short x){...}
int M(int x){...}

short y = M(-1);

オーバーロードの解決で「-1はintであるため、通常はM(int)を選択しますが、そうでない場合は割り当てが行われないため、代わりにM(short)を選択します」とは思わないでしょう。仕事だ」過負荷の解決は、結果がどこに行くのかについて何も知りません。呼び出しのコンテキストに基づくのではなく、与えられた引数に基づいて、適切なオーバーロードが何であるかを理解することが仕事です。

条件式のタイプの決定は同じように機能します。行き先の型ではなく、式に含まれる型を調べます。

OK、これがshortに割り当てられているという事実は、式のタイプを決定するためには無関係であることがわかりました。しかし、それでも「条件式の型が短いのではなくintであるのはなぜですか?」という疑問が残ります。

それはとても良い質問です。スペックに行きましょう。

?:演算子の2番目と3番目のオペランドxとyは、条件式のタイプを制御します。

タイプがXで、タイプがYの場合、次のようになります。

XからYへの暗黙の変換が存在するが、YからXへの変換は存在しない場合、Yは条件式のタイプです。

YからXへの暗黙の変換が存在するが、XからYへの変換は存在しない場合、Xは条件式のタイプです。

そうしないと、式の種類を判別できず、コンパイル時エラーが発生します。

この場合、オペランドは両方とも型を持っています。(「xに型がある場合...」に関する言い回しは、nullまたはラムダが含まれている場合です。これらには型がありません!)最初のオペランドはint型で、2番目のオペランドは短いタイプ。

shortからintへの暗黙の変換は存在しますが、intからshortへの変換は存在しません。したがって、条件式のタイプはintであり、shortに割り当てることはできません。

さて、このアルゴリズムはそれができるほど良くはないと言うことができます。アルゴリズムを非常に複雑にして、2つの可能な「候補」タイプが存在するすべてのケースを処理することができます。この場合、特定の式と見なすと、両方のブランチがintとshortの両方に変換可能であるため、intとshortの両方がもっともらしい候補です。単に型を持つのではなく。その場合、2つのタイプのうち小さい方が好ましいタイプであると言えます。

(C#では、2つのタイプの一般的な方が良いタイプであると言うことがありますが、この場合は、より具体的なものを選択する必要があります。残念ながら、この特定の設計の側面では言語に一貫性がありません。常により具体的なものを選択しますが、それが今や重大な変化となる型推論のシナリオがあります。)

2006年にそれを行うことを検討しました。LINQが複数のタイプから選択でき、1つを「最良」として選択する必要がある状況を処理する動作を設計するときに、条件演算子はすでにこの問題を解決する必要があることに気付きました。さらに、C#2では、仕様に従って実際に実装されていませんでした。これについては長い議論があり、条件演算子の仕様にいくつかの小さな変更を加えて、実装された(そして望ましい)動作にさらに一致させることになりました。ただし、選択できるタイプがいくつかある場合は、アルゴリズムを微調整して2つの可能なタイプのうち小さい方を使用するという大きな変更は行わないことにしました。

この問題に関するいくつかの考察については、2006年の私の投稿を参照してください。

于 2010-06-30T17:03:50.173 に答える
6

デフォルトでは-1は整数であるためです。コンパイラーが何をしたいのかを推測するよりも、コンパイラーが何をすべきかを明示的に指示する必要があると言う方がはるかに安全です。

あなたの例は非常に簡単です。少し余分な作業を行うことで、コンパイラは明らかに-1を短くしたいことを認識できます。ただし、暗黙の変換に伴うすべてのエッジケースがありますが、それほど単純ではありません。コンパイラにルールを追加して、必要なものを想定する場合は、1つだけでなくすべてのケースに適用する必要があり、それが困難になります。

注意として、Eric Lippertのブログをチェックする必要があります。彼は、コンパイラがそのような仮定を行わない理由を説明していることを知っています。

于 2010-06-30T14:17:10.653 に答える
1

intanとaに適用される条件演算子shortは型intです。コンパイラは、割り当てられた型から式の型を推測しません。

このshort式を暗黙的ににキャストすることはできませんint

于 2010-06-30T14:17:41.697 に答える
0

条件演算子は、可能な両方の結果式が同じタイプであることを強制します。この場合、左側はanintで、右側はメソッドshortによって返されgetPooます。ショートをコンパイラに変換することは常に安全であるためint、コンパイラは操作の結果が。になることを選択しintます。

したがって、結果はintaへの割り当てになりますshort。そのため、明示的にshortにキャストする必要があります。

if / elseアプローチを明示的に使用する場合は、リテラル整数をshortに割り当てることになります。これにより、コンパイラは、明示的なキャストを必要とせずに、リテラル整数がshortに安全に割り当てられていることを確認できます。

内部の説明については、以下をご覧ください。

キャストオペレーターは分配法則に従わない

于 2010-06-30T14:22:47.087 に答える