Wie kann ich mit einer anonymen Methode einen Wert zurückgeben?

87

Dies schlägt fehl

string temp = () => {return "test";};

mit dem Fehler

Der Lambda-Ausdruck kann nicht in den Typ 'string' konvertiert werden, da es sich nicht um einen Delegattyp handelt

Was bedeutet der Fehler und wie kann ich ihn beheben?

4thSpace
quelle
Warum ist diese Frage das erste Ergebnis in Google bei der Suche nach dem Fehler "Anonyme Funktion, die in einen ungültig zurückgegebenen Delegaten konvertiert wurde, kann keinen Wert zurückgeben", wenn sie eindeutig nichts damit zu tun hat?
Calmarius

Antworten:

134

Das Problem hierbei ist, dass Sie eine anonyme Methode definiert haben, die a zurückgibt, stringaber versucht, sie direkt a zuzuweisen string. Es ist ein Ausdruck, der beim Aufrufen ein stringnicht direktes a erzeugt string. Es muss einem kompatiblen Delegatentyp zugewiesen werden. In diesem Fall ist die einfachste WahlFunc<string>

Func<string> temp = () => {return "test";};

Dies kann in einer Zeile durch ein wenig Casting oder mithilfe des Delegate-Konstruktors erfolgen, um den Typ des Lambda zu bestimmen, gefolgt von einem Aufruf.

string temp = ((Func<string>)(() => { return "test"; }))();
string temp = new Func<string>(() => { return "test"; })();

Hinweis: Beide Beispiele könnten mit der Ausdrucksform kurzgeschlossen werden, der das fehlt { return ... }

Func<string> temp = () => "test";
string temp = ((Func<string>)(() => "test"))();
string temp = new Func<string>(() => "test")();
JaredPar
quelle
Vielen Dank. Also keine Möglichkeit, alles in einer Zeile zu erledigen (einschließlich der Zuweisung von Zeichenfolgen)? Der Wert, den ich möchte ("Test", der im wirklichen Leben tatsächlich eine Variable ist), befindet sich in einem anderen Lambda, sodass ich den Umfang verliere, wenn ich versuche, wie oben definiert zu definieren.
4. Raum
@ 4thSpace kann mit bösem Casting in einer Zeile ausgeführt werden. Ich habe meine Antwort aktualisiert, um den Weg zu zeigen
JaredPar
Oder in diesem Fall einfach Func<string> temp = () => "test";.
Gabe
Oder im Falle Ihrer Bearbeitungstring temp = new Func<string>(() => "test")();
Gabe
Perfekt! Wenn ich ein int übergeben wollte, können Sie das in einer Zeile zeigen? Ich habe es versucht, aber es geht nicht: ((Func <int, string>) ((4) => {return "test";})) ();
4. Raum
15

Sie versuchen , einem Zeichenfolgentyp einen Funktionsdelegierten zuzuweisen . Versuche dies:

Func<string> temp = () => {return "test";};

Sie können die Funktion nun folgendermaßen ausführen:

string s = temp();

Die Variable "s" hat jetzt den Wert "test".

Dave Swersky
quelle
1
Dies wird nicht kompiliert: "Lambda-Ausdruck kann keiner implizit typisierten lokalen Variablen zugewiesen werden"
Dave Bish
@ Dave: Interessant, wusste nichts über diese Einschränkung. Aktualisiert, danke!
Dave Swersky
8

Mit ein wenig Hilfsfunktion und Generika können Sie den Compiler auf den Typ schließen lassen und ihn ein wenig verkürzen:

public static TOut FuncInvoke<TOut>(Func<TOut> func)
{
    return func();
}

var temp = FuncInvoke(()=>"test");

Randnotiz: Dies ist auch schön, da Sie dann einen anonymen Typ zurückgeben können:

var temp = FuncInvoke(()=>new {foo=1,bar=2});
Joeriks
quelle
Interessante Technik. Fügt dies den Laufzeitaufwand hinzu oder ist alles zur Kompilierungszeit?
ToolmakerSteve
@ToolmakerSteve: Ich vermute, dass dadurch ein wenig Laufzeitaufwand entsteht (ein Aufruf einer anonymen Methode wird in eine andere Methode eingeschlossen). Ich vermute jedoch, dass dies auch davon abhängt, wo die FuncInvoke-Methode definiert wurde (dieselbe Assembly wie wo) Es wird gegen verschiedene Assemblys usw. aufgerufen, da es die Art von Dingen sein könnte , die der Compiler "inline" machen könnte. Dies ist die Art von Frage, die die Leute beantworten, indem sie ein schnelles Testprogramm schreiben, kompilieren und dann die resultierende IL auseinander nehmen.
Daniel Scott
@ToolmakerSteve Nach dieser letzten "Vermutung" der Auswirkungen auf die Leistung würde ich hinzufügen, dass selbst die schlimmsten Auswirkungen auf die Leistung praktisch null wären (ein zusätzlicher Funktionsaufruf für eine nicht virtuelle, statische Methode). Jeder, der diese Technik anwendet, tut dies wahrscheinlich, weil er Lambdas herumwirft. Das bedeutet, dass sie wahrscheinlich irgendwo mindestens ein paar LINQ-Erweiterungsmethoden verwenden. Die Chancen stehen also gut, dass sie versehentlich ein paar LINQ-Methoden so verkettet haben, dass die Leistung 100.000-mal schlechter ist als bei einem zusätzlichen Funktionsaufruf ;)
Daniel Scott
5

Sie können eine anonyme Methode mit Argument verwenden:

int arg = 5;

string temp = ((Func<int, string>)((a) => { return a == 5 ? "correct" : "not correct"; }))(arg);
HamidReza
quelle
Sie können, aber bitte erklären Sie, wie dies eine Antwort auf die Frage ist.
ToolmakerSteve
2

Eine anonyme Methode kann mithilfe eines func-Delegaten einen Wert zurückgeben. Hier ist ein Beispiel, in dem ich gezeigt habe, wie ein Wert mit einer anonymen Methode zurückgegeben wird.

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();
        }
    }
}
Debendra Dash
quelle
0

Dies ist ein weiteres Beispiel für die Verwendung von C # 8 ( könnte auch mit anderen .NET-Versionen funktionieren, die parallele Aufgaben unterstützen ).

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();
        }
    }
}
wbadry
quelle