Як повернути значення за допомогою анонімного методу?


89

Це не вдається

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

з помилкою

Неможливо перетворити лямбда-вираз у тип "рядок", оскільки він не є типом делегата

Що означає помилка і як я можу її усунути?


Чому це питання є першим результатом у Google при пошуку помилки "анонімна функція, перетворена на порожній делегат, що повертається, не може повернути значення", коли це явно не має до цього ніякого відношення?
Calmarius

Відповіді:


136

Проблема тут полягає в тому, що ви визначили анонімний метод, який повертає a, stringале намагаєтеся призначити його безпосередньо a string. Це вираз, який при виклику створює a stringце не безпосередньо a 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
Це не компілюється: "Не вдається присвоїти лямбда-вираз імпліцитно введеній локальній змінній"
Дейв Біш,

@Dave: Цікаво, я не знав про це обмеження. Оновлено, дякую!
Dave Swersky

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 (така ж збірка, як де це називається проти різної збірки тощо), оскільки це може бути те, що компілятор може "вбудувати". Це питання, на яке люди відповідають, написавши програму швидкого тестування, склавши, а потім виділивши отриманий ІЛ.
Даніель Скотт

@ToolmakerSteve Виходячи з останнього "здогадки" про вплив продуктивності, я б додав, що навіть найгірший вплив, який це могло б мати на продуктивність, був би практично нульовим (один додатковий виклик функції до невіртуального, статичного методу). Кожен, хто використовує цю техніку, швидше за все, робить це, бо кидає лямбди навколо. Це означає, що вони, мабуть, десь використовують принаймні пару методів розширення LINQ, тому шанси справедливі і добрі, що вони ненавмисно об’єднали пару методів LINQ разом таким чином, що шкодить продуктивності в 100 000 разів гірше, ніж один додатковий виклик функції ;)
Даніель Скотт

5

Ви можете використовувати анонімний метод з аргументом:

int arg = 5;

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

Ви можете, але поясніть, будь ласка, як це відповідь на запитання.
ToolmakerSteve

2

Анонімний метод може повернути значення за допомогою делегата функції. Ось приклад, коли я показав, як повернути значення за допомогою анонімного методу.

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();
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.