Il est possible de déclarer une fonction lambda et de l'appeler immédiatement:
Func<int, int> lambda = (input) => { return 1; };
int output = lambda(0);
Je me demande s'il est possible de le faire sur une seule ligne, par exemple quelque chose comme
int output = (input) => { return 1; }(0);
ce qui donne une erreur de compilation "Nom de méthode attendu". La diffusion vers Func<int, int>
ne fonctionne pas non plus:
int output = (Func<int, int>)((input) => { return 1; })(0);
donne la même erreur, et pour les raisons mentionnées ci-dessous, je voudrais éviter d'avoir à spécifier explicitement le type d'argument d'entrée (le premier int
).
Vous vous demandez probablement pourquoi je veux faire cela, au lieu de simplement intégrer le code directement, par exemple int output = 1;
. La raison est la suivante: j'ai généré une référence pour un service Web SOAP avec svcutil
lequel, en raison des éléments imbriqués, génère des noms de classe extrêmement longs, que j'aimerais éviter d'avoir à taper. Donc au lieu 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()
};
et une CreateAddress(GetOrderResultOrderShipment_OrderShipmentShipment_Address address)
méthode distincte (les vrais noms sont encore plus longs, et j'ai un contrôle très limité sur le formulaire), je voudrais écrire
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()
};
Je sais que je pourrais écrire
Address = sh.ReceiverAddress_Shipment == null ? null : new Address {
Street = sh.ReceiverAddress_Shipment.Address.Street,
...
}
mais même cela (la sh.ReceiverAddress_Shipment.Address
partie) devient très répétitif s'il y a beaucoup de champs. Déclarer un lambda et l'appeler immédiatement serait plus élégant, moins de caractères à écrire.
int output = ((Func<int>) (() => { return 1; }))();
public T Exec<T>(Func<T> func) => return func();
et l'utiliser comme ceci:int x = Exec(() => { return 1; });
Cela me semble beaucoup plus agréable que le casting avec toutes ses parens.Réponses:
Au lieu d'essayer de lancer le lambda, je vous propose d'utiliser une petite fonction d'aide:
que vous pouvez ensuite utiliser comme ceci:
int x = Exec(myVar => myVar + 2, 0);
. Cela me semble beaucoup plus agréable que les alternatives suggérées ici.la source
C'est moche, mais c'est possible:
Vous pouvez transtyper, mais le lambda doit être placé entre parenthèses.
Ce qui précède peut également être simplifié:
la source
int output = (Func<int>)(() => { return 1; })();
mais la distribution a une priorité inférieure à l'exécution lambda.Les littéraux lambda en C # ont une curieuse distinction en ce que leur signification dépend de leur type. Ils sont essentiellement surchargés sur leur type de retour qui est quelque chose qui n'existe nulle part ailleurs en C #. (Les littéraux numériques sont quelque peu similaires.)
Le même littéral lambda peut être évalué comme une fonction anonyme que vous pouvez exécuter (c'est-à-dire a
Func
/Action
) ou une représentation abstraite des opérations à l'intérieur du corps, un peu comme un arbre de syntaxe abstraite (c'est-à-dire un arbre d'expression LINQ).Ce dernier est, par exemple, comment LINQ to SQL, LINQ to XML, etc. fonctionnent: les lambdas n'évaluent pas en code exécutable, ils évaluent en LINQ Expression Trees, et le fournisseur LINQ peut ensuite utiliser ces Expression Trees pour comprendre ce que le le corps du lambda fait et génère par exemple une requête SQL à partir de cela.
Dans votre cas, il n'y a aucun moyen pour le compilateur de savoir si le littéral lambda est censé être évalué en une
Func
ou une expression LINQ. C'est pourquoi la réponse de Johnathan Barclay fonctionne: elle donne un type à l'expression lambda et par conséquent, le compilateur sait que vous voulez unFunc
code compilé qui exécute le corps de votre lambda au lieu d'un arbre d'expression LINQ non évalué qui représente le code à l'intérieur le corps de la lambda.la source
Vous pouvez aligner la déclaration du
Func
en faisantet l'invoquer immédiatement.
la source
Vous pouvez également créer l'alias dans la
Select
méthodeou avec l'
??
opérateurla source
Si cela ne vous dérange pas de violer quelques-unes des directives de conception des méthodes d'extension, les méthodes d'extension combinées à un opérateur conditionnel nul
?.
peuvent vous mener raisonnablement loin:vous donnera ceci:
et si vous avez principalement besoin de tableaux, remplacez la
ToArray
méthode d'extension pour encapsuler quelques appels de méthode supplémentaires:résultant en:
la source