¿Cómo devolver valor con un método anónimo?


89

Esto falla

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

con el error

No se puede convertir la expresión lambda al tipo 'cadena' porque no es un tipo delegado

¿Qué significa el error y cómo puedo solucionarlo?


¿Por qué esta pregunta es el primer resultado en Google cuando se busca el error "la función anónima convertida en un delegado de retorno nulo no puede devolver un valor" cuando claramente no tiene nada que ver con eso?
Calmarius

Respuestas:


136

El problema aquí es que ha definido un método anónimo que devuelve un stringpero está intentando asignarlo directamente a un string. Es una expresión que cuando se invoca produce un stringno es directamente un string. Debe asignarse a un tipo de delegado compatible. En este caso, la opción más sencilla esFunc<string>

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

Esto se puede hacer en una línea mediante un poco de conversión o usando el constructor delegado para establecer el tipo de lambda seguido de una invocación.

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

Nota: Ambas muestras se pueden acortar a la forma de expresión que carece de { return ... }

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

Gracias. Entonces, ¿no hay forma de hacer todo en una línea (incluida la asignación de cadenas)? El valor que quiero ("prueba", que en realidad es una variable en la vida real) está dentro de otra lambda, por lo que pierdo el alcance si trato de definirlo como lo hizo anteriormente.
4thSpace

@ 4thSpace se puede hacer en una línea con un casting malvado.
Actualicé

O en este caso, simplemente Func<string> temp = () => "test";.
Gabe

O en el caso de su edición,string temp = new Func<string>(() => "test")();
Gabe

¡Perfecto! Si quisiera pasar un int, ¿puedes mostrar eso en una línea? Intenté esto pero no lo hice: ((Func <int, string>) ((4) => {return "test";})) ();
4thSpace

15

Está intentando asignar un delegado de función a un tipo de cadena. Prueba esto:

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

Ahora puede ejecutar la función así:

string s = temp();

La variable "s" ahora tendrá el valor "prueba".


1
Esto no compila: "No se puede asignar una expresión lambda a una variable local escrita implícitamente"
Dave Bish

@Dave: Interesante, no conocía esa limitación. ¡Actualizado, gracias!
Dave Swersky

8

Usando una pequeña función auxiliar y genéricos, puede dejar que el compilador infiera el tipo y acortarlo un poco:

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

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

Nota al margen: esto también es bueno, ya que luego puede devolver un tipo anónimo:

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

Interesante técnica. ¿Esto agrega sobrecarga de tiempo de ejecución, o es todo en tiempo de compilación?
ToolmakerSteve

@ToolmakerSteve: Supongo que agregaría un poco de sobrecarga de tiempo de ejecución (está envolviendo una llamada a un método anónimo dentro de otro método); sin embargo, sospecho que también dependería de dónde se definió el método FuncInvoke (el mismo ensamblado que donde se llama frente a un ensamblaje diferente, etc.), ya que podría ser el tipo de cosas que el compilador podría "en línea". Este es el tipo de pregunta que la gente responde escribiendo un programa de prueba rápida, compilando y luego separando el IL resultante.
Daniel Scott

@ToolmakerSteve Siguiendo con esa última "suposición" sobre el impacto en el rendimiento, agregaría que incluso el impacto en el peor de los casos que esto tendría en el rendimiento sería prácticamente nulo (una llamada de función adicional a un método estático no virtual). Cualquiera que utilice esta técnica probablemente lo haga porque está lanzando lambdas. Eso significa que probablemente estén usando al menos un par de métodos de extensión LINQ en algún lugar, por lo que las probabilidades son justas o buenas de que hayan encadenado inadvertidamente un par de métodos LINQ juntos de una manera que perjudica el rendimiento 100.000 veces peor que una llamada de función adicional. ;)
Daniel Scott

5

puedes usar un método anónimo con argumento:

int arg = 5;

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

Puede, pero explique cómo es esta una respuesta a la pregunta.
ToolmakerSteve

2

Un método anónimo puede devolver un valor usando un delegado func. Aquí hay un ejemplo en el que he mostrado cómo devolver un valor utilizando un 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();
        }
    }
}

0

Este es otro ejemplo que usa C # 8 ( también podría funcionar con otras versiones de .NET que admitan tareas 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();
        }
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.