Algumas novidades do C# 6 - Delegado Anônimo
Piadinha

Algumas novidades do C# 6

Mais meio tom para cima

Postado por Marcelo Palladino em 02-01-2015

Auto Property initializers

O C# 3 trouxe um recurso muito interessante chamado Auto Property. Seu objetivo era facilitar a criação daquele tipo de propriedade que apenas expõe um estado. Antes das propriedades auto implementadas era comum códigos como o fragmento abaixo.

 1 class Charp2Entity
 2 {
 3     private Guid _id;
 4 
 5     public Guid Id
 6     {
 7         get { return _id; }
 8         protected set { _id = value; }
 9     }
10 }

Este mesmo código com a propriedade auto implementada fica mais expressivo, deixando para o código gerado pelo compilador a parte meramente burocrática de utilizar uma variável ali.

1 public Guid Id { get; protected set; }

Bem melhor, não é? Agora digamos que esta propriedade tivesse um valor inicial. Para inicializá-la, tinhamos que implementar um construtor para fazer o serviço.

1 class Charp3Entity
2 {
3     public Charp3Entity()
4     {
5         Id = Guid.NewGuid();
6     }
7 
8     public Guid Id { get; protected set; }
9 }

O C# 6 trouxe um recurso para facilitar este trabalho. A ideia é fornecer uma forma mais fluída de inicializar propriedades auto implementadas, novamente deixando a parte burocrática para o código gerado pelo compilador.

1 class Charp6Entity
2 {
3     public Guid Id { get; protected set; } = Guid.NewGuid();
4 }

BEEEEMMMM melhor, hein! Apesar de ser um simples açucar sintático, quando analisamos historicamente vemos claramente que a linguagem proporcionou que o código ficasse bem mais expressivo com o tempo, não é?

Vale ressaltar que este tipo de inicialização também funciona muito bem com propriedades somente leitura.

1 class Charp6Entity
2 {
3     public string Tip { get; } = "Getter-only auto-properties also works...";
4 }

Estruturas com construtores sem parâmetros

Até esta versão, não era possível declarar um construtor sem parâmetros em uma estrutura. No C# 6 isso é plenamente possível.

1 struct Cpf
2 {
3     public Cpf()
4     {
5         IsValid = false;
6         Number = string.Empty;
7     }
8 }

Para entender este recurso é primordial pensar um pouco sobre o código abaixo vai funcionar:

1 var cpf = default(Cpf);

Isso cria uma instância da estrutura sem a necessidade de passar os parâmetros. Ou seja, até aqui não tinhamos como declarar um construtor padrão para estruturas em c#, o que nos impedia de ter uma forma alternativa de criar uma instância da estrutura sem passar todos os parâmetros. O que temos no c# 6 é uma maneira de dizer na estrutura como ela deve ser inicializada sem os parâmetros.

é importante ter mente que default(T) continua com o mesmo comportamento de antes. Ele não vai desencadear uma chamada para seu construtor sem parâmetros.

Dictionary initializers

Se não me engano, também foi o C# 3 que trouxe uma forma mais simples de inicializar um dictionary.

 1 class Charp2Style
 2 {
 3     public Charp2Style()
 4     {
 5         Dictionary<string, Person> kids = new Dictionary<string, Person>();
 6         kids.Add("1", new Person("Lucas"));
 7         kids.Add("2", new Person("Caio"));
 8     }
 9 
10 }
 1 class Charp3Style
 2 {
 3     public Charp3Style()
 4     {
 5         var simpleDictionary = new Dictionary<string, Person>
 6         {
 7             { "1", new Person("Lucas") },
 8             { "2", new Person("Caio") }
 9         };
10     }
11 }

Assim como nas propriedades auto implementadas, a inicialização de dicionários também ficou mais expressiva no c# 6.

 1 class Charp6Style
 2 {
 3     public Charp6Style()
 4     {
 5         var simpleDictionary = new Dictionary<string, Person>
 6         {
 7             ["1"] = new Person("Lucas"),
 8             ["2"] = new Person("Caio")
 9         };
10     }
11 }

Desta vez o nÚmero de caracteres envolvidos não mudou. Apenas trocamos o par de chaves pelo pelos colchetes que definem a chave do item no dicionário. No entanto, para quem olha o código fica bem mais claro que estamos trabalhando com um dicionário.

Utilizando membros de classes estáticas

