csharp06a00

Neste quarto artigo da série sobre C# 6.0 serão demonstrados os seguintes recursos:

  • Inicialização de propriedades somente leitura a partir de um construtor;
  • Implementação de construtores sem parâmetros em structs [REMOVIDO];
  • String Interpolation.

OBSERVAÇÃO: todos os exemplos aqui descritos foram implementados através do Visual Studio 2015 CTP 5.

Inicialização de propriedades somente leitura a partir de um construtor

A segunda parte desta série abordou um novo recurso do C# 6.0 chamado “Auto-Property Initializers”. Em termos práticos, este mecanismo permite a atribuição de valores a propriedades a partir da própria declaração destes elementos. É importante destacar que tal aspecto também é válido para propriedades definidas como somente leitura, dispensando assim a necessidade de utilização de referências criadas apenas para o armazenamento de um valor.

Esta nova versão da linguagem C# trouxe ainda uma outra alternativa no que se refere à inicialização de propriedades read-only. Além da especificação de um valor na própria declaração de um item deste tipo, agora também é possível efetuar tal associação no construtor da classe em questão (diferentemente do que acontecia em releases anteriores, como observado na Imagem 1 em um exemplo no Visual Studio 2013).


Imagem 1. Erro ao tentar atribuir um valor a uma propriedade read-only no construtor de uma classe (Visual Studio 2013)

Retomando o exemplo de “Auto-Property Initializers” apresentado no segundo artigo da série, na Listagem 1 está uma versão refatorada da classe MensagemLog. Conforme se nota nesta implementação, a propriedade somente leitura “Data” está sendo preenchida no construtor do tipo.

using System;

namespace TesteInicializacaoPropriedades
{
    public enum TipoLog
    {
        Informacao,
        Alerta,
        Erro
    }

    public class MensagemLog
    {
        public DateTime Data { get; }
        public TipoLog Tipo { get; set; }
        public string Mensagem { get; set; }

        public MensagemLog()
        {
            this.Data = DateTime.Now;
            this.Tipo = TipoLog.Informacao;
        }
    }
}

Listagem 1: Associando um valor a uma propriedade read-only no construtor de uma classe

Já na Listagem 2 é demonstrada a utilização da classe MensagemLog (cujas instâncias servem de base para que o método ExibirConteudoLog mostre informações de registros de log). A execução deste programa de testes produzirá um resultado similar ao que consta na Imagem 2.

using System;

namespace TesteInicializacaoPropriedades
{
    class Program
    {
        public static string ExibirConteudoLog(MensagemLog log)
        {
            return String.Format(
                "*** Mensagem de Log ***\nData: {0}\nTipo: {1}\nMensagem: {2}",
                log.Data, log.Tipo, log.Mensagem);
        }

        static void Main(string[] args)
        {
            MensagemLog msgLog = new MensagemLog();

            Console.WriteLine("Valores do objeto MensagemLog logo após a inicialização...\n");
            Console.WriteLine(ExibirConteudoLog(msgLog));

            msgLog.Tipo = TipoLog.Alerta;
            msgLog.Mensagem = "Exemplo de mensagem de alerta.";

            Console.WriteLine("\n\nValores do objeto MensagemLog logo após alterações...\n");
            Console.WriteLine(ExibirConteudoLog(msgLog));

            Console.ReadKey();
        }
    }
}

Listagem 2: Exemplo de utilização da classe MensagemLog


Imagem 2. Resultado dos testes demonstrando a inicialização de uma propriedade read-only no construtor

Implementação de construtores sem parâmetros em structs [REMOVIDO]

Structs são construções empregadas na representação de informações simples, tais como tempo, coordenadas geométricas ou dados geográficos. O tipo DateTime (namespace System) constitui um bom exemplo de uso desta estrutura, sendo comumente utilizado na manipulação de datas e horários.

Em versões anteriores da linguagem C#, structs não poderiam ser implementados com um construtor padrão declarado de forma explícita. Eram possíveis apenas as seguintes alternativas:

  • A implementação de um struct sem nenhum construtor (Listagem 3);
  • A codificação de um struct com parâmetros (Listagem 4), os quais normalmente serviam de base para a inicialização de propriedades destas instâncias. Importante ressaltar que esta opção obrigava à invocação do construtor sem parâmetros (representado pela palavra-chave “this”) de forma implícita.
namespace TesteStruct
{
    public struct Paralelepipedo
    {
        public double Comprimento { get; set; }
        public double Largura { get; set; }
        public double Altura { get; set; }

        public double Volume
        {
            get
            {
                return this.Comprimento * this.Largura * this.Altura;
            }
        }
    }
}

Listagem 3: Exemplo de struct sem construtores

namespace TesteStruct
{
    public struct Paralelepipedo
    {
        public double Comprimento { get; set; }
        public double Largura { get; set; }
        public double Altura { get; set; }

        public double Volume
        {
            get
            {
                return this.Comprimento * this.Largura * this.Altura;
            }
        }

