Thursday, August 14, 2008 3:38 PM

Não tenho dúvidas de que o C# é a linguagem que melhor evoluiu nos últimos anos. No entanto, são tantas mudanças e novidades que às vezes fica difícil acompanhar e aplicá-las no dia-a-dia.

Por exemplo, desde o C# 2.0, a linguagem vem sendo influenciada por conceitos de linguagem funcional. Estas novidades têm impacto na forma como escrevemos nosso código, nos constructors que utilizamos. E isto não muda de um dia para outro.

Por isto resolvi fazer algumas brincadeiras com C# para mostrar novas possibilidades na forma de programar já oferecidas pela linguagem. Vou começar com C# 2.0, sem as novidades do 3.5 e depois evoluir os exemplos.

High order function é um conceito típico da programação funcional: São funções que recebem uma ou mais funções como parâmetro ou retornam uma função. Para explicar melhor vou implementar alguns exemplos clássicos de high order functions: Filter, Map e Fold.

Filter

Um filtro processa uma coleção de objetos, filtrando-a de acordo com uma regra de decisão. Vamos considerar um exemplo simples, mas funcional, preciso filtrar de uma coleção de clientes todos que residem no estado do Pará. A implementação mais simples para resolver este problema seria:

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    List<Cliente> resultado = new List<Cliente>();

    foreach (Cliente cliente in clientes)
    if (cliente.Estado.Equals("Para"))
        resultado.Add(cliente);

    return resultado;
}

No dia seguinte preciso filtrar todos os clientes cujo nome começa com “P”. Posso utilizar a velha técnica de reuso de código conhecida como Ctrl+C, Ctrl+V. Todavia, estamos aqui para escrever código de qualidade, então esta opção não é aceitável. Para tornar este método reutilizável, preciso identificar o que pode ser reaproveitado e o que deve ser mutável.

Figura2

 

 

 

 

 

 

Tudo que está rachurado é código necessário e repetido para qualquer filtro sobre um cliente. É preciso criar uma nova lista de clientes, iterar sobre a lista atual, adicionar os escolhidos na nova lista e retorná-la ao final. O único trecho que muda é o algoritmo de decisão se o cliente entra ou não na nova lista.

O problema é que este algoritmo é uma função, que retorna um boleano, ou seja, preciso de uma função high-order, que recebe como parâmetro uma função. A forma de fazer isto em C# é utilizando delegate. Delegates permitem a passagem de uma função, com uma determinada assinatura, para outra função. Então vou: Abstrair a lógica de filtro para uma nova função, chamada FiltraClientes, que recebe a lista de clientes e o delegate da função de decide se o cliente é filtrado ou não; Criar este delegate, que recebe um cliente e retorna um boleano; e abstrair a lógica de filtro em um método que segue a assinatura deste delegate. Veja como ficou:

delegate bool Predicate(Cliente cliente);

private bool ClienteResideNoPara(Cliente cliente)
{
    return cliente.Estado.Equals("Pará");
}

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    return FilterClientes(clientes, ClienteResideNoPara);
}

private List<Cliente> FilterClientes(List<Cliente> clientes, Predicate filter)
{
    List<Cliente> resultado = new List<Cliente>();

    foreach (Cliente cliente in clientes)
        if (filter(cliente))
            resultado.Add(cliente);

    return resultado;
}

Para finalizar utilizo o generics e a interface IEnumerable para tornar tudo independente do tipo da coleção e do objeto, ou seja filtro qualquer coleção de objetos, não interessa o seu tipo.

delegate bool Predicate<T>(T item);

private bool ClienteResideNoPara(Cliente cliente)
{
    return cliente.Estado.Equals("Pará");
}

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    return (List<Cliente>) Filter(clientes, ClienteResideNoPara);
}

private IEnumerable<T> Filter<T>(IEnumerable<T> collection, Predicate<T> filter)
{
    List<T> resultado = new List<T>();

    foreach (T item in collection)
        if (filter(item))
            resultado.Add(item);

    return resultado;
}

Na próxima vou fazer o mesmo exercício para o Map. Aguardem

< Exemplos >

Comments

At 8/14/2008 4:34 PM, Bruno Feliciano said:

# re: Brincando com C#

Bela metodologia Eduardo

um exemplo simples e direto mas que diz muita coisa =)

No aguardo das novas "brincadeiras"...
At 8/14/2008 11:45 PM, João Carlos Clementoni said:

# re: Brincando com C#

Legal,

Bem didático.
Post Comment
Title *
Name *
Email (never displayed)
Website
Comment * (Allowed tags: blockquote, a, strong, em, p, u, strike, super, sub, code)  
Please add 1 and 1 and type the answer here: