Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
194 views
in Technique[技术] by (71.8m points)

c# 6.0 - 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!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You're not the only one! SLaks raised this as an issue (now here)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...