web-dev-qa-db-ja.com

Null Coalescing演算子を使用するユニークな方法

C#でNull合体演算子を使用する標準的な方法は、デフォルト値を設定することです。

string nobody = null;
string somebody = "Bob Saget";
string anybody = "";

anybody = nobody   ?? "Mr. T"; // returns Mr. T
anybody = somebody ?? "Mr. T"; // returns "Bob Saget"

しかし、??は他に何に使用できますか?より簡潔で読みやすいことを除けば、三項演算子ほど有用ではないようです:

nobody = null;
anybody = nobody == null ? "Bob Saget" : nobody; // returns Bob Saget

だから、null合体演算子を知っている人が少ないということを考えると...

  • ??を他の何かに使用しましたか?

  • ??が必要ですか、または三項演算子(ほとんどの人は知っている)を使用する必要があります

153
Armstrongest

まあ、まず第一に、標準の三元よりも連鎖がはるかに簡単です:

string anybody = parm1 ?? localDefault ?? globalDefault;

vs.

string anyboby = (parm1 != null) ? parm1 
               : ((localDefault != null) ? localDefault 
               : globalDefault);

Nullの可能性のあるオブジェクトが変数でない場合にもうまく機能します。

string anybody = Parameters["Name"] 
              ?? Settings["Name"] 
              ?? GlobalSetting["Name"];

vs.

