.NET Properties - Gunakan Set Pribadi atau Properti ReadOnly?

45

Dalam situasi apa saya harus menggunakan Set Pribadi pada properti versus menjadikannya properti ReadOnly? Pertimbangkan dua contoh yang sangat sederhana di bawah ini.

Contoh pertama:

Public Class Person

    Private _name As String

    Public Property Name As String
        Get
            Return _name
        End Get
        Private Set(ByVal value As String)
            _name = value
        End Set
    End Property

    Public Sub WorkOnName()

        Dim txtInfo As TextInfo = _
            Threading.Thread.CurrentThread.CurrentCulture.TextInfo

        Me.Name = txtInfo.ToTitleCase(Me.Name)

    End Sub

End Class

// ----------

public class Person
{
    private string _name;
    public string Name
    {
        get { return _name; }
        private set { _name = value; }
    }

    public void WorkOnName()
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        this.Name = txtInfo.ToTitleCase(this.Name);
    }
}

Contoh kedua:

Public Class AnotherPerson

    Private _name As String

    Public ReadOnly Property Name As String
        Get
            Return _name
        End Get
    End Property

    Public Sub WorkOnName()

        Dim txtInfo As TextInfo = _
            Threading.Thread.CurrentThread.CurrentCulture.TextInfo

        _name = txtInfo.ToTitleCase(_name)

    End Sub

End Class

// ---------------

public class AnotherPerson
{
    private string _name;
    public string Name
    {
        get { return _name; }
    }

    public void WorkOnName()
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        _name = txtInfo.ToTitleCase(_name);
    }
}

Keduanya menghasilkan hasil yang sama. Apakah ini situasi di mana tidak ada yang benar dan salah, dan itu hanya masalah pilihan?

tgxiii
sumber
public string Name { get; protected set; }melalui warisan.
samis

Jawaban:

42

Ada beberapa alasan untuk menggunakannya private set.

1) Jika Anda sama sekali tidak menggunakan bidang dukungan dan menginginkan properti otomatis hanya-baca:

public string Name { get; private set; }   

public void WorkOnName()
{
    TextInfo txtInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
    Name = txtInfo.ToTitleCase(Name);
}  

2) Jika Anda ingin melakukan pekerjaan tambahan ketika Anda memodifikasi variabel di dalam kelas Anda dan ingin menangkapnya di satu lokasi:

private string _name = string.Empty;
public string Name 
{ 
    get { return _name; }
    private set 
    {
        TextInfo txtInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
        _name = txtInfo.ToTitleCase(value);
    }
}

Namun, secara umum, ini masalah preferensi pribadi. Sejauh yang saya tahu, tidak ada alasan kinerja untuk menggunakan salah satunya.

Adam Lear
sumber
1
Hanya menambahkan ini karena pertanyaannya juga memiliki tag vb.net, tetapi di vb.net Anda perlu menentukan pendukung jika Anda menggunakan pribadi baik di get atau set. Jadi di vb.net itu sebenarnya kurang bekerja untuk membuat properti hanya baca saya pikir.
user643192
Saya tidak pernah tahu tentang itu private set. :-)
Afzaal Ahmad Zeeshan
10
Update untuk orang-orang membaca jawaban ini di 2016. C # 6.0 telah memperkenalkan auto-sifat readonly, yang memungkinkan Anda untuk memiliki properti dibaca tanpa bidang dukungan: public string Name { get; }. Jika Anda tidak ingin properti yang dapat diubah-ubah, itulah sintaks yang disukai sekarang.
Alexey
4
Satu alasan yang sangat bagus untuk tidak menggunakan private setadalah bahwa itu tidak kekal seperti yang kita inginkan. Jika Anda ingin menerapkan kelas yang benar-benar tidak dapat diubah, baca saja adalah suatu keharusan.
RubberDuck
Mungkin menjadi alasan kinerja untuk TIDAK menggunakan hanya baca. Tampaknya menyebabkan penyalinan struct yang tidak perlu saat mengakses metode bidang readonly struct. codeblog.jonskeet.uk/2014/07/16/…
Triynko
28

Gunakan set pribadi ketika Anda ingin setter tidak dapat diakses dari luar .

Gunakan hanya baca saat Anda ingin mengatur properti hanya sekali . Dalam konstruktor atau penginisialisasi variabel.

UJI INI:

void Main()
{
    Configuration config = new Configuration();
    config.ResetConfiguration();

    ConfigurationReadOnly configRO = new ConfigurationReadOnly();
    configRO.ResetConfiguration();
}

public class Configuration
{
    public Color BackgroundColor { get; private set; }
    public Color ForegroundColor { get; private set; }
    public String Text { get; private set; }

