Perbedaan antara Properti dan Bidang dalam C # 3.0+


140

Saya menyadari bahwa itu sepertinya duplikat Apa perbedaan antara Field dan Properti di C #? tetapi pertanyaan saya memiliki sedikit perbedaan (dari sudut pandang saya):

Begitu saya tahu itu

  • Saya tidak akan menggunakan kelas saya dengan "teknik yang hanya bekerja pada properti" dan
  • Saya tidak akan menggunakan kode validasi dalam pengambil / penyetel.

Apakah ada perbedaan (kecuali gaya / pengembangan masa depan), seperti beberapa jenis kontrol dalam pengaturan properti?

Apakah ada perbedaan tambahan antara:

public string MyString { get; set; }

dan

public string myString;

(Saya sadar bahwa, versi pertama memerlukan C # 3.0 atau lebih tinggi dan bahwa kompiler memang membuat bidang pribadi.)


Jawaban:


117

Enkapsulasi.

Dalam contoh kedua Anda baru saja mendefinisikan sebuah variabel, pada contoh pertama, ada pengambil / penyetel di sekitar variabel. Jadi jika Anda memutuskan untuk memvalidasi variabel di kemudian hari - itu akan jauh lebih mudah.

Plus mereka tampil berbeda di Intellisense :)

Sunting: Perbarui untuk pertanyaan yang diperbarui OP - jika Anda ingin mengabaikan saran lain di sini, alasan lainnya adalah karena itu sama sekali bukan desain OO yang bagus. Dan jika Anda tidak memiliki alasan yang sangat baik untuk melakukannya, selalu pilih properti daripada variabel / bidang publik.


9
Mengapa lebih mudah? Apa yang mencegah saya mengubah bidang menjadi properti dan menambahkan bidang dukungan pribadi? Bagaimana ini memengaruhi kode panggilan?
Serge Wautier

30
@Serge - Ini memengaruhi kode yang sudah dikompilasi. Misalnya, jika Anda mengembangkan perpustakaan yang digunakan oleh beberapa aplikasi, mengubah bidang ke properti di perpustakaan itu akan memerlukan kompilasi ulang dari setiap aplikasi. Jika itu adalah properti, Anda dapat memperbarui properti tanpa khawatir.
Dustin Campbell

Saya sangat setuju dengan Anda, saya selalu menggunakan properti. Saya hanya ingin tahu tentang kemungkinan perbedaan
p4bl0

24
Jika kode mengkonsumsi selalu dikompilasi ulang pada waktu yang sama sebagai kelas yang terkena (sehingga apa pun pribadi atau internal tanpa internal terlihat adalah 100% aman) kemudian membuat lapangan ini sangat OK
ShuggyCoUk

1
wow Shuggy komentar Anda persis jawaban yang saya cari!
p4bl0

160

Bidang dan properti terlihat sama, tetapi tidak. Properti adalah metode dan karena itu ada hal-hal tertentu yang tidak didukung untuk properti, dan beberapa hal yang mungkin terjadi dengan properti tetapi tidak pernah dalam kasus bidang.

Berikut daftar perbedaannya:

  • Fields dapat digunakan sebagai input untuk out/refargumen. Properti tidak bisa.
  • Bidang akan selalu menghasilkan hasil yang sama ketika dipanggil berulang kali (jika kami mengabaikan masalah dengan banyak utas). Properti seperti DateTime.Nowitu tidak selalu sama dengan dirinya sendiri.
  • Properti dapat melempar pengecualian - bidang tidak akan pernah melakukan itu.
  • Properti mungkin memiliki efek samping atau membutuhkan waktu sangat lama untuk dieksekusi. Bidang tidak memiliki efek samping dan akan selalu secepat yang diharapkan untuk jenis yang diberikan.
  • Properti mendukung aksesibilitas berbeda untuk getter / setter - bidang tidak (tetapi bidang dapat dibuat readonly)
  • Saat menggunakan refleksi, properti dan bidang diperlakukan sebagai berbeda MemberTypessehingga lokasinya berbeda ( GetFieldsvs GetPropertiesmisalnya)
  • JIT Compiler dapat memperlakukan akses properti sangat berbeda dibandingkan dengan akses lapangan. Namun itu dapat dikompilasi ke kode asli yang identik tetapi ruang lingkup perbedaan ada di sana.

