C#で2つの疑問符を一緒にするとどうなりますか?


1630

次のコード行を実行しました。

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

2つの疑問符はどういう意味ですか、それは一種の三項演算子ですか?グーグルで調べるのは難しい。


50
これは間違いなく三項演算子ではありません -オペランドは2つしかありません!これは、(条件演算子のようなビット情報である三成分)が、ヌル合体オペレータがバイナリ演算子です。
Jon Skeet、

90
私は以前にJavaを専門的に使用していたため、将来の雇用主が以前に私のC#能力について疑問を表明していたインタビューでそれを説明しました。彼らは以前にそれを聞いたことがなく、その後のC#への私の親しみに疑問を投げかけませんでした:)
Jon Skeet

77
@ジョン・スキートビートルズを断った男以来、スキルを認識できないような壮大な失敗はありませんでした。:-)これからは、表紙に書かれているSOプロファイルへのURLリンクを含む本のコピーを送信してください。
Iainホルダー

6
IainMHは:どのようなことの価値については、私はしていなかった非常にまだ本を書き始めました。(または多分私はちょうど1章に取り組んでいた- 。そのようなもの)確かに私のための検索が素早くなど私のブログ+の記事を見つけただろう
ジョンスキート

7
Re:qの最後の文-今後の参考として、SymbolHoundはこの種のものに最適です。とにかく、良いツールを見つけたときのように...]
スティーブチェンバーズ

回答:


2155

これはnullの合体演算子であり、三項(即時IF)演算子とよく似ています。も参照してください?オペレーター-MSDN

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

展開する:

FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();

これはさらに次のように拡張されます。

if(formsAuth != null)
    FormsAuth = formsAuth;
else
    FormsAuth = new FormsAuthenticationWrapper();

英語では、「左側にあるものがnullでない場合はそれを使用し、そうでない場合は右側にあるものを使用する」という意味です。

これらはいくつでも順番に使用できることに注意してください。次のステートメントは、最初の非null Answer#を割り当てますAnswer(すべての回答がnullの場合、Answerはnullです)。

string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;

また、上記の展開は概念的には同等ですが、各式の結果は1回しか評価されませんが、言及する価値もあります。これは、たとえば式が副作用のあるメソッド呼び出しである場合に重要です。(これを指摘してくれた@Joeyへのクレジット)


17
これらを多分連鎖させることは潜在的に危険
コープは

6
@CodeBlendどうやって?
lc。

68
@CodeBlend、それは危険ではありません。展開する場合は、一連のネストされたif / elseステートメントがあるだけです。構文は、見慣れていないので奇妙です。
joelmdev

31
空の文字列に対しても機能するなら、それは神からの
贈り物だったでしょう

14
@Gusdor ??は関連付けられたままなので、a ?? b ?? c ?? dと同等((a ?? b) ?? c ) ?? dです。「代入演算子と3項演算子(?:)は右結合です。他のすべての2項演算子は左結合です。」出典:msdn.microsoft.com/en-us/library/ms173145.aspx
Mark E. Haase

284

まだ誰も魔法の言葉を言っていないからといって、それはnullの合体演算子です。これは、C#3.0言語仕様のセクション7.12で定義されています。

特に式の中で複数回使用された場合の動作方法のため、非常に便利です。フォームの式:

a ?? b ?? c ?? d

式がanullでない場合は式の結果が返されます。それ以外の場合はb、それ以外の場合はc、それ以外の場合はを試してくださいd。あらゆる点で短絡します。

また、の型がdnull可能でない場合、式全体の型もnull可能ではありません。


2
「null合体演算子」にその意味を簡略化した方法が気に入っています。それだけで十分です。
FrankO

2
タンジェンシャルしかし関連:それは、スウィフトになりましたが、それは非常に異なるのです:「無記号合体演算子」 developer.apple.com/library/ios/documentation/Swift/Conceptual/...
ダンRosenstark

69

これは、ヌルの合体演算子です。

http://msdn.microsoft.com/en-us/library/ms173224.aspx

