3

我有 2 个语句使用 null 条件 (?) 运算符并对结果执行 ToString。这两个语句似乎应该具有相同的结果,但事实并非如此。唯一不同的是一个包含括号,另一个不包含括号。

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()等于null

4

3 回答 3

6

someClass?.StatusCode评估为Nullable<HttpStatusCode>ToStringNullable结果为空字符串。

someClass?.StatusCode.ToString()将整个表达式短路到null.

通过使用括号,您可以有效地分解整个表达式。

于 2019-09-06T13:39:54.150 回答
0

As Daniel said this is the result of the type created on the fly being Nullable. I should have thought about that.

As has been stated, the statement without parenthesis simply stops evaluation basically because anything to the right of ?. (short circuits) becomes null if what precedes the ?. is null. I understood how the operator works in that respect.

The statement with the parenthesis forces the creation of an instance of a Nullable type hence the empty string resulting from the call to ToString. This didn't occur to me although it probably should have.

I used LINQPad to get the IL and verify all of that. I should have just done that in the first place. Sorry for wasting everyone's time. I do appreciate your answers though. Thank you.

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
于 2019-09-06T15:48:27.427 回答
0

您的期望是错误的(这很明显),但让我解释一下原因..

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-ed)。使用括号进行评估,然后将出现 ToString。

于 2019-09-06T13:43:44.610 回答