No post anterior eu comentei sobre algumas das possíveis funcionalidades da próxima versão do C#.
No evento Build 2014 (que ocorreu algumas semanas atras) a MS confirmou algumas destas funcionalidades bem como apresentou algumas que eu não tinha conhecimento (e que realmente gostei). Abaixo segue uma discussão das mesmas, começando por aquela que mais me animou:
Projeto Roslyn
A MS não apensas confirmou que a próxima versão dos compiladores C#/VB.Net serão baseados neste projeto, como surpreendeu muita gente ao anunciar que o mesmo agora é um projeto open source! Isso mesmo, você ouviu correto. Você já pode baixar o código fonte e ver com seus próprios olhos (inclusive muitas das funcionalidades anunciadas para a próxima versão do C# já funcionam com o compilador implementado baseado neste projeto).Com esta abertura, subtamente, um monte de informação se tornou disponível. Por exemplo, você pode ver aqui a lista completa de funcionalidades para a próxima vesão do C# / VB.NET.
Apesar de, na minha opnião, baixar o código fonte e estudar o mesmo seja o caminho para aprender sobre o Roslyn, caso você não tenha tido contato com o mesmo anteriormente eu recomendo baixar/instalar o End user preview (na minha opnião, um caminho muito mais simples).
Propriedades automaticas (somente leitura)
Implementado; a medida que eu uso mais estes novos recursos eu gosto cada vez mais dos mesmos! :) Veja o exemplo abaixo (especial atenção à linha 3):class Test(string name)
{
public string Name { get; } = name;
public static void Main(string[] args)
{
System.Console.WriteLine(new Test(args[0]).Name);
}
}
“Primary Constructors”
Melhor do que eu esperava. Não apenas o comportamento dos parâmetros definidos em primary constructors obedecem as regras de escopo atuais como também é possível obter o resultado que eu propus no post anterior, ou seja, o conceito de “campos automáticos”. Veja o exemplo abaixo:class Example (private int value, string n)
{
private string name = n;
public static void Main(string[] args)
{
new Example(42, "foo").Print();
}
private void Print()
{
System.Console.WriteLine("{0} = {1}", name, value);
}
}
Observe que o campo value (usado na linha 12) nunca foi declarado explicitamente (pelo menos não usando-se a sintaxe tradicional)“using” para membros estáticos (ou static using)
Lembra-se que eu comentei que não fiquei muito empolgado com esta funcionalidade? Pois é, depois de usá-lo bastante (ao escrever os exemplos deste post) estou começando a mudar de idéia ;)Declaração inline para parâmetros out
Mais um uau! Acontece que meu entendimento da funcionalidade estava incorreta! Na realidade o nome correto da mesma é “declaration expressions” (desculpa, não sei uma boa tradução sem entrar em detalhes sobre conceitos de compiladores, o que não é meu objetivo neste post - além de não conhecer o assunto o suficiente).Na prática, nesta nova versão, podemos declarar variáveis, por exemplo, na expressão de testes de if s, for s, etc.
Veja o exemplo abaixo:
using System.IO;
using System.Console;
class Test
{
public static void Main(string[] args)
{
if (args.Length == 0)
{
WriteLine("arquivo?");
return;
}
using(var arq = File.OpenText(args[0]))
{
while ( (var line = arq.ReadLine()) != null )
{
WriteLine("> {0}", line);
}
}
}
}
Note que na linha 16 declaramos a variável line na expressão de teste do bloco while!Como sempre, quando bem utilizado, este recurso tem o potencial de eliminar “ruido” do código.
Funcionalidades que eu não estava ciente (e não comentei no post anterior)
Separadores em literais e constantes binárias
Ok, essa é mais uma “me too” copiado do Java ;)Confesso que torci o nariz quando vi a funcionalidade implementada no Java, mas após usá-la algumas vezes acabei me convencendo da conveniência da mesma (infelizmente não esta implementado nesta preview ainda).
Basicamente, agora podemos usar o separador _ em valores de constantes além de declaras constantes binárias. Veja o exemplo:
class Test
{
public static void Main(string[] args)
{
var value = 0xDEAD_BEEF;
var bin = 0b00000100;
}
}
Exception Filters
Na versão corrente do C# (5.0), cenários que demandam tratamento específico de exceções baseados em dados da mesma acabam sendo um tanto quanto difíceis. Imagine o exemplo abaixo:class Example
{
public void M()
{
try
{
}
catch(MyException me)
{
if (me.SomeProp == some_value)
{
// trata a exceção aqui
}
else
{
throw;
}
}
}
}
O if dentro do bloco catch (linha 10) tem como único objetivo filtrar exceções baseado no valor de uma propriedade. A partir da versão 6.0 do C# a seguinte sitaxe é válida:class Example
{
public static void Main()
{
try
{
}
catch(MyException me) if (CheckException(me))
{
// trata a exceção aqui
}
}
private static bool CheckException(MyException ex)
{
return ex.SomeProp == 42;
}
}
class MyException : System.Exception
{
public int SomeProp;
}
Eu, particularmente gostaria de poder usar uma sintaxe mais parecida com a declaração de uma expressão lambda:class Example
{
public static void Main()
{
try
{
}
catch(MyException me => me.SomeProp == 42)
{
// trata a exceção aqui
}
}
}
class MyException : System.Exception
{
public int SomeProp;
}
Membros indexados
Esta funcionalidade tem como objetivo simplificar o processo de inicialização de tipos que sobrecarregam o operador de indexação [] introduzindo uma sintaxe alternativa, mais natural em alguns cenários:using System.Collections.Generic;
using System.Console;
class Example
{
private IDictionary<string, int> data = new Dictionary<string, int>();
public int this[string i]
{
get { return data[i]; }
set { data[i] = value ; }
}
public static void Main(string[] args)
{
var dic2 = new Dictionary<int, string>()
{
{0, "nada" },
{1, "uno" }
};
var dic = new Dictionary<int, string>() { [0] = "nada", [1] = "uno" };
var inst = new Example { $zero = 0, $one = 1, $two = 2 };
WriteLine("Hello World from roslyn! {0} {1}", inst.$zero, inst["zero"]);
}
}
Outro ponto positivo é que esta sintaxe é válida também na inicialização de objetos.Note que, além da sintaxe simplificada quando o operador de indexação utiliza strings, também pode-se utilizar a sintaxe de indexadores (quando a chave não é string).
Recurso muito bem vindo em minha opinião.
Extension “Add” Methods em inicializadores de coleções
Caso você nunca tenha usado “collection initializers” em seus programas veja o exemplo abaixo:
using System.Collections;
class Coll : IEnumerable
{
public void Add(string s)
{
System.Console.WriteLine(s);
}
public IEnumerator GetEnumerator() { return null; }
}
class Test
{
public static void Main(string[] args)
{
var x = new Coll()
{
"foo",
"bar",
"baz"
};
}
}
A existência do método Add() (linhas 5 ~ 8) (bem como implementar IEnumerable) é uma condição indispensável para que a syntaxe de “Collection Initializers” (linhas 17 ~ 22) possa ser utilizada. Até a versão 5.0 (inclusive) do C# este método tinha que, obrigatóriamente, ser um método na hierarquia da classe.A partir da versão 6.0 do C# Extension Methods também são suportados:
using System.Collections;
static class Extensoes
{
public static void Add(this Coll coll, string s)
{
System.Console.WriteLine(s);
}
}
class Coll : IEnumerable
{
public IEnumerator GetEnumerator() { return null; }
}
class Test
{
public static void Main(string[] args)
{
var x = new Coll()
{
"foo",
"bar",
"baz"
};
}
}
Outras funcionalidades planejadas
Dentre as funcionalides comentadas no post anterior que ainda não foram implementadas mas que estão planejadas podemos citar:- Property Expressions / “Method expressions”: Na documentação do projeto aparecem com o nome de Expression-bodied members.
- Enumerables como parâmetros do tipo “params”
- Inferência de tipos a partir de parêmtros de construtores
Você pode ver a lista completa das funcionalidades planejadas / já implementadas para as próximas versões do C#/VB.NET nestes links.
O que você acha? (eu, particularmente, estou entusiasmado com o futuro da plataforma .Net!)
No comments:
Post a Comment