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

2024-01-28

为了彻底解释这个问题已经被彻底修改。

我注意到 C# 6.0 中的 null 传播运算符似乎有一个相当糟糕的限制,因为您无法调用属性setters针对已传播 null 的对象(尽管您可以调用属性getters针对已传播 null 的对象)。正如您将从生成的 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;
    }
}

我在下面的测试类中测试了空传播的能力。

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,三元运算符用于获取以下值Name or 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语句,属性分配将通过空传播进行。

到目前为止,我还没有看到任何令人信服的论据来说明为什么这不应该成为可能,因此我仍在寻找答案!


你并不是唯一的一个!SLaks https://stackoverflow.com/users/34397/slaks将此提出为an issue https://github.com/dotnet/roslyn/issues/1276 (now here https://github.com/dotnet/csharplang/issues/737)

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

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

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

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

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

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

Object?.Prop = false;

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 6.0 空传播运算符和属性赋值 的相关文章

随机推荐