Verbatim Strings

Interpolated Verbatim Strings

Verbatim strings can be combined with the new String interpolation features found in C#6.
Console.WriteLine($@"Testing \n 1 2 {5 - 2}
New line");
Output:
Testing \n 1 2 3
New line

Escaping Double Quotes

Double Quotes  escaped by using 2 sequential double quotes “” to represent one double quote ” in the resulting string.
var str = @"""I don't think so,"" he said.";
Console.WriteLine(str);
Output:
"I don't think so," he said.

var filename = @"c:\temp\newfile.txt"
Output:
c:\temp\newfile.txt

Multiline Strings

var multiLine = @"This is a
multiline paragraph";
Output:
This is a
multiline paragraph

Operators

Overloadable Operators

The following example illustrates an implementation of the + operator.
If we have a Complex class which represents a complex number:

public struct Complex
{
public double Real { get; set; }
public double Imaginary { get; set; }
}

And we want to add the option to use the + operator for this class. i.e.:

Complex a = new Complex() { Real = 1, Imaginary = 2 };
Complex b = new Complex() { Real = 4, Imaginary = 8 };
Complex c = a + b;

We will need to overload the + operator for the class. This is done using a static function and the operator keyword:

public static Complex operator +(Complex c1, Complex c2)
{
return new Complex
{
Real = c1.Real + c2.Real,
Imaginary = c1.Imaginary + c2.Imaginary
};
} Operators such as +, -, *, / can all be overloaded. Comparison operators have to be overloaded in pairs (e.g. if < is overloaded, > also needs to be overloaded). Overloading of operator is was introduced with the pattern matching mechanism of C# 7.0.

Overloading equality operators

When overriding Equals, GetHashCode must also be overriden. When implementing Equals, there are many special cases: comparing to objects of a different type, comparing to self etc.


class Student : IEquatable
{
 public string Name { get; set; } = "";
 public bool Equals(Student other)
 {
 if (ReferenceEquals(other, null)) return false;
 if (ReferenceEquals(other, this)) return true;
 return string.Equals(Name, other.Name);
 }
 public override bool Equals(object obj)
 {
 if (ReferenceEquals(null, obj)) return false;
 if (ReferenceEquals(this, obj)) return true;
 return Equals(obj as Student);
 
}
 public override int GetHashCode()
 {
 return Name?.GetHashCode() ?? 0;
 }
 public static bool operator ==(Student left, Student right)
 {
 return Equals(left, right);
 }
 public static bool operator !=(Student left, Student right)
 {
 return !Equals(left, right);
 }
}

Extension methods

Extension methods extend and add behavior to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.

static class StringExtensions
{
public static string Shorten(this string text, int length)
{
return text.Substring(0, length);
}
}
class Program
{
static void Main()
{
// This calls method String.ToUpper()
var myString = "Hello World!".ToUpper();
// This calls the extension method StringExtensions.Shorten()
var newString = myString.Shorten(5);
// It is worth noting that the above call is purely syntactic sugar
// and the assignment below is functionally equivalent
var newString2 = StringExtensions.Shorten(myString, 5);
}
}

An extension method is created by adding a static method to a static class which is distinct from the original type being extended. The static class holding the extension method is often created for the sole purpose of holding extension methods.

Generic Extension Methods

Just like other methods, extension methods can use generics. For example:
static class Extensions
{
public static bool HasMoreThanThreeElements<T>(this IEnumerable<T> enumerable)
{
return enumerable.Take(4).Count() > 3;
}
}
and calling it would be like:
IEnumerable<int> numbers = new List<int> {1,2,3,4,5,6};
var hasMoreThanThreeElements = numbers.HasMoreThanThreeElements();

Collection Initializers

var stringList = new List<string>{ "foo", "bar", };

var dict = new Dictionary<string, int>
{
["key1"] = 1,
["key2"] = 50
};
This is equivalent to:
var dict = new Dictionary<string, int>();

dict["key1"] = 1;
dict["key2"] = 50

Format dates in strings

var date = new DateTime(2015, 11, 11);
var str = $"It's {date:MMMM d, yyyy}, make a wish!";

async, await

The await keyword is used to pause the current asynchronous method’s execution until the awaited asynchronous task is completed and/or its results returned. In order to use the await keyword, the method that uses it must be marked with the async keyword.
Using async with void is strongly discouraged.

public async Task DoSomethingAsync()
{
Console.WriteLine("Starting a useless process...");
Stopwatch stopwatch = Stopwatch.StartNew();
int delay = await UselessProcessAsync(1000);
stopwatch.Stop();
Console.WriteLine("A useless process took {0} milliseconds to execute.",
stopwatch.ElapsedMilliseconds);
}
public async Task<int> UselessProcessAsync(int x)
{
await Task.Delay(x);
return x;
}

The keyword pairs async and await can be omitted if a Task or Task returning method only returns a single asynchronous operation.

public Task PrintAndDelayAsync(string message, int delay)
{
Debug.WriteLine(message);
return Task.Delay(x);
}

dynamic

The dynamic keyword is used with dynamically typed objects. Objects declared as dynamic forego compile-time static checks, and are instead evaluated at runtime.
using System;
using System.Dynamic;
dynamic info = new ExpandoObject();
info.Id = 123;
info.Another = 456;
Console.WriteLine(info.Another);
// 456
Console.WriteLine(info.DoesntExist);
// Throws RuntimeBinderException

ref, out

The ref and out keywords cause an argument to be passed by reference, not by value. For value types, this means that the value of the variable can be changed by the callee.
int x = 5;
ChangeX(ref x);
// The value of x could be different now

when

try
{
action.Invoke();
}

// exception filter
catch (Exception ex) when (ex.Message.Contains("when"))
{
Console.WriteLine("Caught an exception with when");
}

delegate

Delegates are types that represent a reference to a method. They are used for passing methods as arguments to other methods.
Delegates can hold static methods, instance methods, anonymous methods, or lambda expressions.

class DelegateExample
{
public void Run()
{
//using class method
InvokeDelegate( WriteToConsole );

//using anonymous method
DelegateInvoker di = delegate ( string input )
{
Console.WriteLine( string.Format( "di: {0} ", input ) );
return true;
};
InvokeDelegate( di );

//using lambda expression
InvokeDelegate( input => false );
}
public delegate bool DelegateInvoker( string input );
public void InvokeDelegate(DelegateInvoker func)
{
var ret = func( "hello world" );
Console.WriteLine( string.Format( " > delegate returned {0}", ret ) );
}
public bool WriteToConsole( string input )
{
Console.WriteLine( string.Format( "WriteToConsole: '{0}'", input ) );
return true;
}
}
When assigning a method to a delegate it is important to note that the method must have the same return type as well as parameters. This differs from ‘normal’ method overloading, where only the parameters define the signature of the method.
Events are built on top of delegates.

event

An event allows the developer to implement a notification pattern.

public class Server
{
// defines the event
public event EventHandler DataChangeEvent;
void RaiseEvent()
{
var ev = DataChangeEvent;
if(ev != null)
{
ev(this, EventArgs.Empty);
}
}

}

public class Client
{
public void Client(Server server)
{
// client subscribes to the server's DataChangeEvent
server.DataChangeEvent += server_DataChanged;
}
private void server_DataChanged(object sender, EventArgs args)
{
// notified when the server raises the DataChangeEvent
}
}

Using Statement

using is syntactic sugar that allows you to guarantee that a resource is cleaned up without needing an explicit tryfinally block. This means your code will be much cleaner, and you won’t leak non-managed resources.
Standard Dispose cleanup pattern, for objects that implement the IDisposable interface (which the FileStream’s base class Stream does in .NET):

int Foo()
{
var fileName = "file.txt";
{
FileStream disposable = null;
try
{
disposable = File.Open(fileName, FileMode.Open);
return disposable.ReadByte();
}
finally
{
// finally blocks are always run
if (disposable != null) disposable.Dispose();
}
}
}
using simplifies your syntax by hiding the explicit try-finally:
int Foo()
{
var fileName = "file.txt";
using (var disposable = File.Open(fileName, FileMode.Open))
{
return disposable.ReadByte();
}
// disposable.Dispose is called even if we return earlier
}