Bagikan melalui


Memperluas Metode Parsial

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 tercantum dalam catatan rapat desain bahasa (LDM) yang relevan .

Anda dapat mempelajari lebih lanjut tentang proses untuk mengadopsi speklet fitur ke dalam standar bahasa C# dalam artikel tentang spesifikasi .

Edisi juara: https://github.com/dotnet/csharplang/issues/3301

Ringkasan

Proposal ini bertujuan untuk menghapus semua batasan di sekitar tanda tangan metode partial di C#. Tujuannya adalah untuk memperluas serangkaian skenario di mana metode ini dapat bekerja dengan generator sumber serta menjadi formulir deklarasi yang lebih umum untuk metode C#.

Lihat juga spesifikasi metode parsial asli (ยง15.6.9).

Motivasi

C# memiliki dukungan terbatas untuk pengembang yang membagi metode menjadi deklarasi dan definisi /implementasi.

partial class C
{
    // The declaration of C.M
    partial void M(string message);
}

partial class C
{
    // The definition of C.M
    partial void M(string message) => Console.WriteLine(message);
}

Salah satu perilaku metode partial adalah bahwa ketika definisi tidak ada maka bahasa hanya akan menghapus panggilan apa pun ke metode partial. Pada dasarnya itu berperilaku seperti panggilan ke metode [Conditional] ketika kondisi dievaluasi menjadi salah.

partial class D
{
    partial void M(string message);

    void Example()
    {
        M(GetIt()); // Call to M and GetIt erased at compile time
    }

    string GetIt() => "Hello World";
}

Motivasi asli untuk fitur ini adalah pembuatan sumber dalam bentuk kode yang dihasilkan desainer. Pengguna terus mengedit kode yang dihasilkan karena mereka ingin menghubungkan beberapa aspek kode yang dihasilkan. Sebagian besar bagian dari proses startup Windows Forms, setelah komponen diinisialisasi.

Mengedit kode yang dihasilkan rentan terhadap kesalahan karena tindakan apa pun yang menyebabkan perancang meregenerasi kode akan menyebabkan pengeditan pengguna dihapus. Fitur metode partial meredakan ketegangan ini karena memungkinkan perancang untuk memancarkan kait dalam bentuk metode partial.

Desainer dapat menghasilkan kait seperti partial void OnComponentInit() dan pengembang dapat menentukan deklarasi untuk itu atau tidak menentukannya. Dalam kedua kasus, meskipun demikian, kode yang dihasilkan dapat dikompilasi, dan pengembang yang tertarik dengan proses tersebut dapat terlibat sesuai kebutuhan.

Ini berarti bahwa metode parsial memiliki beberapa batasan:

  1. Harus memiliki jenis pengembalian void.
  2. Tidak boleh memiliki parameter out.
  3. Tidak dapat memiliki aksesibilitas (secara implisit private).

Pembatasan ini ada karena bahasa harus dapat memancarkan kode saat situs panggilan dihapus. Mengingat bahwa elemen ini dapat dihapus, private adalah satu-satunya kemungkinan aksesibilitas karena anggota tidak dapat diekspos dalam metadata rakitan. Pembatasan ini juga berfungsi untuk membatasi serangkaian skenario di mana metode partial dapat diterapkan.

Proposal di sini adalah menghapus semua batasan yang ada di sekitar metode partial. Pada dasarnya, biarkan mereka memiliki parameter out, jenis pengembalian yang bukan void, atau tipe aksesibilitas apa pun. Deklarasi partial tersebut kemudian akan memiliki persyaratan tambahan bahwa definisi harus ada. Itu berarti bahasa tidak perlu mempertimbangkan dampak penghapusan situs panggilan.

Ini akan memperluas kumpulan skenario generator yang dapat diikuti oleh metode partial dan dengan demikian terhubung dengan baik dengan fitur generator sumber kami. Misalnya regex dapat didefinisikan menggunakan pola berikut:

[RegexGenerated("(dog|cat|fish)")]
partial bool IsPetMatch(string input);

Ini memberi pengembang cara deklaratif sederhana untuk memilih generator serta memberikan generator serangkaian deklarasi yang sangat mudah untuk dilihat dalam kode sumber untuk mendorong output yang dihasilkan.

Bandingkan dengan kesulitan yang akan dialami generator saat menyambungkan cuplikan kode berikut.

