C# 6 behind the scenes (part #2)

After examining how the compiler converts C# 6 language expressions to IL code in the first part of this article, let’s check a few additional examples in order to find out how C# 6 code behaves when parsed using reflection.

The nameof expression:

The nameof expression returns the name of some program element as string, which is useful e.g. for raising PropertyChanged events, throwing an ArgumentNullException etc. since it helps eliminating string literals.

If we add the following method to our sample program:

private string TestNameOf()
{
	return nameof(Program);
}

and compile and decompile it, ILSpy will show the following:

private string TestNameOf()
{
	return "Program";
}

which means that the type Program is replaced by the string "Program" during compilation. This won’t surprise you after the observations we made as part of the samples presented in the first part of this article.

In addition, let’s check what happens with the nameof expression during live code analysis using reflection: I added a new method called Start to our sample project which is invoked from within the program’s constructor. In this method, we define a lambda expression that makes use of the nameof operator, and analyse its content (in this sample, I anticipated that the lambda expression’s body will be a ConstantExpression – alternatively, you could of course parse the expression tree and will find out that this assumption is true):

private void Start()
{
	Expression<Func<string>> expression = () => nameof(Program);
	var constantExpression = expression.Body as ConstantExpression;
}

Now, set a breakpoint after the second line of code, start the program, and examine constantExpression! You’ll find out that the nameof expression evaluates to a constant expression that simply returns the string "Program" as its value:

C# 6 Nameof expression example

String interpolation:

String interpolation is mature version of String.Format, as it eliminates the {0} etc. placeholders and instead allows to put the string expressions right into place:

private string TestStringInterpolation()
{
	string word = "interpolation";
	return $"The word {word} contains {word.Length} characters, which is more than {word.Length - 1}";
}

As you can see in the example above, it’s even possible to do calculations and other operations directly within the expressions to be replaces. During compilation, this code is converted to a traditional String.Format method call, as ILSpy shows:

private string TestStringInterpolation()
{
	string text = "interpolation";
	return string.Format("The word {0} contains {1} characters, which is more than {2}", text, text.Length, text.Length-1);
}

Now, let’s try string interpolation within a lambda expression:

private void Start()
{
	string word = "interpolation";
	Expression<Func<string>> expression = 
		() => $"The word {word} contains {word.Length} characters, which is more than {word.Length - 1}";
	var methodCallExpression = expression.Body as MethodCallExpression;
}

Again, I assumed that the expression’s body would be evaluated as a MethodCallExpression – and indeeed, when running the program and watching the methodCallExpression variable, it shows that the expression’s content is implemented as a call to the String.Format method with three placeholders:

C# 6 String interpolation example

The null-conditional operator:

The null conditional operator helps shorten null-checks, as it allows you to access object members only when the object is not null, and returns a null result otherwise. For example, the following method will return 43 which is the length of the given string:

private int TestNullConditional()
{
	string text = "The quick brown fox jumps over the lazy dog";
	return text?.Length ?? 0;
}

However, if we replace the given text with null and run the example again, the first part of the expression (text?) will instantly evaluate as null, and the null coalescing operator ?? will be reached, resulting in a return value of 0.

As we would expect by now, even this expression is converted to conventional syntax by the compiler:

private int TestNullConditional()
{
	string text = "The quick brown fox jumps over the lazy dog";
	return (text != null) ? text.Length : 0;
}

However, testing the same expression as part of a lambda expression ends with a surprising observation: The following code brings up a compile-time error:

private void Start()
{
	string text = null; //"The quick brown fox jumps over the lazy dog";
	Expression<Func<int>> expression = () => text?.Length ?? 0;
}

C# 6 Null-conditional operator example

The reason for this as well as several potential solutions are discussed in detail on codeplex. The short version is: A conversion to a ConditonalExpression is not accurate in all cases, therefore a new type of expression (e.g. NullPropagationExpression) needs to be defined – however, since this would require changes in the .NET framework (not only in the C# compiler), current versions of .NET simply disallow the use of the ? operator in lambda expressions.

In summary, the good news is that all of the sample expressions discussed so far were replaced by conventional language expressions by the compiler. Therefore, anyone parsing code written in C# 6 will not be surprised by unexpected language structures. This, however, goes hand in hand with a small restriction when developing libraries and using lambda expression trees to be defined by other developers, as these developers will not be able to use the null-conditional operator due to the reasons discussed above.