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

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

我注意到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; } } 

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

 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; } } 

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

您可能会注意到,通过调用SetName(...)设置名称的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; } 

请注意,当针对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; } 

在这个例子中,我使用if语句和三元运算符来检查person是否为null然后尝试分配给它的Name属性。 if语句按预期工作; 正如预期的那样,使用三元运算符的语句失败了

你调用的对象是空的。

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

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

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

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

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

之后被简单地关闭为“按设计”

?。 操作员从不产生左值,因此这是设计的。

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

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

Object?.Prop = false;

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

您不能以这种方式使用null-propagation运算符。

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

你需要坚持普通的旧null检查:

 if (a != null) { a.Value = someValue; } 

试试吧……

 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; } } 

}