4

C#のnull 条件演算子を使用すると、便利な短絡が可能になります。

double? range = (unit as RangedUnit)?.WeaponRange;

残念ながら、null 条件演算子は値を返すため (左手代入では使用できません)、省略形代入と同じ方法で使用することはできません。

(unit as RangedUnit)?.PreferredTarget = UnitType.Melee;

その結果、可能な代替構文が得られます。

if (unit is RangedUnit)
{
    (unit as RangedUnit).PreferredTarget = UnitType.Melee;
}

RangedUnit が参照型 (値型ではない) であることをコンパイラが認識している場合、条件付きで短縮構文を実行できないのはなぜですか?

refTypeInstance?.SomeField = value;

(つまり、refTypeInstance が null の場合は何もしません。refTypeInstance が null でない場合は、ステートメントを実行します)

更新 (結論):

  • null 条件演算子は、代入ステートメントの式ツリーの予想される評価ロジックに違反するため、代入ステートメントの左側では使用できません (代入操作を短絡させ、まったく実行しません)。
  • 理想的な解決策は、新しい条件付き代入演算子 (代入の左辺が null でない場合にのみ実行される) です。
4

2 に答える 2

4

あなたが期待している動作:

(つまり、refTypeInstance が null の場合は何もしません。refTypeInstance が null でない場合は、ステートメントを実行します)

オペレーターの働き方により不可能です。より具体的には、演算子の優先順位とそれに基づいて式ツリーがどのように形成されるかに問題があります。

声明では

(unit as RangeUnit).PreferredTarget = UnitType.Melee;

代入演算子 ( =) は式ツリーのルートにあり、左と右の式が枝になります。

NullReferenceException左手が評価されるとき (代入前) にAが発生します。この時点で、コンパイラはすでに=. 逆参照演算子 ( .) は実行時に a をスローするNullReferenceExceptionため、コンパイラが式ツリーの解析を続行しても安全です。

一方、このステートメントが許可される場合:

(unit as RangeUnit)?.PreferredTarget = UnitType.Melee;

refTypeInstance...コンパイラは、の値がnullかどうかをチェックするコードを発行する必要があります。それは可能ですが、問題は、コンパイラが現在実行中の式ツリーをどうするかということです。=上の式ツリーと下の式ツリーを破棄する必要があるため、最初の例のように単純に続けることはできません.。基本的に、ツリーを解析するための 2 つの選択肢を挿入する必要が?.ありnullます。ただし、これは制御フローの変更であり、オペレーターに期待するものではありません。

?.の言い方をすれば、演算子の評価を式ツリーの分岐に沿って短絡するだけであれば、これは予期された動作であると考えることができます。しかし、この場合、式ツリーの上位にある演算子の動作が変更されます。これは、まったく予期しないことです。

于 2016-12-13T10:44:05.667 に答える
1

彼らは同じことをしていないので、

unit が null の場合 (または遠隔ユニットでない場合)、最初のスニペットは null を返します。

何かを設定しようとしているときにそれが発生した場合、 null を値に設定することはできません (そして、エラーが発生します)。

于 2016-12-13T10:24:17.903 に答える