    public Configuration()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }

    public void ResetConfiguration()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }
}

public class ConfigurationReadOnly
{
    public readonly Color BackgroundColor;
    public readonly Color ForegroundColor;
    public readonly String Text;

    public ConfigurationReadOnly()
    {
        BackgroundColor = Color.Black;
        ForegroundColor = Color.White;
        Text = String.Empty;
    }

    public void ResetConfiguration()
    {
        BackgroundColor = Color.Black; // compile error: due to readonly keyword
        ForegroundColor = Color.White; // compile error: due to readonly keyword
        Text = String.Empty; // compile error: due to readonly keyword
    }
}
asakura89
sumber
Meskipun saya setuju dengan jawaban Anda, contoh Anda dapat menggunakan beberapa peningkatan. Anda mungkin ingin membuat komentar di mana kesalahan kompiler akan terjadi.
Michael Richardson
NB Sintaks VB.NET yang terkait dengan readonlykata kunci C # , adalah untuk diterapkan ReadOnlyke bidang alih-alih ke properti.
Zev Spitz
8

Bisakah saya menyarankan opsi ketiga?

public class Person
{
    public string Name { get; protected set; }

    public void SetName(string name)
    {
        TextInfo txtInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
        this.Name = txtInfo.ToTitleCase(name);
    }
}

Ini menjadikan properti Nama hanya Baca secara efektif untuk semua kode luar dan menyediakan metode Tetapkan secara eksplisit. Saya lebih suka Set eksplisit daripada hanya menggunakan set pada properti Name karena Anda mengubah nilai saat mengaturnya. Biasanya jika Anda menetapkan nilai properti, Anda berharap mendapatkan nilai yang sama kembali ketika Anda memanggil get nanti, yang tidak akan terjadi jika Anda melakukan ToTitleCase Anda di set .

Namun, seperti yang Anda katakan, tidak ada jawaban yang benar.

Dave Wise
sumber
Saya percaya 'private set' memiliki semantik khusus dalam kompiler (tidak hanya berfungsi sebagai pengakses pribadi). Apakah ini juga kasus dengan set yang dilindungi? Jika tidak, di mana semantiknya setara dengan set terproteksi jika set privat memiliki semantik khusus? Saya belum dapat menemukan dokumentasi yang menjelaskan hal ini.
Sprague
1
+1 tetapi saya akan memanggil metode "Ganti nama" alih-alih "SetName".
MattDavey
4

Jangan gunakan contoh kedua. Inti dari menggunakan properti - bahkan jika tidak ada yang terjadi di luar pengambil getter dan pengaturan setter - adalah untuk menyalurkan semua akses melalui pengambil dan penyetel sehingga jika Anda perlu mengubah perilaku di masa depan, semuanya ada di satu tempat.

Contoh kedua Anda mengabaikan hal itu jika mengatur properti. Jika Anda menggunakan pendekatan itu di kelas yang besar, kompleks, dan kemudian perlu mengubah perilaku properti, Anda akan berada di tanah pencarian dan ganti, alih-alih melakukan perubahan di satu tempat - setter pribadi.

Carson63000
sumber
2

Setiap kali saya perlu mengubah tingkat akses setter, saya biasanya mengubahnya menjadi Terlindungi (hanya kelas ini dan kelas turunan yang dapat mengubah nilai) atau Teman (hanya anggota majelis saya yang dapat mengubah nilai).

Tetapi menggunakan Private sangat masuk akal ketika Anda ingin melakukan tugas lain di setter selain mengubah nilai backing. Seperti yang ditunjukkan sebelumnya, desain yang bagus untuk tidak merujuk nilai dukungan Anda secara langsung tetapi hanya mengaksesnya melalui properti mereka. Itu memastikan bahwa nanti perubahan yang Anda lakukan pada properti diterapkan secara internal maupun eksternal. Dan hampir tidak ada penalti performa untuk mereferensikan properti vs variabel pendukungnya.

Prlaba
sumber
0

Dan hampir tidak ada penalti kinerja ...

Tapi untuk memperjelas, mengakses properti adalah lebih lambat dari mengakses variabel dukungan nya. Pembuat dan penyetel properti adalah metode yang membutuhkan Panggilan dan Pengembalian, sedangkan variabel dukungan properti diakses secara langsung.

Itu sebabnya, dalam kasus di mana pengambil properti dapat diakses berkali-kali dalam blok kode, nilai properti kadang-kadang di-cache terlebih dahulu (disimpan dalam variabel lokal) dan variabel lokal yang digunakan sebagai gantinya. Tentu saja, itu mengasumsikan properti tidak dapat diubah secara tidak sinkron saat blok mengeksekusi.

Prlaba
sumber