C#6.0空传播运算符和属性赋值

ser*_*0ne 27 c# c#-6.0 null-propagation-operator

为了彻底解释,这个问题已经彻底改革.

我注意到C#6.0中空传播运算符的限制似乎很差,因为你无法针对已经传播的对象调用属性设置器(尽管你可以针对已经传播的对象调用属性getter) .正如您将从生成的IL (我已反映到C#中)看到的那样,没有任何东西可以限制使用空传播调用属性设置器的能力.

首先,我创建了一个简单的类,包括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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

但是,您可能会注意到,通过调用SetName(...)works 来设置名称的Java方式,您可能还会注意到获取null传播属性的值也可以.

我们来看看从这段代码生成的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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,当使用该SetName方法时,null传播转换为直接if语句,并且当使用针对Name属性getter时,使用三元运算符来获取Name或的值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;
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我使用一个if语句和三元运算符来检查人是否null在尝试分配给它的Name属性之前.该if声明按预期工作; 正如预期的那样,使用三元运算符的语句失败

你调用的对象是空的.

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

到目前为止,我还没有看到一个令人信服的论据,为什么这不应该是可能的,因此我仍然在寻找答案!

Raw*_*ing 25

你并不是唯一的一个!SLaks提出这个问题

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

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

之后被简称为"按设计"

?.操作员永远不会产生左值,所以这是设计的.

有人评论说这对财产制定者和事件处理者都有好处

也许将属性setter添加到请求中:

Object?.Prop = false;

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


i3a*_*non 5

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

此运算符允许在评估表达式时传播空值。它不能完全像错误所暗示的那样用作分配的目标。

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

if (a != null)
{
    a.Value = someValue;
}
Run Code Online (Sandbox Code Playgroud)

  • 我已经更新了整个问题来说明我的问题。它不了解操作员的工作方式 - 我知道这一点;它理解为什么,如果 C# 6.0 可以将空传播转换为不同的形式(一种是您建议的答案),为什么它不能为属性分配执行此操作,它绝对可以执行此操作 - 关于它为什么不能执行,没有令人信服的论点做这个。 (2认同)