É possível declarar uma função lambda e chamá-la imediatamente:
Func<int, int> lambda = (input) => { return 1; };
int output = lambda(0);
Gostaria de saber se é possível fazê-lo em uma linha, por exemplo, algo como
int output = (input) => { return 1; }(0);
que fornece um erro do compilador "Nome do método esperado". A transmissão para Func<int, int>
também não funciona:
int output = (Func<int, int>)((input) => { return 1; })(0);
dá o mesmo erro e, pelos motivos mencionados abaixo, gostaria de evitar precisar especificar explicitamente o tipo de argumento de entrada (o primeiro int
).
Você provavelmente está se perguntando por que eu quero fazer isso, em vez de apenas incorporar o código diretamente, por exemplo int output = 1;
. O motivo é o seguinte: Gerei uma referência para um serviço da web SOAP com o svcutil
qual, por causa dos elementos aninhados, gera nomes de classe extremamente longos, que eu gostaria de evitar de digitar. Então, ao invés de
var o = await client.GetOrderAsync(request);
return new Order {
OrderDate = o.OrderDate,
...
Shipments = o.Shipment_Order == null ? new Shipment[0]
o.Shipment_Order.Select(sh => new Shipment {
ShipmentID = sh.ShipmentID,
...
Address = CreateAddress(sh.ReceiverAddress_Shipment);
}).ToArray()
};
e um CreateAddress(GetOrderResultOrderShipment_OrderShipmentShipment_Address address)
método separado (nomes reais são ainda maiores e eu tenho um controle muito limitado sobre o formulário), gostaria de escrever
var o = await client.GetOrderAsync(request);
return new Order {
OrderDate = o.OrderDate,
...
Shipments = o.Shipment_Order == null ? new Shipment[0]
o.Shipment_Order.Select(sh => new Shipment {
ShipmentID = sh.ShipmentID,
...
Address = sh.ReceiverAddress_Shipment == null ? null : () => {
var a = sh.ReceiverAddress_Shipment.Address;
return new Address {
Street = a.Street
...
};
}()
}).ToArray()
};
Eu sei que eu poderia escrever
Address = sh.ReceiverAddress_Shipment == null ? null : new Address {
Street = sh.ReceiverAddress_Shipment.Address.Street,
...
}
mas mesmo isso (a sh.ReceiverAddress_Shipment.Address
parte) se torna muito repetitivo se houver muitos campos. Declarar um lambda e chamá-lo imediatamente seria mais elegante, menos caracteres para escrever.
int output = ((Func<int>) (() => { return 1; }))();
public T Exec<T>(Func<T> func) => return func();
e usá-lo assim:int x = Exec(() => { return 1; });
isso para mim é muito melhor do que o elenco com todas as suas características.Respostas:
Em vez de tentar converter o lambda, proponho que você use uma pequena função auxiliar:
que você pode então usar assim:
int x = Exec(myVar => myVar + 2, 0);
. Isso me parece muito melhor do que as alternativas sugeridas aqui.fonte
É feio, mas é possível:
Você pode transmitir, mas o lambda precisa estar entre parênteses.
O acima pode ser simplificado também:
fonte
int output = (Func<int>)(() => { return 1; })();
mas o elenco tem prioridade mais baixa que a execução lambda.Literais lambda em C # têm uma curiosa distinção, pois seu significado depende de seu tipo. Eles são essencialmente sobrecarregados em seu tipo de retorno que é algo que não existe em nenhum outro lugar no C #. (Literais numéricos são um pouco semelhantes.)
O mesmo literal lambda literal pode ser avaliado para uma função anônima que você pode executar (ou seja, um
Func
/Action
) ou uma representação abstrata das operações dentro do Body, como uma Árvore de Sintaxe Abstrata (por exemplo, uma Árvore de Expressão LINQ).O último é, por exemplo, como o LINQ to SQL, o LINQ to XML etc. funciona: as lambdas não avaliam o código executável, avaliam as Árvores de Expressão do LINQ e o provedor LINQ pode então usá-las para entender o que os corpo do lambda está fazendo e gera, por exemplo, uma consulta SQL a partir disso.
No seu caso, não há como o compilador saber se o literal lambda deve ser avaliado como uma
Func
Expressão ou LINQ. É por isso que a resposta de Johnathan Barclay funciona: ela fornece um tipo para a expressão lambda e, portanto, o compilador sabe que você deseja umFunc
código compilado que execute o corpo da sua lambda em vez de uma Árvore de Expressão LINQ não avaliada que representa o código dentro o corpo da lambda.fonte
Você pode embutir a declaração do
Func
fazendoe invocando-o imediatamente.
fonte
Você também pode criar o alias no
Select
métodoou com o
??
operadorfonte
Se você não se importa de violar algumas das diretrizes de design dos métodos de extensão, os métodos de extensão combinados com o operador nulo-condicional
?.
podem levar você razoavelmente longe:lhe dará o seguinte:
e se você precisar de matrizes, substitua o
ToArray
método de extensão para encapsular mais algumas chamadas de método:resultando em:
fonte