string anybody = (Parameters["Name"] != null ? Parameters["Name"] 
                 : (Settings["Name"] != null) ? Settings["Name"]
                 :  GlobalSetting["Name"];
203
James Curran

遅延ロードワンライナーとして使用しました。

public MyClass LazyProp
{
    get { return lazyField ?? (lazyField = new MyClass()); }
}

読みやすい?自分で決めてください。

173

私は2つの「少し奇妙な」方法でそれが便利だとわかりました:

  • outルーチンの作成時にTryParseパラメーターを使用する代替手段として(つまり、解析が失敗した場合はnull値を返します)
  • 比較のための「わからない」表現として

後者にはもう少し情報が必要です。通常、複数の要素を使用して比較を作成する場合、比較の最初の部分(年齢など)が明確な答えを提供するかどうかを確認し、最初の部分が役に立たなかった場合にのみ次の部分(名前など)を確認する必要があります。 null合体演算子を使用すると、非常に単純な比較を(順序または等価について)書くことができます。たとえば、 MiscUtil でいくつかのヘルパークラスを使用します。

public int Compare(Person p1, Person p2)
{
    return PartialComparer.Compare(p1.Age, p2.Age)
        ?? PartialComparer.Compare(p1.Name, p2.Name)
        ?? PartialComparer.Compare(p1.Salary, p2.Salary)
        ?? 0;
}

確かに、私はMiscUtilにProjectionComparerがあり、この種の機能をさらに簡単にするいくつかの拡張機能がありますが、それでもまだきれいです。

Equalsの実装の開始時に、参照の等価性(または無効性)をチェックするために同じことができます。

51
Jon Skeet

別の利点は、三項演算子が二重評価または一時変数を必要とすることです。

例えば、これを考慮してください:

string result = MyMethod() ?? "default value";

一方、三項演算子を使用すると、次のいずれかが残ります。

string result = (MyMethod () != null ? MyMethod () : "default value");

myMethodを2回呼び出す、または:

string methodResult = MyMethod ();
string result = (methodResult != null ? methodResult : "default value");

いずれにせよ、null合体演算子はよりクリーンで、より効率的です。

33
Mario Cossi

考慮すべきもう1つのことは、3項演算子のように、合体演算子がプロパティのgetメソッドを2回呼び出さないことです。

そのため、たとえば、3成分を使用しないシナリオがあります。

public class A
{
    var count = 0;
    private int? _prop = null;
    public int? Prop
    {
        get 
        {
            ++count;
            return _prop
        }
        set
        {
            _prop = value;
        }
    }
}

使用する場合:

var a = new A();
var b = a.Prop == null ? 0 : a.Prop;

ゲッターは2回呼び出され、count変数は2に等しくなります。使用する場合:

var b = a.Prop ?? 0

count変数は1になります。

21
Fabio Lima

私が見つけた最大の利点は??演算子を使用すると、nullを許可する値型をnullを許可しない型に簡単に変換できます。

int? test = null;
var result = test ?? 0; // result is int, not int?

私はこれをLinqクエリで頻繁に使用します。

Dictionary<int, int?> PurchaseQuantities;
// PurchaseQuantities populated via ASP .NET MVC form.
var totalPurchased = PurchaseQuantities.Sum(kvp => kvp.Value ?? 0);
// totalPurchased is int, not int?
14
Ryan

私は使用しましたか? IDataErrorInfoの私の実装では:

public string Error
{
    get
    {
        return this["Name"] ?? this["Address"] ?? this["Phone"];
    }
}

public string this[string columnName]
{
    get { ... }
}

個々のプロパティが「エラー」状態にある場合、そのエラーが表示されます。それ以外の場合、nullが表示されます。本当にうまくいきます。

9
Matt Hamilton

Null合体演算子を使用して、オプションのパラメーターが設定されていない場合を処理するために、少しきれいにすることができます。

public void Method(Arg arg = null)
{
    arg = arg ?? Arg.Default;
    ...
7

特定のプロパティを遅延ロードするために、null合体演算子を使用するのが好きです。

私の要点を説明するための非常に単純な(そして考案された)例:

public class StackOverflow
{
    private IEnumerable<string> _definitions;
    public IEnumerable<string> Definitions
    {
        get
        {
            return _definitions ?? (
                _definitions = new List<string>
                {
                    "definition 1",
                    "definition 2",
                    "definition 3"
                }
            );
        }
    } 
}
6
mlnyc

?必要な場合、または単に三項演算子を使用する必要があります(ほとんどの場合は使い慣れています)

実際、私の経験では、三項演算子(より正確には条件付き演算子; ?:は、||はバイナリまたは+は単項またはバイナリのいずれかです。しかし、たまたま多くの言語で唯一の三項演算子です)、少なくともその限られたサンプルでは、​​ステートメントはそこで失敗します。

また、前述のように、null合体演算子が非常に便利な場合、および評価される式に何らかの副作用がある場合は常に1つの大きな状況があります。その場合、cannot(a)一時変数の導入、または(b)アプリケーションの実際のロジックの変更なしで条件演算子を使用します。 (b)どんな状況でも明らかに適切ではなく、個人的な好みではありますが、短命の変数であっても、多くの無関係な変数で宣言スコープを乱雑にするのは好きではありません。特定のシナリオ。

もちろん、結果に対して複数のチェックを行う必要がある場合、おそらく条件演算子、またはifブロックのセットがジョブのツールです。しかし、単純な「これがnullの場合、それを使用し、そうでなければそれを使用する」場合、null合体演算子?? 完璧です。

5
a CVn

唯一の問題は、null合体演算子が空の文字列を検出しないことです。


つまり.

string result1 = string.empty ?? "dead code!";

string result2 = null ?? "coalesced!";

出力:

result1 = ""

result2 = coalesced!

現在、??のオーバーライドを検討しています。これを回避する演算子。これをフレームワークに組み込むと便利です。

考え?

4
whatispunk

私が最近やっていることの1つは、asへのバックアップにnullの合体を使用することです。例えば:

object boxed = 4;
int i = (boxed as int?) ?? 99;

Console.WriteLine(i); // Prints 4

また、それぞれが失敗する可能性のある?.の長いチェーンをバックアップするのにも役立ちます

int result = MyObj?.Prop?.Foo?.Val ?? 4;
string other = (MyObj?.Prop?.Foo?.Name as string)?.ToLower() ?? "not there";
4
Blue0500

ですか?必要な場合、または単に三項演算子を使用する必要があります(ほとんどの場合は使い慣れています)

意図を最もよく表すものを使用する必要があります。 is null合体演算子があるので、使用する

一方、それは非常に専門的であるため、他の用途があるとは思わない。他の言語と同様に、||演算子の適切なオーバーロードが望ましいでしょう。これは、言語設計においてよりpar約的です。しかしよく …

3
Konrad Rudolph

クール! null合体演算子を知らなかった人として私を数えてください-それはかなり気の利いたものです。

三項演算子よりも読みやすいと思います。

私がそれを使うかもしれない最初に思い浮かぶのは、すべてのデフォルトパラメータを一箇所に保持することです。

public void someMethod( object parm2, ArrayList parm3 )
{ 
  someMethod( null, parm2, parm3 );
}
public void someMethod( string parm1, ArrayList parm3 )
{
  someMethod( parm1, null, parm3 );
}
public void someMethod( string parm1, object parm2, )
{
  someMethod( parm1, parm2, null );
}
public void someMethod( string parm1 )
{
  someMethod( parm1, null, null );
}
public void someMethod( object parm2 )
{
  someMethod( null, parm2, null );
}
public void someMethod( ArrayList parm3 )
{
  someMethod( null, null, parm3 );
}
public void someMethod( string parm1, object parm2, ArrayList parm3 )
{
  // Set your default parameters here rather than scattered through the above function overloads
  parm1 = parm1 ?? "Default User Name";
  parm2 = parm2 ?? GetCurrentUserObj();
  parm3 = parm3 ?? DefaultCustomerList;

  // Do the rest of the stuff here
}
3
HanClinto

ちょっと変わったユースケースですが、IDisposableオブジェクトが引数として渡される可能性がある(したがって親によって破棄される)メソッドがありましたが、nullになる可能性もあります(したがって、ローカルに作成して破棄する必要があります)方法)

それを使用するには、コードは次のように見えます

Channel channel;
Authentication authentication;

if (entities == null)
{
    using (entities = Entities.GetEntities())
    {
        channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
        [...]
    }
}
else
{
    channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
    [...]
}

しかし、null合体は非常にきれいになります

using (entities ?? Entities.GetEntities())
{
    channel = entities.GetChannelById(googleShoppingChannelCredential.ChannelId);
    [...]
}
2
PaulG

ヌル結合演算子

この演算子は変数をチェックし、nullの場合、「??」演算子の隣に値を返します。それ以外の場合は、変数に保存された値を返します。

例:-1

var name=”ATHUL”;
var result =name ?? “The name is null”
Console.WriteLine(result);

o/p:アスール

例:-2

var name=null;
var result =name ?? “The name is null”
Console.WriteLine(result);

o/p:名前はヌルです

0