Para entender melhor sobre lambda e LINQ é necessário conhecimento em árvore binária e delegates ( ponteiro de função ), pois é o fundamento de uma expressão em LINQ.

Vamos criar um delegate para ilustrar um exemple de lambda.

 /// DEFINIÇÂO de uma função que recebe dois parâmetros e retorna um boleano

/// Verifica se são iguais

delegate bool Igual( int valor1, int valor2 );

//Cria uam variável do tipo função dizendo a implementação

Igual igualFunc = delegate(int valor1, int valor2) {

   return valor1 == valor2;

};

int var1, var2;

var1 = var2 = 1;

bool resultado = igualFunc.Invoke(var1, var2); //Chama a função

Console.WriteLine(“{0} = {1} ? {2}”, var1, var2, resultado);

Console.ReadKey();

O mesmo pode ser feito usando lambda expression, pois uma expressão lambda nada mais é que um delegate.A seguinte declaração é válida e é idêntica acima.

Foi declarada uma função que recebe dois valores e retorna um boleano comparando um com o outro.

Igual igualFunc2 = (valor1, valor2) => valor1 == valor2;

A chamada da expressão lambda pode ser feita da mesma forma como anteriormente.

igualFunc2.Invoke(var1,var2);  ou apenas igualFunc2(var1,var2);

Expressões em LINQ

Quando é feita uma expressão em LINQ, uma árvore binária de expressão é criada e depois compilada em tempo de execução antes da execução da expressão LINQ. Segue exemple abaixo:

(2 + (5 * 3)) + 1

A seguinte expressão pode ser representada em .net da seguinte forma.

Expression> exp = () => (2 + (5 * 3)) + 1;

Acima diz o seguinte: Quero uma variável do tipo expressão ( árvore ) do tipo função que não tem parâmetro e retorna um inteiro.

Como uma função pode ser expressa por uma lambda, podemos definir  () => (2 + (5 * 3)) + 1;

O parentese acima indica que a função não possui parâmetro.

Para obter o resultado da expressão, precisamos compilar e chamar o método.
var valor = exp.Compile()();  ou  var valor = exp.Compile().Invoke();

Com uma variável do tipo expressão, é possível navegar pelos nós da árvore, porém nunca edita-los.

Para isto é necessário recriar a árvore com os nós editados.

var noRoot = exp.Body; //Recupera o nó root da árvore. Neste caso retorna o operador de soma ( + ). noRoot.NodeType retorna o tipo de nó. No caso nó de adição.

var parameters = exp.Parameters; //Retorna os parâmetros da expressão lambda. Neste caso não há parâmetros. No primeiro exemplo dois parâmetros do tipo inteiro seriam retornados.

var returnType = exp.ReturnType; //Recupera o tipo de retorno da árvore ou da expressão lambda.

Uma árvore de expressões possui os métodos Left e Right para navegar entre os nós da árvore quando o nó é do tipo BinaryExpression.

Existem diversos tipos de nó para se criar uma expressão LINQ.

ConstantExpression é um tipo de nó que define um valor constante. Um valor inteiro, por exemplo.

AddExpression define um nó de adição.

OrExpression define um nó do tipo operador lógico. Da mesma forma funciona o AndExpression.

Uma expressão também pode ser montada dinâmicamente.

            var constExp = Expression.Constant(1, typeof(int));

            var exp2 = Expression.Lambda>(constExp, new ParameterExpression[] { });

Neste exemplo acima, é uma árvore com apenas um nó do tipo constante que é um inteiro com valor 1.

Se chamar exp2.Compile().Invoke(), o valor da expressão será 1 como resultado.