Null 条件和 ToString 一起给出意想不到的结果
Null conditional and ToString together give unexpected results
我有 2 个使用空条件 (?) 运算符并对结果执行 ToString 的语句。这 2 条语句似乎应该有相同的结果,但事实并非如此。唯一不同的是一个有括号,一个没有。
using System.Diagnostics;
using System.Net;
namespace ByPermutationConsole
{
class Program
{
static void Main(string[] args)
{
SomeClass someClass = default(SomeClass);
// Why do these evaluate differently?
//
// (someClass?.StatusCode).ToString() is equal to an empty string
//
// someClass?.StatusCode.ToString() is equal to null
//
}
}
public class SomeClass
{
public HttpStatusCode StatusCode { get; set; }
}
}
我希望这 2 个语句的计算结果相同。
(someClass?.StatusCode).ToString() == someClass?.StatusCode.ToString()
然而,他们没有:
(someClass?.StatusCode).ToString()
等于 string.Empty
并且someClass?.StatusCode.ToString()
等于null
someClass?.StatusCode
的计算结果为 Nullable<HttpStatusCode>
。 ToString
空 Nullable
结果为空字符串。
someClass?.StatusCode.ToString()
将整个表达式短路为 null
.
通过使用括号,您可以有效地分解整个表达式。
你的期望是错误的(这很明显),但让我解释一下原因..
someClass?.StatusCode.ToString()
.........^ here the evaluation is already concluded to null - someClass is null
(someClass?.StatusCode).ToString()
.......................^ null to string will result in an empty string
查看代码中进行计算的点 (^)。如果没有括号,评估将立即停止(它永远不会被 ToString 编辑)。使用括号进行评估,然后将出现 ToString。
正如 Daniel 所说,这是动态创建的类型为 Nullable 的结果。我应该考虑一下。
如前所述,不带括号的语句基本上会停止求值,因为 ? 右边的任何内容。如果什么在 ? 之前,(短路)变为空。一片空白。我了解运营商在这方面的工作方式。
带括号的语句强制创建 Nullable 类型的实例,因此调用 ToString 会产生空字符串。我没有想到,虽然它可能应该有。
我使用 LINQPad 获取 IL 并验证所有这些。我一开始就应该这样做。很抱歉浪费了大家的时间。不过,我非常感谢您的回答。谢谢。
class Program
{
static void Main(string[] args)
{
SomeClass someClass1 = default(SomeClass);
string result1 = someClass1?.SomeNumber.ToString();
SomeClass someClass2 = default(SomeClass);
string result2 = (someClass2?.SomeNumber).ToString();
}
}
public class SomeClass
{
public int SomeNumber { get; set; }
}
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0 // someClass1
IL_0003: ldloc.0 // someClass1
IL_0004: brtrue.s IL_0009
IL_0006: ldnull
IL_0007: br.s IL_0018
IL_0009: ldloc.0 // someClass1
IL_000A: call UserQuery+SomeClass.get_SomeNumber
IL_000F: stloc.s 04
IL_0011: ldloca.s 04
IL_0013: call System.Int32.ToString
IL_0018: stloc.1 // result1
IL_0019: ldnull
IL_001A: stloc.2 // someClass2
IL_001B: ldloc.2 // someClass2
IL_001C: brtrue.s IL_002A
IL_001E: ldloca.s 05
IL_0020: initobj System.Nullable<System.Int32>
IL_0026: ldloc.s 05
IL_0028: br.s IL_0035
IL_002A: ldloc.2 // someClass2
IL_002B: call UserQuery+SomeClass.get_SomeNumber
IL_0030: newobj System.Nullable<System.Int32>..ctor
IL_0035: stloc.s 05
IL_0037: ldloca.s 05
IL_0039: constrained. System.Nullable<System.Int32>
IL_003F: callvirt System.Object.ToString
IL_0044: stloc.3 // result2
IL_0045: ret
SomeClass.get_SomeNumber:
IL_0000: ldarg.0
IL_0001: ldfld UserQuery+SomeClass.<SomeNumber>k__BackingField
IL_0006: ret
SomeClass.set_SomeNumber:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld UserQuery+SomeClass.<SomeNumber>k__BackingField
IL_0007: ret
我有 2 个使用空条件 (?) 运算符并对结果执行 ToString 的语句。这 2 条语句似乎应该有相同的结果,但事实并非如此。唯一不同的是一个有括号,一个没有。
using System.Diagnostics;
using System.Net;
namespace ByPermutationConsole
{
class Program
{
static void Main(string[] args)
{
SomeClass someClass = default(SomeClass);
// Why do these evaluate differently?
//
// (someClass?.StatusCode).ToString() is equal to an empty string
//
// someClass?.StatusCode.ToString() is equal to null
//
}
}
public class SomeClass
{
public HttpStatusCode StatusCode { get; set; }
}
}
我希望这 2 个语句的计算结果相同。
(someClass?.StatusCode).ToString() == someClass?.StatusCode.ToString()
然而,他们没有:
(someClass?.StatusCode).ToString()
等于 string.Empty
并且someClass?.StatusCode.ToString()
等于null
someClass?.StatusCode
的计算结果为 Nullable<HttpStatusCode>
。 ToString
空 Nullable
结果为空字符串。
someClass?.StatusCode.ToString()
将整个表达式短路为 null
.
通过使用括号,您可以有效地分解整个表达式。
你的期望是错误的(这很明显),但让我解释一下原因..
someClass?.StatusCode.ToString()
.........^ here the evaluation is already concluded to null - someClass is null
(someClass?.StatusCode).ToString()
.......................^ null to string will result in an empty string
查看代码中进行计算的点 (^)。如果没有括号,评估将立即停止(它永远不会被 ToString 编辑)。使用括号进行评估,然后将出现 ToString。
正如 Daniel 所说,这是动态创建的类型为 Nullable 的结果。我应该考虑一下。
如前所述,不带括号的语句基本上会停止求值,因为 ? 右边的任何内容。如果什么在 ? 之前,(短路)变为空。一片空白。我了解运营商在这方面的工作方式。
带括号的语句强制创建 Nullable 类型的实例,因此调用 ToString 会产生空字符串。我没有想到,虽然它可能应该有。
我使用 LINQPad 获取 IL 并验证所有这些。我一开始就应该这样做。很抱歉浪费了大家的时间。不过,我非常感谢您的回答。谢谢。
class Program
{
static void Main(string[] args)
{
SomeClass someClass1 = default(SomeClass);
string result1 = someClass1?.SomeNumber.ToString();
SomeClass someClass2 = default(SomeClass);
string result2 = (someClass2?.SomeNumber).ToString();
}
}
public class SomeClass
{
public int SomeNumber { get; set; }
}
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0 // someClass1
IL_0003: ldloc.0 // someClass1
IL_0004: brtrue.s IL_0009
IL_0006: ldnull
IL_0007: br.s IL_0018
IL_0009: ldloc.0 // someClass1
IL_000A: call UserQuery+SomeClass.get_SomeNumber
IL_000F: stloc.s 04
IL_0011: ldloca.s 04
IL_0013: call System.Int32.ToString
IL_0018: stloc.1 // result1
IL_0019: ldnull
IL_001A: stloc.2 // someClass2
IL_001B: ldloc.2 // someClass2
IL_001C: brtrue.s IL_002A
IL_001E: ldloca.s 05
IL_0020: initobj System.Nullable<System.Int32>
IL_0026: ldloc.s 05
IL_0028: br.s IL_0035
IL_002A: ldloc.2 // someClass2
IL_002B: call UserQuery+SomeClass.get_SomeNumber
IL_0030: newobj System.Nullable<System.Int32>..ctor
IL_0035: stloc.s 05
IL_0037: ldloca.s 05
IL_0039: constrained. System.Nullable<System.Int32>
IL_003F: callvirt System.Object.ToString
IL_0044: stloc.3 // result2
IL_0045: ret
SomeClass.get_SomeNumber:
IL_0000: ldarg.0
IL_0001: ldfld UserQuery+SomeClass.<SomeNumber>k__BackingField
IL_0006: ret
SomeClass.set_SomeNumber:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld UserQuery+SomeClass.<SomeNumber>k__BackingField
IL_0007: ret