Welcome to GASP Sign in | Join | Help

Paulo Morgado

Tudo sobre Arquitectura de Software

Localização dos Visitantes

  • Localização dos Visitantes

Livros

  • LINQ com C#

Eventos

Renûncia

As opiniões e pontos de vista expressos neste sítio são minhas e podem não reflectir as da Microsoft, do meu empregador, ou de qualquer comunidade a que pertença. Qualquer código ou opinião é oferecido sem qualquer garantia. Os produtos ou serviços mencionados são comprados por mim, disponibilizados pelo meu empregador ou pelo fabricante/vendedor o que não influencia em nada a minha opinião.

Esticando a inferência de tipos

Nota: Código em itálico não corresponde à sintaxe do C# 3.0.

Inferência do tipo de variáveis locais

O C# 3.0 trouxe-nos a possibilidade da inferência do tipo de uma variável local, cujo principal objectivo foi suportar o LINQ. O resultado de uma consulta (query) pode ser uma implementação de IEnumerable<T> ou IQueryable<T> uma instância de T onde T pode ser uma projecção, o que implica que T é um tipo anónimo.

Tomemos a consulta seguinte como exemplo:

from p in persons
select new { Name = p.FirstName + " " + p.LastName, Age = p.Age };

Se persons for uma implementação de IEnumerable<Person>, o resultado da consulta será uma implementação de IEnumerable<T> onde T é um tipo anónimo.

Coloca-se então uma questão: Como é que declaramos uma variável para receber o resultado da consulta?

A solução encontrada foi a introdição da nova palavra-chave var que instrui o compilador para determinar o tipo do resultado da consulta. Sendo assim, tudo é que é ncessário para declarar uma variável para receber  resultado da consulta é:

var q =
    from p in persons
    select new { Name = p.FirstName + " " + p.LastName, Age = p.Age };

Uma vez que o compilador consegue inferir o tipo de algo que arece tão complexo, é óbvio que será capaz de inferir o tipo de algo tão simples directo como:

var v = new Dictionary<Point, Stack<Person>>();

Obviamente, é o mesmo que:

Dictionary<Point, Stack<Person>> v = new Dictionary<Point, Stack<Person>>();

com menos digitação e menor margem para erros de digitação.

Inferência do tipo de campos

A mesma técnica poderia ser aplicada à inferência do tipo de campos:

class Class
{
    private someDicionary = new Dictionary<string, List<string>>();

    // ...
}

com os mesmos benefícios de menos digitação e menor margem para erros de digitação.

Se a inferência do tipo de campos fosse aplicada a campos públicos, deveria ser aplicado o seguinte constrangimento: o tipo inferido não pode ser ou ter como parâmtero um tipo anónimo.

Mas eu não recomendaria o seu uso porque facilmente uma simples modificação na inicialização do campo poderia trazer alterações menos óbvias à interface pública da classe.

Inferência do tipo de parâmetros e retorno de métodos

Dado que a inferência de tipos seria possível fora de métodos, deveria ser permitida em parâmetros e valores de retorno? Algo como isto:

class SomeClass
{
    private listOfStuff = new List<Stuff>();

    public void DoIt()
    {
        if (CreateList(out this.listOfStuff))
        {
            ProcessList(ref this.listOfStuff);

            this.listOfStuff = TransformList(this.listOfStuff);
        }
    }

    private bool CreateList(var out list)
    {
        list = new List<Stuff>();
        return true;
    }

    private void ProcessList(var ref list)
    {
        // ... 
    }

    private var TransformList(var list)
    {
        return list;
    }
}

que tem um aspecto algo estranho e confuso, no mínimo. Não deveríamos ir por aí.

Inferência de construtores

Desde o meu primeiro contacto com a inferência do tipo de variaveis locais que tenho a sensação de que se poderia ter ido mais longe.

Olhemos para este conjunto hipotético de declarações:

Dictionary<Point, Stack<Person>> v = new();
Point p = new(1, 2);

Será fácil, tanto para o compilador como para um humano que leia o código, determinar que é o mesmo que:

Dictionary<Point, Stack<Person>> v = new Dictionary<Point, Stack<Person>>();
Point p = new Point(1, 2);

E isto pode ser mais poderoso que a inferência do tipo de variáveis locais e usado em mais cenários:

class Class
{
    private Dictionary<string, List<string>> someDicionary = new();
    private Point p;

    public Class()
    {
        this.p = new(1, 1);
    }

    public void SomeMethod()
    {
        AnotherMethod(new());
    }

    private void AnotherMethod(List<string> arg)
    {
        // ...
    }
}
Onde parar?

O compilador poderia com igual facilidade inferir o tipo da variável local neste caso:

public void SomeMethod()
{
    var v = new();
    AnotherMethod(v);
}

Queremos ir por aí? Não me parece.

Ambiguidades

O C# 3.0 trouxe-nos também inicializadores de objectos. Em vez disto:

XmlReaderSettings settings = new XmlReaderSettings();
settings.CheckCharacters = false;
settings.IgnoreWhitespace = true;

XmlReader reader = XmlReader.Create("someURI", settings);

podemos apenas escrever isto:

XmlReaderSettings settings = new XmlReaderSettings() { CheckCharacters = false, IgnoreWhitespace = true };

XmlReader reader = XmlReader.Create("someURI", settings);

ou isto:

XmlReader reader = XmlReader.Create("someURI"new XmlReaderSettings() { CheckCharacters = false, IgnoreWhitespace = true });

Não seria bom escrever apenas isto?

XmlReaderSettings settings = new() { CheckCharacters = false, IgnoreWhitespace = true };

Os inicializadores de objectos do C# 3.0 também permitem omitr os parentesis do construtor:

XmlReaderSettings settings = new XmlReaderSettings { CheckCharacters = false, IgnoreWhitespace = true };

que levaria a:

XmlReaderSettings settings = new { CheckCharacters = false, IgnoreWhitespace = true };

que tem a mesma forma que a criação de um objecto de um tipo anónimo e poderia causar algumas ambiguidades.

Mas seria bom escrever apenas isto:

XmlReader reader = XmlReader.Create("someURI", new { settings.CheckCharacters = false, settings.IgnoreWhitespace = true });

Não seria?

Posted: Monday, April 28, 2008 12:09 AM by Paulo Morgado

Comments

Raphael, MagoDigital said:

Cara realmente você mostrou varias ideais que pelo visto seria possível a implementação. Quem sabe talvez isso apareça em uma nova versão!

# April 28, 2008 12:21 PM

Paulo Morgado said:

Algumas seriam muito perigosas porque levariam a ambiguidades. Tem de ser uma escolha muito responsável.

# April 28, 2008 2:39 PM
Anonymous comments are disabled