C# 6.0 空传播运算符 & 属性 赋值
C# 6.0 Null Propagation Operator & Property Assignment
为了解释更透彻,这个问题已经过彻底检查。
我注意到 C# 6.0 中 null 传播运算符的限制似乎很差,因为您不能调用 属性 setters针对已空传播的对象(尽管您可以针对已空传播的对象调用 属性 getters)。正如您将从生成的 IL (我已将其反映到 C# 中) 中看到的那样,没有任何东西应该限制使用 null 调用 属性 setters 的能力传播。
首先,我创建了一个简单的 class,其中包含 Java 风格的 Get/Set 方法,以及 属性 和 public 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;
}
}
我在下面的测试中测试了null传播的能力class。
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;
}
}
The left-hand side of an assignment must be a variable, property or
indexer.
然而,您可能会注意到 Java 设置名称的方式,通过调用 SetName(...)
有效,您可能还会注意到获取 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
方法时,空值传播转换为直接的 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
语句按预期工作;正如预期的那样,使用三元运算符的语句失败了
Object reference not set to an instance of an object.
在我看来,限制来自于 C# 6.0 将 null 传播转换为 if
语句或三元表达式的能力。如果它被设计为仅使用 if
语句,属性 赋值将通过空传播工作。
到目前为止,我还没有看到一个令人信服的论据来说明为什么这不应该是可能的,因此我仍在寻找答案!
您不能以这种方式使用空值传播运算符。
此运算符允许在计算表达式时传播空值。它不能完全按照错误提示用作赋值的目标。
您需要坚持使用普通的旧空检查:
if (a != null)
{
a.Value = someValue;
}
你不是唯一一个! SLaks raised this as an issue (now here)
Why can't I write code like this?
Process.GetProcessById(2)?.Exited += delegate { };
在它被短暂关闭为“按设计”之后
the ?. Operator never produces an lvalue, so this is by design.
有人评论说这对 属性 setter 和事件处理程序都有好处
Maybe add also properties setters into request like:
Object?.Prop = false;
它已作为 C#7 的功能请求重新打开。
像这样尝试...
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; }
}
}
为了解释更透彻,这个问题已经过彻底检查。
我注意到 C# 6.0 中 null 传播运算符的限制似乎很差,因为您不能调用 属性 setters针对已空传播的对象(尽管您可以针对已空传播的对象调用 属性 getters)。正如您将从生成的 IL (我已将其反映到 C# 中) 中看到的那样,没有任何东西应该限制使用 null 调用 属性 setters 的能力传播。
首先,我创建了一个简单的 class,其中包含 Java 风格的 Get/Set 方法,以及 属性 和 public 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;
}
}
我在下面的测试中测试了null传播的能力class。
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;
}
}
The left-hand side of an assignment must be a variable, property or indexer.
然而,您可能会注意到 Java 设置名称的方式,通过调用 SetName(...)
有效,您可能还会注意到获取 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
方法时,空值传播转换为直接的 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
语句按预期工作;正如预期的那样,使用三元运算符的语句失败了
Object reference not set to an instance of an object.
在我看来,限制来自于 C# 6.0 将 null 传播转换为 if
语句或三元表达式的能力。如果它被设计为仅使用 if
语句,属性 赋值将通过空传播工作。
到目前为止,我还没有看到一个令人信服的论据来说明为什么这不应该是可能的,因此我仍在寻找答案!
您不能以这种方式使用空值传播运算符。
此运算符允许在计算表达式时传播空值。它不能完全按照错误提示用作赋值的目标。
您需要坚持使用普通的旧空检查:
if (a != null)
{
a.Value = someValue;
}
你不是唯一一个! SLaks raised this as an issue (now here)
Why can't I write code like this?
Process.GetProcessById(2)?.Exited += delegate { };
在它被短暂关闭为“按设计”之后
the ?. Operator never produces an lvalue, so this is by design.
有人评论说这对 属性 setter 和事件处理程序都有好处
Maybe add also properties setters into request like:
Object?.Prop = false;
它已作为 C#7 的功能请求重新打开。
像这样尝试...
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; }
}
}