Func <T> tanpa parameter

167

Bisakah saya meneruskan metode dengan parameter keluar sebagai Fungsi?

public IList<Foo> FindForBar(string bar, out int count) { }

// somewhere else
public IList<T> Find(Func<string, int, List<T>> listFunction) { }

Func membutuhkan tipe sehingga out tidak dapat dikompilasi di sana, dan memanggil listFunction membutuhkan int dan tidak akan mengizinkan masuk.

Apakah ada cara untuk melakukan ini?

blu
sumber

Jawaban:

228

refdan outbukan bagian dari definisi parameter tipe sehingga Anda tidak bisa menggunakan Funcdelegasi bawaan untuk meneruskan refdan outargumen. Tentu saja, Anda dapat mendeklarasikan delegasi Anda sendiri jika Anda ingin:

delegate V MyDelegate<T,U,V>(T input, out U output);
Mehrdad Afshari
sumber
7
Dalam C # 4 (2010) dan yang lebih baru (tidak dirilis ketika Anda menulis jawaban Anda) dimungkinkan untuk menandai Tsebagai contravarian, dan Vsebagai kovarian. Namun, karena parameter ( output) tipe Udilewati oleh referensi , Utidak dapat ditandai co-atau contravarian dan harus tetap "invarian". Jadi pertimbangkan public delegate V MyDelegate<in T, U, out V>(T input, out U output);jika Anda menggunakan C # 4 atau lebih baru.
Jeppe Stig Nielsen
24

Mengapa tidak membuat kelas untuk merangkum hasilnya?

public class Result
{
     public IList<Foo> List { get; set; }
     public Int32 Count { get; set; }
}
Kekacauan Kekacauan
sumber
13

The Funckeluarga delegasi (atau Actiondalam hal ini) tidak lain hanyalah jenis delegasi sederhana dinyatakan seperti

//.NET 4 and above
public delegate TResult Func<out TResult>()
public delegate TResult Func<in T, out TResult>(T obj)

//.NET 3.5
public delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2)
public delegate TResult Func<T1, T2, T3, TResult>(T1 obj1, T2 obj2, T3 obj3)

dll. Delegasi dapat memiliki parameter out / ref, jadi dalam kasus Anda ini hanya masalah implementasi kustom sendiri seperti yang ditunjukkan oleh jawaban lain. Mengenai mengapa Microsoft tidak mengemas ini secara default, pikirkan banyaknya kombinasi yang diperlukan.

delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2)
delegate TResult Func<T1, T2, TResult>(out T1 obj1, T2 obj2)
delegate TResult Func<T1, T2, TResult>(T1 obj1, out T2 obj2)
delegate TResult Func<T1, T2, TResult>(out T1 obj1, out T2 obj2)

hanya untuk dua parameter. Kami bahkan belum menyentuh ref. Ini sebenarnya akan merepotkan dan membingungkan bagi pengembang.

nawfal
sumber
2
Perhatikan bahwa fungsi C # yang berlebihan tidak dapat membedakan antara delegate TResult Func<T1, T2, TResult>(T1 obj, T2 obj)dan delegate TResult Func<T1, T2, TResult>(out T1 obj, T2 obj). Jadi selain jumlah nama simbol kelebihan adalah alasan lain mengapa Microsoft tidak bisa menambahkan kelebihan ini Func.
Kasper van den Berg
Dapatkah seseorang merujuk saya ke artikel MSDN pada delegasi di atas?
Su Llewellyn
@SuLlewellyn Saya tidak dapat menemukan artikel asli msdn, tetapi Anda dapat mencoba: docs.microsoft.com/en-us/dotnet/api/… , docs.microsoft.com/en-us/dotnet/api/…
nawfal
0

Anda bisa membungkusnya dalam lambda / delegate / function / method yang mengekspos antarmuka yang tepat dan bernama FindForBar, tetapi saya menduga bahwa FindForBar telah menghitung sebagai parameter sebagai alasan, jadi Anda harus yakin membuang informasi itu tadinya ok / aman / diinginkan / memiliki hasil yang tepat (Anda harus yakin akan hal ini bahkan jika Anda bisa langsung lulus di FindForBar).

Logan Capaldo
sumber