Come restituire valore con metodo anonimo?


89

Questo fallisce

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

con l'errore

Impossibile convertire l'espressione lambda nel tipo "stringa" perché non è un tipo delegato

Cosa significa l'errore e come posso risolverlo?


Perché questa domanda è il primo risultato in Google durante la ricerca dell'errore "la funzione anonima convertita in un delegato di restituzione vuoto non può restituire un valore" quando chiaramente non ha nulla a che fare con esso?
Calmarius

Risposte:


136

Il problema qui è che hai definito un metodo anonimo che restituisce a stringma stai cercando di assegnarlo direttamente a a string. È un'espressione che quando invocata produce un stringnon è direttamente a string. Deve essere assegnato a un tipo di delegato compatibile. In questo caso la scelta più semplice èFunc<string>

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

Questa operazione può essere eseguita in una riga mediante un po 'di casting o utilizzando il costruttore delegato per stabilire il tipo di lambda seguito da una chiamata.

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

Nota: entrambi i campioni potrebbero essere cortocircuitati nella forma di espressione che non ha l'estensione { return ... }

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

Grazie. Quindi non c'è modo di fare tutto su una riga (inclusa l'assegnazione della stringa)? Il valore che voglio ("test", che in realtà è una variabile nella vita reale) è all'interno di un altro lambda, quindi perdo l'ambito se provo a definire come hai sopra.
4thSpace

@ 4thSpace può essere fatto in una riga con un casting malvagio. Ho aggiornato la mia risposta per indicare la strada
JaredPar

O in questo caso, solo Func<string> temp = () => "test";.
Gabe

O nel caso della tua modifica,string temp = new Func<string>(() => "test")();
Gabe

Perfetto! Se volessi passare un int, puoi mostrarlo in una riga? Ho provato questo ma non è andato: ((Func <int, string>) ((4) => {return "test";})) ();
4thSpace

15

Stai tentando di assegnare un delegato di funzione a un tipo di stringa. Prova questo:

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

È ora possibile eseguire la funzione in questo modo:

string s = temp();

La variabile "s" ora avrà il valore "test".


1
Questo non viene compilato: "Impossibile assegnare l'espressione lambda a una variabile locale tipizzata in modo implicito"
Dave Bish,

@ Dave: interessante, non conoscevo quella limitazione. Aggiornato, grazie!
Dave Swersky

8

Usando una piccola funzione di aiuto e generici puoi lasciare che il compilatore deduca il tipo e accorciarlo un po ':

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

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

Nota a margine: anche questo è bello in quanto puoi restituire un tipo anonimo:

var temp = FuncInvoke(()=>new {foo=1,bar=2});

Tecnica interessante. Questo aggiunge un sovraccarico in fase di esecuzione o è tutto in fase di compilazione?
ToolmakerSteve

@ToolmakerSteve: La mia ipotesi è che aggiungerebbe un po 'di overhead di runtime (sta avvolgendo una chiamata a un metodo anonimo all'interno di un altro metodo) - tuttavia, sospetto che dipenda anche da dove è stato definito il metodo FuncInvoke (stesso assembly di dove viene chiamato vs assembly diverso, ecc.), poiché potrebbe essere il genere di cose che il compilatore potrebbe "inline". Questo è il tipo di domanda a cui le persone rispondono scrivendo un programma di test rapido, compilando e quindi separando l'IL risultante.
Daniel Scott

@ToolmakerSteve In seguito a quell'ultima "ipotesi" sull'impatto sulle prestazioni, aggiungerei che anche l'impatto nel caso peggiore che avrebbe sulle prestazioni sarebbe praticamente nullo (una chiamata di funzione extra, a un metodo statico non virtuale). Chiunque utilizzi questa tecnica probabilmente lo fa perché lancia lambda in giro. Ciò significa che probabilmente stanno usando almeno un paio di metodi di estensione LINQ da qualche parte, quindi le probabilità sono da buone a buone che abbiano inavvertitamente concatenato un paio di metodi LINQ insieme in un modo che danneggia le prestazioni 100.000 volte peggio di una chiamata di funzione extra ;)
Daniel Scott

5

puoi usare il metodo anonimo con argomento:

int arg = 5;

string temp = ((Func<int, string>)((a) => { return a == 5 ? "correct" : "not correct"; }))(arg);

Puoi, ma per favore spiega come questa sia una risposta alla domanda.
ToolmakerSteve

2

Un metodo anonimo può restituire un valore utilizzando un delegato func. Ecco un esempio in cui ho mostrato come restituire un valore utilizzando un metodo anonimo.

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

0

Questo è un altro esempio che utilizza C # 8 ( potrebbe funzionare anche con altre versioni .NET che supportano attività parallele )

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();
        }
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.