为什么我们更喜欢?到 ??C#中的运算符?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1543522/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 18:40:28  来源:igfitidea点击:

why do we prefer ? to ?? operator in c#?

c#conditional-operator

提问by RameshVel

I recently found that we can use ?? operator to check nulls. Please check the below code samples:

我最近发现我们可以使用 ?? 运算符来检查空值。请检查以下代码示例:

   var res = data ?? new data();

This is exactly similar to

这完全类似于

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

I checked my whole project source repository and some of other open source projects. And this ??operator never been used.

我检查了我的整个项目源代码库和其他一些开源项目。而这个??运算符从未被使用过。

I just wondering is there any reason behind this, like performance problems or something?

我只是想知道这背后是否有任何原因,例如性能问题或其他原因?

EDIT:

编辑:

I just updated my sample code based on the comments from recursive & Anton. Its a mistake in careless. :(

我刚刚根据 recursive & Anton 的评论更新了我的示例代码。这是一个粗心大意的错误。:(

采纳答案by Bob

The null coalesce operator is much clearer when checking for null, that is its main purpose. It can also be chained.

null 合并运算符在检查 null 时更加清晰,这是它的主要目的。它也可以被链接。

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

While that operator is limited to null checking, the ternary operator is not. For example

虽然该运算符仅限于空检查,但三元运算符不是。例如

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

I think people just aren't aware of the null coalesce operator so they use the ternary operator instead. Ternary existed before C# in most C style languages so if you don't know C# inside and out and/or you programmed in another language, ternary is a natural choice. If you are checking for null though, use the null coalesce operator, it is designed for that, and the IL is slightly optimized (compare ?? to an if then else).

我认为人们只是不知道空合并运算符,所以他们改用三元运算符。在大多数 C 风格语言中,三元存在于 C# 之前,因此如果您不了解 C# 和/或您使用另一种语言进行编程,三元是一个自然的选择。如果您正在检查 null,请使用 null 合并运算符,它是为此而设计的,并且 IL 稍微优化(比较 ?? 与 if then else)。

Here is an example comparing the use of each

这是一个比较每个使用的示例

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;

First, just look at the syntax for null coalesce, it is way clearer. Ternary is really confusing. Now lets look at the IL

首先,看看空合并的语法,它更清晰。三元真的很混乱。现在让我们看看 IL

Null Coalesce Only

仅空合并

.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 

Ternary Only

仅三元

.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 

If Then Else Only

如果那么只有

.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 isn't one of my strong points, so maybe someone can edit my answer and expand on it. I was going to explain my theory, but I'd rather not confuse myself and others. The number of LOC is similar for all three, but not all IL operators take the same length of time to execute.

IL 不是我的强项之一,所以也许有人可以编辑我的答案并对其进行扩展。我打算解释我的理论,但我不想混淆我自己和其他人。所有三个的 LOC 数量相似,但并非所有 IL 操作符执行的时间长度都相同。

回答by Binoj Antony

One reason I can think of is that this operator was introduced in .NET 2.0 so the code for .NET 1.1 cannot have it.

我能想到的一个原因是这个运算符是在 .NET 2.0 中引入的,所以 .NET 1.1 的代码不能有它。

I agree with you, we should be using this more often.

我同意你的看法,我们应该更频繁地使用它。

ref link

参考链接

回答by Rytmis

The ?? operator (also known as the null-coalescing operator) is less known than the ternary operator, as it made its debut with .NET 2.0 and Nullable Types. Reasons for not using it probably include not begin aware that it exists, or being more familiar with the ternary operator.

这 ??运算符(也称为空合并运算符)不如三元运算符广为人知,因为它在 .NET 2.0 和 Nullable 类型中首次亮相。不使用它的原因可能包括不知道它存在,或者更熟悉三元运算符。

That said, checking for null is not the only thing the ternary operator is good for, so it's not a replacement for it as such, more like a better alternative for a very specific need. :)

也就是说,检查 null 并不是三元运算符唯一擅长的事情,因此它本身并不是它的替代品,更像是针对特定需求的更好替代品。:)

回答by Karel Bílek

I think it's just a habit from other languages. AFAIK, ?? operator is not used in any other language.

我认为这只是其他语言的习惯。AFAIK, ??运算符未在任何其他语言中使用。

回答by Bryan

I would have thought the equivalent of

我会认为相当于

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

would be

将是

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

回答by Fredrik M?rk

One reason (as others have already touched) is likely to be lack of awareness. It could also be (as in my own case), a wish to keep the number of approaches to do similar things in a code base down as much as possible. So I tend to use the ternary operator for all compact if-a-condition-is-met-do-this-otherwise-do-that situations.

一个原因(正如其他人已经触及的)可能是缺乏意识。也可能是(如我自己的情况),希望尽可能减少在代码库中执行类似操作的方法数量。所以我倾向于在所有紧凑的 if-a-condition-is-met-do-this-otherwise-do-that 情况下使用三元运算符。

For instance, I find the following two statements rather similar on a conceptual level:

例如,我发现以下两个陈述在概念层面上相当相似:

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

回答by Matthew Whited

Based on Bob'sanswer

基于鲍勃的回答

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

... this is the IL from release builds ...

...这是来自发布版本的 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 
}