2009-10-09 14 views
36

私は最近、私たちは?演算子はnullをチェックします。以下のコードサンプルを確認してください:これは私が私の全体のプロジェクトのソースリポジトリや他のオープンソースプロジェクトのいくつかをチェックし私たちはなぜ好きですか? 〜に?オペレータはC#で?

var res = (data==null) ? new data() : data ; 

とまったく同じです

var res = data ?? new data(); 

。そして、この??演算子は使用されていません。

パフォーマンスの問題など何かの理由がありますか?

EDIT:

私は再帰的&アントンからのコメントに基づいて、私のサンプルコードを更新しました。不注意でその間違い。 :(

+21

pplは認識しない可能性があります。 – vpram86

+1

は "var res =(data!= null)?data:new data();"にする必要があります。あなたのサンプルで –

+2

@Rubens、ちょうど愚かではない。 – kenny

答えて

53

ヌル合体演算子はnullをチェックするとき、それはその主な目的である非常に明確である。それはまた連鎖させることができます。

object a = null; 
object b = null; 
object c = new object(); 
object d = a ?? b ?? c; //d == c. 

そのオペレータがnullチェックに制限されているが、三項演算子でありますではない。例えば

bool isQuestion = true; 
string question = isQuestion ? "Yes" : "No"; 

は、私は、彼らが代わりに三項演算子を使用して、人々は単にヌル合体演算子を認識していないと思います。あなたが内部のC#を知らないので、もし三項は、ほとんどのCスタイルの言語でのC#の前に存在していましたアウトしたり、別の言語でプログラミングしたりする3次元は自然な選択です。あなたがnullをチェックしているなら、ヌル合体演算子を使用してください。それはそのために設計されています。そして、ILはわずかに最適化されています(if thenをelseと比較してください)。

はここで各

object a = null; 
object b = null; 
object c = null; 

object nullCoalesce = a ?? b ?? c; 

object ternary = a != null ? a : b != null ? b : c; 

object ifThenElse; 

if (a != null) 
    ifThenElse = a; 
else if (b != null) 
    ifThenElse = b; 
else if (c != null) 
    ifThenElse = c; 

ファーストの使用を比較した一例であり、単にヌル合体の構文を見て、それが道明確です。三元は本当に混乱しています。今、ILで

ヌル合体を見ることができますのみ

.entrypoint 
.maxstack 2 
.locals init (
    [0] object a, 
    [1] object b, 
    [2] object c, 
    [3] object nullCoalesce) 
L_0000: ldnull 
L_0001: stloc.0 
L_0002: ldnull 
L_0003: stloc.1 
L_0004: newobj instance void [mscorlib]System.Object::.ctor() 
L_0009: stloc.2 
L_000a: ldloc.0 
L_000b: dup 
L_000c: brtrue.s L_0015 
L_000e: pop 
L_000f: ldloc.1 
L_0010: dup 
L_0011: brtrue.s L_0015 
L_0013: pop 
L_0014: ldloc.2 
L_0015: stloc.3 
L_0016: ldloc.3 
L_0017: call void [mscorlib]System.Console::WriteLine(object) 
L_001c: ret 

のみ

.entrypoint 
.maxstack 1 
.locals init (
    [0] object a, 
    [1] object b, 
    [2] object c, 
    [3] object ifThenElse) 
L_0000: ldnull 
L_0001: stloc.0 
L_0002: ldnull 
L_0003: stloc.1 
L_0004: newobj instance void [mscorlib]System.Object::.ctor() 
L_0009: stloc.2 
L_000a: ldloc.0 
L_000b: brfalse.s L_0011 
L_000d: ldloc.0 
L_000e: stloc.3 
L_000f: br.s L_001a 
L_0011: ldloc.1 
L_0012: brfalse.s L_0018 
L_0014: ldloc.1 
L_0015: stloc.3 
L_0016: br.s L_001a 
L_0018: ldloc.2 
L_0019: stloc.3 
L_001a: ldloc.3 
L_001b: call void [mscorlib]System.Console::WriteLine(object) 
L_0020: ret 

ILが私の長所の一つではないだけ

.entrypoint 
.maxstack 2 
.locals init (
    [0] object a, 
    [1] object b, 
    [2] object c, 
    [3] object ternary) 
L_0000: ldnull 
L_0001: stloc.0 
L_0002: ldnull 
L_0003: stloc.1 
L_0004: newobj instance void [mscorlib]System.Object::.ctor() 
L_0009: stloc.2 
L_000a: ldloc.0 
L_000b: brtrue.s L_0016 
L_000d: ldloc.1 
L_000e: brtrue.s L_0013 
L_0010: ldloc.2 
L_0011: br.s L_0017 
L_0013: ldloc.1 
L_0014: br.s L_0017 
L_0016: ldloc.0 
L_0017: stloc.3 
L_0018: ldloc.3 
L_0019: call void [mscorlib]System.Console::WriteLine(object) 
L_001e: ret 

そして、そうでない場合には三元、多分誰かが私の答えを編集してそれを拡大することができます。私は自分の理論を説明しようとしていましたが、私は自分自身と他者を混同しないでください。 LOCの数は3つすべてで似ていますが、すべてのIL演算子が同じ長さの時間を実行するわけではありません。

+7

*三項演算子ではなく、* one *三項演算子です。あなたが参照するものは、**条件付き演算子**と呼ばれます。 –

+1

@Bob、それは素晴らしい比較です...合体演算子はnullを扱うときにすべてよりも優れています... – RameshVel

+3

@divo:C#の唯一の3進演算子です: – Lucas

6

私が考えることができる理由の1つは、この演算子が.NET 2.0で導入されたため、.NET 1.1用のコードではこの演算子が使用できないということです。

私はあなたに同意する、私たちはこれをより頻繁に使用する必要があります。

REF link

12

?演算子(null-coalescing operatorとも呼ばれます)は、.NET 2.0およびNullable型でデビューしたため、3項演算子よりもあまり知られていません。おそらくそれを使用しない理由には、それが存在すること、または三項演算子にもっと精通していることを認識し始めないことが含まれます。

これは、3値演算子が唯一のものではないことを確認しているので、非常に特殊な必要性のためのより良い代替品のようなものではありません。 :)

