Dlaczego to pytanie jest pierwszym wynikiem w wyszukiwarce Google podczas wyszukiwania błędu „funkcja anonimowa przekonwertowana na void zwracający delegat nie może zwrócić wartości”, skoro wyraźnie nie ma z tym nic wspólnego?
Calmarius
Odpowiedzi:
136
Problem polega na tym, że zdefiniowałeś anonimową metodę, która zwraca a, stringale próbujesz przypisać ją bezpośrednio do pliku string. Jest to wyrażenie, które po wywołaniu daje stringto nie jest bezpośrednio a string. Musi być przypisany do zgodnego typu delegata. W tym przypadku najłatwiejszym wyborem jestFunc<string>
Func<string> temp = () => {return"test";};
Można to zrobić w jednym wierszu przez rzutowanie lub użycie konstruktora delegata w celu ustalenia typu lambda, po którym następuje wywołanie.
Dzięki. Więc nie ma możliwości zrobienia wszystkiego w jednej linii (w tym przypisania ciągu)? Wartość, którą chcę („test”, która w rzeczywistości jest zmienną w prawdziwym życiu) znajduje się wewnątrz innej lambdy, więc tracę zakres, jeśli spróbuję zdefiniować tak, jak masz powyżej.
4thSpace
@ 4thSpace można to zrobić w jednej linii z jakimś złym rzucaniem. Zaktualizowałem swoją odpowiedź, aby pokazać drogę
JaredPar
Albo w tym przypadku po prostu Func<string> temp = () => "test";.
Gabe
Lub w przypadku twojego string temp = new Func<string>(() => "test")();
montażu
Idealny! Gdybym chciał podać int, czy możesz to pokazać w jednej linii? Próbowałem tego, ale nie idź: ((Func <int, string>) ((4) => {return "test";})) ();
4thSpace
15
Próbujesz przypisać delegata funkcji do typu ciągu. Spróbuj tego:
Ciekawa technika. Czy powoduje to dodatkowe obciążenie w czasie wykonywania, czy też wszystko w czasie kompilacji?
ToolmakerSteve
@ToolmakerSteve: Domyślam się, że dodałoby to trochę teeeeensy narzutu czasu wykonania (zawija wywołanie metody anonimowej w innej metodzie) - podejrzewam jednak, że zależałoby to również od tego, gdzie zdefiniowano metodę FuncInvoke (ten sam zestaw, co gdzie jest wywoływany w porównaniu z innym zestawem itp.), ponieważ może to być coś, co kompilator mógłby „wbudować”. Jest to rodzaj pytania, na które ludzie odpowiadają, pisząc program szybkiego testu, kompilując, a następnie oddzielając wynikowy IL.
Daniel Scott
@ToolmakerSteve Kontynuując ostatnie „przypuszczenie” dotyczące wpływu na wydajność, chciałbym dodać, że nawet najgorszy wpływ, jaki miałoby to na wydajność, byłby praktycznie zerowy (jedno dodatkowe wywołanie funkcji do niewirtualnej, statycznej metody). Każdy, kto używa tej techniki, prawdopodobnie to robi, ponieważ rzuca dookoła lambdy. Oznacza to, że prawdopodobnie używają gdzieś co najmniej kilku metod rozszerzających LINQ, więc szanse są całkiem dobre, że nieumyślnie połączyli ze sobą kilka metod LINQ w sposób, który obniża wydajność 100 000 razy bardziej niż jedno dodatkowe wywołanie funkcji ;)
Możesz, ale proszę wyjaśnij, w jaki sposób jest to odpowiedź na pytanie.
ToolmakerSteve
2
Metoda anonimowa może zwrócić wartość przy użyciu delegata funkcji. Oto przykład, w którym pokazałem, jak zwrócić wartość przy użyciu metody anonimowej.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespaceConsoleApp1
{
classProgram
{
staticvoidMain(string[] args)
{
Func<int, int> del = delegate (int x)
{
return x * x;
};
int p= del(4);
Console.WriteLine(p);
Console.ReadLine();
}
}
}
Odpowiedzi:
Problem polega na tym, że zdefiniowałeś anonimową metodę, która zwraca a,
string
ale próbujesz przypisać ją bezpośrednio do plikustring
. Jest to wyrażenie, które po wywołaniu dajestring
to nie jest bezpośrednio astring
. Musi być przypisany do zgodnego typu delegata. W tym przypadku najłatwiejszym wyborem jestFunc<string>
Func<string> temp = () => {return "test";};
Można to zrobić w jednym wierszu przez rzutowanie lub użycie konstruktora delegata w celu ustalenia typu lambda, po którym następuje wywołanie.
string temp = ((Func<string>)(() => { return "test"; }))(); string temp = new Func<string>(() => { return "test"; })();
Uwaga: Obie próbki można skrócić do formy wyrażenia, która nie zawiera rozszerzenia
{ return ... }
Func<string> temp = () => "test"; string temp = ((Func<string>)(() => "test"))(); string temp = new Func<string>(() => "test")();
źródło
Func<string> temp = () => "test";
.string temp = new Func<string>(() => "test")();
Próbujesz przypisać delegata funkcji do typu ciągu. Spróbuj tego:
Func<string> temp = () => {return "test";};
Możesz teraz wykonać tę funkcję w ten sposób:
string s = temp();
Zmienna „s” będzie miała teraz wartość „test”.
źródło
Używając małej funkcji pomocniczej i typów ogólnych, możesz pozwolić kompilatorowi wywnioskować typ i trochę go skrócić:
public static TOut FuncInvoke<TOut>(Func<TOut> func) { return func(); } var temp = FuncInvoke(()=>"test");
Uwaga dodatkowa: jest to również przyjemne, ponieważ możesz wtedy zwrócić typ anonimowy:
var temp = FuncInvoke(()=>new {foo=1,bar=2});
źródło
możesz użyć metody anonimowej z argumentem:
int arg = 5; string temp = ((Func<int, string>)((a) => { return a == 5 ? "correct" : "not correct"; }))(arg);
źródło
Metoda anonimowa może zwrócić wartość przy użyciu delegata funkcji. Oto przykład, w którym pokazałem, jak zwrócić wartość przy użyciu metody anonimowej.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Func<int, int> del = delegate (int x) { return x * x; }; int p= del(4); Console.WriteLine(p); Console.ReadLine(); } } }
źródło
To kolejny przykład wykorzystujący C # 8 ( może również działać z innymi wersjami .NET obsługującymi równoległe zadania )
using System; using System.Threading.Tasks; namespace Exercise_1_Creating_and_Sharing_Tasks { internal static class Program { private static int TextLength(object o) { Console.WriteLine($"Task with id {Task.CurrentId} processing object {o}"); return o.ToString().Length; } private static void Main() { const string text1 = "Welcome"; const string text2 = "Hello"; var task1 = new Task<int>(() => TextLength(text1)); task1.Start(); var task2 = Task.Factory.StartNew(TextLength, text2); Console.WriteLine($"Length of '{text1}' is {task1.Result}"); Console.WriteLine($"Length of '{text2}' is {task2.Result}"); Console.WriteLine("Main program done"); Console.ReadKey(); } } }
źródło