Menerapkan kelas menggunakan kelas parsial
Dimungkinkan untuk membagi definisi kelas atau metode lebih dari dua file sumber atau lebih. Setiap file sumber berisi bagian dari definisi jenis atau metode, dan semua bagian digabungkan saat aplikasi dikompilasi.
Kelas parsial
Ada beberapa situasi ketika memisahkan definisi kelas diinginkan:
- Mendeklarasikan kelas melalui file terpisah memungkinkan beberapa programmer untuk mengerjakannya secara bersamaan.
- Anda dapat menambahkan kode ke kelas tanpa harus membuat ulang file sumber yang menyertakan sumber yang dihasilkan secara otomatis. Visual Studio menggunakan pendekatan ini saat membuat Windows Forms, kode pembungkus layanan Web, dan sebagainya. Anda dapat membuat kode yang menggunakan kelas ini tanpa harus mengubah file yang dibuat oleh Visual Studio.
- Generator sumber dapat menghasilkan fungsionalitas tambahan di kelas.
Untuk memisahkan definisi kelas, gunakan pengubah kata kunci parsial. Dalam praktiknya, setiap kelas parsial biasanya didefinisikan dalam file terpisah, sehingga lebih mudah untuk mengelola dan memperluas kelas dari waktu ke waktu.
Contoh Employee berikut menunjukkan bagaimana kelas mungkin dibagi menjadi dua file: Employee_Part1.cs dan Employee_Part2.cs.
// This is in Employee_Part1.cs
public partial class Employee
{
public void DoWork()
{
Console.WriteLine("Employee is working.");
}
}
// This is in Employee_Part2.cs
public partial class Employee
{
public void GoToLunch()
{
Console.WriteLine("Employee is at lunch.");
}
}
//Main program demonstrating the Employee class usage
public class Program
{
public static void Main()
{
Employee emp = new Employee();
emp.DoWork();
emp.GoToLunch();
}
}
// Expected Output:
// Employee is working.
// Employee is at lunch.
Kata kunci partial menunjukkan bahwa bagian lain dari kelas dapat ditentukan dalam namespace. Semua bagian harus menggunakan kata kunci partial. Semua bagian harus tersedia pada waktu kompilasi untuk membentuk jenis akhir. Semua bagian harus memiliki aksesibilitas yang sama, seperti public, private, dan sebagainya.
Jika ada bagian yang dinyatakan abstrak, maka seluruh jenis dianggap abstrak. Jika ada bagian yang dinyatakan disegel, maka seluruh jenis dianggap disegel. Jika ada bagian yang mendeklarasikan jenis dasar, maka seluruh jenis mewarisi kelas tersebut.
Semua bagian yang menentukan kelas dasar harus setuju, tetapi bagian yang menghilangkan kelas dasar masih mewarisi jenis dasar. Bagian dapat menentukan antarmuka dasar yang berbeda, dan jenis akhir mengimplementasikan semua antarmuka yang tercantum oleh semua deklarasi parsial. Anggota kelas, struktur, atau antarmuka apa pun yang dideklarasikan dalam definisi parsial tersedia untuk semua bagian lainnya. Jenis akhir adalah kombinasi semua bagian pada waktu kompilasi.
Nota
Pengubah partial tidak tersedia pada deklarasi delegasi atau enumerasi.
Contoh berikut menunjukkan bahwa jenis berlapis dapat berupa parsial, bahkan jika jenis yang ditumpuk di dalamnya tidak sebagian.
class Container
{
partial class Nested
{
void Test() { }
}
partial class Nested
{
void Test2() { }
}
}
Pada waktu kompilasi, atribut definisi jenis parsial digabungkan. Misalnya, pertimbangkan deklarasi berikut:
[SerializableAttribute]
partial class Moon { }
[ObsoleteAttribute]
partial class Moon { }
Ini setara dengan deklarasi berikut:
[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }
Berikut ini digabungkan dari semua definisi jenis parsial:
- Komentar XML. Namun, jika kedua deklarasi anggota parsial menyertakan komentar, hanya komentar dari anggota pelaksana yang disertakan.
- Antarmuka
- atribut parameter jenis generik
- atribut kelas
- anggota
Misalnya, pertimbangkan deklarasi berikut:
partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }
Ini setara dengan deklarasi berikut:
class Earth : Planet, IRotate, IRevolve { }
Pembatasan definisi kelas parsial
Ada beberapa aturan yang harus diikuti saat Anda bekerja dengan definisi kelas parsial:
Semua definisi jenis parsial yang dimaksudkan untuk menjadi bagian dari jenis yang sama harus dimodifikasi dengan parsial. Misalnya, deklarasi kelas berikut menghasilkan kesalahan:
public partial class A { } //public class A { } // Error, must also be marked partialPengubah parsial hanya dapat muncul segera sebelum kelas kata kunci, struct, atau antarmuka.
Jenis parsial berlapis diizinkan dalam definisi jenis parsial seperti yang diilustrasikan dalam contoh berikut:
partial class ClassWithNestedClass { partial class NestedClass { } } partial class ClassWithNestedClass { partial class NestedClass { } }Semua definisi jenis parsial yang dimaksudkan untuk menjadi bagian dari jenis yang sama harus didefinisikan dalam rakitan yang sama dan modul yang sama (.exe atau file .dll). Definisi parsial tidak dapat mencakup beberapa modul.
Nama kelas dan parameter jenis generik harus cocok pada semua definisi jenis parsial. Jenis generik bisa parsial. Setiap deklarasi parsial harus menggunakan nama parameter yang sama dalam urutan yang sama.
Kata kunci berikut pada definisi jenis parsial bersifat opsional, tetapi jika ada pada satu definisi jenis parsial, hal yang sama harus ditentukan pada definisi parsial lainnya untuk jenis yang sama:
- umum
- privat
- Dilindungi
- intern
- abstrak
- Disegel
- kelas dasar
- pengubah baru (bagian berlapis)
- batasan generik
Menerapkan kelas parsial
Dalam contoh berikut, bidang dan konstruktor kelas Coords dinyatakan dalam satu definisi kelas parsial (Coords_Part1.cs), dan metode PrintCoords dideklarasikan dalam definisi kelas parsial lainnya (Coords_Part2.cs). Pemisahan ini menunjukkan bagaimana kelas parsial dapat dibagi di beberapa file untuk pemeliharaan yang lebih mudah.
// This is in Coords_Part1.cs
public partial class Coords
{
private int x;
private int y;
public Coords(int x, int y)
{
this.x = x;
this.y = y;
}
}
// This is in Coords_Part2.cs
public partial class Coords
{
public void PrintCoords()
{
Console.WriteLine("Coords: {0},{1}", x, y);
}
}
// Main program demonstrating the Coords class usage
class TestCoords
{
static void Main()
{
Coords myCoords = new Coords(10, 15);
myCoords.PrintCoords();
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: Coords: 10,15
Anggota parsial
Kelas parsial dapat berisi anggota parsial. Satu bagian kelas berisi tanda tangan anggota. Implementasi dapat didefinisikan di bagian yang sama atau bagian lain.
Implementasi tidak diperlukan untuk metode parsial saat tanda tangan mematuhi aturan berikut:
Deklarasi tidak menyertakan pengubah akses apa pun. Metode ini memiliki akses privat secara default.
Jenis pengembalian
void.Tidak ada parameter yang memiliki pengubah
out.Deklarasi metode tidak dapat menyertakan salah satu pengubah berikut:
- Virtual
- ambil alih
- Disegel
- baru
- ekstern
Metode dan semua panggilan ke metode dihapus pada waktu kompilasi ketika tidak ada implementasi.
Metode apa pun yang tidak sesuai dengan semua batasan tersebut, termasuk properti dan pengindeks, harus memberikan implementasi. Implementasi tersebut mungkin disediakan oleh generator sumber. Properti parsial tidak dapat diimplementasikan menggunakan properti yang diimplementasikan secara otomatis. Kompilator tidak dapat membedakan antara properti yang diimplementasikan secara otomatis, dan deklarasi deklarasi properti parsial.
Dimulai dengan C# 13, deklarasi penerapan untuk properti parsial dapat menggunakan properti yang didukung bidang untuk menentukan deklarasi penerapan. Properti yang didukung bidang menyediakan sintaks ringkas di mana kata kunci bidang mengakses bidang backing yang disintesis kompilator untuk properti . Misalnya, Anda dapat menulis kode berikut:
// in file1.cs
public partial class PropertyBag
{
// Defining declaration
public partial int MyProperty { get; set; }
}
// In file2.cs
public partial class PropertyBag
{
// Defining declaration
public partial int MyProperty { get => field; set; }
}
Anda dapat menggunakan field baik di aksesor get atau set, atau keduanya.
Penting
Kata kunci field adalah fitur pratinjau di C# 13. Anda harus menggunakan .NET 9 dan mengatur elemen <LangVersion> Anda untuk dipratinjau dalam file proyek Anda untuk menggunakan kata kunci kontekstual field.
Anda harus berhati-hati menggunakan fitur kata kunci field di kelas yang memiliki bidang bernama field. Kata kunci field baru membayangi bidang bernama field dalam cakupan aksesor properti. Anda dapat mengubah nama variabel bidang, atau menggunakan token @ untuk mereferensikan pengidentifikasi bidang sebagai @field.
Metode parsial memungkinkan pelaksana satu bagian kelas untuk mendeklarasikan anggota. Pelaksana bagian lain dari kelas dapat menentukan anggota tersebut. Ada dua skenario di mana pemisahan ini berguna: templat yang menghasilkan kode boilerplate, dan generator sumber.
Kode templat: Templat mencadangkan nama metode dan tanda tangan sehingga kode yang dihasilkan dapat memanggil metode . Metode ini mengikuti pembatasan yang memungkinkan pengembang untuk memutuskan apakah akan menerapkan metode. Jika metode tidak diimplementasikan, pengkompilasi akan menghapus tanda tangan metode dan semua panggilan ke metode . Panggilan ke metode , termasuk hasil apa pun yang akan terjadi dari evaluasi argumen dalam panggilan, tidak berpengaruh pada waktu proses. Oleh karena itu, kode apa pun di kelas parsial dapat dengan bebas menggunakan metode parsial, bahkan jika implementasi tidak disediakan. Tidak ada kesalahan waktu kompilasi atau run-time yang dihasilkan jika metode dipanggil tetapi tidak diimplementasikan.
Generator sumber: Generator sumber menyediakan implementasi untuk anggota. Pengembang manusia dapat menambahkan deklarasi anggota (seringkali dengan atribut yang dibaca oleh generator sumber). Pengembang dapat menulis kode yang memanggil anggota ini. Generator sumber berjalan selama kompilasi dan menyediakan implementasi. Dalam skenario ini, pembatasan untuk anggota parsial yang mungkin tidak sering diimplementasikan tidak diikuti.
// Definition in file1.cs partial void OnNameChanged(); // Implementation in file2.cs partial void OnNameChanged() { // method body }Deklarasi anggota parsial harus dimulai dengan parsial kata kunci kontekstual.
Tanda tangan anggota parsial di kedua bagian dari jenis parsial harus cocok.
Anggota parsial dapat memiliki pengubah statis dan tidak aman.
Anggota parsial dapat bersifat generik. Batasan harus sama pada deklarasi metode yang menentukan dan menerapkan. Nama parameter dan jenis parameter tidak harus sama dalam deklarasi penerapan seperti dalam yang menentukan.
Anda dapat membuat delegasi ke metode parsial yang ditentukan dan diimplementasikan, tetapi tidak ke metode parsial yang tidak memiliki implementasi.