web-dev-qa-db-ja.com

C#セーフナビゲーションオペレーター-実際に何が起こっているのですか?

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つの異なる結果が返される理由にさらに絞って説明しました。

20
recursive

これを論理的に見ていきましょう。

var f = ???;
var i = f?.Measure;
var t = i.HasValue;

fがnullかどうかはわかりません。

  1. fis nullの場合、結果(i)はnull
  2. fis not nullの場合、結果(i)はint

したがって、iint?として定義され、tboolです。

では、これを見ていきましょう。

var f = ???;
var i = f?.Measure.HasValue;
  1. fis nullの場合、結果(i)はnullです
  2. fis not nullの場合、結果(i)はMeasure.HasValueで、これはブール値です。

したがって、ibool?です。

fがnullの場合、短絡してnullを返します。そうでない場合は、.HasValuebool結果を返します。

基本的に、?.を使用する場合、戻り値の型mustは参照値またはNullable<T>にする必要があります。これは、式が短絡してnullを返す場合があるためです。

20
Rob
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null

この場合、fはnullです。

i.HasValuefalseを返したのは、iのタイプがNullable<int>であるためです。したがって、この場合のようにiの値がnullの場合でも、i.HasValueには引き続きアクセスできます。

ただし、f?.Measure.HasValueは、f?が評価された直後にnullを返します。したがって、上記の結果になります。

引用するだけ ロブのコメント

理解すべき主なことは、あなたがこれを読んで理解しているということです:f?.Measure.HasValueは次のようになります:(f?.Measure).HasValue、それはそうではありません。

1
user69234

今日これに遭遇しました。

次の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"

あなたのように、私はコトリンのふるまいを期待していました、そしてそれはその日の大部分のために私をつまずきました。 :(

0
CSJ

Nullable<T>は実際には構造体であり、nullにすることはできません。そのValueのみが可能であるため、HasValueには常にアクセスできます。

0
Spencer Hakim