Este segundo artigo da série sobre novidades do C# 7.2, traz exemplos de uso do modificador private protected, além de melhorias no uso de digit separators e envolvendo a nomeação de argumentos ao se invocar um método.
Caso queira acompanhar ou até mesmo rever o primeiro da série, acesse o link a seguir, que inclui instruções sobre como habilitar o uso do C# 7.2 no Visual Studio 2017 Update 15.5:
O modificador private protected
Presente em versões anteriores da linguagem C#, o modificador protected internal determina que o acesso a um elemento de uma classe fique restrito ao assembly em que a mesma foi declarada e/ou a suas subclasses (estas últimas podem estar localizadas em outros projetos).
No exemplo a seguir é possível observar o uso de uma propriedade (Valor) marcada como protected internal por uma classe-filha (ClasseDerivada), localizada no mesmo assembly do tipo ClasseBase (LibBase):
namespace LibBase { public class ClasseBase { protected internal string Valor { get; set; } public ClasseBase() { Valor = "ClasseBase"; } public string GerarMensagem() { return Valor; } } public class ClasseDerivada : ClasseBase { public ClasseDerivada() { Valor = "ClasseDerivada"; } } }
Já na próxima listagem está a implementação do tipo NovaClasseDerivada, o qual foi declarado em outro assembly (NovaLib). Herdando suas características de ClasseBase, esta classe consegue acessar sem maiores dificuldades a propriedade Valor (definida originalmente em ClasseBase):
using LibBase; namespace NovaLib { public class NovaClasseDerivada : ClasseBase { public NovaClasseDerivada() { Valor = "NovaClasseDerivada"; } } }
Mas e se for necessário impedir o acesso à propriedade Valor em NovaClasseDerivada? O C# 7.2 traz agora uma alternativa que simplifica este processo: o modificador private protected. Este novo recurso permitirá o acesso a um elemento apenas na classe em que o mesmo foi definido, ou em tipos derivados pertencentes ao mesmo assembly de origem.
Alterando a propriedade Valor em ClasseBase para private protected:
namespace LibBase { public class ClasseBase { private protected string Valor { get; set; } public ClasseBase() { Valor = "ClasseBase"; } public string GerarMensagem() { return Valor; } } public class ClasseDerivada : ClasseBase { public ClasseDerivada() { Valor = "ClasseDerivada"; } } }
Aparecerá então um alerta de erro em NovaClasseDerivada indicando que o acesso à propriedade Valor não é possível (a instrução que faz uso deste elemento em ClasseDerivada ainda continuará válida, já que se encontra no mesmo assembly):
Non-trailing named arguments
Em versões anteriores da linguagem C#, o uso de um argumento nomeado em um método exigia que os parâmetros subsequentes também fossem identificados de forma explícita. Um exemplo disto seria a instrução:
Math.Pow(x: 2, y: 5)
Em que ao se especificar o parâmetro x foi também necessário indicar o argumento y. A ordem destes parâmetros também poderia, alternativamente, estar invertida (obviamente com ambos os argumentos nomeados).
Esta forma de declaração era obrigatória e, caso não fosse adotada, resultaria em erros como o indicado a seguir:
O C# 7.2 traz agora uma nova funcionalidade chamada non-trailing named arguments, que contorna esta limitação. Este recurso permitirá que ao se nomear um argumento, a identificação dos demais parâmetros não precise ser declarada de forma explícita, desde – claro – que se leve em conta a ordem em que tais argumentos foram especificados em um método. Um exemplo disto pode ser observado na próxima listagem:
using System; namespace ExemploNonTrailing { class Program { static void Main(string[] args) { Console.WriteLine("2 ^ 3 = " + Math.Pow(x: 2, 3)); // Uso de non-trailing named argument Console.WriteLine("2 ^ 5 = " + Math.Pow(x: 2, y: 5)); Console.WriteLine("2 ^ 10 = " + Math.Pow(2, y: 10)); Console.ReadKey(); } } }
A imagem a seguir traz o resultado da execução deste código:
Digit separators após 0B, 0b, 0X e 0x
Uma das novidades do C# 7.0 foram os digit separators. Este recurso faz uso do caractere “_” (underline) na separação de algarismos em sequências numéricas, tendo como grande vantagem tornar mais legível a visualização de valores no código C#:
using System; namespace ExemploDigitSeparators { class Program { private const int LETRA_Y_BIN = 0b01_01_10_01; // 01011001 (binário) = 89 (dec.) private const int LETRA_Z_HEX = 0X5_A; // 5A (hexadecimal) = 80 (decimal) private const int POPULACAO_ESTIMADA_BRASIL = 204_500_000; private const double RENDA_PER_CAPITA_BRASIL_USD = 11_208.08; static void Main(string[] args) { Console.WriteLine("Valor numérico de alguns caracteres ASCII"); Console.WriteLine(quot;Y = {LETRA_Y_BIN}"); Console.WriteLine(quot;Z = {LETRA_Z_HEX}"); Console.WriteLine(String.Empty); Console.WriteLine( quot;População estimada do Brasil = {POPULACAO_ESTIMADA_BRASIL}"); Console.WriteLine( quot;Renda per capita do Brasil (US$) = {RENDA_PER_CAPITA_BRASIL_USD}"); Console.ReadKey(); } } }
Quando ocorreu o lançamento desta funcionalidade, não era permitida a utilização do caracter “_” antes de 0B, 0b, 0X e 0x (empregados nas representações de valores binários e hexadecimais). Já o C# 7.2 traz agora também esta possibilidade:
using System; namespace ExemploDigitSeparators { class Program { private const int LETRA_Y_BIN = 0b_01_01_10_01; // 01011001 (binário) = 89 (dec.) private const int LETRA_Z_HEX = 0X_5_A; // 5A (hexadecimal) = 80 (decimal) private const int POPULACAO_ESTIMADA_BRASIL = 204_500_000; private const double RENDA_PER_CAPITA_BRASIL_USD = 11_208.08; static void Main(string[] args) { Console.WriteLine("Valor numérico de alguns caracteres ASCII"); Console.WriteLine(quot;Y = {LETRA_Y_BIN}"); Console.WriteLine(quot;Z = {LETRA_Z_HEX}"); Console.WriteLine(String.Empty); Console.WriteLine( quot;População estimada do Brasil = {POPULACAO_ESTIMADA_BRASIL}"); Console.WriteLine( quot;Renda per capita do Brasil (US$) = {RENDA_PER_CAPITA_BRASIL_USD}"); Console.ReadKey(); } } }
Na próxima imagem está o resultado da execução deste último exemplo: