为什么空条件运算符会更改常规属性访问权限?

时间:2018-08-01 18:56:35

标签: c# null-conditional-operator safe-navigation-operator

我对空条件运算符与常规属性访问如何级联感到困惑。举两个例子:

ANY_NUMBER_SRCH = r"(?P<number_capture>(?P<pre1>(?<![^0-9,.+-])|)(?P<number>(?P<sign_symbol_opt1>(?<![0-9])[+-])?(?P<whole_number_w_thous_sep>(?P<first_group>\d{1,3})(?P<thousands_separator>[ ,])(?P<three_digits_w_sep>(?P<three_digits>\d{3})(?P=thousands_separator))*(?P<last_group_of_three>\d{3})(?!\d)|(?P<whole_number_w_o_thous_sep>\d+))(?P<decimal_separator_1>[.])?(?P<fractional_w_whole_before>(?<=[.])(?P<digits_after_decimal_sep_1>\d+))?(?P<post1>(?<![^0-9,.+-])|)|(?P<pre2>(?<![^0-9,.+-])|)(?P<fractional_without_whole_before>(?P<sign_symbol_opt2>(?<![0-9])[+-])?(?P<decimal_separator_2>[.])(?P<digits_after_decimal_sep_2>\d+)))(?P<post2>(?<![^0-9,.+-])|))"

我希望它们是等效的:首先,评估a?.b.c (a?.b).c 的值,然后评估a?.b。因此,如果result.c,则应引发异常。

但是,这仅在第二个表达式中发生。第一个表达式的计算结果为a == null,这意味着它与null相同。 为什么?

2 个答案:

答案 0 :(得分:9)

这只是运算符优先级的问题。让我们看一下这些案例:

  

a?.b.c

  1. 返回评估a => null,鉴于the null-conditional operators are short-circuiting,没有其他评估。
  

(a?.b).c

  1. 评估a =>返回null
  2. 评估((B)null).c =>抛出NullReferenceException

要使这些情况相同,您应该进行比较

  1. a?.b.c
  2. (a?.b)?.c
  3. a?.b?.c(您已经提到过)

答案 1 :(得分:1)

除了Camilo已经提供的功能外,我不知道这是否会有所帮助,但这是一个简短的比较,显示了在没有空条件运算符的情况下逻辑的外观。

public class Program
{
    public static void Main()
    {
        A a;

        a = new A { b = new B { c = 5 } };

        Console.WriteLine(a?.b.c);        // returns 5;
        Console.WriteLine((a?.b).c);      // returns 5;

        a = null;

        Console.WriteLine(a?.b.c ?? -1);  // returns -1;
        Console.WriteLine((a?.b).c);      // throws NullReferenceException


        // Similar to a?.b.c

        if (a != null)
            Console.WriteLine(a.b.c);     // returns 5;
        else
            Console.WriteLine(-1);        // returns -1;


        // Similar to (a?.b).c

        B tmp;
        if (a != null)
            tmp = a.b;
        else
            tmp = null;

        Console.WriteLine(tmp.c);         // returns 5 or throws NullReferenceException
    }
}


public class A
{
    public B b { get; set; }
}

public class B
{
    public int c { get; set; }
}