Anonim yöntemle değer nasıl döndürülür?


90

Bu başarısız

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

hata ile

Bir temsilci türü olmadığından lambda ifadesi 'dizge' türüne dönüştürülemiyor

Hata ne anlama geliyor ve bunu nasıl çözebilirim?


Açıkça bir ilgisi olmadığı halde "void'e dönen anonim işlev bir değer döndüremez" hatasını aradığında bu soru neden Google'da ilk sonuç oluyor?
Calmarius

Yanıtlar:


137

Buradaki sorun, a döndüren stringancak onu doğrudan bir string. Bu, çağrıldığında a üreten bir ifadedir, stringdoğrudan a değildir string. Uyumlu bir temsilci türüne atanması gerekir. Bu durumda en kolay seçim şudur:Func<string>

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

Bu, lambda türünü ve ardından bir çağırma oluşturmak için delegate yapıcısını kullanarak bir parça çevrim veya delegate yapıcı kullanılarak bir satırda yapılabilir.

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

Not: Her iki örnek de, eksik olan ifade formuna kısaltılabilir. { return ... }

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

Teşekkürler. Yani her şeyi tek bir satırda yapmanın bir yolu yok (dize atamak dahil)? İstediğim değer (aslında gerçek hayatta bir değişken olan "test") başka bir lambda içindedir, bu yüzden yukarıdaki gibi tanımlamaya çalışırsam kapsamı kaybederim.
4thSpace

@ 4thSpace bazı kötü dökümlerle tek bir satırda yapılabilir. Cevabımı yolu göstermek için güncelledim
JaredPar

Veya bu durumda, sadece Func<string> temp = () => "test";.
Gabe 9'12

Veya düzenlemeniz durumundastring temp = new Func<string>(() => "test")();
Gabe

Mükemmel! Bir int geçmek istersem, bunu tek satırda gösterebilir misin? Bunu denedim ama gitmedim: ((Func <int, string>) ((4) => {return "test";})) ();
4thSpace

15

Bir dizi türüne bir işlev temsilcisi atamaya çalışıyorsunuz . Bunu dene:

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

Artık işlevi şu şekilde çalıştırabilirsiniz:

string s = temp();

"S" değişkeni artık "test" değerine sahip olacaktır.


1
Bu derlemez: "Örtülü olarak yazılan bir yerel değişkene lambda ifadesi
atanamaz

@Dave: İlginç, bu sınırlamayı bilmiyordum. Güncellendi, teşekkürler!
Dave Swersky

8

Küçük bir yardımcı işlev ve jenerik kullanarak, derleyicinin türü çıkarmasına izin verebilir ve biraz kısaltabilirsiniz:

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

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

Yan not: Bu, anonim bir türü döndürebileceğiniz için de güzel:

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

İlginç teknik. Bu çalışma zamanı ek yükü mü yoksa hepsi derleme zamanında mı?
ToolmakerSteve

@ToolmakerSteve: Tahminime göre bu, çok ufak bir çalışma zamanı ek yükü ekleyeceği (başka bir yöntemin içindeki anonim bir yönteme yapılan bir çağrıyı sarıyor) - ancak, FuncInvoke yönteminin nerede tanımlandığına da bağlı olacağını düşünüyorum ( derleyicinin "satır içi" yapabileceği türden bir şey olabileceğinden , buna farklı birleştirme vs deniyor . Bu, insanların hızlı bir test programı yazarak, derleyerek ve sonra ortaya çıkan bilgi düzeyini ayırarak yanıtladıkları türden bir sorudur.
Daniel Scott

@ToolmakerSteve Performans etkisindeki son "tahminden" sonra, bunun performans üzerinde yaratacağı en kötü durum etkisinin bile neredeyse sıfır olacağını eklemek isterim (sanal olmayan, statik bir yönteme ekstra bir işlev çağrısı). Bu tekniği kullanan herkes muhtemelen bunu yapıyor çünkü etrafa lambdalar fırlatıyorlar. Bu, muhtemelen bir yerlerde en az birkaç LINQ uzatma yöntemi kullandıkları anlamına gelir, bu nedenle, birkaç LINQ yöntemini, bir ekstra işlev çağrısından 100.000 kat daha kötü performansa zarar verecek şekilde yanlışlıkla birbirine zincirlemiş olma ihtimalleri iyidir ;)
Daniel Scott

6

bağımsız değişkenle anonim yöntemi kullanabilirsiniz:

int arg = 5;

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

Yapabilirsiniz, ancak lütfen bunun soruya nasıl bir cevap olduğunu açıklayın.
ToolmakerSteve

3

Anonim bir yöntem, bir işlev temsilcisi kullanarak bir değer döndürebilir. Anonim bir yöntem kullanarak bir değerin nasıl döndürüleceğini gösterdiğim bir örnek burada.

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

Bu, C # 8 kullanan başka bir örnektir ( paralel görevleri destekleyen diğer .NET sürümleriyle de çalışabilir )

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();
        }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.