Kapan menggunakan [Murni] pada konstruktor?


19

Saya belajar tentang kontrak kode di .NET, dan saya mencoba memahami gagasan konstruktor murni. The kontrak Kode negara dokumentasi:

Semua metode yang disebut dalam kontrak harus murni; yaitu, mereka tidak boleh memperbarui keadaan yang sudah ada sebelumnya. Metode murni diizinkan untuk memodifikasi objek yang telah dibuat setelah masuk ke metode murni.

Dan PureAttributedokumentasinya menyatakan:

Menunjukkan bahwa suatu jenis atau metode adalah murni, artinya, itu tidak membuat perubahan status apa pun yang terlihat.

Saya mengerti pernyataan ini ketika datang ke metode, tetapi bagaimana dengan konstruktor? Misalkan Anda memiliki kelas seperti ini:

public class Foo
{
    public int Value { get; set; }

    public Foo(int value) {
        this.Value = value;
    }
}

Konstruktor ini jelas mempengaruhi keadaan Fooobjek baru , tetapi tidak memiliki efek samping lain (misalnya tidak memanipulasi salah satu parameter atau memanggil metode non-murni). Apakah ini kandidat untuk [Pure]atau tidak? Apa pentingnya menempatkan [Pure]atribut pada konstruktor, dan kapan saya harus melakukan ini dalam kode saya sendiri?

Jawaban:


14

Anda menghias metode dengan [Pure]:

  • Jika metode ini tidak memiliki efek samping. Misalnya, jika metode mengakses database dan memodifikasinya atau hasilnya tergantung pada database, itu tidak murni.

  • Dan jika Anda berharap untuk menggunakannya dalam kontrak kode. Misalnya, jika metode ini murni , tetapi Anda tidak memiliki niat untuk menggunakannya dalam kontrak kode, menambahkan tidak [Pure]akan bermanfaat dan tidak akan membuat kode Anda lebih cepat.

Sejauh menyangkut konstruktor, sepertinya mereka dianggap murni dalam. NET dan tidak memerlukan atribut eksplisit. Saya melihat beberapa konstruktor dalam sumber .NET Framework, seperti DateTime, dan mereka tidak memiliki [Pure]atribut.

Saya kira ini dilakukan karena beberapa alasan:

  • Mungkin terlalu tidak praktis untuk harus menulis konstruktor tanpa parameter dengan [Pure]atribut hanya untuk dapat menggunakan kelas / struct dalam kontrak.

  • Beberapa, seperti String, tidak memiliki konstruktor eksplisit.

  • Konstruktor menerima perlakuan khusus bahkan di luar kontrak kode; misalnya, Anda tidak diharapkan untuk melemparkan pengecualian di dalamnya .

  • [Pure]hanyalah sebuah konvensi yang ada di sini untuk menyederhanakan hidup Anda, tetapi tidak ada pemeriksaan statis yang sebenarnya untuk memastikan bahwa metode yang didekorasi dengan atribut ini murni. void DestroyDatabase()dapat didekorasi sebagai murni, dan kontrak kode tidak akan menemukan kesalahan.

    Saat ini tidak ada komponen Kontrak Kode yang memeriksa apakah metode yang dinyatakan murni memang murni. Jadi jika seorang programmer menghias metode dengan [Murni], itu hanya diyakini.

    Dari Kontrak Code # 5: Metode kemurnian

  • .NET Framework sendiri berisi konstruktor yang tidak murni. Misalnya, List<T>(IEnumerable<T> collection)sebenarnya tidak murni jika perulangan melalui koleksi memiliki efek samping.

  • Teriakan kontrak dibuat sederhana. Saya dapat dengan mudah membayangkan kontrak seperti itu Contract.Requires(!string.IsNullOrEmpty(name)), jadi ada alasan bagus untuk menyatakan statis string.IsNullOrEmptymurni.

    Di sisi lain, jika Anda memerlukan a StringBuilderuntuk membangun string Anda akan memeriksa kemudian untuk sesuatu dengan memanggil metode instan kelas bisnis Anda, Anda mungkin menyalahgunakan kontrak. Itu juga mengapa StringBuilder.ToStringtidak ditandai sebagai murni, bahkan jika itu mungkin (bukan?)


Banyak kontrak kode pada tipe sistem diasumsikan oleh pemeriksa kontrak, termasuk " metode apa pun yang nama lengkapnya dimulai dengan" System.Diagnostics.Contracts.Contract "," System.String "," System.IO.Path ", atau" System .Type " ". Sayangnya, saya tidak yakin apakah melihat tipe .NET terlalu berguna untuk kontrak kode.
pswg

3
Kemurnian adalah salah satu hal di mana semua kode yang disebut juga harus murni, atau penelepon tidak "murni". Saya merasa sulit untuk percaya semua konstruktor dianggap murni secara default.
Frank Hileman

@ FrankHileman: saya juga. Saya tidak memiliki kompiler C # sekarang, tetapi akan cukup untuk menulis kelas dengan konstruktor dan tanpa [Pure]atribut, dan menggunakannya di tempat lain dalam kontrak untuk mendapatkan jawaban yang pasti.
Arseni Mourzenko

1

Objek tidak dapat digunakan sampai dibangun dalam kasus ini. Karena itu konstruktornya murni. Jika konstruktor memanggil kode lain, atau memanggil delegasi, dan kode lain memodifikasi properti yang bisa berubah, itu tidak akan murni. Agar lebih aman, lebih baik membuat properti tidak berubah.


Jadi konstruktor murni adalah metode murni yang diizinkan untuk mengubah keadaan kelas saat ini, asalkan memenuhi syarat lain menjadi murni? BTW, Properti ini bisa berubah karena saya ingin menekankan bahwa kelas ini sendiri tidak murni.
pswg

@ pswg: Anda membuat pertanyaan menarik yang mungkin harus dijawab oleh Microsoft. Misalkan konstruktor memanggil metode yang mengubah properti yang bisa berubah-ubah; akankah konstruktornya tetap murni? Saya pikir secara teknis tidak akan, meskipun modifikasi itu "tidak terlihat" oleh pemirsa eksternal. Karena tidak ada kode lain yang dipanggil dalam contoh asli Anda, itu harus murni dengan definisi apa pun yang dapat saya pikirkan.
Frank Hileman

@ pswg: Kecuali bahwa set properti juga merupakan panggilan metode .. Saya pikir Anda harus bertanya di forum MSDN.
Frank Hileman

Saya kira jika ide sentral dari kemurnian adalah apakah atau tidak metode membuat perubahan yang dapat diamati , maka dalam arti itu, terlepas dari apakah itu memanggil metode tidak murni, asalkan perubahan tidak dapat diamati oleh penelepon mana pun, itu masih akan menjadi metode murni.
pswg

@ pswg: Itu adalah definisi abstrak. Tetapi jika saya menulis analisa untuk hal-hal ini, mungkin pemanggilan metode yang tidak murni juga akan dianggap membuat pemanggil tidak murni. Hanya untuk kesederhanaan implementasi. Maka pertanyaannya adalah, apakah konstruktor panggilan metode normal, atau seberapa dalam analisisnya.
Frank Hileman
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.