Mengapa pertanyaan ini muncul pertama kali di Google saat menelusuri kesalahan "fungsi anonim yang diubah menjadi delegasi yang kembali kosong tidak dapat mengembalikan nilai" padahal jelas tidak ada hubungannya dengan itu?
Calmarius
Jawaban:
137
Masalahnya di sini adalah Anda telah menentukan metode anonim yang mengembalikan a stringtetapi mencoba untuk menetapkannya langsung ke string. Ini adalah ekspresi yang ketika dipanggil menghasilkan a stringitu tidak langsung a string. Ini harus ditetapkan ke jenis delegasi yang kompatibel. Dalam hal ini pilihan termudah adalahFunc<string>
Func<string> temp = () => {return"test";};
Ini dapat dilakukan dalam satu baris dengan sedikit casting atau menggunakan konstruktor delegasi untuk menetapkan jenis lambda yang diikuti dengan pemanggilan.
Terima kasih. Jadi tidak ada cara untuk melakukan semuanya dalam satu baris (termasuk menetapkan string)? Nilai yang saya inginkan ("test", yang sebenarnya merupakan variabel dalam kehidupan nyata) ada di dalam lambda lain jadi saya kehilangan ruang lingkup jika saya mencoba mendefinisikan seperti yang Anda miliki di atas.
4thSpace
@ 4thSpace itu dapat dilakukan dalam satu baris dengan beberapa pengecoran jahat. Saya memperbarui jawaban saya untuk menunjukkan jalan
JaredPar
Atau dalam kasus ini, adil Func<string> temp = () => "test";.
Gabe
Atau dalam kasus suntingan Anda,string temp = new Func<string>(() => "test")();
Gabe
Sempurna! Jika saya ingin memasukkan int, dapatkah Anda menunjukkannya dalam satu baris? Saya mencoba ini tetapi tidak berhasil: ((Func <int, string>) ((4) => {return "test";})) ();
4thSpace
15
Anda mencoba untuk menetapkan delegasi fungsi ke tipe string. Coba ini:
Func<string> temp = () => {return"test";};
Sekarang Anda dapat menjalankan fungsi tersebut dengan cara berikut:
Teknik yang menarik. Apakah ini menambah run-time overhead, atau apakah semuanya pada waktu kompilasi?
ToolmakerSteve
@ToolmakerSteve: Dugaan saya adalah bahwa itu akan menambahkan sedikit overhead runtime yang teeeeensy (itu membungkus panggilan ke metode anonim di dalam metode lain) - namun, saya curiga itu juga akan tergantung di mana metode FuncInvoke didefinisikan (perakitan yang sama seperti di mana itu disebut vs rakitan berbeda dll), karena ini mungkin semacam hal yang kompilator dapat "sebaris". Ini adalah jenis pertanyaan yang dijawab dengan menulis program tes cepat, menyusun, dan kemudian memilah-milah IL yang dihasilkan.
Daniel Scott
@ToolmakerSteve Mengikuti dari "tebakan" terakhir pada dampak kinerja, saya akan menambahkan bahwa bahkan dampak terburuk yang akan terjadi pada kinerja akan hampir nihil (satu panggilan fungsi tambahan, ke metode statis non-virtual). Siapa pun yang menggunakan teknik ini kemungkinan besar melakukannya karena mereka melempar lambda. Itu berarti mereka mungkin menggunakan setidaknya beberapa metode ekstensi LINQ di suatu tempat, jadi kemungkinannya cukup besar bahwa mereka secara tidak sengaja merangkai beberapa metode LINQ bersama-sama dengan cara yang merusak kinerja 100.000 kali lebih buruk daripada satu panggilan fungsi tambahan ;)
Daniel Scott
6
Anda dapat menggunakan metode anonim dengan argumen:
Bisa, tapi tolong jelaskan bagaimana ini menjadi jawaban atas pertanyaan tersebut.
ToolmakerSteve
3
Metode anonim dapat mengembalikan nilai menggunakan func delegate. Berikut adalah contoh di mana saya telah menunjukkan bagaimana mengembalikan nilai menggunakan metode anonim.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespaceConsoleApp1
{
classProgram
{
staticvoidMain(string[] args)
{
Func<int, int> del = delegate (int x)
{
return x * x;
};
int p= del(4);
Console.WriteLine(p);
Console.ReadLine();
}
}
}
Jawaban:
Masalahnya di sini adalah Anda telah menentukan metode anonim yang mengembalikan a
string
tetapi mencoba untuk menetapkannya langsung kestring
. Ini adalah ekspresi yang ketika dipanggil menghasilkan astring
itu tidak langsung astring
. Ini harus ditetapkan ke jenis delegasi yang kompatibel. Dalam hal ini pilihan termudah adalahFunc<string>
Func<string> temp = () => {return "test";};
Ini dapat dilakukan dalam satu baris dengan sedikit casting atau menggunakan konstruktor delegasi untuk menetapkan jenis lambda yang diikuti dengan pemanggilan.
string temp = ((Func<string>)(() => { return "test"; }))(); string temp = new Func<string>(() => { return "test"; })();
Catatan: Kedua sampel dapat disingkat menjadi bentuk ekspresi yang tidak memiliki ekstensi
{ return ... }
Func<string> temp = () => "test"; string temp = ((Func<string>)(() => "test"))(); string temp = new Func<string>(() => "test")();
sumber
Func<string> temp = () => "test";
.string temp = new Func<string>(() => "test")();
Anda mencoba untuk menetapkan delegasi fungsi ke tipe string. Coba ini:
Func<string> temp = () => {return "test";};
Sekarang Anda dapat menjalankan fungsi tersebut dengan cara berikut:
string s = temp();
Variabel "s" sekarang akan memiliki nilai "test".
sumber
Dengan menggunakan sedikit fungsi pembantu dan generik, Anda dapat membiarkan kompiler menyimpulkan jenisnya, dan memendekkannya sedikit:
public static TOut FuncInvoke<TOut>(Func<TOut> func) { return func(); } var temp = FuncInvoke(()=>"test");
Catatan samping: ini juga bagus karena Anda kemudian dapat mengembalikan tipe anonim:
var temp = FuncInvoke(()=>new {foo=1,bar=2});
sumber
Anda dapat menggunakan metode anonim dengan argumen:
int arg = 5; string temp = ((Func<int, string>)((a) => { return a == 5 ? "correct" : "not correct"; }))(arg);
sumber
Metode anonim dapat mengembalikan nilai menggunakan func delegate. Berikut adalah contoh di mana saya telah menunjukkan bagaimana mengembalikan nilai menggunakan metode anonim.
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(); } } }
sumber
Ini adalah contoh lain menggunakan C # 8 ( juga bisa bekerja dengan versi .NET lain yang mendukung tugas paralel )
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(); } } }
sumber