Saya memiliki kelas ini
public class Overloaded
{
public void ComplexOverloadResolution(params string[] something)
{
Console.WriteLine("Normal Winner");
}
public void ComplexOverloadResolution<M>(M something)
{
Console.WriteLine("Confused");
}
}
Jika saya menyebutnya seperti ini:
var blah = new Overloaded();
blah.ComplexOverloadResolution("Which wins?");
Ini menulis Normal Winner
ke konsol.
Tapi, jika saya menambahkan metode lain:
public void ComplexOverloadResolution(string something, object somethingElse = null)
{
Console.WriteLine("Added Later");
}
Saya mendapatkan kesalahan berikut:
Panggilan tersebut ambigu antara metode atau properti berikut:> '
Overloaded.ComplexOverloadResolution(params string[])
' dan 'Overloaded.ComplexOverloadResolution<string>(string)
'
Saya dapat memahami bahwa menambahkan metode mungkin memperkenalkan ambiguitas panggilan, tetapi itu adalah ambiguitas antara dua metode yang sudah ada (params string[])
dan <string>(string)
! Jelas tak satu pun dari dua metode yang terlibat dalam ambiguitas adalah metode yang baru ditambahkan, karena yang pertama adalah params, dan yang kedua adalah generik.
Apakah ini bug? Bagian mana dari spesifikasi yang mengatakan bahwa seharusnya demikian?
sumber
'Overloaded.ComplexOverloadResolution(string)'
mengacu pada<string>(string)
metode; Saya pikir ini mengacu pada(string, object)
metode tanpa objek yang diberikan.Jawaban:
Iya.
Selamat, Anda menemukan bug dalam resolusi kelebihan beban. Bug mereproduksi di C # 4 dan 5; itu tidak mereproduksi dalam versi "Roslyn" dari penganalisis semantik. Saya telah memberi tahu tim penguji C # 5, dan mudah-mudahan kami dapat menyelidiki dan menyelesaikan masalah ini sebelum rilis final. (Seperti biasa, tidak ada janji.)
Analisis yang benar mengikuti. Kandidatnya adalah:
Kandidat nol jelas tidak dapat diterapkan karena
string
tidak dapat dikonversistring[]
. Tinggal tiga.Dari ketiganya, kita harus menentukan metode unik terbaik. Kami melakukannya dengan membuat perbandingan berpasangan dari tiga kandidat yang tersisa. Ada tiga pasangan seperti itu. Semuanya memiliki daftar parameter yang identik setelah kita menghapus parameter opsional yang dihilangkan, yang berarti kita harus pergi ke putaran tiebreaking lanjutan yang dijelaskan dalam bagian 7.5.3.2 spesifikasi.
Mana yang lebih baik, 1 atau 2? Tiebreaker yang relevan adalah bahwa metode generik selalu lebih buruk daripada metode non-generik. 2 lebih buruk dari 1. Jadi 2 tidak bisa menjadi pemenang.
Mana yang lebih baik, 1 atau 3? Tiebreak yang relevan adalah: metode yang hanya dapat diterapkan dalam bentuk yang diperluas selalu lebih buruk daripada metode yang dapat diterapkan dalam bentuk normalnya. Oleh karena itu 1 lebih buruk dari 3. Jadi 1 tidak bisa menjadi pemenang.
Mana yang lebih baik, 2 atau 3? Tiebreaker yang relevan adalah bahwa metode generik selalu lebih buruk daripada metode non-generik. 2 lebih buruk dari 3. Jadi 2 tidak bisa menjadi pemenang.
Untuk dipilih dari sekumpulan beberapa kandidat yang berlaku, seorang kandidat harus (1) tidak terkalahkan, (2) mengalahkan setidaknya satu kandidat lainnya, dan (3) menjadi kandidat unik yang memiliki dua properti pertama. Kandidat tiga dikalahkan oleh kandidat lain, dan mengalahkan setidaknya satu kandidat lainnya; itu adalah satu-satunya kandidat dengan properti ini. Oleh karena itu, kandidat ketiga adalah kandidat terbaik yang unik . Ini harus menang.
Tidak hanya compiler C # 4 yang salah, seperti yang Anda catat dengan benar, compiler ini melaporkan pesan kesalahan yang aneh. Bahwa kompiler salah melakukan analisis resolusi kelebihan beban sedikit mengejutkan. Bahwa mendapatkan pesan kesalahan yang salah sama sekali tidak mengejutkan; heuristik kesalahan "metode ambigu" pada dasarnya mengambil dua metode dari kumpulan kandidat jika metode terbaik tidak dapat ditentukan. Tidaklah pandai menemukan ambiguitas yang "sebenarnya", jika sebenarnya ada.
Orang mungkin bertanya mengapa demikian. Sangat sulit untuk menemukan dua metode yang "sangat ambigu" karena hubungan "betterness" adalah intransitif . Ada kemungkinan untuk menghadapi situasi di mana kandidat 1 lebih baik dari 2, 2 lebih baik dari 3, dan 3 lebih baik dari 1. Dalam situasi seperti itu, kita tidak dapat melakukan lebih baik daripada memilih dua di antaranya sebagai "yang ambigu".
Saya ingin meningkatkan heuristik ini untuk Roslyn tetapi ini adalah prioritas rendah.
(Latihan untuk pembaca: "Rancang algoritma waktu linier untuk mengidentifikasi anggota terbaik yang unik dari himpunan n elemen di mana hubungan betterness adalah intransitif" adalah salah satu pertanyaan yang saya tanyakan pada hari saya mewawancarai tim ini. Bukan algoritma yang sangat sulit; cobalah.)
Salah satu alasan mengapa kami menunda untuk menambahkan argumen opsional ke C # untuk waktu yang lama adalah banyaknya situasi ambigu kompleks yang diperkenalkannya ke dalam algoritma resolusi berlebih; ternyata kami tidak melakukannya dengan benar.
Jika Anda ingin memasukkan masalah Hubungkan untuk melacaknya, silakan. Jika Anda hanya ingin hal itu diperhatikan kami, anggap saja sudah selesai. Saya akan menindaklanjuti dengan pengujian tahun depan.
Terima kasih sudah membawa ini padaku. Maaf atas kesalahannya.
sumber
Bagian 7.5.3 (resolusi kelebihan beban), bersama dengan bagian 7.4 (pencarian anggota) dan 7.5.2 (jenis inferensi).
Perhatikan terutama bagian 7.5.3.2 (anggota fungsi yang lebih baik), yang mengatakan di bagian "parameter opsional tanpa argumen yang sesuai akan dihapus dari daftar parameter", dan "Jika M (p) adalah metode non-generik dan M (q) adalah metode umum, maka M (p) lebih baik dari M (q). "Namun, saya tidak memahami bagian-bagian spesifikasi ini dengan cukup menyeluruh untuk mengetahui bagian mana dari spesifikasi yang mengontrol perilaku ini, apalagi untuk menilai apakah itu sesuai.
sumber
Anda dapat menghindari ambiguitas ini dengan mengubah nama parameter pertama dalam beberapa metode dan menentukan parameter yang ingin Anda tetapkan
seperti ini :
sumber
Jika Anda menghapus
params
dari metode pertama Anda, ini tidak akan terjadi. Anda metode pertama dan ketiga memiliki kedua panggilan yang validComplexOverloadResolution(string)
, tetapi jika metode pertama Anda adalahpublic void ComplexOverloadResolution(string[] something)
tidak akan ada ambiguitas.Memasok nilai untuk sebuah parameter
object somethingElse = null
menjadikannya parameter opsional dan karenanya tidak harus ditentukan saat memanggil kelebihan beban itu.Sunting: Kompiler melakukan beberapa hal gila di sini. Jika Anda memindahkan metode ketiga dalam kode setelah yang pertama, metode itu akan melaporkan dengan benar. Jadi tampaknya itu mengambil dua kelebihan pertama dan melaporkannya, tanpa memeriksa yang benar.
Edit2: Temuan baru. Menghapus metode apa pun dari ketiga metode di atas tidak akan menghasilkan ambiguaty antara keduanya. Jadi tampaknya konflik hanya muncul jika ada tiga metode yang ada, terlepas dari urutannya.
sumber
Jika Anda menulis
atau hanya menulis
itu akan berakhir dengan metode yang sama , dalam metode
Hal ini menyebabkan
params
kata kunci yang membuatnya paling cocok juga untuk kasus ketika tidak ada parameter yang ditentukanJika Anda mencoba menambahkan metode baru seperti ini
Ini akan mengkompilasi dan memanggil metode ini dengan sempurna karena ini sangat cocok untuk panggilan Anda dengan
string
parameter. Jauh lebih kuatparams string[] something
.Anda mendeklarasikan metode kedua seperti yang Anda lakukan
Compiler, kebingungan total antara metode pertama dan ini, baru saja menambahkan satu. Karena tidak tahu fungsi mana yang harus dia lakukan sekarang dalam panggilan Anda
Faktanya, jika Anda menghapus parameter string dari panggilan, seperti kode berikut, semuanya dikompilasi dengan benar dan berfungsi seperti sebelumnya
sumber
state
3 fungsi, bukan satu atau beberapa dari mereka, tepatnya. Faktanya, cukup mengomentari salah satu dari mereka, untuk menyelesaikan masalah. Yang paling cocok di antara fungsi yang tersedia adalah yang denganparams
, yang kedua adalah dengangenerics
parameter, ketika kita menambahkan yang ketiga itu menciptakan kebingungan di salahset
satu fungsi. Saya pikir, kemungkinan besar, itu bukan pesan kesalahan yang jelas yang dihasilkan oleh compiler.