These are notes jotted down while watching an overview of new C# 6 features by Mads Torgersen.

Provides a quick and succinct overview of new syntax.

Additional Reading Material

New Features

Getter-Only Auto-properties

1
2
3
4
5
6
7
public class Point
{
  public int X { get; set; }
  public int Y { get; set; }

  public Point(int x, int y) { X = x; Y = y; }
}

Auto-properties no longer need to have setters.

1
2
3
4
5
6
7
public class Point
{
  public int X { get; }
  public int Y { get; }

  public Point(int x, int y) { X = x; Y = y; }
}

This will create a read-only backing field but no setter. This backing field can be set from the constructor.

The previous setter requirement put immutables at a disadvantage, which we don’t want to do.

Initializers for Auto-properties

1
2
3
4
5
6
7
public class Point
{
  public int X { get; } = 3;
  public int Y { get; } = 4;

  public Point(int x, int y) { X = x; Y = y; }
}

Work the same way as with fields.

Using Static Classes

You can now use using statements for static classes which will let you use the functions on that static class without explicitly naming it. E.g., Math.Sqrt(n) becomes Sqrt(n);. In other words, it puts the static class directly onto scope.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System.Math;

public class Point
{
  public int X { get; };
  public int Y { get; };

  public Point(int x, int y) { X = x; Y = y; }

  public double Dist()
  {
    get { return Sqrt(X * X + Y * Y); }
  }
}

String Interpolation

You can now use values in-place instead of with String.Format and indexed params with placeholder syntax.

So this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System.Math;

public class Point
{
  public int X { get; };
  public int Y { get; };

  public Point(int x, int y) { X = x; Y = y; }

  public override string ToString()
  {
    return string.Format("({0},{1})", X, Y);
  }
}

Becomes this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System.Math;

public class Point
{
  public int X { get; };
  public int Y { get; };

  public Point(int x, int y) { X = x; Y = y; }

  public override string ToString()
  {
    return "(\{X},\{Y})";
  }
}

Usage: Escape curly braces and put property or field between them.

Expression-bodied Methods

You can now define methods with a single expression using lambda arrow.

1
2
3
4
5
6
7
8
9
10
11
using System.Math;

public class Point
{
  public int X { get; };
  public int Y { get; };

  public Point(int x, int y) { X = x; Y = y; }

  public override string ToString() => "(\{X},\{Y})";
}

Expression-bodied Properties

This works for property getters as well, so this:

1
2
3
4
5
6
7
8
9
10
11
using System.Math;

public class Point
{
  //...

  public double Dist()
  {
    get { return Sqrt(X * X + Y * Y); }
  }
}

Becomes this:

1
2
3
4
5
6
7
8
using System.Math;

public class Point
{
  //...

  public double Dist() => Sqrt(X * X + Y * Y);
}

Index Initializers

We’ve already had object initializers but before 6.0 indexers had to be initialized in separate statements.

This method to turn our Point into a JSON object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System.Math;

public class Point
{
  public int X { get; };
  public int Y { get; };

  //...

  public JObject ToJson()
  {
    var result = new JObject();
    result["x"] = X;
    result["y"] = Y;
    return result;
  }
}

Becomes this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using System.Math;

public class Point
{
  public int X { get; };
  public int Y { get; };

  //...

  public JObject ToJson()
  {
    return new JObject() { ["x"] = X, ["y"] = Y };
  }
}

Or better yet:

1
2
3
4
5
6
7
8
9
10
11
using System.Math;

public class Point
{
  public int X { get; };
  public int Y { get; };

  //...

  public JObject ToJson() => new JObject() { ["x"] = X, ["y"] = Y };
}

Null-conditional Operators

How about going from JSON back to Point objects?

Behold:

1
2
3
4
5
6
7
8
9
10
11
12
public static Point FromJson(JObject json)
{
  if (json != null &&
    json["x"] != null &&
    json["x"].Type == JTokenType.Integer &&
    json["y"] != null &&
    json["y"].Type == JTokenType.Integer)
  {
    return new Point((int)json["x"], (int)json["y"]);
  }
  return null;
}

The biggest annoyance is all the null checking. This is simplified with the new question-dot operator, ?., or Elvis operator, which is demonstrated here:

1
2
3
4
5
6
7
8
9
10
public static Point FromJson(JObject json)
{
  if (json != null &&
    json["x"]?.Type == JTokenType.Integer &&
    json["y"]?.Type == JTokenType.Integer)
  {
    return new Point((int)json["x"], (int)json["y"]);
  }
  return null;
}

It essentially adds an implicit json["x"] !== null && before the current expression.

What about that initial null check? Indexing can be made null conditional by inserting a question mark in front of the square brackets.

1
2
3
4
5
6
7
8
9
public static Point FromJson(JObject json)
{
  if (json?["x"]?.Type == JTokenType.Integer &&
    json?["y"]?.Type == JTokenType.Integer)
  {
    return new Point((int)json["x"], (int)json["y"]);
  }
  return null;
}

One of the best use cases for this operator is triggering events.

1
2
3
4
5
6
7
8
9
10
11
{
  // first copy the delegate reference for thread safety
  var onChanged = OnChanged;
  // then check if it's null
  if (onChanged != null)
  {
    onChanged(this, args);
  }

  // blech!
}

With the new syntax it becomes this (yep, it’s thread safe):

1
2
3
{
  OnChanged?.Invoke(this, args);
}

The nameof Operator

Hard-coded name string:

1
2
3
4
5
6
7
public Point Add(Point point)
{
  if (point == null)
  {
    throw new ArgumentNullException("point");
  }
}

Can now do this:

1
2
3
4
5
6
7
public Point Add(Point point)
{
  if (point == null)
  {
    throw new ArgumentNullException(nameof(point));
  }
}

Exception Filters

When you catch and rethrow an exception you lose information about where it originally occurred. In F# and VB you can filter exceptions and thereby catch them conditionally, avoiding this problem. This is now supported in C#:

1
2
3
4
5
6
7
8
try
{
  //...
}
catch (ConfigurationException e) if (e.IsSevere)
{
  //...
}

Using await in catch and finally

You can now have await in catch and finally blocks.

1
2
3
4
5
6
7
8
9
10
11
12
try
{
  //...
}
catch (ConfigurationException e) if (e.IsSevere)
{
  await LogAsync(e);
}
finally
{
  await CloseAsync();
}