Considere a utilização do método estático no código abaixo.

 1 namespace csharp6news
 2 {
 3     using System;
 4 
 5     class UsingStaticMembers
 6     {
 7         class BeforeCSharp6Style
 8         {
 9             public BeforeCSharp6Style()
10             {
11                 Console.WriteLine("Linha 1");
12                 Console.WriteLine("Linha 2");
13                 Console.WriteLine("Linha 3");
14             }
15         }
16     }
17 }

No C# 6 existe a possibilidade de declarar o tipo estático com using com a finalidade de suprimir seu nome no momento da utilização do membro estático.

 1 namespace csharp6news_1
 2 {
 3     using System.Console; //key point...
 4 
 5     class UsingStaticMembers
 6     {
 7         class CSharp6Style
 8         {
 9             public CSharp6Style()
10             {
11                 WriteLine("Linha 1");
12                 WriteLine("Linha 2");
13                 WriteLine("Linha 3");
14             }
15         }
16     }
17 }

Me parece que o ponto aqui é escrever menos código. No entanto, eu, particularmente, pretendo ter um pouco de cautela para jogar este açucar no meu código. Pensando sobre isso e baseado em nada (é sempre importante dizer), acho que remover o contexto da chamada do método tem potencial para tornar o código mais obscuro e difícil de entender. Classes puramente estáticas para mim já são consideradas um mal sinal. Podem existir situações nas quais elas são Úteis, mas já me deparei com alguns exemplos nos quais estas classes eram bolsões de métodos de tudo que é tipo.

Vou extrapolar para um exemplo meio radical aqui, mas vai servir para mostrar o meu receio quanto à utilização desmedida desse recurso. Vejamos uma aplicação de um Factory clássico.

 1 namespace csharp6news_1
 2 {
 3     interface IComposer
 4     {
 5     }
 6 
 7     class Composer : IComposer
 8     {
 9         public Composer(string name)
10         {
11             Name = name;
12         }
13 
14         public string Name { get; private set; }
15     }
16 
17     static class ComposerFactory
18     {
19         public static IComposer Create()
20         {
21             return new Composer("Wolfgang Amadeus Mozart");
22         }
23     }
24 }

Sua utilização poderia ficar assim:

 1 namespace csharp6news_1
 2 {
 3     using ComposerFactory; //importando a classe estatica
 4 
 5     class UsingStaticMembers
 6     {
 7         class CSharp6Style
 8         {
 9             public CSharp6Style()
10             {
11                 var c = Create();
12             }
13         }
14     }
15 }

Tá, eu apelei e declarei a variável de uma forma que dado o nome do método, fica impossível saber o que Create está retornando. Agora, quem nunca viu uma variável declarada assim? Pode ser besteira minha, coisa de velho rabugento e/ou falta de contexto para entender melhor isso, mas inicialmente não curti tanto assim.

Null propagation

Para compensar minha ‘rabugice’ em relação à importação de tipos estáticos, vamos falar sobre este ótimo recurso (um dos mais votados no user's voice) que veio com a versão 6 do C#. Considere o código abaixo.

1 string OldStyle()
2 {
3     if (_person != null && _person.Address != null)
4         return _person.Address.ToString();
5 
6     return string.Empty;
7 }

Agora considere a mesma coisa sendo feita com null propagation:

1 string CSharp6Style()
2 {
3     return _person?.Address?.ToString() ?? string.Empty;
4 }

Percebeu a utilização do "?."? Isso substitui aquele "if" burocrático. Muito mais limpo, não é? Novamente se trata de deixar a burocracia para o código gerado pelo compilador. Obviamente não existe mágica. O código que faz as checagens está lá. Basta verificar em qualquer descompilador de .NET.

 1 private string CSharp6Style()
 2 {
 3     NullPropagation.Person person = this._person;
 4     string str;
 5     if (person == null)
 6     {
 7         str = (string) null;
 8     }
 9     else
10     {
11         NullPropagation.Address address = person.Address;
12         str = address != null ? address.ToString() : (string) null;
13     }
14     return str;
15 }

Bom, ainda restam algumas coisas para dizer sobre este tema, algo que provavelmente vai ser feito em um artigo futuro. Vale dizer também que a lista de recursos para o C# 6 ainda não está fechada e você pode acompanhar seu status aqui.

Até mais!

Código fonte utilizado no artigo