C# Null条件和ToString一起给出意外的结果
我有两条语句使用null条件(?)运算符并对结果执行ToString。这两条语句似乎应该有相同的结果,但它们没有。唯一不同的是一个包含括号,而另一个不包含括号C# Null条件和ToString一起给出意外的结果,c#,null-conditional-operator,C#,Null Conditional Operator,我有两条语句使用null条件(?)运算符并对结果执行ToString。这两条语句似乎应该有相同的结果,但它们没有。唯一不同的是一个包含括号,而另一个不包含括号 using System.Diagnostics; using System.Net; namespace ByPermutationConsole { class Program { static void Main(string[] args) { SomeCl
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; }
}
}
我希望这两个语句的计算结果相同
(someClass?.StatusCode).ToString() == someClass?.StatusCode.ToString()
但是,它们没有:
(someClass?.StatusCode).ToString()
等于string.Empty
和
someClass?.StatusCode.ToString()
等于nullsomeClass?.StatusCode
计算为null
<空Nullable
上的code>ToString
会导致空字符串
someClass?.StatusCode.ToString()
将整个表达式短路到null
通过使用paren,您实际上是在分解整个表达式。您的期望是错误的(这是显而易见的),但让我解释一下原因
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 正如Daniel所说,这是动态创建的类型可为null的结果。我应该考虑一下 如前所述,不带括号的语句基本上停止求值,因为在?的右边有任何内容?。(短路)如果?之前的内容变为空?。是空的。我理解操作员在这方面的工作方式 带括号的语句强制创建可为null类型的实例,因此调用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
类程序
{
静态void Main(字符串[]参数)
{
SomeClass someClass1=默认值(SomeClass);
字符串结果1=someClass1?.SomeNumber.ToString();
SomeClass someClass2=默认值(SomeClass);
字符串result2=(someClass2?.SomeNumber).ToString();
}
}
公共类
{
公共int SomeNumber{get;set;}
}
IL_0000:没有
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:调用UserQuery+SomeClass.get_SomeNumber
IL_000F:stloc.s 04
IL_0011:ldloca.s 04
IL_0013:调用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系统。可为空
IL_0026:ldloc.s 05
IL_0028:br.s IL_0035
IL_002A:ldloc.2//someClass2
IL\u 002B:调用UserQuery+SomeClass.get\u SomeNumber
IL_0030:newobj System.Nullable..ctor
IL_0035:stloc.s 05
IL_0037:ldloca.s 05
IL_0039:受限。系统。可为空
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.k_ubackingfield
IL_0006:ret
SomeClass.set\u SomeNumber:
IL_0000:ldarg.0
IL_0001:ldarg.1
IL\u 0002:stfld UserQuery+SomeClass.k\u BackingField
IL_0007:ret
使用(someClass?.StatusCode)?.ToString()可以得到相同的结果代码>这比Daniel A.White的回答更准确,它短路
为空。请检查此项。我认为他们感到困惑的原因是他们不知道为什么评估会提前停止。因为他们不理解空条件运算符是如何工作的。因此,使用提供的代码示例进行解释。。我希望你的代码能说明发生了什么。它没有解释为什么或者如何知道发生了什么。我想我必须看看IL,因为你上面说的内容基本上是(null)。ToString的计算结果是一个空字符串,而它不是。唯一有意义的方法是,如果偏执论中的类型本质上是一个可为空的类型,就像上面Daniel White所说的。