Jak zwrócić wartość metodą anonimową?


89

To się nie udaje

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

z błędem

Nie można przekonwertować wyrażenia lambda na typ „ciąg”, ponieważ nie jest to typ delegata

Co oznacza błąd i jak mogę go rozwiązać?


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.

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

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:

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”.


1
To się nie kompiluje: „Nie można przypisać wyrażenia lambda do niejawnie wpisanej zmiennej lokalnej”
Dave Bish

@Dave: Interesujące, nie wiedziałem o tym ograniczeniu. Zaktualizowano, dzięki!
Dave Swersky

8

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

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 ;)
Daniel Scott

5

możesz użyć metody anonimowej z argumentem:

int arg = 5;

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

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;

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

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();
        }
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.