2009-10-09 63 views
36

我最近發現我們可以使用??操作員檢查空值。請檢查下面的代碼示例:我們爲什麼更喜歡?至 ??運營商在C#?

var res = data ?? new data(); 

這正是類似於

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

我檢查了我的整個項目源代碼庫和其他一些開源項目。而這個??運算符從未被使用過。

我只是想知道背後有什麼理由,像性能問題或什麼?

編輯:

我剛剛更新基於來自遞歸&安東的評論我的示例代碼。這是一個粗心大意的錯誤。 :(

+21

一個原因是脂肪酶可能​​不知道! – vpram86 2009-10-09 12:42:51

+1

應該是「var res =(data!= null)?data:new data();」在你的樣本 – 2009-10-09 12:55:46

+2

@Rubens,只是愚蠢的,不對。 – kenny 2009-10-09 14:27:47

回答

53

空聚結操作更清晰的空當檢查,這是它的主要目的。它也可以鏈接。

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"; 

我認爲人們只是不知道空COALESCE運營商,因此他們使用三元運算來代替。三元,所以如果你不知道里面C#之前,C#在大多數C風格的語言存在和/或用另一種語言編程,te rnary是一個自然的選擇。如果您正在檢查null,請使用null coalesce運算符,它是爲此設計的,並且IL稍微優化(將其與if相比較)。

這裏是比較使用的每個

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 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 

如果那麼否則只有

.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是不是我的強項之一,所以也許有人可以編輯我的答案並擴展它。我將解釋我的理論,但我不想讓自己和其他人混淆。所有三個LOC的數量都相似,但並非所有IL運營商的執行時間都相同。

+7

它不是* *三元運算符,它只是*一個*三元運算符。你所指的是**條件運算符**。 – 2009-10-09 12:56:34

+1

@Bob,這是一個很好的比較...當我們處理空值時,合併運算符比所有運算符更好... – RameshVel 2009-10-09 13:09:15

+3

@divo:它是C#中唯一的三元運算符:P – Lucas 2009-10-09 13:14:59

6

我能想到的一個原因是,這個操作符是在.NET 2.0中引入的,因此.NET 1.1的代碼不能擁有它。

我同意你的意見,我們應該更頻繁地使用它。

REF link

12

的??運算符(也稱爲null-coalescing operator)不如三元運算符,因爲它在.NET 2.0和可空類型中處於初始狀態。不使用它的原因可能包括沒有意識到它存在,或者更熟悉三元運算符。

也就是說,檢查null不是三元運算符的唯一好處,所以它不是替代它,更像是一個更好的替代方案,以滿足特定的需求。 :)

1

我認爲這只是其他語言的習慣。據我所知, ??操作符不用於任何其他語言。

+2

我知道這是超舊的,但我想評論並說,它在v5.10中也用於Perl,只能用'//'而不用''''。示例(取自[wikipedia](http://en.wikipedia.org/wiki/Null_coalescing_operator#Perl)): '$ possible_null_value // $ value_if_null' – 2013-03-04 15:11:26

0

我會想到

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

相當於將

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

一個原因(如其他已經談到)很可能是缺乏認識。它也可能(就像我自己的情況一樣),希望儘可能多地保持在代碼庫中執行類似事情的方法數量。所以我傾向於使用三元運算符來處理所有緊湊的if-a-condition-is-met-do-this-otherwise-do-do-情況。

例如,我發現下面的兩個語句在概念層面,而類似:

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

基於Bob's答案

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; 
} 

...這是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 
}