Learn C# 6 - By Example

October 2015

Follow along at:

http://itsnull.com/

http://itsnull.com/presentations/csharp6/

Created by Kip Streithorst / @itsnull

C# 6 High-Level

  • Visual Studio 2015.
  • 99% syntax change, can be targeted all the way back to .NET Framework 4.
  • More concise code, easier to maintain code.
  • Nice improvements for small objects, e.g. Data Transfer Objects (DTOs)
  • Improved syntax for immutable types.

C# Features

Click on links for MSDN documentation

using static directive

  • using directive imports a namespace.
  • New using static directive imports static members of specified type.
  • using static can also import enum values.
  • Why? The same benefit of using to shorten namespaces, but now for static members of types and enums.

using static directive (Example)

//C# 6
using static System.Console;
using static System.ConsoleColor; //enumeration
using static System.Math;
void Calculate(double value) {
  ForegroundColor = Blue;
  WriteLine("Result is " + Sqrt(value));
}
//C# 5
using System;
void Calculate(double value) {
  Console.ForegroundColor = ConsoleColor.Blue;
  Console.WriteLine("Result is " + Math.Sqrt(value));
}

Exception Filters

Add when (expression) to end of a catch clause. Exception is caught only if expression is true.

//C# 6
try {
  //...
} catch (ArgumentException e) when (e.ParamName == "creditCard") {
  abortSale();
}
//C# 5
try {
  //...
} catch (ArgumentException e)
  if (e.ParamName == "creditCard") 
    abortSale();
  else
    throw; //re-throw changes stack-trace
}

Exception Filters - Why?

  • In C# 5, for equivalent behavior, you have to re-throw which alters the stack trace.
  • If the catch expression is false, the stack trace is unaffected.

Exception Filters - Why? (Cont.)

  • The catch expression can have side-effects. Expression can work with exception without affecting the stack trace.
//C# 6
try {
  //...
} catch (Exception e) when (LogException(e)) {}
//C# 5
try {
  //...
} catch (Exception e) {
  LogException(e);
  throw;
}

Async/Await in catch/finally

  • C# 5 added async/await keywords but they were forbidden in catch or finally blocks.
  • C# 6 fixes that oversight.
  • Why? If your happy path is async why shouldn't your error path be async?
//C# 6
async Task ProcessData() {
  try {
    await UpdateRecord();
  } catch (Exception e) {
    await LogException(e); //compile error in C# 5, now works
  } finally {
    await NotifySubscribers(); //compile error in C# 5, now works
  }
}

Index Initializers

new TestObj { [index] = value, [index2] = value2 }

//C# 6
var numbers = new Dictionary<int, string> { 
    [7] = "seven", 
    [13] = "thirteen" 
};
numbers[8] = "eight";
//C# 5
var numbers = new Dictionary<int, string> { 
    {7, "seven"}
    {13, "thirteen"}
};
numbers[8] = "eight";

Index Initializers - Why?

  • To initialize in C# 5 e.g. {index, value} syntax, class must have an Add method and implement IEnumerable.
  • To initialize using in C# 6 e.g. [index] = value syntax, class only needs an indexer method, nothing else.

Null Conditional Access, ?.

  • Replace . with ?. and null is returned, instead of throwing NullPointerException.
  • Replace [] with ?[] and null is returned, instead of throwing NullPointerException.
//C# 6
void TestMethod(Customer person) {
  string name = person.FirstName; //might throw NullPointerException
  string name2 = person?.FirstName;
  int? age = person?.Age; //Age is int
  bool? inUs = person?.Address?.IsInUS(); //IsInUs() method returns bool
  string recentOrder = person?.Orders?[0]?.OrderId;
  //throws IndexOutOfRangeException if Orders is non-null but empty
}

Null Conditional Access, ?. - Why

  • Can be used to invoke delegates, e.g. PropertyChanged
  • ?. and ?[] are compiled to use temporary variables making them thread-safe as well.
  • Fewer exceptions, with less code, who doesn't like that?
  • //C# 6
    var zip = person?.Address?.ZipCode ?? "Unknown Zip";
    
    //C# 5
    var zip = "Unknown Zip";
    var tempPerson = person;
    if (tempPerson != null)
      var tempAddress = tempPerson.Address;
      if (tempAddress != null)
        zip = tempAddress.ZipCode ?? "Unknown Zip";
    
  • DEMO

nameof operator

Returns a string, which is the unqualified name of a variable, type or member.