var regex = new RegularExpression("(dog|cat|fish)");
if (regex.IsMatch(someInput))
{

}

Mengingat bahwa pengompilasi tidak memungkinkan generator untuk memodifikasi kode, menghubungkan pola ini akan sangat mustahil bagi generator. Mereka mungkin perlu menggunakan refleksi dalam implementasi IsMatch, atau meminta pengguna untuk mengubah lokasi pemanggilan mereka ke metode baru dan merefaktor regex untuk meneruskan literal string sebagai argumen. Ini cukup berantakan.

Desain Terperinci

Bahasa ini akan berubah untuk memungkinkan metode partial dianotasikan dengan pengubah aksesibilitas eksplisit. Ini berarti mereka dapat diberi label sebagai private, public, dll ...

Ketika metode partial memiliki pengubah aksesibilitas eksplisit, bahasa akan mengharuskan deklarasi memiliki definisi yang cocok bahkan ketika aksesibilitas private:

partial class C
{
    // Okay because no definition is required here
    partial void M1();

    // Okay because M2 has a definition
    private partial void M2();

    // Error: partial method M3 must have a definition
    private partial void M3();
}

partial class C
{
    private partial void M2() { }
}

Selanjutnya bahasa akan menghapus semua batasan tentang apa yang dapat muncul pada metode partial yang memiliki aksesibilitas eksplisit. Deklarasi tersebut dapat berisi jenis pengembalian yang tidak kosong, parameter out, pengubah extern, dll ... Tanda tangan ini akan memiliki kemampuan ekspresif penuh dari bahasa C#.

partial class D
{
    // Okay
    internal partial bool TryParse(string s, out int i); 
}

partial class D
{
    internal partial bool TryParse(string s, out int i) { ... }
}

Ini secara eksplisit memungkinkan metode partial untuk berpartisipasi dalam implementasi overrides dan interface:

interface IStudent
{
    string GetName();
}

partial class C : IStudent
{
    public virtual partial string GetName(); 
}

partial class C
{
    public virtual partial string GetName() => "Jarde";
}

Pengkompilasi akan mengubah pesan kesalahan yang dikeluarkannya ketika metode partial berisi elemen ilegal, sehingga secara esensial memberi tahu:

Tidak dapat menggunakan ref pada metode partial yang tidak memiliki aksesibilitas eksplisit

Ini akan membantu mengarahkan pengembang ke arah yang benar saat menggunakan fitur ini.

Restriksi:

  • partial deklarasi dengan aksesibilitas eksplisit harus memiliki definisi
  • partial deklarasi dan tanda tangan definisi harus cocok dengan semua pengubah metode dan parameter. Satu-satunya aspek yang dapat berbeda adalah nama parameter dan daftar atribut (ini bukan baru melainkan persyaratan metode partial yang ada).

Pertanyaan

sebagian untuk semua anggota

Mengingat bahwa kami memperluas partial agar lebih ramah terhadap generator sumber kode, haruskah kami juga memperluasnya agar dapat berfungsi pada semua anggota kelas? Misalnya, kita harus dapat mendeklarasikan konstruktor partial, operator, dll ...

Resolusi Idenya bagus, tetapi pada tahap ini dalam jadwal C# 9, kami mencoba menghindari kelebihan fitur yang tidak perlu. Ingin menyelesaikan masalah yang mendesak dengan memperluas fitur agar dapat bekerja dengan generator sumber modern.

Akan dipertimbangkan memperluas partial untuk mendukung anggota lainnya pada rilis C# 10. Sepertinya kita akan mempertimbangkan ekstensi ini. Ini tetap menjadi proposal aktif, tetapi belum diimplementasikan.

Gunakan abstrak daripada parsial

Crux dari proposal ini pada dasarnya memastikan bahwa deklarasi memiliki definisi / implementasi yang sesuai. Sebab, sebaiknya kita menggunakan abstract karena sudah menjadi kata kunci bahasa yang menyebabkan pengembang memikirkan tentang implementasi.

Resolusi Ada diskusi yang sehat tentang hal ini tetapi akhirnya diputuskan untuk tidak melanjutkan. Ya persyaratannya akrab tetapi konsepnya sangat berbeda. Dapat dengan mudah membuat pengembang percaya bahwa mereka sedang membuat slot virtual padahal sebenarnya tidak.