はい、それが何と呼ばれるかを知らない限り、検索するのはほとんど不可能です!:-)

編集:そして、これは別の質問からのクールな機能です。あなたはそれらを連鎖させることができます。

C#の隠された機能?


33
少なくとも今では、簡単に検索できます。名前がわからなくても、「ダブルクエスチョンマークc#」と
ググっただけです

27

みんなありがとう、MSDNサイトで見つけた最も簡潔な説明は次のとおりです。

// y = x, unless x is null, in which case y = -1.
int y = x ?? -1;

4
これは??の重要な側面を示唆しています。演算子-null許容型の操作を支援するために導入されました。あなたの例では、「x」は「int?」型です。(Nullable <int>)。
Drew Noakes、

9
@vituleいいえ、null結合演算子の2番目のオペランドがnull可能でない場合、結果はnull可能で-1はありません(null可能ではない単なるintです)。
スザンヌデュペロン2013

私はそれがこのように機能したことを本当に望みます。いつもこれを実行したいのですが、使用している変数がnull許容型ではないため、実行できません。コーヒースクリプトy = xで動作しますか?-1
PandaWood 2014年

@PandaWood実際にはできます。場合はx型であるint?が、yタイプのものでありint、あなたが書くことができますint y = (int)(x ?? -1)。そうでない場合は解析さxれ、intそうでない場合はnull代入さ-1れます。yxnull
Johan Wintgens、

21

??値がnullの場合、null許容型の値を提供するためのものです。そのため、formsAuthがnullの場合、新しいFormsAuthenticationWrapper()を返します。


19

ここに画像の説明を入力してください

2つの疑問符(??)は、その合体演算子であることを示します。

結合演算子は、チェーンから最初のNON-NULL値を返します。全体を実際に示すこのYouTubeビデオを見ることができます。

しかし、動画の内容にさらに追加してみましょう。

合体の英語の意味を見ると、「一緒に統合する」と書かれています。以下の例は、4つの文字列をチェーン化する単純な結合コードです。

つまり、そうである場合str1null試行されstr2、そうでない場合str2は、null以外の値を持つ文字列が見つかるまでnull試行さstr3れます。

string final = str1 ?? str2 ?? str3 ?? str4;

簡単に言うと、結合演算子はチェーンから最初のNON-NULL値を返します。


この説明は図が付いているので気に入っています。最後の文で説明するのはとても簡単です。理解しやすくなり、使用に対する自信が高まります。ありがとう!
ジョシュアK

14

三項演算子の省略形です。

FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();

または、3項を行わない人のために:

if (formsAuth != null)
{
  FormsAuth = formsAuth;
}
else
{
  FormsAuth = new FormsAuthenticationWrapper();
}

3
私は「3項」のスペルを修正しただけですが、実際にあなたが意味する演算子は条件付き演算子です。たまたまC#で唯一の三項演算子ですが、ある時点で別の演算子が追加される可能性があります。その場合、「三項」があいまいになりますが、「条件付き」はそうではありません。
Jon Skeet、

これは、三項(条件付き)演算子を使用て実行できる処理の省略形です。長い形式では、テスト(!= null)と2番目のテストformsAuth(の後)の両方を?変更できます。null合体形式では、どちらも指定した値を暗黙的に取得します。
Bob Sammers

12

Rubyに精通している場合は、||=C#に似??ています。Rubyは次のとおりです。

irb(main):001:0> str1 = nil
=> nil
irb(main):002:0> str1 ||= "new value"
=> "new value"
irb(main):003:0> str2 = "old value"
=> "old value"
irb(main):004:0> str2 ||= "another new value"
=> "old value"
irb(main):005:0> str1
=> "new value"
irb(main):006:0> str2
=> "old value"

そしてC#では:

string str1 = null;
str1 = str1 ?? "new value";
string str2 = "old value";
str2 = str2 ?? "another new value";

4
x ||= y以下のようなものにdesugars x = x || yので、??実際には無地に似ている||Rubyで。
qerub 2013