//C# 6
void TestMethod(Customer person) {
  nameof(person); // variable - returns "person" - variable
  nameof(person.Address.ZipCode); // member - returns "ZipCode"
  nameof(System.DateTime); // type - returns "DateTime"
  nameof(System.Collections.Generic.List<int>); // type - returns "List"
}

nameof operator - Why?

  • Useful with ArgumentNullException.
  • Useful with XAML, WPF implementations of INotifyPropertyChanged interface.
  • In C# 5, you would have to manually type the string, which means it can become out-of-date.
  • With nameof operator, a compile error occurs if the variable, type or member is renamed.
  • Efficient, done by compiler, no reflection occurs.
  • DEMO

String Interpolation, $""

In-line template strings, use $"" instead of "" where {expression} is replaced with the ToString representation.

//C# 6
void Format(string name, DateTime startDate, double salary) {
  string tag = $"{name}, hired {startDate:D}";
  string wage = $"Paid: {salary:c}";
  string desc = $"Is {(startDate.Year < 2010 ? "pre" : "post")} reorg";
}
//C# 5
void Format(string name, DateTime startDate, double salary) {
  string tag = String.Format("{0}, hired {1:D}", name, startDate);
  string wage = String.Format("Paid: {0:c}", salary);
  string desc = String.Format("Is {0} reorg",
    (startDate.Year < 2010 ? "pre" : "post"));
}

String Interpolation, $""

Globalization

  • Can assign to System.FormattableString if you want to render for specific country culture (e.g. globalization).
  • System.FormattableString requires .NET 4.6 runtime.
//C# 6
static string Format(DateTime day) {
  System.FormattableString temp = $"Modified {day:d}";
  return temp.ToString(CultureInfo.GetCultureInfo("de-DE"));
}
Format(new DateTime(2012, 3, 15)); //returns "15.03.2012"

String Interpolation, $"" - Why?

  • More concise that String.Format, but exactly equivalent. Supports format specifiers and alignment syntax.
  • No need to worry about mis-matching {0} and arguments to String.Format.
  • Still have intellisense for expressions and compile-time errors if variables are renamed.
  • DEMO

Expression Bodied Methods

  • Lambda syntax => to declare methods, read-only properties, and read-only indexers.
  • Why? Simple methods are expressed simply.

Expression Bodied Methods

Example: Read-only computed property.

//C# 6
string FullName => First + " " + Last;
//C# 5
string FullName
{
  get
  {
    return First + " " + Last;
  }
}

Expression Bodied Methods

Example: Method that immediately returns a value.

//C# 6
double ConvertCtoF(double temp) => (temp * 9/5) + 32;
//C# 5
double ConvertCtoF(double temp)
{
  return (temp * 9/5) + 32;
}

Expression Bodied Methods

Example: Single line void method.

//C# 6
void Log() => Console.WriteLine(First + " " + Last);
//C# 5
void Log()
{
  Console.WriteLine(First + " " + Last);
}

Expression Bodied Methods

Example: Read-only indexer.

//C# 6
Customer this[long id] => store.LookupCustomer(id);
//C# 5
Customer this[long id]
{
  get
  {
    return store.LookupCustomer(id);
  }
}

Auto Property Enhancements

Read-only property

  • Auto properties can now be read-only.
  • Read-only property can only be set in constructor.
  • Auto property with private set; can be updated in any class method.
  • Why? Useful for creating immutable types.
//C# 6
public string FullName { get; }; //read-only
public string FirstName { get; set; }; //read-write
//C# 5
public string FullName { get; private set; }; //read-only
public string FirstName { get; set; }; //read-write

Auto Property Enhancements

Initialization

  • Can initialize auto properties like fields now.
  • Initializer runs when instance created before constructor is run.
  • Why? Same benefits of field initializers. For simple classes, can avoid writing constructor.
//C# 6
public List<Address> Addresses { get; set; } = new List<Address>();
//works for read-only properties as well
public DateTime Created { get; } = DateTime.UtcNow;

My top 5 new features with one last DEMO

  1. Null conditionals, ?. and ?[]
  2. String interpolation
  3. Expression bodied methods
  4. nameof operator
  5. Exception filters
C# 7 - Wait, What??
  1. Being developed by C# Team in the open
  2. Design meeting notes in GitHub https://github.com/dotnet/roslyn/issues?q=label%3A%22Design+Notes%22+
  3. Channel 9 Video https://channel9.msdn.com/Blogs/Seth-Juarez/Looking-Ahead-to-C-7-with-Mads-Torgersen

Thanks, Any Questions?