1

私はそれが他の言語からのちょうど習慣だと思う。私の知る限り、 ??演算子は他の言語では使用されません。

+2

私はこれが超古かったと知っていますが、私はコメントして、v5.10のPerlでも '?'ではなく '//'のみで使用されていると言っていました。例([wikipedia](http://en.wikipedia.org/wiki/Null_coalescing_operator#Perl)から取得): '$ possible_null_value // $ value_if_null' –

0

私は

var res = data ?? data.toString(); 

の相当

var res = (data!=null) ? data : data.toString(); 
2

一つの理由は、(他の人がすでに触れてきたように)意識の欠如である可能性が高いだろうと思っているだろう。また、(私の場合と同様に)コードベース内で同様のことをできるだけ多く行う手法の数を抑えたいという希望もあります。だから私は、すべてのコンパクトな状態のために3値演算子を使用する傾向があります。

は、例えば、私は概念レベルで次の2つのステートメントは、かなり類似した見つける:リリースビルドから

return a == null ? string.Empty : a;  
return a > 0 ? a : 0; 
4

基づいて回答

public object nullCoalesce(object a, object b, object c) 
{ 
    return a ?? b ?? c; 
} 
public object ternary(object a, object b, object c) 
{ 
    return a != null ? a : b != null ? b : c; 
} 
public object ifThenElse(object a, object b, object c) 
{ 
    if (a != null) 
     return a; 
    else if (b != null) 
     return b; 
    else 
     return c; 
} 

Bob'sに...これはILは..です

.method public hidebysig instance object nullCoalesce(
    object a, 
    object b, 
    object c) cil managed 
{ 
    .maxstack 8 
    L_0000: ldarg.1 
    L_0001: dup 
    L_0002: brtrue.s L_000b 
    L_0004: pop 
    L_0005: ldarg.2 
    L_0006: dup 
    L_0007: brtrue.s L_000b 
    L_0009: pop 
    L_000a: ldarg.3 
    L_000b: ret 
} 

.method public hidebysig instance object ternary(
    object a, 
    object b, 
    object c) cil managed 
{ 
    .maxstack 8 
    L_0000: ldarg.1 
    L_0001: brtrue.s L_000a 
    L_0003: ldarg.2 
    L_0004: brtrue.s L_0008 
    L_0006: ldarg.3 
    L_0007: ret 
    L_0008: ldarg.2 
    L_0009: ret 
    L_000a: ldarg.1 
    L_000b: ret 
} 

.method public hidebysig instance object ifThenElse(
    object a, 
    object b, 
    object c) cil managed 
{ 
    .maxstack 8 
    L_0000: ldarg.1 
    L_0001: brfalse.s L_0005 
    L_0003: ldarg.1 
    L_0004: ret 
    L_0005: ldarg.2 
    L_0006: brfalse.s L_000a 
    L_0008: ldarg.2 
    L_0009: ret 
    L_000a: ldarg.3 
    L_000b: ret 
} 
関連する問題