quarta-feira, 20 de maio de 2009

Novidades do C# 4.0

Estava vendo este artigo (http://software.intel.com/en-us/blogs/2009/03/30/the-c-programming-language-version-40/) que mostra as novidades que serão implementadas no C# 4.0, que chegará em 2010 juntamente com a nova versão do .NET e do Visual Studio.

A primeira delas é a criação de tipos dinâmicos, declarados através da keyword dynamic. Objetos deste tipo permite invocarmos seus métodos diretamente sem a necessidade de sabermos o seu tipo, ou seja, como se fosse um object onde teríamos que usar reflection para executar um método. Por exemplo, suponhamos que tenhamos um método GetCalculator() que nos retorna um object, sendo que este object pode ser um COM+ ou um tipo carregado de um assembly .NET qualquer. Sabemos que este object possui um método Add(int a, int b) que retorna um inteiro. Atualmente para executarmos este método, precisamos utilizar reflection. O código ficaria da seguinte forma:

object calculator = GetCalculator();
Type type = calculator.GetType();

int result = (int)type.InvokeMember("Add",
BindingFlags.InvokeMethod,
null,
calculator,
new object[] { 10, 20 });


Já utilizando o dynamic, isto poderia ser feito da seguinte forma:

dynamic calculator = GetCalculator();
int result = calculator.Add(10, 20);


Claro que este tipo de implementação tem seus problemas, principalmente em relação a performance por utilizar reflection e para a verificação do código, pois os erros só são descobertos em tempo de execução. Mas de qualquer jeito, é uma forma mais elegante de se escrever código dinâmico pois não usa uma string para invocar o método.

Outra novidade interessante são os optional parameters que permite que valores default sejam atribuídos a parâmetros dos métodos, de forma a criar overloads automaticamente sem a necessidade de explicitar cada assinatura do overload do método. Ou seja, ao invés de fazer isso:

public int ExecuteOperation(Operation operation, int a)
{
return ExecuteOperation(operation, a, 0, 0);
}

public int ExecuteOperation(Operation operation, int a, int b)
{
return ExecuteOperation(operation, a, b, 0);
}

public int ExecuteOperation(Operation operation, int a, int b, int c)
{
// TODO: Implementação do método
throw new NotImplementedException();
}

O C# 4.0 nos permite fazer isso:

public int ExecuteOperation(Operation operation, int a, int b = 0, int c = 0)
{
// TODO: Implementação do método
throw new NotImplementedException();
}


E caso o programador queira, no exemplo acima, não especificar o valor de b mas especificar o de c, ele invoca o método da seguinte forma:

calculator.ExecuteOperation(Operation.Add, 1, c: 3);

O último recurso é a suporte da linguagem para a covariância e contravariância para generics. Códigos como do exemplo abaixo serão possíveis:

IEnumerable<string> names = new List<string>();
IEnumerable<object> objects = names;


No sentido inverso também será possível:

IEnumerable<object> objects = new List<object>();
IEnumerable<string> names = objects;

Com isso, suponha que exista um método com a seguinte assinatura:

public void Write(List<object> objects)
{
// TODO: Implementação do método
}


Poderemos passar como parâmetro um objeto do tipo List<string>.

Para isso tudo isso ser possível, é necessário especificar na classe genérica que a covariância e contravariância é possível, utilizando as keywords in e out, da seguinte forma:

public interface IEnumerator<out T>
{
T Current { get; }
bool MoveNext();
}

Neste caso, a palavra out indica que é seguro receber um objeto mais especializado (string) e tratá-lo como menos especializado (object), pois neste caso a interface indica ações de somente leitura para T, tornando-a covariante. A contravariância é explicitada com a keyword in:

public interface IComparer<int T>
{
int Compare(T x, T y);
}

Que afirma que é possivel receber como T um tipo menos especializado (object) e tratá-lo como mais especializado (string) como segurança, tornando a interface contravariante.