C# 6 equivalents in C# 5 by @byteblastdev. Inspired by @addyosmani's document . Contributions are welcome.
- Auto-property initializers
- Getter-only properties
- Parameterless struct constructors
- Using Static
- Expression-bodied members
- Index Initializers
- Await in catch/finally
- Exception filters
- Null-conditional operator
- String interpolation
- nameof operator
Auto-property initializers can be used to succinctly associate a default value with a property. They are syntactically similar to field initializers.
C# 6:
public class User
{
public Guid Id { get; set; } = Guid.NewGuid();
public List<string> Answers { get; set; } = new List<string>();
}
C# 5:
public class User
{
public Guid Id { get; set; }
public List<string> Answers { get; set; }
public User()
{
Id = Guid.NewGuid();
Answers = new List<string>();
}
}
Getter-only properties - as the name would suggest - allow you to define a read-only property much more succinctly than ever before.
C# 6:
public class User
{
public Guid Id { get; };
}
C# 5:
public class User
{
private readonly Guid _id;
public Guid Id
{
get { return _id; }
}
}
It used to be erroneous to define a parameter-less constructor for a struct
type. This is now allowed.
C# 6:
public struct Rational
{
private long numerator;
private long denominator;
public Rational()
{
numerator = 0;
denominator = 1;
}
}
C# 5:
public struct Rational
{
private long numerator;
private long denominator;
private Rational(long numerator, long denominator)
{
this.numerator = numerator;
this.denominator = denominator;
}
public static Rational Create()
{
return new Rational(0, 1);
}
}
The using static feature allows you to refer to a static class at the top of your code file and then subsequently access all of that classes static members without full qualification.
C# 6:
using System;
using static System.Console;
public class Program
{
private static void Main()
{
Title = "Demo";
Write("Please enter your name: ");
var name = ReadLine();
ForegroundColor = ConsoleColor.Red;
Write("Hello ");
ForegroundColor = ConsoleColor.White;
Write(name);
ReadKey();
}
}
C# 5:
using System;
public class Program
{
private static void Main()
{
Console.Title = "Demo";
Console.Write("Please enter your name: ");
var name = Console.ReadLine();
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("Hello ");
Console.ForegroundColor = ConsoleColor.White;
Console.Write(name);
Console.ReadKey();
}
}
Expression-bodied members allow you to omit syntax (such as braces and semicolons) and keywords (such as return
) that the compiler can easily infer when the whole of the body is only a single expression.
C# 6:
public class Answer
{
private List<string> _voters = new List<string>();
public bool CanVote(string username) => !_voters.Contains(username);
}
C# 5:
public class Answer
{
private List<string> _voters = new List<string>();
public bool CanVote(string username)
{
return !_voters.Contains(username);
}
}
Index initializers offer a more elegant way to give an initial set of elements to dictionaries and other similarly indexed objects.
C# 6:
var postData = new Dictionary<string, string>
{
["username"] = "admin",
["password"] = "password",
["authToken"] = "123"
}
C# 5:
var postData = new Dictionary<string, string>();
postData["username"] = "admin";
postData["password"] = "password";
postData["authToken"] = "123";
It should be noted that index initializers are not necessarily an alternative to the collection initializers syntax (introduced with C# 3.0).
It used to be erroneous to use the await
keyword in a catch
or finally
block. This is now allowed.
C# 6:
var logger = new ExceptionLogger();
try
{
}
catch (Exception exception)
{
await logger.LogAsync(exception);
throw;
}
C# 5:
var logger = new ExceptionLogger();
ExceptionDispatchInfo capturedException = null;
try
{
}
catch (Exception exception)
{
capturedException = ExceptionDispatchInfo.Capture(exception);
}
if (capturedException != null)
{
await logger.LogAsync(capturedException.SourceException);
capturedException.Throw();
}
Exception filters allow you to conditionally catch
exceptions according to a filter. If the filter expression returns false
then the exception will not be handled by that particular catch
block.
C# 6:
try
{
throw new AggregateException();
}
catch (AggregateException ex) if (ex.Data.Count > 1)
{
// Handle the AggregateException
}
catch (Exception exception)
{
// Because the filter expression returns false the first catch is skipped.
// Handle the general Exception instead.
}
C# 5:
try
{
try
{
throw new AggregateException();
}
catch (AggregateException ex)
{
if (ex.Data.Count > 1)
{
// Handle the AggregateException
}
else
{
throw;
}
}
}
catch (Exception ex)
{
// Handle the general Exception
}
The null-conditional operator removes the need for tedious null-checking.
C# 6:
var user = User.Find("byteblast");
if (user?.Answers != null)
{
Console.WriteLine("Answer count: " + user.Answers.Count);
}
C# 5:
var user = User.Find("byteblast");
if (user != null && user.Answers != null)
{
Console.WriteLine("Answer count: " + user.Answers.Count);
}
String interpolation allows you to interpolate (insert) values in the string in a natural and highly readable way.
C# 6:
var expected = 201;
var actual = 404;
throw new Exception($"Expected status code to be {expected}, but instead was {actual}.");
C# 5:
var expected = 201;
var actual = 404;
throw new Exception(string.Format("Expected status code to be {0}, but instead was {1}.", expected, actual));
##nameof operator
The nameof
operator takes an identifier (such as a variable name or method name) and returns that object's name as a string.
In a nutshell, it removes the need to define hard-coded string literals containing variable names, whose values may not be updated after a botched or automated refactoring.
C# 6:
public static User Find(string username)
{
if (username == null)
{
throw new ArgumentNullException(nameof(username));
}
// Contrived.
return null;
}
C# 5:
public static User Find(string username)
{
if (username == null)
{
throw new ArgumentNullException("username");
}
// Contrived.
return null;
}
It should be noted that the syntax rules for the nameof
operator are expected to change prior to the final release.
Inspired by:
Additional learning resources:
- Language features in C# 6
- C# feature descriptions
- What's new in C# 6.0? by Scott Allen
- C# 6 in action
This work is licensed under a Creative Commons Attribution 4.0 International License.