6
なお??だけを気にnull、一方||Rubyで、オペレータは、ほとんどの言語のように、より程度であるnullfalseまたはの値をブール考えることができるものfalse(例えば、いくつかの言語で、"")。これは良いことでも悪いことでもありません、ただの違いです。
Tim S.

11

合体演算子

それは同等です

FormsAuth = formsAUth == null ? new FormsAuthenticationWrapper() : formsAuth

11

これについては何も危険ではありません。実は綺麗です。必要に応じて、デフォルト値を追加できます。次に例を示します。

コード

int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;

1
X1、X2、X3、およびX4はNull許容型の、例かもしれないので:int? x1 = null;その権利です
ケビン・メレディス

1
@KevinMeredith x1- x4null許容型である必要があります。つまり、「結果は0x4取り得ない可能性のある値である場合」と言っても意味がありません(null)。ここでの「null許容型」には、null許容型と参照型の両方が含まれます。1つ以上のチェーンされた変数(最後のものを除く)がNULL可能でない場合、これはコンパイル時エラーです。
Bob Sammers

11

"null合体演算子"(??)である多数の回答で正しく指摘されているように、その演算子である "Null条件演算子(?。または?[)何度も使用されますか?

ヌル条件演算子

メンバーアクセス(?。)またはインデックス(?[)操作を実行する前にnullをテストするために使用されます。これらの演算子を使用すると、特にデータ構造に降りる場合などに、nullチェックを処理するための少ないコードを記述できます。

例えば:

// if 'customers' or 'Order' property or 'Price' property  is null,
// dollarAmount will be 0 
// otherwise dollarAmount will be equal to 'customers.Order.Price'

int dollarAmount = customers?.Order?.Price ?? 0; 

?のない古い方法そして?? これを行うのは

int dollarAmount = customers != null 
                   && customers.Order!=null
                   && customers.Order.Price!=null 
                    ? customers.Order.Price : 0; 

より冗長で扱いにくいです。


10

あなたの娯楽のためだけに(あなたがすべてC#の人であることを知っている;-)。

それは、Smalltalkが起源であると私は思います。そこでは次のように定義されています。

オブジェクト内:

? anArgument
    ^ self

UndefinedObject(別名nilのクラス):

? anArgument
    ^ anArgument

これには、評価版(?)と非評価版(??)の両方があります。
これは、遅延初期化されたプライベート(インスタンス)変数のゲッターメソッドでよく見られ、本当に必要になるまでnilのままです。


UserControlのプロパティでViewStateをラップするように聞こえます。まだ設定されていない場合は、最初のgetでのみ初期化します。=)
Seiti

9

結合を使用して値を取得するここでのいくつかの例は非効率的です。

あなたが本当に欲しいのは:

return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();

または

return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());

これにより、オブジェクトが毎回再作成されるのを防ぎます。プライベート変数がnullのままで、リクエストごとに新しいオブジェクトが作成される代わりに、新しいオブジェクトが作成された場合にプライベート変数が割り当てられます。


されていない??ショートカットが評価しますか?new FormsAuthenticationWrapper();がnilの場合にのみ 評価され_formsAuthWrapperます。
MSalters 2017年

はい、それがすべてのポイントです。変数がnullの場合にのみメソッドを呼び出します。@MSalters
KingOfHypocrites

8

注意:

このスレッド全体と他の多くのスレッドを読みましたが、これほど完全な答えは見つかりません。

「なぜ??を使う理由と??と使う方法??」を完全に理解した。

ソース:

Windowsコミュニケーションの基盤が解き放たれるCraig McMurtry著ISBN 0-672-32948-4

ヌル値のタイプ

値が値型のインスタンスに割り当てられているかどうかを知りたい状況は2つあります。1つ目は、インスタンスがデータベースの値を表す場合です。このような場合、インスタンスを調べて、データベースに値が実際に存在するかどうかを確認できます。この本の主題に関連するもう1つの状況は、インスタンスがリモートソースから受信したデータアイテムを表す場合です。この場合も、インスタンスから、そのデータ項目の値が受信されたかどうかを判別したいとします。

