web-dev-qa-db-ja.com

C#Null伝播演算子/条件付きアクセス式&ifブロック

Null伝播演算子/条件付きアクセス式c#-6. に登場すると、非常に便利な機能のように見えます。しかし、子メンバーがnullでないかどうかを確認し、ifブロック内でその子メンバーに対してブールメソッドを呼び出す問題の解決に役立つかどうか、私は興味があります。

_  public class Container<int>{
       IEnumerable<int> Objects {get;set;}
  }

  public Container BuildContainer()
  { 
      var c = new Container();

      if (/* Some Random Condition */)
         c.Objects = new List<int>{1,2,4};
  }

  public void Test()
  {
      var c = BuildContainer();

      //Old way
      if ( null != c && null != c.Objects && c.Objects.Any())
         Console.Write("Container has items!");


      //C# 6 way?
      if (c?.Object?.Any())
          Console.Write("Container has items!");
  }
_

c?.Object?.Any()はコンパイルされますか?伝搬演算子がnullに短絡した場合(私はそれが正しいと思います)、if (null)があり、これは無効です。

C#チームはこの問題に対処しますか、それともnull伝播演算子の意図した使用例を見逃していますか?

21
Philip Pittle

この方法では機能しません。説明をスキップして、以下のコードを参照してください:)

ご存じのとおり、子メンバーがnullの場合、_?._演算子はnullを返します。しかし、Any()メソッドのように、boolを返すnull不可のメンバーを取得しようとするとどうなりますか?答えは、コンパイラが戻り値を_Nullable<>_に「ラップ」することです。たとえば、Object?.Any()は、boolではなく_bool?_(_Nullable<bool>_)を提供します。

この式をifステートメントで使用できないのは、暗黙的にboolにキャストできないことです。しかし、あなたは明示的に比較を行うことができます、私はこのようにtrueと比較することを好みます:

_if (c?.Object?.Any() == true)
    Console.Write("Container has items!");
_

@ DaveSextonに感謝 別の方法があります:

_if (c?.Object?.Any() ?? false)
    Console.Write("Container has items!");
_

しかし、私にとっては、trueとの比較はより自然に見えます:)

44
Eldar Dordzhiev

NULL条件演算子は、nullまたは式の最後の値を返します。 value types の場合、結果はNullable<T>で返されるため、あなたの場合はNullabe<bool>になります。 C#の今後の機能(指定された ここのドキュメントの例を見てみると、例があります:

int? first = customers?[0].Orders.Count();

上記の例では、intの代わりにNullable<int>が返されます。 boolの場合、Nullable<bool>を返します。

Visual Studio "14" CTP で次のコードを試した場合:

Nullable<bool> ifExist = c?.Objects?.Any();

上記の行の結果はNullable<bool>/bool?になります。後で、次のように比較できます。

null-coalescing operator ?? を使用する

 if (c?.Object?.Any() ?? false)

Nullable<T>.GetValueOrDefault メソッドの使用

if ((c?.Objects?.Any()).GetValueOrDefault())

trueとの比較を使用する

if (c?.Objects?.Any() == true)
6
Habib