O uso da palavra-chave out está comumente associado à passagem de valores por referência. Em versões anteriores da linguagem C# há algumas implicações ao empregar este recurso:
- É preciso primeiramente declarar as variáveis a serem utilizadas em conjunto com este modificador. Isso acontece antes da chamada de um método com um ou mais parâmetros devolvidos como referência, não sendo necessário a inicialização das variáveis envolvidas (diferentemente da palavra-chave ref);
- Além disso, não é possível a utilização do modificador var na declaração das variáveis utilizadas.
A próxima listagem exemplifica o que foi descrito até aqui, com um exemplo de uso da palavra-chave out no método CalcularDiasVividos:
using System; namespace ExemploOutVariables01 { class Program { private static void CalcularDiasVividos(string strDataNasc) { DateTime dataNasc; if (DateTime.TryParse(strDataNasc, out dataNasc)) { DateTime dataAtual = DateTime.Now.Date; Console.WriteLine( quot;Data Atual: { dataAtual: dd/MM/yyyy}"); Console.WriteLine( quot;Data de Nascimento: { dataNasc: dd/MM/yyyy}"); TimeSpan intervalo = dataAtual.Subtract(dataNasc); Console.WriteLine( quot;Quantidade de dias vividos: { intervalo.TotalDays}"); } else { Console.WriteLine(quot;Data invalida: {strDataNasc}"); } Console.Write(Environment.NewLine); } static void Main(string[] args) { CalcularDiasVividos("07/03/2017"); CalcularDiasVividos("ERRO"); CalcularDiasVividos("31/01/1990"); Console.ReadKey(); } } }
O C# 7.0 conta agora com um novo recurso conhecido como Out Variables, o qual foi concebido com o intuito de simplificar a passagem de valores por referência:
- Esta funcionalidade permite a declaração de uma variável no ponto em que a mesma é repassada como parâmetro, bastando apenas que se especifique o modificador out e o tipo a ser empregado para a variável;
- A variável declarada ao acionar um método poderá ser utilizada logo após o processamento deste último.
A listagem a seguir traz o exemplo anterior refatorado, de forma a demonstrar a utilização de uma Out Variable (neste caso a variável dataNasc, que foi declarada na chamada ao método CalcularDiasVividos):
using System; namespace ExemploOutVariables01 { class Program { private static void CalcularDiasVividos(string strDataNasc) { if (DateTime.TryParse(strDataNasc, out DateTime dataNasc)) // Out Variable { DateTime dataAtual = DateTime.Now.Date; Console.WriteLine( quot;Data Atual: { dataAtual: dd/MM/yyyy}"); Console.WriteLine( quot;Data de Nascimento: { dataNasc: dd/MM/yyyy}"); TimeSpan intervalo = dataAtual.Subtract(dataNasc); Console.WriteLine( quot;Quantidade de dias vividos: { intervalo.TotalDays}"); } else { Console.WriteLine(quot;Data invalida: {strDataNasc}"); } Console.Write(Environment.NewLine); } static void Main(string[] args) { CalcularDiasVividos("07/03/2017"); CalcularDiasVividos("ERRO"); CalcularDiasVividos("31/01/1990"); Console.ReadKey(); } } }
A execução deste conjunto de instruções produzirá o seguinte resultado:
É possível ainda combinar o uso das palavras-chave out e var, como indicado na próxima listagem em outra variação do exemplo apresentado inicialmente:
using System; namespace ExemploOutVariables01 { class Program { private static void CalcularDiasVividos(string strDataNasc) { if (DateTime.TryParse(strDataNasc, out var dataNasc)) // Out Variable { DateTime dataAtual = DateTime.Now.Date; Console.WriteLine( quot;Data Atual: { dataAtual: dd/MM/yyyy}"); Console.WriteLine( quot;Data de Nascimento: { dataNasc: dd/MM/yyyy}"); TimeSpan intervalo = dataAtual.Subtract(dataNasc); Console.WriteLine( quot;Quantidade de dias vividos: { intervalo.TotalDays}"); } else { Console.WriteLine(quot;Data invalida: {strDataNasc}"); } Console.Write(Environment.NewLine); } static void Main(string[] args) { CalcularDiasVividos("07/03/2017"); CalcularDiasVividos("ERRO"); CalcularDiasVividos("31/01/1990"); Console.ReadKey(); } } }
Conversões e validações correspondem a cenários nos quais o modificar out é utilizado com relativa frequência. Em situações deste tipo a declaração de variáveis empregadas apenas na invocação de um método constitui uma prática comum, conforme se observa no próximo exemplo (com a variável valor definida na operação EfetuarValidacao):
using System; namespace ExemploOutVariables02 { class Program { private static void EfetuarValidacao(string strValorInteiro) { int valor; if (int.TryParse(strValorInteiro, out valor)) Console.WriteLine(quot;{strValorInteiro} é um número inteiro válido..."); else Console.WriteLine(quot;{strValorInteiro} não é um valor inteiro..."); } static void Main(string[] args) { EfetuarValidacao("1000"); EfetuarValidacao("057"); EfetuarValidacao("5.70"); Console.ReadKey(); } } }
Uma alternativa a fim de evitar a declaração de uma variável seria o uso de um discard, através do símbolo “_” (underline) empregado em conjunto com o modificador out:
using System; namespace ExemploOutVariables02 { class Program { private static void EfetuarValidacao(string strValorInteiro) { if (int.TryParse(strValorInteiro, out _)) // Utilizando um discard Console.WriteLine(quot;{strValorInteiro} é um número inteiro válido..."); else Console.WriteLine(quot;{strValorInteiro} não é um valor inteiro..."); } static void Main(string[] args) { EfetuarValidacao("1000"); EfetuarValidacao("057"); EfetuarValidacao("5.70"); Console.ReadKey(); } } }
Ao executar este bloco de código teremos como resultado:
Não deixe de assistir a gravação de um hangout realizado recentemente pelo Canal .NET sobre este assunto:
Disponibilizei também no GitHub os diferentes exemplos apresentados durante a transmissão:
https://github.com/renatogroffe/CSharp7_VS2017