C#6で追加されたセーフナビゲーションオペレーター機能に興味を持ってフォローしてきました。しばらく楽しみにしてきました。しかし、私は予想とは異なる動作を見つけています。私はそれが実際にどのように機能するのか本当に理解していないことに気付いています。
このクラスを考えると
class Foo {
public int? Measure;
}
New演算子を使用したコードを次に示します。
Foo f = new Foo { Measure = 3 };
Console.WriteLine(f?.Measure); // 3
f = new Foo { Measure = null };
Console.WriteLine(f?.Measure); // null
f = null;
Console.WriteLine(f?.Measure); // null
ここまでは、すべてが期待どおりに機能しています。 ?.
は、左側がnullでない場合にメンバーにアクセスし、それ以外の場合はnullを返します。しかし、ここでは私が予期していなかった方向に進んでいます。
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null
何?
HasValue
からi
を取得できるのに、i
に割り当てた同じ式から取得できないのはなぜですか? HasValue
をnullにするにはどうすればよいですか?
編集:私の本当の質問は、コンパイルエラーではなく、プログラムの動作についてです。コンパイルに関する余分なものを削除し、この質問を、同じロジックのように見えるものから2つの異なる結果が返される理由にさらに絞って説明しました。
これを論理的に見ていきましょう。
var f = ???;
var i = f?.Measure;
var t = i.HasValue;
f
がnullかどうかはわかりません。
f
is nullの場合、結果(i
)はnull
f
is not nullの場合、結果(i
)はint
したがって、i
はint?
として定義され、t
はbool
です。
では、これを見ていきましょう。
var f = ???;
var i = f?.Measure.HasValue;
f
is nullの場合、結果(i
)はnullですf
is not nullの場合、結果(i
)はMeasure.HasValue
で、これはブール値です。したがって、i
はbool?
です。
f
がnullの場合、短絡してnullを返します。そうでない場合は、.HasValue
のbool
結果を返します。
基本的に、?.
を使用する場合、戻り値の型mustは参照値またはNullable<T>
にする必要があります。これは、式が短絡してnullを返す場合があるためです。
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null
この場合、fはnullです。
i.HasValue
がfalse
を返したのは、i
のタイプがNullable<int>
であるためです。したがって、この場合のようにi
の値がnullの場合でも、i.HasValue
には引き続きアクセスできます。
ただし、f?.Measure.HasValue
は、f?
が評価された直後にnull
を返します。したがって、上記の結果になります。
引用するだけ ロブのコメント :
理解すべき主なことは、あなたがこれを読んで理解しているということです:f?.Measure.HasValueは次のようになります:(f?.Measure).HasValue、それはそうではありません。
今日これに遭遇しました。
次のC#スニペットは何を出力しますか?
public class NullTests
{
public static void Main(string[] args)
{
object obj = DoIt();
Console.WriteLine(obj?.ToString().NullToNothing());
}
private static object DoIt() => null;
}
public static class Extensions
{
public static string NullToNothing(this string input) => input ?? "nothing";
}
回答:null。
次のKotlinスニペットは何を出力しますか?
fun main() {
val obj = doIt()
println(obj?.toString().NullToNothing())
}
fun doIt() = null
fun String?.NullToNothing() = this ?: "nothing"
回答:"nothing"。
あなたのように、私はコトリンのふるまいを期待していました、そしてそれはその日の大部分のために私をつまずきました。 :(
Nullable<T>
は実際には構造体であり、nullにすることはできません。そのValue
のみが可能であるため、HasValue
には常にアクセスできます。