私はc#6でコードを書いていますが、奇妙な理由でこれが機能します
var value = objectThatMayBeNull?.property;
しかし、これはしません:
int value = nullableInt?.Value;
動作しないということは、Cannot resolve symbol 'Value'
。 null条件演算子?.
は機能していませんか?
さて、私はいくつかの思考とテストを行いました。これが起こることです:
_int value = nullableInt?.Value;
_
コンパイル時にこのエラーメッセージが表示されます。
タイプ「int」には「Value」の定義が含まれていません
つまり、_?
_は_int?
_を実際のint
値に「変換」します。これは実質的に次と同じです。
_int value = nullableInt ?? default(int);
_
結果は整数であり、明らかにValue
を持ちません。
さて、これは役立つでしょうか?
_int value = nullableInt?;
_
いいえ、その構文は許可されていません。
それでは何ですか?この場合、.GetValueOrDefault()
を使用し続けるだけです。
_int value = nullableInt.GetValueOrDefault();
_
これは、null条件演算子を使用して値にアクセスしても意味がないためです。
x?.p
を適用すると、p
はnullを許可しない値型T
で、結果はT?
型になります。同様に、nullableInt?.Value
操作の結果mustはNULL可能です。Nullable<T>
に値がある場合、nullableInt?.Value
の結果は値自体と同じになりますNullable<T>
に値がない場合、結果はnull
になりますが、これも値自体と同じです。?.
演算子を使用してValue
にアクセスすることは意味がありませんが、null許容値タイプの他のプロパティにアクセスすることは意味があります。演算子は、null許容値型と参照型で一貫して動作するため、これら2つの実装は同じ動作を生成します。
class PointClass {
public int X { get; }
public int Y { get; }
public PointClass(int x, int y) { X = x; Y = y; }
}
struct PointStruct {
public int X { get; }
public int Y { get; }
public PointStruct(int x, int y) { X = x; Y = y; }
}
...
PointClass pc = ...
PointStruct? ps = ...
int? x = pc?.X;
int? y = ps?.Y;
Nullを許可するstruct
の場合、演算子を使用すると、基になる型PointStruct
のプロパティにアクセスできます。また、参照タイプPointClass
。
Null許容型に関しては、_?.
_演算子は_if not null, use the wrapped value
_と言っています。したがって、nullable intでは、nullableの値が_8
_である場合、_?.
_の結果は_8
_を含むnullableではなく_8
_になります。 Value
はint
のプロパティではないため、エラーが発生します。
そのため、プロパティValue
を使用しようとする例はまったく正しくありませんが、次のように動作します。
var x = nullableInt?.ToString();
ヌル合体演算子_??
_を検討してください。
_var x = nullableInt ?? 0;
_
ここで、オペレーターは_if null, return 0, otherwise return the value inside the nullable
_と言います。この場合はint
です。 _?.
_演算子は、nullableのコンテンツの抽出に関して同様に実行しています。
特定の例では、_??
_演算子ではなく、_?.
_演算子と適切なデフォルトを使用する必要があります。
私は基本的に他の答えに同意します。観測された動作が何らかの形式の信頼できるドキュメントによってバックアップされることを望んでいました。
C#6.0仕様はどこにも見つからないので(まだ出ていますか?)、「ドキュメント」に最も近いのは 2014年2月3日のC#言語設計ノート です。そこにある情報が現在の状況をまだ反映していると仮定すると、観察された行動を正式に説明する関連部分がここにあります。
セマンティクスは、式が1回だけ評価されることを除いて、3項演算子をnullの等価性チェック、nullリテラル、および演算子の非質問マーク付きアプリケーションに適用するようなものです。
e?.m(…) => ((e == null) ? null : e0.m(…)) e?.x => ((e == null) ? null : e0.x) e?.$x => ((e == null) ? null : e0.$x) e?[…] => ((e == null) ? null : e0[…])
e0
はe
と同じです。e
がNULL値を許可する値型である場合を除き、その場合はe0
はe.Value
です。
最後のルールを以下に適用します:
nullableInt?.Value
...意味的に等価な式は次のようになります。
((nullableInt == null) ? null : nullableInt.Value.Value)
明らかに、nullableInt.Value.Value
はコンパイルできません。それはあなたが観察したことです。
その特別なルールを具体的にnullable型に適用するという設計決定がなされた理由については、dasblinkenlight
の答えがそれをうまくカバーしていると思うので、ここでは繰り返しません。
さらに、仮に仮に、null許容型に対するこの特別なルールがなく、式nullableInt?.Value
が元々考えていたようにコンパイルして動作したとしても...
// let's pretend that it actually gets converted to this...
((nullableInt == null) ? null : nullableInt.Value)
それでも、質問からの次のステートメントは無効であり、コンパイルエラーが生成されます。
int value = nullableInt?.Value; // still would not compile
それでも機能しない理由は、nullableInt?.Value
式のタイプがint
ではなくint?
になるためです。したがって、value
変数のタイプをint?
に変更する必要があります。
これは 2014年2月3日のC#言語設計ノート でも正式に説明されています:
結果の型は、基になる演算子の右側の型
T
に依存します。
T
が(既知である)参照型である場合、式の型はT
ですT
がnull不可の値型であることがわかっている場合、式の型はT?
T
がNULL値可能型であることがわかっている場合、式の型はT
です。- それ以外の場合(つまり、
T
が参照型であるか値型であるかが不明な場合)、式はコンパイル時エラーです。
ただし、コンパイルするために次の記述を強制される場合:
int? value = nullableInt?.Value;
...それはかなり無意味に思えます、そしてそれは単にすることと何の違いもありません:
int? value = nullableInt;
他の人が指摘したように、あなたのケースでは、おそらく null-conditional operator ??
ではなく、 null-coalscing operator ?.
を使用するつもりでした。 _。
int
にはValue
プロパティがありません。
考慮してください:
_var value = obj?.Property
_
以下と同等です:
_value = obj == null ? null : obj.Property;
_
それはint
では意味がないため、_int?
_を介した_?.
_では意味がありません。
ただし、古いGetValueOrDefault()
は_int?
_で意味をなします。
または、_?
_はnullを許可するものを返さなければならないので、単純に:
_int? value = nullableInt;
_
単に(上記のスタンの回答に基づいて)
var value = objectThatMayBeNull?.property;
コンパイラによって評価されます
var value = (objectThatMayBeNull == null) ? null : objectThatMayBeNull.property
そして
int value = nullableInt?.Value;
お気に入り
int value = (nullableInt == null) ? null : nullableInt.Value.Value;
いつ nullableInt.Value.Value
はCannot resolve symbol 'Value'
構文エラー!
Null条件演算子は、null許容変数もラップ解除します。それで、「?.」の後に演算子の場合、「Value」プロパティは不要になりました。
どうやってこれに出会ったかについて、より詳細に説明する投稿を書きました。あなたが疑問に思っている場合
http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/