Looking back at Some of the Changes in C# 6

We’re currently on C# 7.4 and approaching C# 8 (Wow!); but C# 6 was the first version of C# post Roslyn (Compiler rewrite, to oversimplify it a bit). C# 6 was the first version of C# to coincide with .NET Core, and so it’s where the development of C# seemed to… skyrocket. I’m revisiting changes to C# starting particularly with C# 6. C# 6 has been around since 2015; and arguably represents the first time core features of the language have changed since 3.0.

C# 6.0 unveiled several language features that are useful for removing verbosity from common class operations, and set the groundwork for future improvements that we’re only really scratching the surface of.

Readonly Auto-Properties

Prior to C#6, if you wanted to make a “read only” property, the best you could do was:

public class M1 
{
public string P1 {get; private set;}
public M1()
{
P1 = "hi there";
}
}

There were a few problems with this approach.

First, if M1 implmented an interface, you couldn’t use a private accessor. Second, the string P1could still be mutated inside the class; probably not what you wanted semantically.

If you forsook auto-properties entirely you’d be fine, but that’s going in the wrong direction:

public class M1 {
private readonly string p1;
public string P1
{
get { return p1; }
}
public M1(string text)
{
p1 = text;
}
}

With a readonly auto-property, you can now have reduce the above sets of code to this:

public class M1
{
public string P1 { get; }
public M1()
{
P1 = "hi there"; //can only be changed in constructor!
}
}

This improved syntax allows you to semantically and concisely declare your intent for a property: That it should be set at construction and not changed. It is immutable. This is extremely useful in the following situations:

  • For read only DTOs (Data Transfer Objects), getting data from the database for display where it wouldn’t make semantic sense for an implementor to try to change the value; or for ViewModels.
  • For a public value that will be set at construction and should be able to be referenced by other classes throughout the application in an easy manner.
  • For immutable objects. Immutable objects are easier to reason about and interact with.

Property Initialization

This feature in itself is pretty cool; but what if you don’t want to create a default constructor just to deal with creating an immutable property? You can now combine property initialization (a la field initalization) with readonly auto-properties:

public string P1 { get; } = "hi there";

This reduces the use of a default constructor just to set this property; and it ensures that no matter which constructor is used, this property gets set.

Expression-Bodied Members

These changes to C# are neat; but if you wanted to have more complex logic inside your getter; you were stuck using the ‘old’ style properties:

public class M1
 {
   public string P1
   {
     get 
     {  
         DateTime.Now.Month == 11 ? return "Month Left" : return "Months Left";
     } 
   }
 }

With C# 6, you can change this to a single line of code:

public class M1
 {
   public string P1 {get; } => DateTime.Now.Month == 11 ? "Month Left" : "Months Left";
 }

The biggest change here is the use of the Expression Body syntax (which would later be expanded in C# 7); and that there’s no “return” in this expression. This mimics the closure syntax used by LINQ.

Expression-Bodies can also be used in methods in C# 6:

public class M1
 {
    public string GetMonthPluralText() => DateTime.Now.Month == 11 ? "Month Left" : "Months Left";
 }

Null-Conditional Operator

The next ‘big’ feature in C# 6 was the change to how null checks were handled. Prior to C# 6, if you wanted to check for null, you had to do something like the following:

public class M2
{
public int? P1 {get; set;}
}
public class M1
{
public M2 M2P1 {get; set;}
}
public int GetValue(M1 m1)
{
if (M1 != null && M1.M2P1 != null && M1.M2P1.P1 != null)
{
return M1.M2P1.P1.Value;
}
return 0;
}

Ok, ok, so this seems like a convoluted example. I’ll give you that. But in order to successfully determine if class member property P1 of class M2 has a value, you have to check its parentage *first*. If anything in the chain of calls is null, you’ll get a NullReferenceException. That would be bad.

C# 6 fixed this by allowing the use of a new operator, the null-conditional operator. So that the above code becomes:

public int GetValue(M1 m1)
{
if (M1?.M2P1?.P1 != null)
{
return M1.M2P1.P1.Value;
}
return 0;
}

This is far more concise, though I’d argue that it’s not really clearer to a casual observer what’s going on.

If you read code long enough, you don’t really “read” the code any more, you skim it. With less concise code; it’s easier to ‘see’ mistakes when skimming, for instance if you leave out a null conditional check. With the ?. syntax, there’s no easy way to see that you’ve forgotten to make a null check: M1.M2P1?.P1 != null but overall it’s been a solid addition to C#.

When C# 6 came out I was quite against the Null conditional operator and the expression-body syntax; but after a few years of using them, I am happy to have them in the language.

2 thoughts on “Looking back at Some of the Changes in C# 6”

  1. DateTime.Now() is a property not a method – DateTime.Now

    Also for “Expression-Bodied Members” the correct way to define the property is :
    public string P1 => DateTime.Now.Month == 11 ? “Month Left” : “Months Left”;

Leave a Reply to Petar PetrovCancel reply

Discover more from George Stocker

Subscribe now to keep reading and get access to the full archive.

Continue reading