2

I can't understand how it works.

private Person _user;

private Person User
{
  get
  {
    return _user ?? ( _user = GetUser() );
  }
}

The first time I refer to User property, _user is null so it returns ( _user = GetUser() )????

What am I missing?

shadow
  • 1,883
  • 1
  • 16
  • 24
  • https://msdn.microsoft.com/en-us/library/ms173224.aspx Thoroughly read over that first. The purpose of it is to check if `_user` is null, and if it is, return the value of what is on the right hand side (`_user = GetUser()`) in your case – Rogue May 15 '15 at 18:15
  • Side note: `Lazy` maybe preferable way to express lazy initialization. – Alexei Levenkov May 15 '15 at 18:20
  • @Alexei: Application is in Framework 3.5. Thanks anyway! – shadow May 15 '15 at 18:30
  • 1
    @JohnSaunders, I think it is not the duplicate of the linked question, OP was confused about the assignment expression, IMHO. – Habib May 15 '15 at 18:52
  • I sure can't tell based on what the OP says. – John Saunders May 15 '15 at 20:43

7 Answers7

7

First, it is null-coalescing operator and it returns the left hand operand if the that is not null, otherwise it returns the right hand operand.

return _user ?? ( _user = GetUser() );

In case of _user being null, it returns what is returned by GetUser method and set the private field to it as well.

So it works like:

  1. GetUser returns value which is assigned to _user
  2. Assignment expression (_user = GetUser()) returns the value.

See: How assignment expression returns value.

Community
  • 1
  • 1
Habib
  • 219,104
  • 29
  • 407
  • 436
  • 3
    So we learn something today about assignment expressions! Thanks Habib! – shadow May 15 '15 at 18:27
  • 1
    @Habib no problem. +1 as I liked your answer the best as it explains everything but yet is concise and links all material for further investigation. – Frank J May 15 '15 at 18:45
  • 1
    Good explanation. I would add this is one area where tools like ReSharper can be useful as a learning resource. If you have the functionally equivalent express (using if(_user == null) ... ) Resharper will offer to refactor it. That can make it easy to see the equivalent snippets. In C#6.0 it can be replaced with an expression body private Person User => _user ?? (_user = GetUser() ); Maybe that is too much sugar? – Gerald Davis May 15 '15 at 18:57
2

That code is essentially the same as this:

private Person _user;

private Person User
{
    get
    {
        if (_user == null) _user = GetUser();
        return _user;
    }
}

How it works

The null coalescing operator (??) returns the object if it's not null, otherwise it returns whatever is on the other side of the operator. So the statement:

return _user ?? ( _user = GetUser() );

Says, "return _user, unless it's null, in which case return the result of the assignment ( _user = GetUser() )". This is a clever way of assigning a value to _user and returning that assigned value in the same line.

That being said, some developers will argue that the first method I wrote above, which uses two lines instead of one, is more readable (the intent is clearer) and easier to maintain.

