C# 7.0 Pattern MatchingGreat news! You can already try new C# 7.0 features. All you need is Visual Studio 15 Preview. Let's start!

Today we are going to talk about Pattern Matching and will look under the hood of this nice feature. Unfortunately, it is only partly available in VS 15. So we need to wait until next release. Or you can try to get latest Roslyn from GitHub.

is operator

The is operator is extended to test an expression against a pattern.

With that you can replace this:

object obj = "Hello, World!";
var str = obj as string;
if (str != null)
{
    Console.WriteLine(str);
}

With shorter (and safer) version:

object obj = "Hello, World!";
if (obj is string str)
{
    Console.WriteLine(str);
}

It is safer because str variable is visible only in the if scope

Produced IL code is identical:

IL_0000:  ldstr      "Hello, Wolrd!"
IL_0005:  isinst     [mscorlib]System.String
IL_000a:  stloc.0
IL_000b:  ldloc.0
IL_000c:  brfalse.s  IL_0014

IL_000e:  ldloc.0
IL_000f:  call       void [mscorlib]System.Console::WriteLine(string)
IL_0014:  ret

You can also use pattern matching to match value type:

object obj = 1;
if (obj is int num)
{
    Console.WriteLine(num);
}

But you should be aware that internally it will be unboxed to Nullable<T> type. Here is IL code:

.locals init ([0] int32 num,
         [1] valuetype [mscorlib]System.Nullable`1<int32> V_1)
IL_0000:  ldc.i4.1
IL_0001:  box        [mscorlib]System.Int32
IL_0006:  isinst     valuetype [mscorlib]System.Nullable`1<int32>
IL_000b:  unbox.any  valuetype [mscorlib]System.Nullable`1<int32>
IL_0010:  stloc.1
IL_0011:  ldloca.s   V_1
IL_0013:  call       instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
IL_0018:  stloc.0
IL_0019:  ldloca.s   V_1
IL_001b:  call       instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_0020:  brfalse.s  IL_0028

IL_0022:  ldloc.0
IL_0023:  call       void [mscorlib]System.Console::WriteLine(int32)
IL_0028:  ret

It is equivalent to following C# code:

object obj = 1;
Nullable<int> V_1 = obj as Nullable<int>;
int num = V_1.GetValueOrDefault();
if (V_1.HasValue)
{
    Console.WriteLine(num);
}

Even though it is unboxed to Nullable<int> type, in if scope you will have num variable of System.Int type.

You can also use var in pattern matching. A match to the var pattern is always succeeded.

object obj = "test";
if (obj is var str)
{
    Console.WriteLine(str);
}

As well as * pattern:

object obj = "test";
if (obj is *)
{
    Console.WriteLine(true);
}

There is constant pattern match:

object obj = 1;
if (obj is 1)
{
    Console.WriteLine(true);
}

Which will be replaced with call to the object.Equals method

object obj = 1;
if (object.Equals(obj, 1))
{
 Console.WriteLine(true);
}

Unfortunately, User-defined operator is is not implemented yet. So recursive pattern matching is not working.

That's it for today. In the next part, we will talk about pattern matching in switch statement:

object obj = "String";

switch (obj)
{
    case string s:
        Console.WriteLine(s + "test");
        break;
    case int i:
        Console.WriteLine(i + 10);
        break;
}