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(quot;Data: {cotacao.DataCotacao:dd/MM/yyyy}"); Console.WriteLine(quot;Sigla: {cotacao.SiglaMoeda}"); Console.WriteLine(quot;Moeda: {cotacao.NomeMoeda}"); Console.WriteLine(quot;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(quot;Data: {cotacao.DataCotacao:dd/MM/yyyy}"); Console.WriteLine(quot;Sigla: {cotacao.SiglaMoeda}"); Console.WriteLine(quot;Moeda: {cotacao.NomeMoeda}"); Console.WriteLine(quot;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(quot;Data: {cotacao.DataCotacao:dd/MM/yyyy}"); Console.WriteLine(quot;Sigla: {cotacao.SiglaMoeda}"); Console.WriteLine(quot;Moeda: {cotacao.NomeMoeda}"); Console.WriteLine(quot;Valor: {valorCotacao:0.0000}"); }