28

为了彻底解释,这个问题已经过彻底检查。

我注意到 C# 6.0 中空传播运算符的一个似乎很差的限制,因为您不能针对已传播空的对象调用属性设置器(尽管您可以针对已传播空的对象调用属性获取器) . 正如您将从生成的 IL (我已反映到 C#)中看到的那样,没有什么可以限制使用 null 传播调用属性设置器的能力。

首先,我创建了一个简单的类,它具有 Java 样式的 Get/Set 方法和一个具有公共 getter/setter 访问权限的属性。

public class Person
{
    public Person(string name, DateTime birthday)
    {
        Name = name;
    }

    public string Name { get; set; }

    public void SetName(string name)
    {
        Name = name;
    }

    public string GetName()
    {
        return Name;
    }
}

我已经在下面的测试类中测试了 null 传播的能力。

public class Program
{
    public static void Main(string[] args)
    {
        Person person = new Person("Joe Bloggs", DateTime.Parse("01/01/1991"));

        // This line doesn't work - see documented error below
        person?.Name = "John Smith";

        person?.SetName("John Smith");

        string name = person?.Name;
    }
}

赋值的左侧必须是变量、属性或索引器。

然而,您可能会注意到,通过调用设置名称的 Java 方法是SetName(...)有效的,您可能还会注意到获取空传播属性的值也有效。

让我们看一下从这段代码生成的 C#:

public static void Main(string[] args)
{
    Person person = new Person("Joe Bloggs", DateTime.Parse("01/01/1991"));
    if (person != null)
    {
        person.SetName("John Smith");
    }
    string arg_33_0 = (person != null) ? person.Name : null;
}

请注意,当用于SetName方法时,空传播转换为简单的if语句,而当用于Name属性 getter 时,使用三元运算符来获取Nameor的值null

我在这里注意到的一件事是使用if语句和使用三元运算符之间的行为差​​异:使用 setter 时,使用if语句会起作用,而使用三元运算符则不会。

public static void Main(string[] args)
{
    Person person = null;

    if (person != null)
    {
        person.Name = "John Smith";
    }

    person.Name = (person != null) ? "John Smith" : null;
}

在此示例中,我同时使用if语句和三元运算符来检查 person 是否null在尝试分配其Name属性之前。该if语句按预期工作;正如预期的那样,使用三元运算符的语句失败

你调用的对象是空的。

在我看来,限制来自于 C# 6.0 将 null 传播转换为if语句或三元表达式的能力。如果它被设计为仅使用if语句,则属性分配将通过空传播工作。

到目前为止,我还没有看到一个令人信服的论点来说明为什么这不应该发生,因此我仍在寻找答案!

4

3 回答 3

28

你并不是唯一的一个!SLaks将此作为一个问题提出(现在在这里

为什么我不能写这样的代码?

Process.GetProcessById(2)?.Exited += delegate { };

在它被短暂关闭为“按设计”之后

这 ?。运算符从不产生左值,所以这是设计使然。

有人评论说这对属性设置器和事件处理程序都有好处

也许还将属性设置器添加到请求中,例如:

Object?.Prop = false;

它作为 C#7 的功能请求重新打开。

于 2015-09-22T11:11:04.090 回答
6

您不能以这种方式使用空传播运算符。

此运算符允许在评估表达式时传播空值。不能完全按照错误提示将其用作分配的目标。

您需要坚持使用普通的旧空检查:

if (a != null)
{
    a.Value = someValue;
}
于 2015-09-11T09:03:39.927 回答
-2

试试这样...

using System;

namespace TestCon
{
    class Program
    {
        public static void Main()
    {

        Person person = null;
        //Person person = new Person() { Name = "Jack" };

        //Using an "if" null check.
        if (person != null)
        {
            Console.WriteLine(person.Name);
            person.Name = "Jane";
            Console.WriteLine(person.Name);
        }

        //using a ternary null check.
        string arg = (person != null) ? person.Name = "John" : arg = null;
        //Remember the first statment after the "?" is what happens when true. False after the ":". (Just saying "john" is not enough)
        //Console.WriteLine(person.Name);

        if (arg == null)
        {
            Console.WriteLine("arg is null");
        }

        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
public class Person
{
    public string Name { get; set; }
}

}

于 2015-09-23T02:31:19.347 回答