.NET Framework 2.0には、値型のインスタンスにnullを割り当てて、インスタンスの値がnullかどうかをテストしたい場合のような、一般的な型定義が組み込まれています。そのジェネリック型の定義はSystem.Nullableであり、Tの代わりに使用できるジェネリック型の引数を値の型に制限します。System.Nullableから構築された型のインスタンスには、nullの値を割り当てることができます。実際、それらの値はデフォルトではnullです。したがって、System.Nullableから構築された型は、null許容値型と呼ばれることがあります。System.Nullableには、Valueというプロパティがあります。これにより、インスタンスの値がnullでない場合、それから構成される型のインスタンスに割り当てられた値を取得できます。したがって、次のように書くことができます:

System.Nullable<int> myNullableInteger = null;
myNullableInteger = 1;
if (myNullableInteger != null)
{
Console.WriteLine(myNullableInteger.Value);
}

C#プログラミング言語は、System.Nullableから構築された型を宣言するための省略構文を提供します。この構文により、次のように省略できます。

System.Nullable<int> myNullableInteger;

int? myNullableInteger;

コンパイラーは、次のようにして、null許容値型の値を通常の値型に割り当てようとするのを防ぎます。

int? myNullableInteger = null;
int myInteger = myNullableInteger;

nullable値の型にはnullが含まれている可能性があり、この場合は実際にnull値が含まれる可能性があり、その値を通常の値の型に割り当てることができないため、これはできません。コンパイラはこのコードを許可しますが、

int? myNullableInteger = null;
int myInteger = myNullableInteger.Value;

System.Nullableから構築された型に有効なTの値が割り当てられていない場合、System.Nullable.Valueプロパティへのアクセスは無効な操作であるため、2番目のステートメントは例外をスローします。場合。

結論:

null可能値型の値を通常の値型に割り当てる適切な方法の1つは、System.Nullable.HasValueプロパティを使用して、Tの有効な値がnull可能値型に割り当てられているかどうかを確認することです。

int? myNullableInteger = null;
if (myNullableInteger.HasValue)
{
int myInteger = myNullableInteger.Value;
}

別のオプションは、この構文を使用することです:

int? myNullableInteger = null;
int myInteger = myNullableInteger ?? -1;

通常の整数myIntegerにnull可能整数「myNullableInteger」の値が割り当てられる場合、後者には有効な整数値が割り当てられています。それ以外の場合、myIntegerには-1の値が割り当てられます。


1

これは、3項演算子と同様に機能するnullの合体演算子です。

    a ?? b  => a !=null ? a : b 

これに関するもう1つの興味深い点は、 「null許容型には値が含まれる場合と、未定義の場合があります」です。したがって、null値を許容する値の型をnull値を許容しない値の型に割り当てようとすると、コンパイル時エラーが発生します。

int? x = null; // x is nullable value type
int z = 0; // z is non-nullable value type
z = x; // compile error will be there.

だからそれを使うには?オペレーター:

z = x ?? 1; // with ?? operator there are no issues

1
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

に相当

FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();

しかし、他の人が言ったように、それを連鎖させることができるというのが素晴らしいところです。触れられていないのは、実際にそれを使用して例外をスローできることです。

A = A ?? B ?? throw new Exception("A and B are both NULL");

質問にオペレーターが何であるか、または何であるかについての説明を求めていましたが、投稿に例を含めたのは本当に素晴らしいことです。
TGP1994

1

この??演算子は、ヌル結合演算子と呼ばれます。オペランドがnullでない場合は、左側のオペランドを返します。それ以外の場合は、右側のオペランドを返します。

int? variable1 = null;
int variable2  = variable1 ?? 100;

variable2の値に設定されます(がnullでないvariable1場合variable1)。それ以外の場合はvariable1 == nullvariable2100 に設定します。


0

他の人はNull Coalescing Operatorかなりよく説明しています。興味がある人のために、これ(SOの質問)の短縮された構文があります:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

これと同等です:

FormsAuth ??= new FormsAuthenticationWrapper();

読みやすく簡潔な人もいます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.