        public Paralelepipedo(
            double comprimento, double largura, double altura)
            : this()
        {
            Comprimento = comprimento;
            Largura = largura;
            Altura = altura;
        }
    }
}

Listagem 4: Exemplo de struct com construtor implementado em versões anteriores do C#

Com o C# 6.0 é permitida agora a codificação de structs com construtores sem parâmetros explicitamente. Na Listagem 5 está um exemplo em que se observa uma versão reformulada da classe Paralelepipedo, já contemplando este novo recurso.

namespace TesteStruct
{
    public struct Paralelepipedo
    {
        public double Comprimento { get; set; }
        public double Largura { get; set; }
        public double Altura { get; set; }

        public double Volume
        {
            get
            {
                return this.Comprimento * this.Largura * this.Altura;
            }
        }

        public Paralelepipedo()
        {
            this.Comprimento = 4;
            this.Largura = 5;
            this.Altura = 6;
        }
    }
}

Listagem 5: Exemplo de um struct no C# 6.0 com um construtor sem parâmetros

Neste novo release é possível ainda que um construtor sem parâmetros invoque outra estrutura deste tipo, como indicado na Listagem 6.

namespace TesteStruct
{
    public struct Paralelepipedo
    {
        public double Comprimento { get; set; }
        public double Largura { get; set; }
        public double Altura { get; set; }

        public double Volume
        {
            get
            {
                return this.Comprimento * this.Largura * this.Altura;
            }
        }

        public Paralelepipedo(
            double comprimento, double largura, double altura)
        {
            Comprimento = comprimento;
            Largura = largura;
            Altura = altura;
        }

        public Paralelepipedo() : this(4, 5, 6)
        {
        }
    }
}

Listagem 6: Outro exemplo de implementação de construtores para um struct no C# 6.0

Por fim, a Listagem 7 apresenta um exemplo de utilização do construtor sem parâmetros do struct Paralelepipedo. O processo envolvendo o uso dessa estrutura é bem simples, com os valores de uma instância sendo inicializados quando o construtor escolhido acionar a segunda construção de mesmo tipo (conforme detalhado na Listagem 6). O resultado da execução deste programa de testes pode ser visualizado na Imagem 3.

using System;

namespace TesteStruct
{
    class Program
    {
        static void Main(string[] args)
        {
            Paralelepipedo p = new Paralelepipedo();
            Console.WriteLine(
                "Volume do paralelepípedo: " + p.Volume);

            p.Comprimento = 10;
            Console.WriteLine(
                "Volume do paralelepípedo após modificações: " + p.Volume);

            Console.ReadKey();
        }
    }
}

Listagem 7: Exemplo de utilização de um struct com um construtor sem parâmetros


Imagem 3. Resultado dos testes utilizando um construtor sem parâmetros definido em um struct

ATENÇÃO!!! ESTE RECURSO FOI REMOVIDO NOS RELEASES  MAIS RECENTES DO C# 6.0.  PARA MAIORES DETALHES CONSULTAR:

https://github.com/dotnet/roslyn/pull/1106
https://github.com/dotnet/roslyn/issues/1029

String Interpolation

Desde os primórdios do .NET Framework métodos como Format na classe String (ou ainda, Write e WriteLine na classe Console) permitem o uso de placeholders na manipulação de sequências de texto. Em termos práticos, um placeholder nada mais é do que um índice numérico delimitado por chaves dentro de uma cadeia de caracteres, tendo por objetivo simplificar a geração de strings ao evitar numerosas concatenações envolvendo variáveis e constantes de texto.

Na Listagem 8 encontra-se um exemplo de utilização deste recurso:

  • Uma nova string contendo informações de data e horário foi gerada a partir do uso de funcionalidades disponibilizadas pelas classes DateTime e CultureInfo (namespace System.Globalization);
  • Nota-se ainda a existência de 4 placeholders, com o último destes contando com uma máscara para a formatação do horário atual.
...

DateTime dataAtual = DateTime.Now;
CultureInfo configLocais = new CultureInfo("pt-BR");

string mensagem = String.Format(
    "São Paulo, {0} de {1} de {2} - {3:HH:MM:ss}",
    dataAtual.Day,
    configLocais.DateTimeFormat.GetMonthName(dataAtual.Month),
    dataAtual.Year,
    dataAtual);

...

Listagem 8: Exemplo de utilização de placeholders com o método Format da classe String

Caso fosse necessário incluir neste último trecho de código a descrição do dia da semana logo após a cidade, tal ajuste não se resumiria à inclusão da expressão que produziria esta informação. Na verdade, a alteração necessária levaria a uma mudança no valor de todos os placeholders que já haviam sido definidos anteriormente. Esta abordagem é suscetível a erros, os quais geralmente seriam decorrentes de desatenção do desenvolvedor. O código que está na Listagem 9 ilustra a situação aqui descrita.

...

DateTime dataAtual = DateTime.Now;
CultureInfo configLocais = new CultureInfo("pt-BR");