11
Namun perlu dicatat bahwa beberapa poin ini seharusnya tidak menjadi perbedaan jika praktik yang baik diterapkan. Artinya, properti seharusnya tidak pernah memiliki efek samping, juga tidak perlu waktu lama untuk dieksekusi.
Noldorin

15
@Noldorin: Saya setuju, tapi sayangnya kata kunci di sini seharusnya . Dengan bidang yang perilaku dijamin. Saya tidak mengatakan Anda harus menggunakan bidang, tetapi penting untuk menyadari perbedaan semantik.
Brian Rasmussen

4
Ya, cukup adil. Programmer pemula tidak memiliki petunjuk tentang hal-hal ini seringkali, sayangnya ...
Noldorin

2
Juga, bidang mungkin memiliki penginisialisasi bidang sementara properti harus diinisialisasi dalam konstruktor.
Dio F

3
Saya merasa jawaban ini jauh lebih baik daripada jawaban yang diterima. Saya mulai berpikir bahwa cara "dapat diterima" untuk selalu lebih suka properti daripada bidang adalah pemikiran buruk. Jika Anda hanya perlu berurusan dengan data, gunakan bidang. Jika Anda perlu menerapkan fungsionalitas ke data, gunakan metode. Karena properti mungkin memiliki efek samping yang tidak Anda sadari (terutama jika Anda tidak mendesain pustaka dan memiliki sedikit dokumentasi), mereka tampaknya berlawanan secara intuitif bagi saya dalam banyak kasus.
David Peterson

41

Pasangan cepat, perbedaan yang jelas

  1. Properti dapat memiliki accessor atau kata kunci.

    public string MyString { get; private set; }
  2. Properti dapat diganti dalam keturunan.

    public virtual string MyString { get; protected set; }

1
mmh .. nr 2 menarik .. saya tidak memikirkannya
p4bl0

14

Perbedaan mendasar adalah bahwa bidang adalah posisi di memori tempat data dari jenis yang ditentukan disimpan. Properti mewakili satu atau dua unit kode yang dieksekusi untuk mengambil atau menetapkan nilai dari jenis yang ditentukan. Penggunaan metode pengakses ini disembunyikan secara sintaksis dengan menggunakan anggota yang tampaknya berperilaku seperti bidang (dalam hal itu dapat muncul di kedua sisi operasi penugasan).


11

Pengakses lebih dari bidang. Yang lain sudah menunjukkan beberapa perbedaan penting, dan saya akan menambahkan satu lagi.

Properti ambil bagian dalam kelas antarmuka. Sebagai contoh:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

Antarmuka ini dapat dipenuhi dengan beberapa cara. Sebagai contoh:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

Dalam implementasi ini kami melindungi kedua Personkelas agar tidak masuk ke keadaan tidak valid, serta penelepon agar tidak keluar dari properti yang belum ditetapkan.

Tapi kami bisa mendorong desain lebih jauh. Misalnya, antarmuka mungkin tidak berurusan dengan setter. Sangat sah untuk mengatakan bahwa konsumen IPersonantarmuka hanya tertarik untuk mendapatkan properti, bukan dalam pengaturannya:

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

Implementasi Personkelas sebelumnya memenuhi antarmuka ini. Fakta bahwa itu memungkinkan penelepon juga mengatur properti tidak ada artinya dari sudut pandang konsumen (yang mengkonsumsi IPerson). Fungsionalitas tambahan dari implementasi konkret dipertimbangkan oleh, misalnya, pembangun:

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

Dalam kode ini, konsumen tidak tahu tentang setter properti - bukan urusannya untuk mengetahuinya. Konsumen hanya membutuhkan getter, dan ia mendapatkan getter dari antarmuka, yaitu dari kontrak.

Implementasi lain yang benar-benar valid IPersonadalah kelas orang yang tidak dapat diubah dan pabrik orang yang sesuai:

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

