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