A quick glance at the new capabilities of C# 6
This is a code demo, not elaborate theories.
If you are like me who got little late in catching up with the latests and greatests of the C#
language, this will help you catch up quickly.
There are no theoretical or academic details here. If you are interested in them, there are tons of resources in MSDN and all over internet, just do your reserach. This article will directly introduce you to some of the most useful features of C# 6
in a code & code-only manner (with a bit of explanation in the comments).
C# 6
does not add new framework features, rather gives a bunch of cool new language constructs. All the enhancements we’ll see, will help developers write cleaner & more precise code.
These new stuffs are covered in code below
- Auto read-only property
- Auto property initializer
- Expression-bodied functions
- Using static
- Null-conditionals OR null-propagation operators
- String interpolation
- Exception filters
- nameof() Expressions
- Await in Catch & Finally blocks
- Index initializers
So, here you go
public class DemoType //A demo class that we'll be using in example
{
public string Name { get; set; }
public int Count { get; set; }
public static string AddSmiley(string message)
{
return message + " :)";
}
}
[1] Auto read-only property
- Makes a read-only property, that can be set ONLY in constructor or initializer
- Earlier, declaring only get accessor was not allowed,
private set;
was allowed though
public string ReadOnlyProperty { get; } //See [3] for an alternative syntax
//constructor can Set ReadOnlyProperty
public CSharp6()
{
ReadOnlyProperty = "Value";
}
[2] Auto property initializer
- Set initial value of properties in declaration with an assignment sign
public int AutoInitializedProperty { get; set; } = 10;
//Read-only properties can also be initialized
public IList<decimal> AutoInitializedListProperty { get; } = new List<decimal>();
//See Expression-bodied function & String Interpolation below
public Func<string, string> WelcomeMessageGeneratorProp { get; set; } = (name) => $"Welcome {name}.";
[3] Expression-bodied functions
- Shorten code for simple Methods or Read-Only Properties with lambda expressions
public int DoubleOf(int num) => 2 * num;
//Another representation of read-only property
public string AnotherReadonlyProp => "Hello there";
//[1] Alternative syntax
[4] Using static
- Import static methods of a class by declaring - using static Namespace.Class;
- After that use all the STATIC methods directly wothout mentioning class-name
using static CSharpLearning.DemoType; //this
//namespace & class declaration
void SomeMethod()
{
//class-name not used, like - SomeUtility.AddSmiley("Hello devs");
var cuteMessage = AddSmiley("Hello devs");
}
- Note 1: This way imported methods can only be used as static methods, not as extensions - even if they are
- Note 2: When a class is imported like this, nested classes are also imported
[5] Null-conditionals OR null-propagation operators
- When this (.?) is used, compiler will always check for null before invoking the next member. If null is encountered, null is returned as result
void NullDemoMethod()
{
DemoType demoObject = null;
//this will throw null reference exception as DemoProperty is null
var name = demoObject.Name;
//Now if left hand side of ?. is null, null will be set as final value
var name2 = demoObject?.Name;
//like this, null check is performed and propagated. Any null will result in null being returned.
//var result = SomeObject?.Details?.Address?.City;
//setting default value with null coalescing operator
var safeName = demoObject?.Name ?? "No name";
//here, since left side is not-nullable, it MUST be given a default value TO COMPILE
int count = demoObject?.Count ?? 0;
}
- Note: With null conditional operator, the expression is EVALUATED JUST ONCE AND CACHED. So it wil not face a situation where the check has reached
nth
level and then some other code sets(n-1)th
part tonull
. It will still work as it has been cached already. Really helpful for delegate invokation.
[6] String interpolation
- New syntax for string formatting. String expression is prefixed with
$
, then variables/expressions are placed within{braces}
- Functionally a better alternative (still available though) for
String.Format
void StringFormattingDemo()
{
var obj = new DemoType { Name = "AC", Count = 10 };
//old style formatting with positional parameters - still works
var messageOld = string.Format("Name is {0}, count is {1}", obj.Name, obj.Count);
//New cool syntax. Intellisense works fine within string expression
var messageNew = $"Name is {obj.Name}, count is {obj.Count}";
//takes any expression and string formatting too!
var itsCool = $"Name starts with {obj.Name.Take(1)}. Percentage: {(obj.Count / 100):F2}";
}
[7] Exception filters
- You can now filter
catch
blocks with conditions. Only when the condition (and Exception type) matches, the block will execute. Else, skip. - Condition is checked before entering block. If none of the catch blocks match (Exception type + condition), program skips all and throws.
void ExceptionFilterDemo()
{
//assume obj is set in some other code
var obj = new DemoType { Name = "AC", Count = 10 };
try
{
var message = $"The initial is - {obj.Name.First()}";
}
//this catch will NOT execute if obj.Name is null
catch (NullReferenceException ex) when (obj == null)
{
Log("Told you to populate the object first");
}
}
- NOTE: Interesting, if
obj.Name
isnull
, stack will show originalException
thrown in original point, as execution never reached the catch block.
Following dummy log methods are used in following code samples
void Log(string msg) { }
public async Task LogAsync(Exception ex) { await Task.Delay(2000); }
[8] nameof() Expressions
- Gets you the simple (unqualified) string name of a variable, type, or member.
- The basic idea is to use an expressions rather than a hard-coded string value, so that code survives through refactorin/rename
public void NameofDemo()
{
var obj = new DemoType { Name = "AC", Count = 10 };
//examples
var n1 = nameof(obj); //produces "obj"
var n2 = nameof(obj.Name); //produces "Name"
var n3 = nameof(DemoType); //produces "DemoType"
//Compile error: Expression does not have a name
//var n4 = nameof(obj.GetType());
//Compile error: Expression does not have a name
//var n5 = nameof(typeof(DemoType));
//sample use case
//Upgrade from hard coded "Name" in log message "Value of Name was null"
Log($"Value of {nameof(obj.Name)} was null");
}
- Note the huge benefit here - if name of
Name
property is changed, the log message will automatically be updated! Or throw error in compile time.
[9] Await in Catch & Finally blocks
- Now await can be used in
catch
&finally
blocks as well
public async void AwaitDemo()
{
try
{
await System.IO.File.ReadAllLinesAsync("path to file");
}
catch (Exception exception)
{
//Async catch //can be in finally too
await LogAsync(exception);
}
}
[10] Index initializers
C# 6
introduces initializing indexed collections and dictionaries like lists
public void IndexInitializerDemo()
{
Dictionary<int, string> students = new Dictionary<int, string>
{
[101] = "Sumit",
[102] = "Deepmala",
[110] = "Priyanka"
};
//This may look very similar to the OLD syntax as below
Dictionary<int, string> oldStudents = new Dictionary<int, string>
{
{5, "Neha" },
{8, "Vikas" }
};
//Understand the differences below
}
- Well, functionally the old and new syntax above are similar. There is a inherent difference though
- The old syntax uses the
Add
method on the Type whereas the new syntax actually uses theindexer
- Note: If you have a custom collections that does not have an
Add()
method, you can now create an extension method and use collection initializers.
One REMOVED feature - Primary constructor
- Idea was to define constructor parameters with class declaration. It was never released.
public class CoolNew (string name, int code)
{
public string AreaName { get; set; } = name;
public int AreaCode { get; } = code;
}
So that’s all we had for today. It’ll be good idea to copy-paste the whole code, call the methods and debug, to understand them better. You can run all the snippets above by wrapping them inside a code like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static CSharpLearning.DemoType; //see [4] using static
namespace CSharpLearning
{
public class CSharp6
{
//all code snippets here
}
}
Once done, continue to features demo of C# 7.
comments powered by DisqusNote: Source of knowledge for this article are MSDN, StackOverflow and other forums.