.NET

19 jan, 2018

Novidades do C# 7.2 – Parte 02: private protected, non-trailing named arguments e digit separators

Publicidade

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:

Referências