string mensagem = String.Format(
    "São Paulo, {0}, {1} de {2} de {3} - {4:HH:MM:ss}",
    configLocais.DateTimeFormat.GetDayName(dataAtual.DayOfWeek),
    dataAtual.Day,
    configLocais.DateTimeFormat.GetMonthName(dataAtual.Month),
    dataAtual.Year,
    dataAtual);

...

Listagem 9: Um segundo exemplo de utilização de placeholders com o método Format da classe String

Procurando simplificar tarefas baseadas na manipulação de strings, o C# 6.0 introduziu um novo recurso chamado “String Interpolation”. A ideia com este mecanismo é, via de regra, substituir o uso de placeholders indexados pelas próprias expressões que seriam empregadas em conjunto com os mesmos (além de descartar a necessidade de chamadas a métodos como Format da classe String).

Na Listagem 10 está um exemplo de utilização de String Interpolation:

  • O uso deste recurso requer que as strings venham precedidas pelo caracter “$” (dólar);
  • As expressões ficam entre chaves (“{” e “}”), sendo possível ainda aplicar formatação (como no caso do horário).
...

DateTime dataAtual = DateTime.Now;
CultureInfo configLocais = new CultureInfo("pt-BR");

string mensagem =
    $"São Paulo, {configLocais.DateTimeFormat.GetDayName(dataAtual.DayOfWeek)}, {dataAtual.Day} " +
    $"de {configLocais.DateTimeFormat.GetMonthName(dataAtual.Month)} de {dataAtual.Year} - {dataAtual:HH:MM:ss}";

...

Listagem 10: Exemplo envolvendo o uso de String Interpolation

Importante destacar ainda que o próprio Visual Studio 2015 já oferece o suporte do IntelliSense para a codificação de sequências de texto que empreguem String Interpolation. É o que demonstra a Imagem 4.


Imagem 4. Suporte a String Interpolation no Visual Studio 2015

Expressões mais complexas também podem ser utilizadas com o recurso String Interpolation. A Listagem 11 é uma variação do trecho de código anterior e exemplifica bem isto, sendo possível observar na mesma o uso do operador condicional “?” em uma verificação que indicará qual o semestre atual. A execução destas instruções produzirá como resultado uma tela similar à que consta na Imagem 5.

using System;
using System.Globalization;

namespace TesteStringInterpolation
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime dataAtual = DateTime.Now;
            CultureInfo configLocais = new CultureInfo("pt-BR");

            string mensagem =
                $"São Paulo, {configLocais.DateTimeFormat.GetDayName(dataAtual.DayOfWeek)}, {dataAtual.Day} " +
                $"de {configLocais.DateTimeFormat.GetMonthName(dataAtual.Month)} de {dataAtual.Year} - {dataAtual :HH:MM:ss}";
            Console.WriteLine(mensagem);

            Console.WriteLine(
                $"{dataAtual :dd/MMM/yyyy} - {(dataAtual.Month <= 6 ? 1 : 2)}º Semestre");

            Console.ReadKey();
        }
    }
}

Listagem 11: Um segundo exemplo do recurso String Interpolation


Imagem 5. Resultado da execução de um trecho de código que faz uso de String Interpolation

Conclusão

Neste post retomei, após um breve hiato, a apresentação de novos recursos do C# 6.0. Como já afirmado anteriormente, as alterações na linguagem não impõem mudanças drásticas no trabalho rotineiro dos desenvolvedores. De forma geral, tais atualizações buscam preencher lacunas oriundas de releases anteriores ou, até mesmo, oferecer alternativas visando simplificar a implementação de aplicações .NET.

Aproveito mais uma vez para agradecer o ótimo feedback que venho recebendo ao longo desta série. Embora planejasse 4 artigos, devo nos próximos dias liberar um quinto e último post encerrando esta discussão sobre C# 6.0 e recursos relacionados do Visual Studio 2015.

Até uma próxima oportunidade!

Links

A C# 6.0 Language Preview
http://msdn.microsoft.com/en-us/magazine/dn683793.aspx

Languages features in C# 6 and VB 14
https://roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status&referringTitle=Documentation

New Features in C# 6
http://blogs.msdn.com/b/csharpfaq/archive/2014/11/20/new-features-in-c-6.aspx

The New and Improved C# 6.0
http://msdn.microsoft.com/en-us/magazine/dn802602.aspx

What’s New In C# 6.0
http://channel9.msdn.com/Events/Visual-Studio/Connect-event-2014/116

Renato Groffe

Atua como consultor em atividades voltadas ao desenvolvimento de softwares há mais de 13 anos. Bacharel em Sistemas de Informação, com especialização em Engenharia de Software. Microsoft Certified Technology Specialist (Web, WCF, Distributed Applications, ADO.NET, Windows Forms), Microsoft Specialist (HTML5 with JavaScript and CSS3, Developing ASP.NET MVC 4 Web Applications), Oracle Certified Associate (PL/SQL), Sun Certified (SCJP, SCWCD), ITIL Foundation V2, Cobit 4.1 Foundation.

Facebook Google+ 

Comentários

comentarios