Como retornar valor com método anônimo?

90

Isso falha

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

com o erro

Não é possível converter a expressão lambda para o tipo 'string' porque não é um tipo delegado

O que significa o erro e como posso resolvê-lo?

4º Espaço
fonte
Por que essa pergunta é o primeiro resultado no Google ao pesquisar o erro "função anônima convertida em um delegado de retorno void não pode retornar um valor" quando claramente não tem nada a ver com isso?
Calmarius

Respostas:

137

O problema aqui é que você definiu um método anônimo que retorna a, stringmas está tentando atribuí-lo diretamente a a string. É uma expressão que, quando invocada, produz um string, não é diretamente um string. Ele precisa ser atribuído a um tipo de delegado compatível. Neste caso, a escolha mais fácil éFunc<string>

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

Isso pode ser feito em uma linha por um pouco de conversão ou usando o construtor delegado para estabelecer o tipo de lambda seguido por uma invocação.

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

Nota: Ambas as amostras podem ser encurtadas para a forma de expressão que não possui o { return ... }

Func<string> temp = () => "test";
string temp = ((Func<string>)(() => "test"))();
string temp = new Func<string>(() => "test")();
JaredPar
fonte
Obrigado. Portanto, não há como fazer tudo em uma linha (incluindo atribuição de string)? O valor que eu quero ("teste", que na verdade é uma variável na vida real) está dentro de outro lambda, então eu perco o escopo se tentar definir como você fez acima.
4º Espaço
@ 4thSpace, pode ser feito em uma linha com algum elenco maligno. Eu atualizei minha resposta para mostrar o caminho
JaredPar
Ou, neste caso, apenas Func<string> temp = () => "test";.
Gabe
Ou, no caso da sua edição,string temp = new Func<string>(() => "test")();
Gabe
Perfeito! Se eu quiser passar em um int, você pode mostrar isso em uma linha? Eu tentei isso, mas não vá: ((Func <int, string>) ((4) => {return "test";})) ();
4º Espaço
15

Você está tentando atribuir um delegado de função a um tipo de string. Experimente isto:

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

Agora você pode executar a função desta forma:

string s = temp();

A variável "s" agora terá o valor "teste".

Dave Swersky
fonte
1
Isso não compila: "Não é possível atribuir a expressão lambda a uma variável local digitada implicitamente"
Dave Bish
@Dave: Interessante, não sabia dessa limitação. Atualizado, obrigado!
Dave Swersky
8

Usando um pouco de função auxiliar e genéricos, você pode deixar o compilador inferir o tipo e encurtá-lo um pouco:

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

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

Observação lateral: isso também é bom, pois você pode retornar um tipo anônimo:

var temp = FuncInvoke(()=>new {foo=1,bar=2});
joeriks
fonte
Técnica interessante. Isso adiciona sobrecarga de tempo de execução ou é tudo em tempo de compilação?
ToolmakerSteve
@ToolmakerSteve: Meu palpite é que isso adicionaria um pouco de sobrecarga de tempo de execução (envolve uma chamada para um método anônimo dentro de outro método) - no entanto, suspeito que também dependeria de onde o método FuncInvoke foi definido (mesmo assembly de onde está sendo chamado em comparação com um assembly diferente, etc.), já que pode ser o tipo de coisa que o compilador poderia "embutir". Esse é o tipo de pergunta que as pessoas respondem escrevendo um programa de teste rápido, compilando e, em seguida, separando o IL resultante.
Daniel Scott de
@ToolmakerSteve Seguindo a partir da última "suposição" no impacto no desempenho, eu acrescentaria que mesmo o pior caso de impacto que isso teria no desempenho seria virtualmente nulo (uma chamada de função extra, para um método estático não virtual). Qualquer pessoa que use essa técnica provavelmente está fazendo isso porque está jogando lambdas por aí. Isso significa que eles provavelmente estão usando pelo menos alguns métodos de extensão LINQ em algum lugar, então as chances são boas de que eles inadvertidamente encadearam alguns métodos LINQ juntos de uma forma que prejudica o desempenho 100.000 vezes pior do que uma chamada de função extra ;)
Daniel Scott
6

você pode usar o método anônimo com o argumento:

int arg = 5;

string temp = ((Func<int, string>)((a) => { return a == 5 ? "correct" : "not correct"; }))(arg);
HamidReza
fonte
Você pode, mas explique como essa é uma resposta à pergunta.
Toolmaker Steve
3

Um método anônimo pode retornar um valor usando um delegado func. Aqui está um exemplo em que mostrei como retornar um valor usando um método anônimo.

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
fonte
0

Este é outro exemplo usando C # 8 ( também pode funcionar com outras versões .NET que suportam tarefas paralelas )

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
fonte