Rufus L
  • 36,127
  • 5
  • 30
  • 43
  • This is not correct. If the line was this: `return _user ?? GetUser();` then _user would not be updated when `GetUser` is invoked, but the value from `GetUser` would still be returned. In your case if we expand the line, when it would be: `if(_user == null) GetUser(); return _user;` which would not return the value of `GetUser()`, but the value of _user which is null. – Anders May 15 '15 at 18:32
  • 1
    @Nautious Not sure I follow you, I think you are misreading my code. I am doing an assignment if `_user` is null, then I'm returning `_user` (which will not be null in either case). In my description of what is happening, I also say it returns "the result of the assignment", which again means not `null`. – Rufus L May 15 '15 at 18:34
  • Your code is correct, if compared to the code line in OP's question: (`return _user ?? (_user = GetUser());`). However your code in incorrect as an representation of what ?? means, since if we try to explain this code line: `return _user ?? GetUser()` with your alternative, then when using ?? value from GetUser will be returned, but with your code the value would be lost, and the value of _user which is null would be returned. – Anders May 15 '15 at 18:43
  • 1
    @Nautious your code is functionally identical to Rufus solution. Also the value of GetUser() is not lost. "_user = GetUser()" Notice _user is assigned the value of GetUser(). Maybe you should put all three code snippets (question, your solution, and rufus' solution) into an IDE and verify before "correcting" further? – Gerald Davis May 15 '15 at 18:46
  • @Nautious, No, the value is not lost as I explained before. Do you not see the assignment?? – Rufus L May 15 '15 at 18:46
  • @RufusL it must be hiding from him. However you are not crazy other people can see the assignment too. Maybe dropping the assignment to the next line (indented) would make it more visible. – Gerald Davis May 15 '15 at 18:47
  • It is not hiding from me. I understand your code fine. i'm just comparing your code to what ?? actually does, which is return left part if left part is not null, otherwise return right part. If the right part of ?? was `GetUser` NOT `_user = GetUser`, then _user would NOT be updated, but the line would still return the return value of `GetUser`. If we would take your code as an representation of ?? then it would be like so: `if(_user == null) GetUser(); return _user;` which would return null. Your code does the same as the code in question, but it is not the equivalent of ??. – Anders May 15 '15 at 18:59
  • @Nautious Yeah, no kidding, and I addressed how the operator works in a simple sentence (after "How it works"). But the operator itself was not the code he was asking about, was it? You started by saying, "This is not correct". Can you point to something I said that was not correct? – Rufus L May 15 '15 at 19:18
0

It's called the Null Coalescing operator. If the object on the left hand side of it is null, it'll perform the expression on the right hand side.

Here, the operator on the right hand side sets the _user object, so next time User is referenced, it will no longer perform the right-hand side, and return _user

Jonesopolis
  • 25,034
  • 12
  • 68
  • 112
0

The assingment expression = both does the assignment to _user and returns the value that was assigned, so it can be used like an expression.

Kratz
  • 4,280
  • 3
  • 32
  • 55
  • 1
    not my downvote, but it is the assignment expression that returns the value. But it is just terms and wordings. – Habib May 15 '15 at 18:17
0

So after Habibs tip I found this in MSDN. = Operator (C# Reference) where is clear...

"The assignment operator (=) stores the value of its right-hand operand in the storage location, property, or indexer denoted by its left-hand operand and returns the value as its result."

I still can't believe that I didn't know that.

shadow
  • 1,883
  • 1
  • 16
  • 24
-1

?? is syntax sugar for the following:

if(_user != null)
    return _user; // first part before ??
else
    return (_user = GetUser() ); //Second part after ??

Edit:

As @Rufus L pointed out:

The (_user = GetUser() ); part assigns the return value of GetUser to _user and then returns the value of _user. If we simplify the previous code:

if(_user != null)
    return _user;
else
{
    _user = GetUser();
    return _user;
}

Extra info: you can chain assignments, as long as the type is the same, or implicit casting are implemented:

int x, y, z;
x = y = z = 4;
Anders
  • 1,590
  • 1
  • 20
  • 37
-2

It basically checks if _user is not null first. If is not null returns it. Otherwise, it sets _user to whatever GetUser() returns.

Pseudocode

_user != null 
    return _user 
otherwise 
    _user = GetUser()

Here is a post that talks about the "Null Coalescing operator"

Community
  • 1
  • 1
Luis Lavieri
  • 4,064
  • 6
  • 39
  • 69
  • Your code would be the equivalent of return _user ?? GetUser() which also works but is less efficient because it doesn't also set _user so baring some other assignment _user remains null the next time the getter is called as well. – Gerald Davis May 15 '15 at 18:41
  • Actually this code only returns something if `_user` is not `null` (the `otherwise` block only does an assignement, but there is no `return` statement). – Rufus L May 15 '15 at 18:43