Dalam contoh kode ini, konsumen sekali lagi tidak memiliki pengetahuan untuk mengisi properti. Konsumen hanya berurusan dengan getter dan implementasi konkret (dan logika bisnis di belakangnya, seperti pengujian jika nama kosong) diserahkan kepada kelas khusus - pembangun dan pabrik. Semua operasi ini sama sekali tidak mungkin dengan bidang.


7

Yang pertama:

public string MyString {get; set; }

adalah properti; yang kedua ( public string MyString) menunjukkan suatu bidang.

Perbedaannya adalah, bahwa teknik-teknik tertentu (penyatuan data ASP.NET untuk instance), hanya bekerja pada properti, dan bukan pada bidang. Hal yang sama berlaku untuk Serialisasi XML: hanya properti yang diserialisasi, bidang tidak diserialisasi.


8
Salah. Serialisasi XML TIDAK membuat serialisasi bidang publik.
Serge Wautier

2
Mungkin. Tetapi ketika Anda membuat Sumber Data Objek dari kelas, Anda hanya bisa menggunakan properti, bukan bidang. (Kecuali saya telah melakukan sesuatu yang salah: P)
Svish

Bagus untuk KERING;) tetapi saya menulis sekali lagi, saya suka peran properti yang kuat dalam bahasa C #. Jauh lebih baik diimplementasikan daripada di Jawa (akibatnya dari awal) Banyak, mungkin semua solusi .net hanya bekerja pada properti. WPF, ASPX dan banyak lagi.
Jacek Cz

3

Properti dan Fields mungkin, dalam banyak kasus, tampak serupa, tetapi mereka tidak. Ada batasan untuk properti yang tidak ada untuk bidang, dan sebaliknya.

Seperti yang telah disebutkan orang lain. Anda dapat membuat properti hanya-baca atau hanya-menulis dengan menjadikannya aksesor atau pribadi. Anda tidak dapat melakukannya dengan bidang. Properti juga bisa virtual, sementara bidang tidak bisa.

Pikirkan properti sebagai gula sintaksis untuk fungsi getXXX () / setXXX (). Ini adalah bagaimana mereka diimplementasikan di belakang layar.


1

Ada satu perbedaan penting lainnya antara bidang dan properti.

Saat menggunakan WPF, Anda hanya dapat mengikat ke properti publik. Mengikat ke bidang publik tidak akan berfungsi. Ini benar bahkan ketika tidak menerapkan INotifyPropertyChanged(meskipun Anda harus selalu melakukannya).


Bagus untuk KERING;) tetapi saya menulis sekali lagi, saya suka peran properti yang kuat dalam bahasa C #. Jauh lebih baik diimplementasikan daripada di Jawa (akibatnya dari awal) Banyak, mungkin semua solusi .net hanya bekerja pada properti. WPF, ASPX dan banyak lagi.
Jacek Cz

1

Di antara jawaban dan contoh lain, saya pikir contoh ini berguna dalam beberapa situasi.

Misalnya, katakan Anda memiliki yang berikut:OnChange property

public Action OnChange { get; set; }

Jika Anda ingin menggunakan delegasi, Anda perlu mengubahnya OnChangemenjadi fieldseperti ini:

public event Action OnChange = delegate {};

Dalam situasi seperti itu kami melindungi bidang kami dari akses atau modifikasi yang tidak diinginkan.


0

Anda harus selalu menggunakan properti alih-alih bidang untuk bidang publik apa pun. Ini memastikan bahwa perpustakaan Anda memiliki kemampuan untuk menerapkan enkapsulasi untuk bidang apa pun jika diperlukan di masa depan tanpa melanggar kode yang ada. Jika Anda mengganti bidang dengan properti di perpustakaan yang ada maka semua modul dependen menggunakan perpustakaan Anda juga perlu dibangun kembali.


"selalu" adalah kata yang sulit untuk diucapkan. Dalam C # (lebih baik daripada di Jawa) properti memiliki posisi kuat, (mungkin tanpa kecuali) utama / metode "mengikat" di ASP, WPF dan lain-lain. Namun demikian saya dapat membayangkan desain dengan bidang yang tidak memiliki properti memiliki arti (kadang-kadang)
Jacek Cz
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.