Pertama, izinkan saya mengatakan bahwa jawaban Jon benar. Ini adalah salah satu bagian paling hairiest dari spesifikasi, sangat bagus bagi Jon untuk menyelami kepalanya terlebih dahulu.
Kedua, izinkan saya mengatakan bahwa baris ini:
Ada konversi implisit dari grup metode ke tipe delegasi yang kompatibel
(penekanan ditambahkan) sangat menyesatkan dan sangat disayangkan. Saya akan berbicara dengan Mads tentang menghapus kata "kompatibel" di sini.
Alasan mengapa hal ini menyesatkan dan tidak menguntungkan adalah karena sepertinya ini memanggil bagian 15.2, "Kompatibilitas delegasi". Bagian 15.2 menjelaskan hubungan kompatibilitas antara metode dan tipe delegasi , tetapi ini adalah pertanyaan tentang konvertibilitas grup metode dan tipe delegasi , yang berbeda.
Sekarang setelah kita menyelesaikannya, kita dapat berjalan melalui bagian 6.6 dari spesifikasi dan melihat apa yang kita dapatkan.
Untuk melakukan resolusi kelebihan beban, pertama-tama kita perlu menentukan kelebihan beban mana yang merupakan kandidat yang berlaku . Kandidat dapat diterapkan jika semua argumen secara implisit dapat diubah menjadi tipe parameter formal. Pertimbangkan versi program Anda yang disederhanakan ini:
class Program
{
delegate void D1();
delegate string D2();
static string X() { return null; }
static void Y(D1 d1) {}
static void Y(D2 d2) {}
static void Main()
{
Y(X);
}
}
Jadi mari kita bahas baris demi baris.
Ada konversi implisit dari grup metode ke tipe delegasi yang kompatibel.
Saya sudah membahas bagaimana kata "kompatibel" tidak menguntungkan di sini. Bergerak. Kami bertanya-tanya ketika melakukan resolusi kelebihan beban pada Y (X), apakah metode grup X dikonversi ke D1? Apakah itu dikonversi ke D2?
Diberikan tipe delegasi D dan ekspresi E yang diklasifikasikan sebagai grup metode, konversi implisit ada dari E ke D jika E berisi setidaknya satu metode yang dapat diterapkan [...] ke daftar argumen yang dibuat dengan menggunakan parameter jenis dan pengubah D, seperti yang dijelaskan berikut ini.
Sejauh ini baik. X mungkin berisi metode yang dapat diterapkan dengan daftar argumen D1 atau D2.
Aplikasi waktu kompilasi konversi dari metode grup E ke tipe delegasi D dijelaskan berikut ini.
Baris ini benar-benar tidak mengatakan sesuatu yang menarik.
Perhatikan bahwa keberadaan konversi implisit dari E ke D tidak menjamin bahwa aplikasi waktu kompilasi konversi akan berhasil tanpa kesalahan.
Garis ini sangat menarik. Ini berarti bahwa ada konversi implisit yang ada, tetapi dapat berubah menjadi kesalahan! Ini adalah aturan C # yang aneh. Untuk menyimpang sejenak, berikut contohnya:
void Q(Expression<Func<string>> f){}
string M(int x) { ... }
...
int y = 123;
Q(()=>M(y++));
Operasi increment ilegal di pohon ekspresi. Namun, lambda masih dapat diubah menjadi tipe pohon ekspresi, meskipun jika konversi pernah digunakan, itu adalah kesalahan! Prinsipnya di sini adalah bahwa kita mungkin ingin mengubah aturan tentang apa yang bisa masuk dalam pohon ekspresi nanti; mengubah aturan tersebut seharusnya tidak mengubah aturan sistem jenis . Kami ingin memaksa Anda untuk membuat program Anda tidak ambigu sekarang , sehingga saat kami mengubah aturan pohon ekspresi di masa mendatang untuk membuatnya lebih baik, kami tidak memperkenalkan perubahan yang melanggar dalam resolusi kelebihan beban .
Bagaimanapun, ini adalah contoh lain dari aturan aneh semacam ini. Sebuah konversi bisa saja ada untuk tujuan resolusi yang berlebihan, tapi bisa menjadi kesalahan untuk benar-benar digunakan. Padahal sebenarnya, bukan itu situasi kita saat ini.
Bergerak:
Sebuah metode tunggal M dipilih sesuai dengan pemanggilan metode dari bentuk E (A) [...] Daftar argumen A adalah daftar ekspresi, masing-masing diklasifikasikan sebagai variabel [...] dari parameter yang sesuai secara formal -parameter-daftar D.
BAIK. Jadi kami melakukan resolusi overload pada X sehubungan dengan D1. Daftar parameter formal D1 kosong, jadi kami melakukan resolusi berlebih pada X () dan kegembiraan, kami menemukan metode "string X ()" yang berfungsi. Demikian pula, daftar parameter formal D2 kosong. Sekali lagi, kami menemukan bahwa "string X ()" adalah metode yang berfungsi di sini juga.
Prinsipnya di sini adalah bahwa menentukan konvertibilitas grup metode memerlukan pemilihan metode dari grup metode menggunakan resolusi kelebihan beban , dan resolusi kelebihan beban tidak mempertimbangkan jenis kembalian .
Jika algoritma [...] menghasilkan kesalahan, maka kesalahan waktu kompilasi terjadi. Jika tidak, algoritme menghasilkan satu metode terbaik M yang memiliki jumlah parameter yang sama dengan D dan konversinya dianggap ada.
Hanya ada satu metode dalam metode grup X, jadi itu pasti yang terbaik. Kami telah berhasil membuktikan bahwa ada konversi dari X ke D1 dan dari X ke D2.
Sekarang, apakah baris ini relevan?
Metode yang dipilih M harus kompatibel dengan tipe delegasi D, atau jika tidak, kesalahan waktu kompilasi terjadi.
Sebenarnya, tidak, tidak dalam program ini. Kami tidak pernah sejauh mengaktifkan baris ini. Karena, ingat, yang kami lakukan di sini adalah mencoba melakukan resolusi kelebihan beban pada Y (X). Kami memiliki dua kandidat Y (D1) dan Y (D2). Keduanya dapat diterapkan. Mana yang lebih baik ? Tidak ada dalam spesifikasi yang kami gambarkan tentang kehebatan antara dua kemungkinan konversi ini .
Sekarang, orang pasti dapat berargumen bahwa konversi yang valid lebih baik daripada konversi yang menghasilkan kesalahan. Itu kemudian akan secara efektif mengatakan, dalam kasus ini, bahwa resolusi kelebihan beban TIDAK mempertimbangkan jenis kembalian, yang merupakan sesuatu yang ingin kita hindari. Pertanyaannya kemudian adalah prinsip mana yang lebih baik: (1) pertahankan invarian bahwa resolusi kelebihan beban tidak mempertimbangkan jenis pengembalian, atau (2) mencoba memilih konversi yang kita tahu akan berhasil yang kita tahu tidak akan?
Ini adalah panggilan penghakiman. Dengan lambda , kami melakukannya mempertimbangkan tipe kembali di semacam ini konversi, di bagian 7.4.3.3:
E adalah fungsi anonim, T1 dan T2 adalah tipe delegasi atau tipe pohon ekspresi dengan daftar parameter yang identik, tipe X yang disimpulkan ada untuk E dalam konteks daftar parameter tersebut, dan salah satu dari yang berikut ini:
T1 memiliki tipe pengembalian Y1, dan T2 memiliki tipe pengembalian Y2, dan konversi dari X ke Y1 lebih baik daripada konversi dari X ke Y2
T1 memiliki tipe pengembalian Y, dan T2 tidak berlaku kembali
Sayangnya, konversi grup metode dan konversi lambda tidak konsisten dalam hal ini. Namun, saya bisa menerimanya.
Bagaimanapun, kami tidak memiliki aturan "betterness" untuk menentukan konversi mana yang lebih baik, X ke D1 atau X ke D2. Oleh karena itu kami memberikan kesalahan ambiguitas pada resolusi Y (X).