Ao manipular objetos cujas classes derivam de um mesmo tipo básico é extremamente comum se recorrer a checagens empregando o operador is. Também são frequentes operações de typecast indicando o uso de uma estrutura requerida por um contexto específico.

Para exemplificar isto serão utilizadas as seguintes classes:
  • Cotacao, tipo abstrato que representa uma cotação de moeda estrangeira;
  • CotacaoDolar, implementação concreta baseada em Cotacao e contendo informações da cotação do dólar norte-americano em uma data (tanto o valor comercial, quanto o correspondente para fins de turismo);
  • CotacaoEuro, com dados relativos a uma cotação do euro.
using System;
 
namespace ExemploPatternMatching
{
    public abstract class Cotacao
    {
        public DateTime DataCotacao { get; set; }
        public abstract string SiglaMoeda { get; }
        public abstract string NomeMoeda { get; }
    }
 
    public class CotacaoDolar : Cotacao
    {
        public override string SiglaMoeda
        { get { return "Dólar norte-americano"; } }
 
        public override string NomeMoeda
        { get { return "USD"; } }
 
        public double ValorComercial { get; set; }
        public double ValorTurismo { get; set; }
    }
 
    public class CotacaoEuro : Cotacao
    {
        public override string SiglaMoeda
        { get { return "Euro"; } }
 
        public override string NomeMoeda
        { get { return "EUR"; } }
 
        public double ValorCotacao { get; set; }
    }
}

Na próxima listagem está a definição de um método chamado ExibirInformacoesCotacao:
  • Esta operação receberá como parâmetro uma instância do tipo Cotacao, a fim de exibir informações sobre uma moeda estrangeira;
  • Um único valor de cotação será mostrado. Para referências baseadas em CotacaoEuro este dado se encontra na propriedade ValorCotacao. Já para o tipo CotacaoDolar será assumido o valor associado à propriedade ValorComercial. Até o C# 6.0 todo este processo acontecia empregando o operador is, além de incluir casts quando fosse necessário manipular implementações mais específicas da classe-base.
public static void ExibirInformacoesCotacao(Cotacao cotacao)
{
    double valorCotacao = 0;
    if (cotacao is CotacaoDolar)
    {
        valorCotacao =
            ((CotacaoDolar)cotacao).ValorComercial;
    }
    else if (cotacao is CotacaoEuro)
    {
        valorCotacao =
            ((CotacaoEuro)cotacao).ValorCotacao;
    }
 
    Console.WriteLine(new String('-', 40));
    Console.WriteLine($"Data: {cotacao.DataCotacao:dd/MM/yyyy}");
    Console.WriteLine($"Sigla: {cotacao.SiglaMoeda}");
    Console.WriteLine($"Moeda: {cotacao.NomeMoeda}");
    Console.WriteLine($"Valor: {valorCotacao:0.0000}");
}

A seguir é possível observar um exemplo de uso do recurso de Pattern Matching (após a refatoração do método ExibirInformacoesCotacao):
  • Esta funcionalidade permite definir uma variável em conjunto com o operador is, com a mesma sendo preenchida caso a referência em análise corresponda ao tipo que se está verificando;
  • A vantagem deste novo mecanismo está em eliminar a necessidade de codificação de um typecast, contribuindo assim para um código mais limpo e direto.
using System;
 
namespace ExemploPatternMatching
{
    class Program
    {
        public static void ExibirInformacoesCotacao(Cotacao cotacao)
        {
            double valorCotacao = 0;
            if (cotacao is CotacaoDolar dolar)
                valorCotacao = dolar.ValorComercial;
            else if (cotacao is CotacaoEuro euro)
                valorCotacao = euro.ValorCotacao;
 
            Console.WriteLine(new String('-', 40));
            Console.WriteLine($"Data: {cotacao.DataCotacao:dd/MM/yyyy}");
            Console.WriteLine($"Sigla: {cotacao.SiglaMoeda}");
            Console.WriteLine($"Moeda: {cotacao.NomeMoeda}");
            Console.WriteLine($"Valor: {valorCotacao:0.0000}");
        }
 
        static void Main(string[] args)
        {
            CotacaoDolar dolar = new CotacaoDolar();
            dolar.DataCotacao = new DateTime(2017, 3, 24);
            dolar.ValorComercial = 3.1083;
            dolar.ValorTurismo = 3.2700;
            ExibirInformacoesCotacao(dolar);
 
            CotacaoEuro euro = new CotacaoEuro();
            euro.DataCotacao = new DateTime(2017, 3, 24);
            euro.ValorCotacao = 3.3695;
            ExibirInformacoesCotacao(euro);
 
            Console.ReadKey();
        }
    }
}

A execução deste bloco de código apresentará como resultado:



O método ExibirInformacoesCotacao pode ainda ser refatorado, de forma a se fazer uso de um switch em conjunto com a funcionalidade de Pattern Matching:

public static void ExibirInformacoesCotacao(Cotacao cotacao)
{
    double valorCotacao;
    switch (cotacao)
    {
        case CotacaoDolar dolar:
            valorCotacao = dolar.ValorComercial;
            break;
        case CotacaoEuro euro:
            valorCotacao = euro.ValorCotacao;
            break;
        default:
            valorCotacao = 0;
            break;
    }
 
    Console.WriteLine(new String('-', 40));
    Console.WriteLine($"Data: {cotacao.DataCotacao:dd/MM/yyyy}");
    Console.WriteLine($"Sigla: {cotacao.SiglaMoeda}");
    Console.WriteLine($"Moeda: {cotacao.NomeMoeda}");
    Console.WriteLine($"Valor: {valorCotacao:0.0000}");
}

Referências

New Features in C# 7.0
https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/