Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Nota
Artikel ini adalah spesifikasi fitur. Spesifikasi berfungsi sebagai dokumen desain untuk fitur tersebut. Ini termasuk perubahan spesifikasi yang diusulkan, bersama dengan informasi yang diperlukan selama desain dan pengembangan fitur. Artikel ini diterbitkan sampai perubahan spesifikasi yang diusulkan diselesaikan dan dimasukkan dalam spesifikasi ECMA saat ini.
Mungkin ada beberapa perbedaan antara spesifikasi fitur dan implementasi yang selesai. Perbedaan tersebut ditangkap dalam catatan rapat desain bahasa (LDM) terkait .
Anda dapat mempelajari lebih lanjut tentang proses untuk mengadopsi speklet fitur ke dalam standar bahasa C# dalam artikel tentang spesifikasi .
Masalah juara: https://github.com/dotnet/csharplang/issues/6010
Ringkasan
Izinkan pengubah parameter di lokasi deklarasi ref readonly dan ubah aturan lokasi pemanggilan sebagai berikut:
| Anotasi titik panggilan | parameter ref |
parameter ref readonly |
parameter in |
parameter out |
|---|---|---|---|---|
ref |
Diperbolehkan | Diizinkan | Peringatan | Kesalahan |
in |
Kesalahan | Diizinkan | Diperbolehkan | Kesalahan |
out |
Kesalahan | Kesalahan |
Kesalahan | Diperbolehkan |
| Tidak ada anotasi | Kesalahan | Peringatan | Diperbolehkan | Kesalahan |
(Perhatikan bahwa ada satu perubahan pada aturan yang ada: parameter in dengan anotasi ref callsite menghasilkan peringatan alih-alih kesalahan.)
Ubah aturan nilai argumen sebagai berikut:
| Jenis nilai | parameter ref |
parameter ref readonly |
parameter in |
parameter out |
|---|---|---|---|---|
| rvalue | Kesalahan | Peringatan | Diperbolehkan | Kesalahan |
| lvalue | Diperbolehkan | Diizinkan | Diperbolehkan | Diperbolehkan |
Jika lvalue berarti variabel (yaitu, nilai dengan lokasi; tidak harus dapat ditulis/ditetapkan) dan rvalue berarti segala jenis nilai.
Motivasi
C# 7.2 memperkenalkan parameter in sebagai cara untuk meneruskan referensi hanya-baca.
Parameter in memungkinkan penggunaan baik lvalue maupun rvalue dan dapat digunakan tanpa anotasi apa pun pada titik pemanggilan.
Namun, API yang menangkap atau mengembalikan referensi dari parameter mereka ingin melarang rvalue dan juga memberlakukan beberapa indikasi di callsite bahwa referensi sedang diambil.
ref readonly parameter-parameter sangat ideal dalam kasus seperti ini karena mereka memberikan peringatan jika digunakan dengan rvalue atau tanpa anotasi apa pun di situs pemanggilan.
Selain itu, ada API yang hanya membutuhkan referensi baca-saja tetapi menggunakan
- parameter
reftelah diperkenalkan sebelumintersedia, dan perubahan keinakan menyebabkan perubahan yang memecahkan keserasian sumber dan biner, misalnya,QueryInterface, atau -
inparameter untuk menerima referensi baca-saja meskipun penerusan rvalue kepada mereka sebenarnya tidak masuk akal, misalnya,ReadOnlySpan<T>..ctor(in T value), atau -
refparameter untuk melarang penggunaan rvalue meskipun tidak mengubah referensi yang diberikan, misalnya,Unsafe.IsNullRef.
API ini dapat bermigrasi ke parameter ref readonly tanpa melanggar pengguna.
Untuk detail tentang kompatibilitas biner, lihat pengodean metadata yang diusulkan.
Secara khusus, mengubah
-
ref→ref readonlyhanya akan menjadi perubahan pemecah biner untuk metode virtual, -
ref→injuga akan menjadi perubahan pemecahan biner untuk metode virtual, tetapi bukan perubahan pemecahan sumber (karena aturan berubah menjadi hanya memperingatkan untuk argumenrefyang diteruskan ke parameterin), -
in→ref readonlybukan perubahan yang mempengaruhi (tetapi anotasi callsite atau rvalue tidak akan menghasilkan peringatan),- perhatikan bahwa ini akan menjadi perubahan yang merusak sumber bagi pengguna yang menggunakan versi kompilator yang lebih lama (saat mereka menafsirkan parameter
ref readonlysebagai parameterref, tidak mengizinkaninatau tanpa anotasi di lokasi pemanggilan) dan versi kompilator baru denganLangVersion <= 11(untuk konsistensi dengan versi kompilator yang lebih lama, kesalahan akan dikeluarkan bahwa parameterref readonlytidak didukung kecuali argumen yang sesuai diteruskan dengan pengubahref).
- perhatikan bahwa ini akan menjadi perubahan yang merusak sumber bagi pengguna yang menggunakan versi kompilator yang lebih lama (saat mereka menafsirkan parameter
Di arah yang berlawanan, berubah
-
ref readonly→refakan berpotensi menjadi perubahan yang dapat memutuskan kompatibilitas dengan kode sumber (kecuali hanya anotasi lokasi pemanggilanrefyang digunakan dan hanya referensi baca-saja yang digunakan sebagai argumen), dan perubahan yang dapat memutuskan kompatibilitas biner untuk metode virtual. -
ref readonly→intidak akan menjadi perubahan yang merusak (tetapi anotasi callsiterefakan menghasilkan peringatan).
Perhatikan bahwa aturan yang diuraikan di atas berlaku untuk tanda tangan metode, tetapi tidak untuk mendelegasikan tanda tangan.
Misalnya, mengubah ref ke in dalam tanda tangan delegasi dapat menjadi perubahan pemecah sumber (jika pengguna menetapkan metode dengan parameter ref ke jenis delegasi tersebut, itu akan menjadi kesalahan setelah API berubah).
Desain terperinci
Secara umum, aturan untuk parameter ref readonly sama dengan yang ditentukan untuk parameter in di proposal mereka, kecuali jika secara eksplisit berubah dalam proposal ini.
Deklarasi parameter
Tidak ada perubahan tata bahasa yang diperlukan.
Pengubah ref readonly akan diizinkan untuk parameter.
Selain metode normal, ref readonly akan diizinkan untuk parameter pengindeks (seperti in tetapi tidak seperti ref), tetapi tidak diizinkan untuk parameter operator (seperti ref tetapi tidak seperti in).
Nilai parameter bawaan akan diizinkan untuk parameter ref readonly dengan peringatan, karena ini setara dengan pengoperan rvalue.
Ini memungkinkan penulis API mengubah parameter in dengan nilai default ke parameter ref readonly tanpa memperkenalkan perubahan pemecahan sumber.
Pengecekan tipe nilai
Perhatikan bahwa meskipun pengubah argumen ref diizinkan untuk parameter ref readonly, tidak ada yang berubah w.r.t. pemeriksaan jenis nilai, yaitu,
-
refhanya dapat digunakan dengan nilai yang dapat ditetapkan; - untuk meneruskan referensi baca-saja, seseorang harus menggunakan pengubah argumen
insebagai gantinya; - untuk mengoperkan rvalue, seseorang harus tidak menggunakan pengubah (yang akan menghasilkan peringatan untuk parameter
ref readonlyseperti yang dijelaskan dalam ringkasan proposal ini).
Penyelesaian kelebihan muatan
Resolusi kelebihan beban akan memungkinkan pencampuran ref/ref readonly/in/tanpa anotasi callsite dan pengubah parameter seperti yang ditunjukkan oleh tabel dalam ringkasanproposal ini, yaitu, semua diizinkan dan peringatan kasus akan dianggap sebagai kandidat mungkin selama resolusi kelebihan beban.
Secara khusus, ada perubahan perilaku yang sudah ada di mana metode dengan parameter in akan sesuai dengan panggilan dengan argumen yang sama yang ditandai sebagai ref—perubahan ini akan dikendalikan pada LangVersion.
Namun, peringatan untuk meneruskan argumen tanpa pengubah callsite ke parameter ref readonly akan diabaikan jika parameternya
- penerima dalam pemanggilan metode ekstensi,
- digunakan secara implisit sebagai bagian dari penginisialisasi koleksi kustom atau handler string terinterpolasi.
Kelebihan beban berdasarkan nilai akan lebih disukai daripada kelebihan beban ref readonly jika tidak ada pengubah argumen ( parameterin memiliki perilaku yang sama).
Konversi metode
Demikian pula, untuk tujuan fungsi anonim [§10.7] dan grup metode [§10.8] konversi, modifikator ini dianggap kompatibel (tetapi konversi yang diizinkan antara modifikator yang berbeda menghasilkan peringatan):
- Parameter
ref readonlydari metode target diizinkan untuk cocok dengan parameterinataurefdari delegasi. - Parameter
indari metode target diizinkan untuk mencocokkan parameterref readonlyatau, berdasarkan LangVersion, parameterrefdari delegasi. - Catatan: parameter
refmetode target tidak diizinkan untuk mencocokkan parameterinatauref readonlydelegasi.
Misalnya:
DIn dIn = (ref int p) => { }; // error: cannot match `ref` to `in`
DRef dRef = (in int p) => { }; // warning: mismatch between `in` and `ref`
DRR dRR = (ref int p) => { }; // error: cannot match `ref` to `ref readonly`
dRR = (in int p) => { }; // warning: mismatch between `in` and `ref readonly`
dIn = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `in`
dRef = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `ref`
delegate void DIn(in int p);
delegate void DRef(ref int p);
delegate void DRR(ref readonly int p);
Perhatikan bahwa tidak ada perubahan perilaku konversi penunjuk fungsi . Sebagai pengingat, konversi penunjuk fungsi implisit tidak diizinkan jika ada ketidakcocokan antara pengubah jenis referensi, dan cast eksplisit selalu diizinkan tanpa peringatan apa pun.
Pencocokan tanda tangan
Anggota yang dinyatakan dalam satu jenis tidak dapat berbeda dalam tanda tangan hanya dengan ref/out/in/ref readonly.
Untuk tujuan lain pencocokan tanda tangan (misalnya, menyembunyikan atau mengambil alih), ref readonly dapat dipertukarkan dengan pengubah in, tetapi itu menghasilkan peringatan di situs deklarasi [§7,6].
Ini tidak berlaku saat mencocokkan deklarasi partial dengan implementasinya dan saat mencocokkan tanda tangan pencegat dengan tanda tangan yang dicegat.
Perhatikan bahwa tidak ada perubahan dalam penggantian untuk pasangan pengubah ref/in dan ref readonly/ref, mereka tidak dapat dipertukarkan, karena tanda tangan tidak kompatibel secara biner.
Untuk konsistensi, hal yang sama berlaku untuk tujuan pencocokan tanda tangan lainnya (misalnya, menyembunyikan).
Pengodean metadata
Sebagai pengingat,
- parameter
refdipancarkan sebagai jenis byref biasa (T&di IL), - parameter
insepertirefditambah mereka diannotasi denganSystem.Runtime.CompilerServices.IsReadOnlyAttribute. Pada C# 7.3 dan versi lebih baru, mereka juga dihasilkan dengan[in]dan jika bersifat virtual, denganmodreq(System.Runtime.InteropServices.InAttribute).
ref readonly parameter akan dipancarkan sebagai [in] T&, ditambah diannotasi dengan atribut berikut:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class RequiresLocationAttribute : Attribute
{
}
}
Selain itu, jika virtual, mereka akan dipancarkan dengan modreq(System.Runtime.InteropServices.InAttribute) untuk memastikan kompatibilitas biner dengan parameter in.
Perhatikan bahwa tidak seperti parameter in, tidak ada [IsReadOnly] yang akan dipancarkan untuk parameter ref readonly untuk menghindari peningkatan ukuran metadata dan juga untuk membuat versi kompilator yang lebih lama menafsirkan parameter ref readonly sebagai parameter ref (dan karenanya ref → ref readonly tidak akan menjadi perubahan pemecah sumber bahkan di antara versi kompilator yang berbeda).
RequiresLocationAttribute akan dicocokkan dengan nama yang memenuhi syarat namespace dan disintesis oleh kompilator jika belum disertakan dalam kompilasi.
Menentukan atribut dalam sumber akan menjadi kesalahan jika diterapkan ke parameter, mirip dengan ParamArrayAttribute.
Penunjuk fungsi
Dalam penunjuk fungsi, parameter in dipancarkan dengan modreq(System.Runtime.InteropServices.InAttribute) (lihat proposal penunjuk fungsi ).
Parameter ref readonly akan dipancarkan tanpa modreq, tetapi menggunakan modopt(System.Runtime.CompilerServices.RequiresLocationAttribute).
Versi kompilator yang lebih lama akan mengabaikan modopt dan karenanya menafsirkan parameter ref readonly sebagai parameter ref (konsisten dengan perilaku kompilator yang lebih lama untuk metode normal dengan parameter ref readonly seperti yang dijelaskan di atas) dan versi kompilator baru yang mengetahui modopt akan menggunakannya untuk mengenali parameter ref readonly untuk memancarkan peringatan selama konversi dan pemanggilan .
Untuk konsistensi dengan versi kompilator yang lebih lama, versi pengkompilasi baru dengan LangVersion <= 11 akan melaporkan kesalahan bahwa parameter ref readonly tidak didukung kecuali argumen yang sesuai diteruskan dengan pengubah ref.
Perhatikan bahwa ini adalah hentian biner untuk mengubah pemodifikasi dalam tanda tangan penunjuk fungsi jika merupakan bagian dari API publik, oleh karena itu akan menjadi hentian biner saat mengubah ref atau in menjadi ref readonly.
Namun, gangguan sumber hanya akan terjadi untuk penelepon dengan LangVersion <= 11 saat mengubah in → ref readonly (jika memanggil penunjuk dengan pengubah situs panggilan in), sesuai dengan metode normal.
Perubahan mendasar
Relaksasi ref/in tidak cocok dalam resolusi kelebihan beban memperkenalkan perubahan yang melanggar perilaku yang ditunjukkan dalam contoh berikut:
class C
{
string M(in int i) => "C";
static void Main()
{
int i = 5;
System.Console.Write(new C().M(ref i));
}
}
static class E
{
public static string M(this C c, ref int i) => "E";
}
Di C# 11, panggilan terikat ke E.M, karenanya "E" dicetak.
Dalam C# 12, C.M diizinkan untuk mengikat (dengan peringatan) dan tidak ada cakupan ekstensi yang dicari karena kami memiliki kandidat yang berlaku, karenanya "C" dicetak.
Ada juga perubahan pemecahan sumber karena alasan yang sama.
Contoh di bawah ini menghasilkan "1" di C# 11, tetapi tidak berhasil dikompilasi karena kesalahan ambigu di C# 12.
var i = 5;
System.Console.Write(C.M(null, ref i));
interface I1 { }
interface I2 { }
static class C
{
public static string M(I1 o, ref int x) => "1";
public static string M(I2 o, in int x) => "2";
}
Contoh di atas menunjukkan pemutusan untuk pemanggilan metode. Namun, karena dipicu oleh perubahan penyelesaian kelebihan beban, pemutusan ini juga dapat terjadi dalam konversi metode.
Alternatif
Deklarasi Parameter
Penulis API dapat membuat anotasi parameter in yang dirancang untuk hanya menerima lvalue dengan atribut kustom dan menyediakan penganalisis untuk menandai penggunaan yang salah.
Ini tidak akan memungkinkan penulis API untuk mengubah tanda tangan API yang ada yang memilih untuk menggunakan parameter ref untuk melarang rvalue.
Penelepon API tersebut masih perlu melakukan pekerjaan ekstra untuk mendapatkan ref jika mereka hanya memiliki akses ke variabel ref readonly.
Mengubah API dari ref ke [RequiresLocation] in akan menyebabkan perubahan yang merusak sumber (dan dalam kasus metode virtual, juga perubahan yang merusak biner).
Alih-alih mengizinkan pengubah ref readonly, pengkompilasi dapat mengenali ketika atribut khusus (seperti [RequiresLocation]) diterapkan ke parameter.
Ini dibahas dalam LDM 2022-04-25, memutuskan ini adalah fitur bahasa, bukan penganalisis, sehingga harus terlihat seperti itu.
pemeriksaan jenis nilai
Meneruskan lvalue tanpa modifikasi apa pun ke parameter ref readonly dapat diizinkan tanpa peringatan, mirip dengan parameter byref implisit pada C++.
Ini dibahas dalam LDM 2022-05-11, dengan mencatat bahwa motivasi utama untuk parameter ref readonly adalah API yang menangkap atau mengembalikan referensi dari parameter-parameter ini, sehingga penanda dari jenis tertentu merupakan hal yang bermanfaat.
Meneruskan rvalue ke ref readonly bisa menjadi kesalahan, bukan peringatan.
Itu awalnya diterima dalam LDM 2022-04-25, tetapi kemudian diskusi email melonggarkannya karena kita akan kehilangan kemampuan untuk mengubah API yang ada tanpa mengganggu pengguna.
in bisa menjadi pengubah callsite "alami" untuk parameter ref readonly dan menggunakan ref dapat mengakibatkan peringatan.
Ini akan memastikan gaya kode yang konsisten dan membuatnya jelas di callsite bahwa referensi tersebut bersifat hanya-baca (tidak seperti ref).
Awalnya diterima pada LDM 2022-04-25.
Namun, peringatan bisa menjadi titik gesekan bagi penulis API untuk berpindah dari ref ke ref readonly.
Selain itu, in telah ditentukan ulang sebagai ref readonly dan fitur kenyamanan, oleh karena itu, hal ini ditolak dalam LDM 2022-05-11.
Ulasan tertunda dari LDM
Tidak satu pun dari opsi berikut diimplementasikan di C# 12. Mereka tetap merupakan usulan yang potensial.
Deklarasi Parameter
Urutan pengubah terbalik (readonly ref alih-alih ref readonly) dapat diizinkan.
Ini akan tidak konsisten dengan bagaimana readonly ref mengembalikan nilai dan kolom bertindak (urutan terbalik tidak diizinkan atau berarti sesuatu yang berbeda, masing-masing) dan dapat berbenturan dengan parameter hanya-baca jika diimplementasikan di masa depan.
Nilai parameter default bisa menjadi kesalahan untuk parameter ref readonly.
pemeriksaan jenis nilai
Kesalahan dapat dipancarkan alih-alih peringatan saat meneruskan rvalue ke parameter ref readonly atau tidak cocok dengan anotasi callsite dan pengubah parameter.
Demikian pula, modreq khusus dapat digunakan alih-alih atribut untuk memastikan parameter ref readonly berbeda dari parameter in pada tingkat biner.
Ini akan memberikan jaminan yang lebih kokoh, sehingga akan baik untuk API baru, tetapi menghambat adopsi pada API runtime yang sudah ada yang tidak memungkinkan perubahan besar.
Pemeriksaan jenis nilai dapat dilonggarkan untuk memungkinkan meneruskan referensi baca-saja melalui ref ke dalam parameter in/ref readonly.
Itu akan mirip dengan cara kerja penugasan ref dan pengembalian ref saat ini—mereka juga memungkinkan pengoperan referensi sebagai readonly melalui pengubah ref pada ekspresi sumber.
Namun, ref biasanya ada dekat dengan tempat di mana target dinyatakan sebagai ref readonly, jadi jelas kami meneruskan referensi sebagai readonly, tidak seperti pemanggilan yang argumen dan pengubah parameternya biasanya jauh terpisah.
Selain itu, mereka memungkinkan hanya pengubah ref tidak seperti argumen yang memungkinkan juga in, oleh karena itu in dan ref akan menjadi dapat dipertukarkan untuk argumen, atau in akan menjadi praktis usang jika pengguna ingin membuat kode mereka konsisten (mereka mungkin akan menggunakan ref di mana-mana karena itu adalah satu-satunya pengubah yang diizinkan untuk penetapan ref dan pengembalian ref).
Penyelesaian Kelebihan Beban
Resolusi, penimpaan, dan konversi kelebihan beban dapat melarang pertukaran pengubah ref readonly dan in.
Perubahan penentuan overload untuk parameter in yang sudah ada dapat diterapkan tanpa syarat (tanpa mempertimbangkan LangVersion), tetapi itu akan menjadi perubahan yang merusak kompatibilitas.
Memanggil metode ekstensi dengan penerima ref readonly dapat mengakibatkan peringatan "Argumen 1 harus diteruskan dengan kata kunci ref atau in" seperti yang akan terjadi untuk pemanggilan non-ekstensi tanpa pengubah callsite (pengguna dapat memperbaiki peringatan tersebut dengan mengubah pemanggilan metode ekstensi menjadi pemanggilan metode statis).
Peringatan yang sama dapat dilaporkan saat menggunakan penginisialisasi koleksi kustom atau handler string terinterpolasi dengan parameter ref readonly, meskipun pengguna tidak dapat mengatasinya.
ref readonly overload dapat lebih diutamakan daripada overload dengan parameter nilai ketika tidak ada pengubah pada lokasi panggilan atau mungkin ada kesalahan ambiguitas.
Konversi Metode
Kita dapat mengizinkan parameter ref dari metode target untuk mencocokkan parameter in dan ref readonly dari delegat.
Ini akan memungkinkan penulis API untuk berubah misalnya ref ke in dalam mendelegasikan tanda tangan tanpa melanggar pengguna mereka (secara konsisten dengan apa yang diizinkan untuk tanda tangan metode normal).
Namun, itu juga akan mengakibatkan pelanggaran jaminan readonly berikut hanya dengan peringatan:
class Program
{
static readonly int f = 123;
static void Main()
{
var d = (in int x) => { };
d = (ref int x) => { x = 42; }; // warning: mismatch between `ref` and `in`
d(f); // changes value of `f` even though it is `readonly`!
System.Console.WriteLine(f); // prints 42
}
}
Konversi pointer fungsi dapat memberikan peringatan pada ketidakcocokan ref readonly/ref/in, tetapi jika kita ingin mengaktifkan peringatan tersebut tergantung pada LangVersion, investasi implementasi yang signifikan akan diperlukan karena konversi tipe saat ini tidak memerlukan akses ke proses kompilasi.
Selain itu, meskipun ketidakcocokan dianggap kesalahan saat ini, mudah bagi pengguna untuk menambahkan cast untuk memungkinkan ketidakcocokan jika diinginkan.
pengodean Metadata
Menentukan RequiresLocationAttribute dalam sumber dapat diizinkan, mirip dengan atribut In dan Out.
Atau, itu bisa menjadi kesalahan ketika diterapkan dalam konteks lain daripada sekadar parameter, mirip dengan atribut IsReadOnly; untuk mempertahankan ruang desain lebih lanjut.
Parameter penunjuk fungsi ref readonly dapat dipancarkan dengan berbagai kombinasi modopt/modreq yang berbeda (catatan: "source break" dalam tabel ini berarti bagi penelepon dengan LangVersion <= 11):
| Pengubah | Dapat dikenali di seluruh kompilasi | Kompiler lama melihatnya sebagai |
ref → ref readonly |
in → ref readonly |
|---|---|---|---|---|
modreq(In) modopt(RequiresLocation) |
Ya | in |
biner, pemisah sumber | pemecahan biner |
modreq(In) |
Tidak | in |
biner, pemisah sumber | Oke |
modreq(RequiresLocation) |
Ya | tidak didukung | biner, pemisah sumber | biner, pemisah sumber |
modopt(RequiresLocation) |
Ya | ref |
pemecahan biner | biner, pemisah sumber |
Kita dapat memancarkan atribut [RequiresLocation] dan [IsReadOnly] untuk parameter ref readonly.
Kemudian in → ref readonly tidak akan menjadi perubahan yang mengganggu bahkan untuk versi kompilator yang lebih lama, tetapi ref → ref readonly akan menjadi perubahan yang memecah sumber untuk versi kompilator yang lebih lama (karena mereka akan menafsirkan ref readonly sebagai in, melarang pengubah ref) dan versi kompilator baru dengan fitur LangVersion <= 11 (untuk konsistensi).
Kita dapat membuat perilaku untuk LangVersion <= 11 berbeda dari perilaku untuk versi kompilator yang lebih lama.
Misalnya, itu bisa menjadi kesalahan setiap kali parameter ref readonly dipanggil (bahkan saat menggunakan pengubah ref di callsite), atau dapat selalu diizinkan tanpa kesalahan apa pun.
perubahan Melanggar
Proposal ini menyarankan untuk menerima perubahan yang mengubah perilaku karena seharusnya jarang terjadi, dibatasi oleh LangVersion, dan pengguna dapat mengatasinya dengan memanggil metode ekstensi secara eksplisit. Sebaliknya, kita bisa menguranginya dengan
- melarang ketidakcocokan
ref/in(yang hanya akan mencegah migrasi keinuntuk API lama yang menggunakanrefkarenainbelum tersedia), - memodifikasi aturan penyelesaian kelebihan muatan untuk terus mencari kecocokan yang lebih baik (ditentukan oleh aturan lebih baik yang dijabarkan di bawah) ketika ada ketidakcocokan jenis ref yang diperkenalkan dalam proposal ini,
- atau lanjutkan hanya untuk ketidakcocokan
refvs.in, bukan untuk yang lainnya (ref readonlyvs.ref/in/by-value).
- atau lanjutkan hanya untuk ketidakcocokan
Aturan perbaikan
Contoh berikut saat ini menghasilkan tiga kesalahan ambiguitas untuk tiga pemanggilan M.
Kita bisa menambahkan aturan kesempurnaan baru untuk menyelesaikan ambiguitas.
Ini juga akan menyelesaikan perubahan pemecahan sumber yang dijelaskan sebelumnya.
Salah satu caranya adalah membuat contoh mencetak 221 (di mana parameter ref readonly dicocokkan dengan argumen in karena akan ada peringatan jika dipanggil tanpa pengubah, sementara untuk parameter in, hal itu diperbolehkan).
interface I1 { }
interface I2 { }
class C
{
static string M(I1 o, in int i) => "1";
static string M(I2 o, ref readonly int i) => "2";
static void Main()
{
int i = 5;
System.Console.Write(M(null, ref i));
System.Console.Write(M(null, in i));
System.Console.Write(M(null, i));
}
}
Aturan perbaikan baru dapat memberikan penilaian buruk kepada parameter yang argumennya seharusnya dapat diteruskan dengan pengubah argumen yang berbeda untuk memperbaikinya.
Dengan kata lain, pengguna harus selalu dapat mengubah parameter yang lebih buruk menjadi parameter yang lebih baik dengan mengubah pengubah argumen yang sesuai.
Misalnya, ketika argumen diteruskan oleh in, parameter ref readonly lebih disukai daripada parameter in karena pengguna dapat meneruskan argumen berdasarkan nilai untuk memilih parameter in.
Aturan ini hanyalah ekstensi dari aturan preferensi by-value/in yang berlaku saat ini (ini adalah aturan resolusi kelebihan beban terakhir dan seluruh kelebihan beban lebih baik jika salah satu parameternya lebih baik dan tidak ada yang lebih buruk dari parameter yang sesuai dari kelebihan beban lain).
| Argumen | Parameter yang lebih baik | parameter yang lebih buruk |
|---|---|---|
ref/in |
ref readonly |
in |
ref |
ref |
ref readonly/in |
| menurut nilai | menurut nilai/in |
ref readonly |
in |
in |
ref |
Kita harus menangani konversi metode dengan cara yang sama.
Contoh berikut saat ini menghasilkan dua kesalahan akibat ambiguitas untuk dua penugasan pendelegasian.
Aturan kesejahteraan baru dapat lebih memilih parameter metode yang pengubah kesempurnaannya cocok dengan pengubah kesempurnaan parameter delegasi target yang sesuai daripada yang memiliki ketidakcocokan.
Oleh karena itu, contoh berikut akan mencetak 12.
class C
{
void M(I1 o, ref readonly int x) => System.Console.Write("1");
void M(I2 o, ref int x) => System.Console.Write("2");
void Run()
{
D1 m1 = this.M;
D2 m2 = this.M; // currently ambiguous
var i = 5;
m1(null, in i);
m2(null, ref i);
}
static void Main() => new C().Run();
}
interface I1 { }
interface I2 { }
class X : I1, I2 { }
delegate void D1(X s, ref readonly int x);
delegate void D2(X s, ref int x);
Rapat desain
- LDM 2022-04-25: fitur diterima
- LDM 2022-05-09: diskusi dibagi menjadi tiga bagian
LDM 2022-05-11: diperbolehkan tanpa anotasi callsite untuk parameter
C# feature specifications