10 features in C# that you really should learn (and use!)

C#Asynchronous Programming

Please contribute by voting. Thanks!

1) async / await

Use the async / await-pattern to allow unblocking of the UI / current thread when execution blocking operations. The async / await-pattern works by letting the code continue executing even if something is blocking the execution (like a web request).

Read more about the async / await-pattern here: https://msdn.microsoft.com/en-us/library/hh191443.aspx

2) Object / array / collection initializers

Create instances of classes, arrays and collections easily by using the object, array and collection initializers:
//Just some demo class
public class Employee {
    public string Name {get; set;}
    public DateTime StartDate {get; set;}

//Create an employlee by using the initializer
Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()};

The above example can be really useful in unit testing but should be avoided in other contexts as instances of classes should be created using a constructor.

Read more about initializers here: https://msdn.microsoft.com/en-us/library/bb384062.aspx

3) Lambdas, predicates, delegates and closures

These features are practically a necessity in many cases (e.g. when using Linq), make sure to actually learn when and how to use them.

Read more about Lambdas, predicates, delegates and closure here: http://www.codeaddiction.net/articles/13/lambda-expressions-delegates-predicates-and-closures-in-c

4) ?? (Null coalescing operator)

The ??-operator returns the left side as long as it's not null, in that case the right side will be returned:
//May be null
var someValue = service.GetValue();
var defaultValue = 23

//result will be 23 if someValue is null
var result = someValue ?? defaultValue;
The ??-operator can be chained:
string anybody = parm1 ?? localDefault ?? globalDefault;
And it can be used to convert nullable types to non nullable:
var totalPurchased = PurchaseQuantities.Sum(kvp => kvp.Value ?? 0);

Read more about the ??-operator here: https://msdn.microsoft.com/en-us/library/ms173224.aspx

5) $"{x}" (String Interpolation) - C# 6

A new feature of C# 6 that lets you assemble strings in an efficient and elegant way:
//Old way
var someString = String.Format("Some data: {0}, some more data: {1}", someVariable, someOtherVariable);

var someString = $"Some data: {someVariable}, some more data: {someOtherVariable}";

You can put C# expressions in between the braces, which makes this very powerful.

6) ?. (Null-conditional operator) - C# 6

The null-conditional operator works like this:
//Null if customer or customer.profile or customer.profile.age is null
var currentAge = customer?.profile?.age;
No more NullReferenceExceptions!

Read more about the ?.-operator here: https://msdn.microsoft.com/en-us/library/dn986595.aspx

7) nameof Expression - C# 6

So the new nameof-expression might not seem important, but it really has it value. When using automatic re-factoring tools (like ReSharper) you sometime need to refer to a method argument by it's name:
public void PrintUserName(User currentUser)
    //The refactoring tool might miss the textual reference to current user below if we're renaming it
    if(currentUser == null)
        _logger.Error("Argument currentUser is not provided");

This is how you should use it...
public void PrintUserName(User currentUser)
    //The refactoring tool will not miss this...
    if(currentUser == null)
        _logger.Error($"Argument {nameof(currentUser)} is not provided");

Read more about the nameof-expression here: https://msdn.microsoft.com/en-us/library/dn986596.aspx

8) Property Initializers - C# 6

Property initializers lets you declare an initial value for a property:
public class User
    public Guid Id { get; } = Guid.NewGuid(); 
    // ...

A benefit of using property initializers is that you can not declare a set:er, thus making the property immutable. Property initializers works great together with C# 6 primary constructor syntax.

9) as and is-operators

The is-operator is used to control if an instance is of a specific type, e.g. if you want to see if a cast is possible:
if (Person is Adult)
    //do stuff
Use the as-operator to try to cast an instance to a class. It will return null if cast was not possible:
SomeType y = x as SomeType;
if (y != null)
    //do stuff

10) yield-keyword

The yield-keyword lets you feed an an IEnumerable-interface with items. The following example will return each powers of 2 up to the exponent of 8 (e.g. 2, 4, 8, 16, 32, 64, 128 ,256):
public static IEnumerable<int> Power(int number, int exponent)
    int result = 1;
    for (int i = 0; i < exponent; i++)
    result = result * number;
    yield return result;
yield return can be very powerful if it's used in the correct way. It enables you to lazily generate a sequence of objects, ie. the system does not have to enumerate the whole collection - it can be done on demand.

Article created: Sep 18 '15. Edited Oct 26 '15.



Daniel Cormier [4]  •  Oct 27 '15  •   •  Reply

In your null-coalescing operator examples, this line needs a tweak:

var totalPurchased = PurchaseQuantities.Sum(kvp => kvp.Value ?? 0);

Assuming that kvp is a nullable numeric type (say, Nullable<int>), that line wouldn't compile (CS0019 Operator '??' cannot be applied to operands of type 'int' and 'int').

This would work, though:

var totalPurchased = PurchaseQuantities.Sum(kvp => kvp ?? 0);
George Papadopoulos [1]  •  Nov 23 '15  •   •  Reply

I think 6) has an error in the comment. For the comment to apply it the line of code should've read: var currentAge = customer?.profile?.age?; and not var currentAge = customer?.profile?.age;

As for 2), I like the new syntax, my only problem with this is that the debugger does not seem to be aware of it, ie you cannot step through each of the init statements whereas with the old-style assignment statements you can of course.

Robert Bengtsson [126]  •  Mar 29 '16  • 

Regarding nr 2. C# is actually doing the initialization atomically when using the object initializer, i.e. it's not possible to step through it line by line. This has it's benefits such as thread safe initialization (it prevents another thread to access a semi initialized object).

Daniel Solin [1]  •  Oct 26 '15  •   •  Reply

Great article. Thanks. Can't get my head around No. 10 though. Did you mean it will return each powers of 2 up to the exponent of 8 IF the method is called like so: Power(2, 8) ?

Matthew Cooper [0]  •  Oct 26 '15  •   •  Reply

I'm not so sure No. 7 is a good example of how to use the nameof operator.

What's the difference between your example $"Argument {nameof(currentUser)} is not provided"

and this? $"Argument currentUser is not provided"

I don't think it's going to give you a compile time error if you make a mistake. Which I think is what you would want to use it for.

Erik OLeary [4]  •  Oct 26 '15  • 

@Matthew Cooper it is a good example, because it will automatically be refactored if the name changes, rather than using a 'magic string' for the name, it actually references the parameter identifier.

malik hejle [1]  •  Dec 7 '15  • 

@Matthew cooper,

This use of name of has the one great advantage that your argument message follows rename refactorings - i see it as a step in the right direction. I can avoid spending time fixing non domain issues.

Christian Kütbach [0]  •  Oct 26 '15  •   •  Reply

I think 2) is a really bad idea.

The "old" way using constructors has the advantage, that one can be sure that all parameter were set after creation.

This is more like a parameter-less constructor and calling 'setProperty1()'.

In my opinion, this is bad code-style hidden behind code-sugar.

Paul Parks [2]  •  Oct 30 '15  • 

@Christian Kütbach: The default constructor is still called when using an object initializer. The following program outputs "Hat contains 123 and xyz".

using System;

namespace PropTest {
    class Hat {
        public int Thing1 { get; set; }
        public string Thing2 { get; set; }

        public Hat() {
            Thing1 = 123;
            Thing2 = "abc";

    class Program {
        static void Main(string[] args) {
            Hat hat = new Hat { Thing2 = "xyz" };
            Console.WriteLine($"Hat contains {hat.Thing1} and {hat.Thing2}");

Your comment

You need to sign up / log in to comment this article


Created by coredev [37] Sep 18 '15

Share article

Do you know about


Write an article