Można zadeklarować funkcję lambda i natychmiast ją wywołać:
Func<int, int> lambda = (input) => { return 1; };
int output = lambda(0);
Zastanawiam się, czy można to zrobić w jednym wierszu, np. Coś takiego
int output = (input) => { return 1; }(0);
co daje błąd kompilatora „Oczekiwana nazwa metody”. Przesyłanie do Func<int, int>
nie działa:
int output = (Func<int, int>)((input) => { return 1; })(0);
daje ten sam błąd iz powodów wymienionych poniżej chciałbym uniknąć konieczności jawnego podawania typu argumentu wejściowego (pierwszy int
).
Prawdopodobnie zastanawiasz się, dlaczego chcę to zrobić, zamiast bezpośrednio osadzać kod, np int output = 1;
. Powód jest następujący: Wygenerowałem odwołanie do usługi internetowej SOAP svcutil
, która ze względu na zagnieżdżone elementy generuje wyjątkowo długie nazwy klas, których nie chciałbym pisać. Więc zamiast
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()
};
i osobna CreateAddress(GetOrderResultOrderShipment_OrderShipmentShipment_Address address)
metoda (prawdziwe nazwy są jeszcze dłuższe, a ja mam bardzo ograniczoną kontrolę nad formularzem), chciałbym pisać
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()
};
Wiem, że mógłbym pisać
Address = sh.ReceiverAddress_Shipment == null ? null : new Address {
Street = sh.ReceiverAddress_Shipment.Address.Street,
...
}
ale nawet to ( sh.ReceiverAddress_Shipment.Address
część) staje się bardzo powtarzalne, jeśli istnieje wiele pól. Zadeklarowanie lambdy i natychmiastowe wywołanie byłoby bardziej eleganckim, mniejszym znakiem do pisania.
int output = ((Func<int>) (() => { return 1; }))();
public T Exec<T>(Func<T> func) => return func();
i użyj go w ten sposób:int x = Exec(() => { return 1; });
To dla mnie brzmi o wiele ładniej niż casting ze wszystkimi jego częściami.Odpowiedzi:
Zamiast rzucać lambda, proponuję użyć funkcji małego pomocnika:
które można następnie wykorzystać tak:
int x = Exec(myVar => myVar + 2, 0);
. To brzmi o wiele ładniej niż sugerowane tutaj alternatywy.źródło
To brzydkie, ale możliwe:
Możesz rzucać, ale lambda musi być ujęta w nawiasy.
Powyższe można również uprościć:
źródło
int output = (Func<int>)(() => { return 1; })();
ale obsada ma niższy priorytet niż wykonanie lambda.Literały lambda w języku C # mają dziwne rozróżnienie, ponieważ ich znaczenie zależy od ich typu. Są zasadniczo przeciążone rodzajem zwrotu, który nie istnieje nigdzie indziej w C #. (Literały liczbowe są nieco podobne.)
Dokładnie to samo lambda dosłowny może też ocenić do anonimowej funkcji, które można wykonać (czyli
Func
/Action
) lub abstrakcyjnej reprezentacji operacji wewnątrz korpusu, rodzaj jak Abstract Syntax drzewo (czyli LINQ Expression Tree).To ostatnie dotyczy na przykład działania LINQ na SQL, LINQ na XML itp.: Lambda nie przetwarzają kodu wykonywalnego, lecz na drzewa wyrażeń LINQ, a dostawca LINQ może następnie użyć tych drzew wyrażeń, aby zrozumieć, co ciało lambda robi i generuje np. zapytanie SQL.
W twoim przypadku kompilator nie ma możliwości sprawdzenia, czy literał lambda ma być
Func
wyrażony jako wyrażenie LINQ. Właśnie dlatego odpowiedź Johnathana Barclaya działa: nadaje typ wyrażeniu lambda, a zatem kompilator wie, że potrzebujeszFunc
skompilowanego kodu, który wykonuje ciało twojej lambdy zamiast nieocenionego drzewa wyrażeń LINQ reprezentującego kod wewnątrz ciało lambda.źródło
Możesz wstawić deklarację
Func
wykonująci natychmiast przywołując to.
źródło
Możesz także utworzyć alias w
Select
metodzielub z
??
operatoremźródło
Jeśli nie masz nic przeciwko naruszeniu kilku wytycznych dotyczących projektowania metod rozszerzeń, metody rozszerzeń w połączeniu z operatorem null-warunkowym
?.
mogą zabrać cię dość daleko:da ci to:
a jeśli potrzebujesz głównie tablic, zastąp
ToArray
metodę rozszerzającą, aby zawrzeć jeszcze kilka wywołań metod:w wyniku czego:
źródło