Es posible declarar una función lambda e inmediatamente llamarla:
Func<int, int> lambda = (input) => { return 1; };
int output = lambda(0);
Me pregunto si es posible hacerlo en una línea, por ejemplo, algo como
int output = (input) => { return 1; }(0);
que da un error del compilador "Nombre del método esperado". Lanzar a Func<int, int>
tampoco funciona:
int output = (Func<int, int>)((input) => { return 1; })(0);
da el mismo error y, por las razones mencionadas a continuación, me gustaría evitar tener que especificar explícitamente el tipo de argumento de entrada (el primero int
).
Probablemente se esté preguntando por qué quiero hacer esto, en lugar de simplemente incrustar el código directamente, por ejemplo int output = 1;
. La razón es la siguiente: he generado una referencia para un servicio web SOAP con svcutil
, que debido a los elementos anidados genera nombres de clase extremadamente largos, que me gustaría evitar tener que escribir. Entonces en lugar 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()
};
y un CreateAddress(GetOrderResultOrderShipment_OrderShipmentShipment_Address address)
método separado (los nombres reales son aún más largos, y tengo un control muy limitado sobre el formulario), me gustaría escribir
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()
};
Se que podria escribir
Address = sh.ReceiverAddress_Shipment == null ? null : new Address {
Street = sh.ReceiverAddress_Shipment.Address.Street,
...
}
pero incluso eso (la sh.ReceiverAddress_Shipment.Address
parte) se vuelve muy repetitivo si hay muchos campos. Declarar una lambda e inmediatamente llamarla sería más elegante, menos caracteres para escribir.
int output = ((Func<int>) (() => { return 1; }))();
public T Exec<T>(Func<T> func) => return func();
Y usarlo así:int x = Exec(() => { return 1; });
eso para mí se lee mucho mejor que el casting con todos sus padres.Respuestas:
En lugar de intentar lanzar el lambda, te propongo que uses una pequeña función auxiliar:
que luego se podría utilizar como esto:
int x = Exec(myVar => myVar + 2, 0);
. Esto me parece mucho mejor que las alternativas sugeridas aquí.fuente
Es feo, pero es posible:
Puede emitir, pero la lambda debe estar entre paréntesis.
Lo anterior también se puede simplificar:
fuente
int output = (Func<int>)(() => { return 1; })();
pero el elenco tiene menor prioridad que la ejecución lambda.Los literales lambda en C # tienen una curiosa distinción en que su significado depende de su tipo. Están esencialmente sobrecargados en su tipo de retorno, que es algo que no existe en ningún otro lugar en C #. (Los literales numéricos son algo similares).
La exacta misma literal lambda puede o bien evaluar a una función anónima que se puede ejecutar (es decir, un
Func
/Action
) o una representación abstracta de las operaciones en el interior del cuerpo, como una especie de árbol de sintaxis abstracta (es decir, una expresión LINQ árbol).Lo último es, por ejemplo, cómo funcionan LINQ to SQL, LINQ to XML, etc.: las lambdas no evalúan el código ejecutable, evalúan los árboles de expresión LINQ, y el proveedor de LINQ puede usar esos árboles de expresión para comprender qué El cuerpo del lambda está haciendo y genera, por ejemplo, una consulta SQL a partir de eso.
En su caso, no hay forma de que el compilador sepa cuándo se supone que el literal lambda debe ser evaluado en una
Func
o una expresión LINQ. Es por eso que la respuesta de Johnathan Barclay funciona: le da un tipo a la expresión lambda y, por lo tanto, el compilador sabe que desea unFunc
código compilado que ejecute el cuerpo de su lambda en lugar de un árbol de expresión LINQ no evaluado que representa el código dentro El cuerpo de la lambda.fuente
Se podría inline la declaración de la
Func
haciendoe inmediatamente invocandolo.
fuente
También puedes crear el alias en el
Select
métodoo con el
??
operadorfuente
Si no le importa violar algunas de las pautas de diseño de los métodos de extensión, los métodos de extensión combinados con el operador condicional nulo
?.
pueden llevarlo razonablemente lejos:te dará esto:
y si en su mayoría necesita matrices, anule el
ToArray
método de extensión para encapsular algunas llamadas de método más:Resultando en:
fuente