C# 6.0 Null Propagation Operator & Property Assignment
This question has been completely overhauled in the interest of being thorough in explanation.
I have noticed what appears to be quite a poor limitation of the null propagation operator in C# 6.0 in that you cannot call property setters against an object that has been null propagated (though you can call property getters against an object that has been null propagated). As you will see from the generated IL (which I have reflected into C#), there is nothing that should limit the ability to call property setters using null propagation.
To start with, I have created a simple class, with both Java style Get/Set methods, and a property with public getter/setter access.
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;
}
}
I have tested the ability of null propagation in the following test 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.
You may notice from this however that the Java way of setting the name, by calling SetName(...)
works, and you may also notice getting the value of a null propagated property also works.
Let's take a look at the C# that was generated from this code:
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;
}
Notice that when used against the SetName
method, null propagation transforms to a straightforward if
statement, and that when used against the Name
property getter, a ternary operator is used to either get the value of Name
or null
.
One thing I have noticed here is the behavior difference between using an if
statement and using the ternary operator: when using a setter, using an if
statement would work, whereas using a ternary operator wouldn't.
public static void Main(string[] args)
{
Person person = null;
if (person != null)
{
person.Name = "John Smith";
}
person.Name = (person != null) ? "John Smith" : null;
}
In this example I am using both an if
statement and the ternary operator to check whether person is null
before attempting to assign to its Name
property. the if
statement works as expected; the statement using the ternary operator fails, as expected
Object reference not set to an instance of an object.
In my opinion, the limitation comes from C# 6.0's ability to transform null propagation into either an if
statement or a ternary expression. Had it been designed to use only if
statements, property assignment would work via null propagation.
So far, I have not seen one compelling argument as to why this SHOULD NOT be possible, therefore I am still looking for answers!
You're not the only one! SLaks raised this as an issue
Why can't I write code like this?
Process.GetProcessById(2)?.Exited += delegate { };
and after it was briefly closed as "By design"
the ?. Operator never produces an lvalue, so this is by design.
someone commented that it would be good for property setters as well as event handlers
Maybe add also properties setters into request like:
Object?.Prop = false;
and it was re-opened as a feature request for C#7.
You can't use the null-propagation operator in this way.
This operator allows to propagate nulls while evaluating an expression. It can't be used as the target of an assignment exactly as the error suggests.
You need to stick to the plain old null check:
if (a != null)
{
a.Value = someValue;
}
Try it like this...
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; }
}
}
链接地址: http://www.djcxy.com/p/13064.html上一篇: 在使用C#6.0的功能时会有性能提升吗?
下一篇: C#6.0空传播操作员和属性分配