Chaining Assignment Operations (or, using a statement as the expression in another statement)

Background

I setup the following property in a WinForms Form, to get an EventAggregator instance from Unity. (This is tightly-coupled legacy code that doesn’t currently support dependency injection via ctor.)

private IEventAggregator eventAgg;  
private IEventAggregator EventAgg  
{
    get
    {
        if (eventAgg == null)
            eventAgg = UnityInstanceProvider.GetInstance<IEventAggregator>();
        return eventAgg;
    }
}

The idea was to get a new instance when first requested, then use the existing instance thereafter.

ReSharper suggested an edit

But then ReSharper suggested this edit:

Convert to ‘??’ expression

Accepting the suggestion, it modified my code accordingly:

private IEventAggregator eventAgg;  
private IEventAggregator EventAgg  
{
    get { return eventAgg ?? (eventAgg = UnityInstanceProvider.GetInstance<IEventAggregator>()); }
}

The code is odd looking. At first glance, it seems like the right-hand side of the ?? (null coalesce operator) should cause a syntax error. Are we assigning a value to a variable, or returning the result of UnityInstanceProvider.GetInstance()?

Both, actually.

How’s it work?

It’s an intentional side-effect that’s carried over from C. Value assignments can be used as expressions in other assignments, which can themselves be used as expressions in yet other assignments.

Let’s start by looking at the definitions of a few closely-related constructs in C#:

Expressions vs statements

  • Expressions: “An expression is a sequence of one or more operands and zero or more operators that can be evaluated to a single value, object, method, or namespace. Expressions can consist of a literal value, a method invocation, an operator and its operands, or a simple name.” (my emphasis)
  • Statements: “The actions that a program takes are expressed in statements. Common actions include declaring variables, assigning values, calling methods.” (my emphasis)
  • Assignment Operators: “The assignment operators assign a new value to a variable, a property, an event, or an indexer element. . . . The = operator is called the simple assignment operator. It assigns the value of the right operand to the variable, property, or indexer element given by the left operand.

An expression evaluates to a value, while a statement (among other things) assigns the value by using an assignment operator.

Another way to demonstrate the difference is through a code sample:

int counter = 0;

// An "expression" evaluates to a value, in this case the number 1
counter + 1;  // syntax error

// A type of "expression statement" called an "assignment statement"
// It assigns the result of an expression to a variable
int i = counter + 1;

//// The above can be split into two parts: ////

// Declaration Statement
int i;

// Assignment Statement, using the assignment operator (=)
i = counter + 1;  

Hopefully now you can see the separation between a simple expression, and a statement that does something with that expression.

Assignment expressions have return values

Now here’s one more thing to consider, from the C# specs:

The result of a simple assignment expression is the value assigned to the left operand. The result has the same type as the left operand and is always classified as a value.

Here, “simple assignment expression” is referring to using an assignment statement as an expression.

In the following code, the statement that assigns the value of “counter + 1” in i is also an expression that can be used to assign a value to j.

int counter = 0;  
int i,j;

// Expression
counter + 1;  // syntax error

// Assignment Statement
i = counter + 1;

// Expression
(i = counter + 1);  // syntax error

// Assignment Statement
j = (i = counter + 1);  

Bringing it Home

Now we have enough to know why this works the way it does.

  • The = sign is an operator, the “simple assignment operator”.
  • The = operator assigns the value of its right operand to the variable represented by its left operand.
  • An expression can be defined as “an operator and its operands”.
  • Therefore, assignment statements using the = operator can themselves be considered expressions.

The same line of code can be a statement, as well as an expression to a larger statement.

           UnityInstanceProvider.GetInstance<IEventAggregator>()   // expression

eventAgg = UnityInstanceProvider.GetInstance<IEventAggregator>();  // statement

        eventAgg = UnityInstanceProvider.GetInstance<IEventAggregator>()    // expression

return (eventAgg = UnityInstanceProvider.GetInstance<IEventAggregator>());  // statement  

Other examples

You’ve most likely used the side-effect of an assignment without even realizing it.

Assigning the result of sr.ReadLine() to a string, then using that assignment as an expression to test against the value null(to determine if there are any more lines to read from the stream):

using (var sr = new StreamReader(""))  
{
    string line;
    while ((line = sr.ReadLine()) != null)
    {
        // do something with 'line'
    }
}

Chaining multiple variables together when assigning a value:

int a, b, c;

a = (b = (c = 5));

a = b = c = 5;  

As with everything, there’s the potential for abuse and ugly code. :)

int a, b, c;  
a = (5 + (b = 3) + (c = 4));  

And it wouldn’t be too difficult (or unimaginable) for someone to think they’re saving a line of code, but in the process produce a side-effect that’s difficult to detect:

private int x;  
private int CalculateAge()  
{
    int age;
    ...
    age = 10 + 2 - 3 * 5;
    ...
    return x = age;  // much later, someone investigates why x changes whenever CalculateAge() runs
}

Subscribe to Weekly Updates!

Get an email with the latest posts, once per week...
* indicates required