Как вернуть значение анонимным методом?

89

Это не удается

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

с ошибкой

Невозможно преобразовать лямбда-выражение в тип 'строка', потому что это не тип делегата

Что означает ошибка и как ее устранить?

4thSpace
источник
Почему этот вопрос является первым результатом в Google при поиске ошибки «анонимная функция, преобразованная в делегат, возвращающий void, не может вернуть значение», когда он явно не имеет к этому никакого отношения?
Calmarius

Ответы:

136

Проблема здесь в том, что вы определили анонимный метод, который возвращает, stringно пытается назначить его напрямую string. Это выражение, которое при вызове производит, а stringне напрямую string. Его необходимо назначить совместимому типу делегата. В этом случае самый простой выбор -Func<string>

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

Это можно сделать в одной строке с помощью небольшого приведения типов или использования конструктора делегата, чтобы установить тип лямбда-выражения, за которым следует вызов.

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

Примечание. Оба образца можно сократить до формы выражения, в которой отсутствует { return ... }

Func<string> temp = () => "test";
string temp = ((Func<string>)(() => "test"))();
string temp = new Func<string>(() => "test")();
ДжаредПар
источник
Спасибо. То есть нет возможности сделать все в одной строке (включая присвоение строки)? Значение, которое я хочу («тест», который на самом деле является переменной в реальной жизни), находится внутри другой лямбды, поэтому я теряю область видимости, если попытаюсь определить, как вы это сделали.
4thSpace
@ 4thSpace это можно сделать в одну строку с каким-то злым кастингом. Я обновил свой ответ, чтобы показать дорогу
JaredPar
Или в данном случае просто Func<string> temp = () => "test";.
Гейб
Или в случае вашего редактирования,string temp = new Func<string>(() => "test")();
Гейб
Отлично! Если бы я хотел передать int, можете ли вы показать это в одной строке? Я пробовал это, но не пошел: ((Func <int, string>) ((4) => {return "test";})) ();
4thSpace
15

Вы пытаетесь назначить делегата функции строковому типу. Попробуй это:

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

Теперь вы можете выполнить функцию следующим образом:

string s = temp();

Переменная «s» теперь будет иметь значение «test».

Дэйв Сверски
источник
1
Это не компилируется: «Невозможно присвоить лямбда-выражение неявно типизированной локальной переменной»
Дэйв Биш,
@ Дэйв: Интересно, я не знал об этом ограничении. Обновлено, спасибо!
Дэйв Сверски,
8

Используя небольшую вспомогательную функцию и дженерики, вы можете позволить компилятору определить тип и немного сократить его:

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

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

Боковое примечание: это также хорошо, так как тогда вы можете вернуть анонимный тип:

var temp = FuncInvoke(()=>new {foo=1,bar=2});
Йерикс
источник
Интересная техника. Добавляет ли это накладные расходы времени выполнения или все это происходит во время компиляции?
ToolmakerSteve
@ToolmakerSteve: Я предполагаю, что это добавит незначительные накладные расходы времени выполнения (он переносит вызов анонимного метода в другой метод) - однако я подозреваю, что это также будет зависеть от того, где был определен метод FuncInvoke (та же сборка, что и где он вызывается по сравнению с другой сборкой и т. д.), поскольку это может быть что-то вроде того, что компилятор может "встроить". Это тот вопрос, на который люди отвечают, написав быструю тестовую программу, компилируя и затем разбирая получившийся IL.
Дэниел Скотт
@ToolmakerSteve. Следуя этой последней «догадке» о влиянии на производительность, я бы добавил, что даже в худшем случае влияние этого на производительность будет практически нулевым (один дополнительный вызов функции для не виртуального статического метода). Любой, кто использует эту технику, скорее всего, делает это, потому что бросает лямбды. Это означает, что они, вероятно, где-то используют по крайней мере пару методов расширения LINQ, поэтому велика вероятность того, что они непреднамеренно связали пару методов LINQ вместе таким образом, что производительность в 100000 раз хуже, чем один дополнительный вызов функции ;)
Дэниел Скотт
5

вы можете использовать анонимный метод с аргументом:

int arg = 5;

string temp = ((Func<int, string>)((a) => { return a == 5 ? "correct" : "not correct"; }))(arg);
HamidReza
источник
Можно, но объясните, пожалуйста, как это ответ на вопрос.
ToolmakerSteve
2

Анонимный метод может возвращать значение с помощью делегата func. Вот пример, в котором я показал, как вернуть значение с помощью анонимного метода.

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

Это еще один пример использования C # 8 ( также может работать с другими версиями .NET, поддерживающими параллельные задачи )

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
источник