空合并赋值运算符的行为
The behavior of null-coalescing assignment operator
我只是想知道 ??= 运算符如何在后台运行。我有两个问题。
考虑以下示例,
string name = "John";
name ??= "George";
1)是否等于name = name ?? "George";
2)
是不是这样,
if (name == null) {
name = "George";
}
或
if (name == null) {
name = "George";
}
else {
name = name;
}
会被评价为:
string text = "John";
if (text == null)
{
text = "George";
}
您可以使用 sharplab
查看实际发生的情况:
更多信息:
C# 8.0 introduces the null-coalescing assignment operator ??=. You can
use the ??= operator to assign the value of its right-hand operand to
its left-hand operand only if the left-hand operand evaluates to null.
null-coalescing assignment operator ??=
assigns the value of its
right-hand operand to its left-hand operand only if the left-hand
operand evaluates to null
. The ??=
operator doesn't evaluate its
right-hand operand if the left-hand operand evaluates to non-null.
在您的代码示例中,它不会被评估,因为 name
不是 null
string name = "John";
name ??= "George";
如果你这样写就可以了
string name = null;
name ??= "George";
名称值将为 George
。扩展变体是
if (name is null) //or name == null
{
name = "George";
}
The null-coalescing operator ??
returns the value of left-hand
operand if it isn't null
; otherwise, it evaluates the right-hand
operand and returns result.
在此示例中 name = name ?? "George"
只有当名称之前有 null
值时,结果才会是 George
。我的样本 name = name ?? "George";
就 return 结果而言等于 name ??= "George";
。但是在这两种情况下,只有当原始 name
为 null
时,您才能获得 George
值。也可以参考language specification了解详情
您可以使用 https://sharplab.io/ 来测试差异。 ??=
和 ??
之间的区别非常小,实际上 一旦代码被 JIT 编译就消失了 。
简而言之:
- 一旦代码被编译成汇编,就一样了。
- 等价于:
if (text == null){
text = "George";
}
SharpLab 示例
this example的代码:
public void M1() {
string name = "John";
name ??= "George";
Console.WriteLine(name);
}
public void M2() {
string name = "John";
name = name ?? "George";
Console.WriteLine(name);
}
生成这个中间 C# 代码,显示出真正的区别:
public void M1()
{
string text = "John";
if (text == null)
{
text = "George";
}
Console.WriteLine(text);
}
public void M2()
{
string text = "John";
text = (text ?? "George");
Console.WriteLine(text);
}
虽然 IL 是 almost the same,但 dup
(复制)和 pop
操作除外。你会认为 ??
为此有点慢:
IL_0000: nop
IL_0001: ldstr "John"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brtrue.s IL_0010
IL_000a: ldstr "George"
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: call void [System.Console]System.Console::WriteLine(string)
IL_0016: nop
IL_0017: ret
对比
IL_0000: nop
IL_0001: ldstr "John"
IL_0006: stloc.0
IL_0007: ldloc.0
*** IL_0008: dup
IL_0009: brtrue.s IL_0011
*** IL_000b: pop
IL_000c: ldstr "George"
IL_0011: stloc.0
IL_0012: ldloc.0
IL_0013: call void [System.Console]System.Console::WriteLine(string)
IL_0018: nop
IL_0019: ret
但是 the assembly in Release mode 是相同的:
C.M1()
L0000: mov ecx, [0x1a58b46c]
L0006: test ecx, ecx
L0008: jnz L0010
L000a: mov ecx, [0x1a58b470]
L0010: call System.Console.WriteLine(System.String)
L0015: ret
C.M2()
L0000: mov ecx, [0x1a58b46c]
L0006: test ecx, ecx
L0008: jnz L0010
L000a: mov ecx, [0x1a58b470]
L0010: call System.Console.WriteLine(System.String)
L0015: ret
我只是想知道 ??= 运算符如何在后台运行。我有两个问题。
考虑以下示例,
string name = "John";
name ??= "George";
1)是否等于name = name ?? "George";
2) 是不是这样,
if (name == null) {
name = "George";
}
或
if (name == null) {
name = "George";
}
else {
name = name;
}
会被评价为:
string text = "John";
if (text == null)
{
text = "George";
}
您可以使用 sharplab
查看实际发生的情况:
更多信息:
C# 8.0 introduces the null-coalescing assignment operator ??=. You can use the ??= operator to assign the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null.
null-coalescing assignment operator
??=
assigns the value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates tonull
. The??=
operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null.
在您的代码示例中,它不会被评估,因为 name
不是 null
string name = "John";
name ??= "George";
如果你这样写就可以了
string name = null;
name ??= "George";
名称值将为 George
。扩展变体是
if (name is null) //or name == null
{
name = "George";
}
The null-coalescing operator
??
returns the value of left-hand operand if it isn'tnull
; otherwise, it evaluates the right-hand operand and returns result.
在此示例中 name = name ?? "George"
只有当名称之前有 null
值时,结果才会是 George
。我的样本 name = name ?? "George";
就 return 结果而言等于 name ??= "George";
。但是在这两种情况下,只有当原始 name
为 null
时,您才能获得 George
值。也可以参考language specification了解详情
您可以使用 https://sharplab.io/ 来测试差异。 ??=
和 ??
之间的区别非常小,实际上 一旦代码被 JIT 编译就消失了 。
简而言之:
- 一旦代码被编译成汇编,就一样了。
- 等价于:
if (text == null){
text = "George";
}
SharpLab 示例
this example的代码:
public void M1() {
string name = "John";
name ??= "George";
Console.WriteLine(name);
}
public void M2() {
string name = "John";
name = name ?? "George";
Console.WriteLine(name);
}
生成这个中间 C# 代码,显示出真正的区别:
public void M1()
{
string text = "John";
if (text == null)
{
text = "George";
}
Console.WriteLine(text);
}
public void M2()
{
string text = "John";
text = (text ?? "George");
Console.WriteLine(text);
}
虽然 IL 是 almost the same,但 dup
(复制)和 pop
操作除外。你会认为 ??
为此有点慢:
IL_0000: nop
IL_0001: ldstr "John"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brtrue.s IL_0010
IL_000a: ldstr "George"
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: call void [System.Console]System.Console::WriteLine(string)
IL_0016: nop
IL_0017: ret
对比
IL_0000: nop
IL_0001: ldstr "John"
IL_0006: stloc.0
IL_0007: ldloc.0
*** IL_0008: dup
IL_0009: brtrue.s IL_0011
*** IL_000b: pop
IL_000c: ldstr "George"
IL_0011: stloc.0
IL_0012: ldloc.0
IL_0013: call void [System.Console]System.Console::WriteLine(string)
IL_0018: nop
IL_0019: ret
但是 the assembly in Release mode 是相同的:
C.M1()
L0000: mov ecx, [0x1a58b46c]
L0006: test ecx, ecx
L0008: jnz L0010
L000a: mov ecx, [0x1a58b470]
L0010: call System.Console.WriteLine(System.String)
L0015: ret
C.M2()
L0000: mov ecx, [0x1a58b46c]
L0006: test ecx, ecx
L0008: jnz L0010
L000a: mov ecx, [0x1a58b470]
L0010: call System.Console.WriteLine(System.String)
L0015: ret