Bagikan melalui


Memanfaatkan Properti (Panduan Pemrograman C#)

Properti menggabungkan aspek dari bidang maupun metode. Untuk pengguna objek, properti tampaknya merupakan bidang; mengakses properti memerlukan sintaks yang sama. Untuk pelaksana kelas, properti adalah satu atau dua blok kode, yang mewakili pengakses get dan/atau pengakses set atau init. Blok kode untuk get aksesor dijalankan ketika properti dibaca; blok kode untuk set atau init aksesor dijalankan ketika properti diberi nilai. Properti tanpa pengakses set dianggap hanya-baca. Properti tanpa pengakses get dianggap hanya-dapat-ditulis. Properti yang memiliki kedua pengakses bersifat baca-tulis. Anda dapat menggunakan aksesor init alih-alih aksesor set agar dapat diatur selama inisialisasi objek tetapi tetap menjadikannya hanya-baca.

Tidak seperti bidang, properti tidak diklasifikasikan sebagai variabel. Oleh karena itu, Anda tidak dapat meneruskan properti sebagai parameter ref atau out.

Properti memiliki banyak penggunaan:

  • Mereka dapat memvalidasi data sebelum mengizinkan perubahan.
  • Mereka dapat mengekspos data secara transparan pada kelas tempat data tersebut diambil dari beberapa sumber lain, seperti database.
  • Mereka dapat mengambil tindakan saat data diubah, seperti menaikkan peristiwa, atau mengubah nilai bidang lain.

Properti dideklarasikan dalam blok kelas dengan menentukan tingkat akses bidang, diikuti oleh jenis properti, nama properti, dan blok kode yang mendeklarasikan pengakses get dan/atau pengakses set. Contohnya:

public class Date
{
    private int _month = 7;  // Backing store

    public int Month
    {
        get => _month;
        set
        {
            if ((value > 0) && (value < 13))
            {
                _month = value;
            }
        }
    }
}

Dalam contoh ini, Month dideklarasikan sebagai properti sehingga pengakses set dapat memastikan bahwa nilai Month diatur antara 1 dan 12. Properti Month menggunakan bidang privat untuk melacak nilai aktual. Lokasi sebenarnya dari data properti sering disebut sebagai "penyimpanan penunjang" dari properti tersebut. Adalah hal yang umum bagi data properti untuk menggunakan bidang privat sebagai lokasi penyimpanan penunjang. Kolom ditandai sebagai akses pribadi untuk memastikan bahwa kolom tersebut hanya dapat diubah melalui pemanggilan properti. Untuk informasi selengkapnya tentang pembatasan akses publik dan privat, lihat Pengubah Akses. Properti yang diterapkan secara otomatis menyediakan sintaks yang disederhanakan untuk deklarasi properti sederhana. Untuk informasi selengkapnya, lihat Properti yang diimplementasikan secara otomatis.

Dimulai dengan C# 13, Anda dapat menggunakan properti yang didukung oleh field untuk menambahkan validasi ke set accessor dari properti yang diimplementasikan secara otomatis, seperti yang ditunjukkan pada contoh berikut ini:

public class DateExample
{
    public int Month
    {
        get;
        set
        {
            if ((value > 0) && (value < 13))
            {
                field = value;
            }
        }
    }
}

Penting

Kata kunci field adalah fitur pratinjau dalam C# 13. Anda harus menggunakan .NET 9 dan mengatur elemen Anda <LangVersion> ke preview dalam file proyek Anda untuk menggunakan field kata kunci kontekstual.

Anda harus berhati-hati menggunakan field fitur kata kunci di kelas yang memiliki bidang bernama field. Kata kunci baru field menyembunyikan bidang bernama field dalam ruang lingkup aksesor properti. Anda dapat mengubah nama field variabel, atau menggunakan @ token untuk mereferensikan field pengidentifikasi sebagai @field. Anda dapat mempelajari lebih lanjut dengan membaca spesifikasi fitur untuk field kata kunci.

Fungsi akses 'get'

Badan pengakses get menyerupai badan dari sebuah metode. Harus mengembalikan nilai bertipe properti. Pengkompilasi C# dan kompilator Just-in-time (JIT) mendeteksi pola umum untuk mengimplementasikan get aksesor, dan mengoptimalkan pola tersebut. Misalnya, get aksesor yang mengembalikan bidang tanpa melakukan komputasi apa pun kemungkinan dioptimalkan untuk pembacaan memori bidang tersebut. Properti-properti yang diimplementasikan secara otomatis mengikuti pola ini dan mendapat manfaat dari pengoptimalan-pengoptimalan ini. Namun, metode aksesor virtual get tidak dapat di-inlin karena pengkompilasi tidak tahu pada waktu kompilasi metode mana yang mungkin benar-benar dipanggil pada waktu proses. Contoh berikut menunjukkan aksesor get yang mengembalikan nilai bidang _nameprivat :

class Employee
{
    private string _name;           // the name field
    public string Name => _name;    // the Name property
}

Saat Anda merujuk properti, kecuali sebagai target penugasan, pengakses get akan dipanggil untuk membaca nilai properti tersebut. Contohnya:

var employee = new Employee();
//...

System.Console.Write(employee.Name); // the get accessor is invoked here

Aksesor get harus menjadi anggota dengan tubuh ekspresi, atau berakhiran pernyataan pengembalian atau pelemparan, dan kontrol tidak dapat keluar dari tubuh aksesor.

Peringatan

Ini umumnya adalah gaya pemrograman yang buruk untuk mengubah status objek dengan menggunakan get aksesor. Satu pengecualian untuk aturan ini adalah properti yang dievaluasi secara malas, di mana nilai properti hanya dihitung saat pertama kali diakses.

Pengakses get dapat digunakan untuk mengembalikan nilai bidang atau untuk mengomputasi dan mengembalikannya. Contohnya:

class Manager
{
    private string _name;
    public string Name => _name != null ? _name : "NA";
}

Dalam contoh sebelumnya, jika Anda tidak menetapkan nilai ke Name properti , nilai tersebut akan mengembalikan nilai NA.

Pengatur nilai

Pengakses set mirip dengan fungsi yang tipe pengembaliannya void. Ini menggunakan parameter implisit yang disebut value, yang jenisnya merupakan jenis properti. Kompilator dan kompilator JIT juga mengenali pola umum untuk set atau init aksesor. Pola umum tersebut dioptimalkan dengan langsung menulis ke memori untuk kolom penyimpanan. Pengakses set ditambahkan ke properti Name dalam contoh berikut:

class Student
{
    private string _name;      // the name field
    public string Name         // the Name property
    {
        get => _name;
        set => _name = value;
    }
}

Saat Anda menetapkan nilai ke properti, pengakses set akan dipanggil dengan menggunakan argumen yang menyediakan nilai baru. Contohnya:

var student = new Student();
student.Name = "Joe"; // the set accessor is invoked here

System.Console.Write(student.Name); // the get accessor is invoked here

Menggunakan nama parameter implisit, value, untuk deklarasi variabel lokal dalam sebuah pengakses set adalah sebuah kesalahan.

Pengakses inisialisasi

Kode untuk membuat pengakses init sama dengan kode untuk membuat pengakses set kecuali jika Anda menggunakan kata kunci init alih-alih set. Perbedaannya adalah bahwa pengakses init hanya dapat digunakan dalam konstruktor atau dengan menggunakan penginisialisasi objek.

Keterangan

Properti dapat ditandai sebagai public, private, protected, internal, protected internal, atau private protected. Pengubah akses ini menentukan cara pengguna kelas dapat mengakses properti. Aksesor get dan set untuk properti yang sama dapat memiliki pengubah akses yang berbeda. Misalnya, get mungkin public untuk mengizinkan akses baca-saja dari luar tipe, dan set bisa private atau protected. Untuk informasi selengkapnya, lihat Pengubah Akses.

Properti dapat dinyatakan sebagai properti statis dengan menggunakan static kata kunci. Properti statis tersedia untuk pemanggil kapan saja, bahkan jika pun tidak ada instans kelas. Untuk informasi lebih lanjut, lihat Kelas Statik dan Anggota Kelas Statik.

Properti dapat ditandai sebagai properti virtual dengan menggunakan kata kunci virtual . Properti virtual memungkinkan kelas turunan untuk menggantikan perilaku properti dengan menggunakan kata kunci override. Untuk informasi selengkapnya tentang opsi tersebut, lihat Pewarisan.

Properti yang menggantikan properti virtual juga dapat menjadi sealed, menentukan bahwa untuk kelas turunan tidak lagi bersifat virtual. Terakhir, properti dapat dideklarasikan sebagai abstrak. Properti abstrak tidak menentukan implementasi di kelas , dan kelas turunan harus menulis implementasi mereka sendiri. Untuk informasi selengkapnya tentang opsi ini, lihat Kelas Abstrak dan Tersegel serta Anggota Kelas.

Catatan

Menggunakan pengubah virtual, abstrak, atau ambil alih pada aksesor properti statik merupakan sebuah kesalahan.

Contoh

Contoh ini menunjukkan properti instans, statik, dan hanya baca. Contoh ini menerima nama karyawan dari keyboard, menambah NumberOfEmployees dengan 1, dan menampilkan nama serta nomor Karyawan.

public class Employee
{
    public static int NumberOfEmployees;
    private static int _counter;
    private string _name;

    // A read-write instance property:
    public string Name
    {
        get => _name;
        set => _name = value;
    }

    // A read-only static property:
    public static int Counter => _counter;

    // A Constructor:
    public Employee() => _counter = ++NumberOfEmployees; // Calculate the employee's number:
}

Contoh properti tersembunyi

Contoh ini menunjukkan cara mengakses properti di kelas dasar yang disembunyikan oleh properti lain dengan nama yang sama di kelas turunan:

public class Employee
{
    private string _name;
    public string Name
    {
        get => _name;
        set => _name = value;
    }
}

public class Manager : Employee
{
    private string _name;

    // Notice the use of the new modifier:
    public new string Name
    {
        get => _name;
        set => _name = value + ", Manager";
    }
}

class TestHiding
{
    public static void Test()
    {
        Manager m1 = new Manager();

        // Derived class property.
        m1.Name = "John";

        // Base class property.
        ((Employee)m1).Name = "Mary";

        System.Console.WriteLine($"Name in the derived class is: {m1.Name}");
        System.Console.WriteLine($"Name in the base class is: {((Employee)m1).Name}");
    }
}
/* Output:
    Name in the derived class is: John, Manager
    Name in the base class is: Mary
*/

Berikut adalah poin penting dalam contoh sebelumnya:

  • Properti Name di kelas turunan menyembunyikan properti Name di kelas dasar. Dalam kasus tersebut, pengubah new digunakan dalam deklarasi properti di kelas turunan:
    public new string Name
    
  • Casting (Employee) digunakan untuk mengakses properti tersembunyi di kelas dasar.
    ((Employee)m1).Name = "Mary";
    

Untuk informasi selengkapnya tentang menyembunyikan anggota, lihat Pengubah baru.

Mengambil alih contoh properti

Dalam contoh ini, dua kelas, Cube dan Square, menerapkan kelas abstrak, Shape, dan mengambil alih properti Area abstraknya. Perhatikan penggunaan pengubah ambil alih pada properti. Program ini menerima sisi sebagai input dan menghitung luas persegi dan kubus. Program ini juga menerima luas sebagai input dan menghitung sisi yang sesuai untuk persegi dan kubus.

abstract class Shape
{
    public abstract double Area
    {
        get;
        set;
    }
}

class Square : Shape
{
    public double side;

    //constructor
    public Square(double s) => side = s;

    public override double Area
    {
        get => side * side;
        set => side = System.Math.Sqrt(value);
    }
}

class Cube : Shape
{
    public double side;

    //constructor
    public Cube(double s) => side = s;

    public override double Area
    {
        get => 6 * side * side;
        set => side = System.Math.Sqrt(value / 6);
    }
}

class TestShapes
{
    static void Main()
    {
        // Input the side:
        System.Console.Write("Enter the side: ");
        double side = double.Parse(System.Console.ReadLine());

        // Compute the areas:
        Square s = new Square(side);
        Cube c = new Cube(side);

        // Display the results:
        System.Console.WriteLine($"Area of the square = {s.Area:F2}");
        System.Console.WriteLine($"Area of the cube = {c.Area:F2}");
        System.Console.WriteLine();

        // Input the area:
        System.Console.Write("Enter the area: ");
        double area = double.Parse(System.Console.ReadLine());

        // Compute the sides:
        s.Area = area;
        c.Area = area;

        // Display the results:
        System.Console.WriteLine($"Side of the square = {s.side:F2}");
        System.Console.WriteLine($"Side of the cube = {c.side:F2}");
    }
}
/* Example Output:
    Enter the side: 4
    Area of the square = 16.00
    Area of the cube = 96.00

    Enter the area: 24
    Side of the square = 4.90
    Side of the cube = 2.00
*/

Lihat juga