为了彻底解释这个问题已经被彻底修改。
我注意到 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
语句,属性分配将通过空传播进行。
到目前为止,我还没有看到任何令人信服的论据来说明为什么这不应该成为可能,因此我仍在寻找答案!