Mengubah aturan untuk kompatibilitas

Sepanjang sejarahnya, .NET telah berusaha mempertahankan tingkat kompatibilitas yang tinggi dari versi ke versi dan di seluruh implementasi .NET. Meskipun .NET 5 (dan .NET Core) dan versi yang lebih baru dapat dianggap sebagai teknologi baru dibandingkan dengan .NET Framework, dua faktor utama membatasi kemampuan implementasi .NET ini untuk menyimpang dari .NET Framework:

  • Sejumlah besar pengembang awalnya mengembangkan atau terus mengembangkan aplikasi .NET Framework. Mereka mengharapkan perilaku yang konsisten di seluruh implementasi .NET.
  • Proyek pustaka .NET Standard memungkinkan pengembang membuat pustaka yang menargetkan API bersama yang digunakan oleh .NET Framework dan .NET 5 (dan .NET Core) serta versi lebih baru. Pengembang mengharapkan bahwa pustaka yang digunakan dalam aplikasi .NET harus ber perilaku identik dengan pustaka yang sama yang digunakan dalam aplikasi .NET Framework.

Seiring dengan kompatibilitas di seluruh implementasi .NET, pengembang mengharapkan tingkat kompatibilitas yang tinggi di seluruh versi implementasi .NET tertentu. Secara khusus, kode yang ditulis untuk versi .NET Core yang lebih lama harus berjalan dengan mulus pada .NET 5 atau versi yang lebih baru. Bahkan, banyak pengembang mengharapkan bahwa API baru yang ditemukan dalam versi .NET yang baru dirilis juga harus kompatibel dengan versi pra-rilis tempat API tersebut diperkenalkan.

Artikel ini menguraikan perubahan yang memengaruhi kompatibilitas dan cara tim .NET mengevaluasi setiap jenis perubahan. Memahami bagaimana tim .NET mendekati kemungkinan perubahan yang dapat menyebabkan gangguan sangat membantu bagi pengembang yang membuka pull request yang memodifikasi perilaku API .NET yang ada.

Bagian berikut menjelaskan kategori perubahan yang dilakukan pada API .NET dan dampaknya pada kompatibilitas aplikasi. Perubahan diperbolehkan (✔️), tidak diizinkan (❌), atau memerlukan penilaian dan evaluasi tentang seberapa dapat diprediksi, jelas, dan konsisten dengan perilaku sebelumnya (❓).

Nota

  • Selain berfungsi sebagai panduan tentang bagaimana perubahan pada pustaka .NET dievaluasi, pengembang pustaka juga dapat menggunakan kriteria ini untuk mengevaluasi perubahan pada pustaka mereka yang menargetkan beberapa implementasi dan versi .NET.
  • Untuk informasi tentang kategori kompatibilitas, misalnya, kompatibilitas maju dan mundur, lihat Bagaimana perubahan kode dapat memengaruhi kompatibilitas.

Modifikasi pada kontrak publik

Perubahan dalam kategori ini mengubah antarmuka publik dari suatu tipe. Sebagian besar perubahan dalam kategori ini tidak diizinkan karena melanggar kompatibilitas mundur (kemampuan aplikasi yang dikembangkan dengan versi API sebelumnya untuk dijalankan tanpa kompilasi ulang pada versi yang lebih baru).

Jenis

  • ✔️ DIIZINKAN: Menghapus implementasi antarmuka dari jenis ketika antarmuka sudah diimplementasikan oleh jenis dasar

  • MEMERLUKAN PENILAIAN: Menambahkan implementasi antarmuka baru ke jenis

    Ini adalah perubahan yang dapat diterima karena tidak berdampak buruk pada klien yang ada. Setiap perubahan pada jenis harus berfungsi dalam batas-batas perubahan yang dapat diterima yang ditentukan di sini agar implementasi baru tetap dapat diterima. Kewaspadaan ekstrem diperlukan saat menambahkan antarmuka yang secara langsung memengaruhi kemampuan perancang atau serializer untuk menghasilkan kode atau data yang tidak dapat dikonsumsi tingkat bawah. Contoh dari antarmuka adalah ISerializable.

  • MEMERLUKAN PENILAIAN: Memperkenalkan kelas dasar baru

    Jenis dapat dimasukkan ke dalam hierarki antara dua jenis yang ada jika tidak memperkenalkan anggota abstrak baru atau mengubah semantik atau perilaku jenis yang ada. Misalnya, di .NET Framework 2.0, kelas DbConnection menjadi kelas dasar baru untuk SqlConnection, yang sebelumnya berasal langsung dari Component.

  • ✔️ DIIZINKAN: Memindahkan jenis dari satu rakitan ke rakitan lainnya

    Rakitan lama harus ditandai dengan TypeForwardedToAttribute yang menunjuk ke rakitan baru.

  • ✔️ DIIZINKAN: Mengubah jenis struct menjadi readonly struct jenis

    Mengubah tipe readonly struct menjadi tipe struct tidak diperbolehkan.

  • ✔️ DIIZINKAN: Menambahkan kata kunci yang disegel atau abstrak ke jenis ketika tidak ada konstruktor yang dapat diakses (publik atau dilindungi)

  • ✔️ DIIZINKAN: Memperluas visibilitas tipe

  • TIDAK DIIZINKAN: Mengubah namespace atau nama jenis

  • TIDAK DIIZINKAN: Mengganti nama atau menghapus jenis publik

    Ini memutus semua kode yang menggunakan tipe yang diubah namanya atau dihapus.

    Nota

    Dalam kasus yang jarang terjadi, .NET dapat menghapus API publik. Untuk informasi selengkapnya, lihat penghapusan API di .NET. Untuk informasi tentang kebijakan dukungan .NET, lihat Kebijakan Dukungan .NET.

  • TIDAK DIIZINKAN: Mengubah jenis enumerasi yang mendasar

    Ini adalah perubahan pemecahan perilaku dan waktu kompilasi serta perubahan pemecahan biner yang dapat membuat argumen atribut tidak dapat diuraikan.

  • TIDAK DIIZINKAN: Menyegel jenis yang sebelumnya tidak disegel

  • TIDAK DIIZINKAN: Menambahkan antarmuka ke kumpulan jenis dasar antarmuka

    Jika antarmuka menerapkan antarmuka yang sebelumnya tidak diterapkan, semua jenis yang mengimplementasikan versi asli antarmuka rusak.

  • MEMERLUKAN PENILAIAN: Menghapus kelas dari set kelas dasar atau antarmuka dari set antarmuka yang diimplementasikan

    Ada satu pengecualian untuk aturan untuk penghapusan antarmuka: Anda dapat menambahkan implementasi antarmuka yang berasal dari antarmuka yang dihapus. Misalnya, Anda dapat menghapus IDisposable jika jenis atau antarmuka sekarang mengimplementasikan IComponent, yang mengimplementasikan IDisposable.

  • TIDAK DIIZINKAN: Mengubah jenis readonly struct menjadi jenis struct

    Namun, perubahan dari jenis struct ke jenis readonly struct diperbolehkan.

  • DILARANG: Mengganti jenis struct ke jenis ref struct, dan sebaliknya

  • TIDAK DIIZINKAN: Pengurangan kejelasan suatu jenis

    Namun, meningkatkan visibilitas jenis tersebut diizinkan.

Anggota

  • ✔️ DIIZINKAN: Memperluas visibilitas anggota yang tidak virtual

  • ✔️ DIIZINKAN: Menambahkan anggota abstrak ke jenis publik yang tidak memiliki konstruktor yang dapat diakses (publik atau dilindungi), atau jenisnya disegel

    Namun, menambahkan anggota abstrak ke jenis yang memiliki konstruktor yang dapat diakses (publik atau dilindungi) dan bukan sealed tidak diperbolehkan.

  • ✔️ DIIZINKAN: Membatasi visibilitas anggota yang dilindungi ketika jenis tidak memiliki konstruktor yang dapat diakses (publik atau dilindungi), atau jenisnya disegel

  • ✔️ DIIZINKAN: Memindahkan anggota ke kelas yang lebih tinggi dalam hierarki daripada tipe asal tempat anggota dihapus

  • ✔️ DIIZINKAN: Menambahkan atau menghapus penggantian

    Memasukkan penimpaan dapat menyebabkan pengguna sebelumnya melewati penimpaan saat memanggil basis.

  • ✔️ DIIZINKAN: Menambahkan konstruktor ke kelas, bersama dengan konstruktor tanpa parameter jika kelas sebelumnya tidak memiliki konstruktor

    Namun, menambahkan konstruktor ke kelas yang sebelumnya tidak memiliki konstruktor tanpa menambahkan konstruktor tanpa parameter tidak diizinkan.

  • ✔️ DIIZINKAN: Mengubah anggota dari abstrak ke virtual

  • ✔️ DIIZINKAN: Mengubah nilai pengembalian dari tipe ref readonly ke tipe ref (kecuali untuk metode atau antarmuka virtual)

  • ✔️ DIIZINKAN: Menghapus readonly dari bidang, kecuali jenis statis bidang adalah jenis nilai yang dapat diubah

  • ✔️ DIIZINKAN: Memanggil peristiwa baru yang sebelumnya tidak ditentukan

  • MEMERLUKAN PENILAIAN: Menambahkan bidang instans baru ke jenis

    Perubahan ini berdampak pada serialisasi.

  • TIDAK DIIZINKAN: Mengganti nama atau menghapus anggota atau parameter publik

    Ini memutus semua kode yang menggunakan anggota atau parameter yang diganti namanya atau dihapus.

    Ini termasuk menghapus atau mengganti nama getter atau setter dari properti, serta mengganti nama atau menghapus anggota enumerasi.

  • MEMERLUKAN PENILAIAN: Menambahkan anggota ke antarmuka

    Meskipun ini adalah perubahan besar dalam arti bahwa menaikkan versi minimum .NET ke .NET Core 3.0 (C# 8.0), yaitu ketika anggota antarmuka default (DIM) diperkenalkan, menambahkan anggota statis, non-abstrak, non-virtual ke antarmuka dapat dilakukan.

    Jika Anda memberikan implementasi, menambahkan anggota baru ke antarmuka yang ada tidak akan selalu mengakibatkan kegagalan kompilasi dalam rakitan hilir. Namun, tidak semua bahasa mendukung DIM. Selain itu, dalam beberapa skenario, runtime tidak dapat memutuskan anggota antarmuka default mana yang akan dipanggil. Dimulai dengan C# 13, ref struct jenis dapat menerapkan antarmuka, tetapi tidak dapat dikelaskan atau dikonversi ke jenis antarmuka. Oleh karena itu, jenis ref struct harus menyediakan implementasi eksplisit untuk setiap anggota antarmuka instans—jenis tersebut tidak dapat menggunakan implementasi default yang disediakan oleh antarmuka. Menambahkan anggota instans default ke antarmuka yang diimplementasikan oleh ref struct memerlukan ref struct untuk menambahkan implementasi yang sesuai, yang merupakan perubahan yang memecahkan kompatibilitas sumber. Untuk alasan ini, gunakan penilaian saat menambahkan anggota ke antarmuka yang ada.

    Nota

    Jika antarmuka Anda diimplementasikan berdasarkan ref struct jenis (dimungkinkan di C# 13 dan yang lebih baru), menambahkan anggota instans default ke antarmuka adalah perubahan pemecah sumber untuk pemanggil tersebut. ref struct harus memberikan implementasi eksplisit anggota baru; tidak dapat kembali ke implementasi default.

  • TIDAK DIIZINKAN: Mengubah nilai konstanta publik atau anggota enumerasi

  • TIDAK DIIZINKAN: Mengubah jenis properti, bidang, parameter, atau nilai pengembalian

  • TIDAK DIIZINKAN: Menambahkan, menghapus, atau mengubah urutan parameter

  • TIDAK DIIZINKAN: Menambahkan atau menghapus kata kunci masuk, keluar, atau ref dari parameter

  • ✔️ DIIZINKAN: Mengubah parameter menjadi refref readonly

    Mengubah parameter dari ref ke ref readonly kompatibel dengan sumber untuk situs panggilan yang ada yang meneruskan argumen dengan pengubah ref —panggilan tersebut terus dikompilasi tanpa perubahan apa pun. Tidak seperti mengubah ref ke in, ref readonly parameter tidak secara diam-diam memungkinkan penelepon untuk meneruskan rvalue (non-variabel); kompilator mengeluarkan peringatan jika argumen bukan variabel. Situs panggilan ref yang ada tetap valid.

  • TIDAK DIIZINKAN: Mengubah parameter menjadi inref readonly

    Lokasi pemanggilan yang meneruskan in argumen tanpa modifikasi in (yang diizinkan kompiler untuk parameter in) akan menerima peringatan ketika parameter berubah menjadi ref readonly, karena ref readonly memerlukan argumen diteruskan sebagai referensi. Pemanggil yang memperlakukan peringatan sebagai error akan mengalami perubahan yang merusak kompatibilitas sumber.

  • TIDAK DIIZINKAN: Mengganti nama parameter (termasuk mengubah kasusnya)

    Ini dianggap melanggar karena dua alasan:

  • TIDAK DIPERBOLEHKAN: Mengubah nilai pengembalian dari ref ke ref readonly

  • ❌️ TIDAK DIIZINKAN: Mengubah dari nilai pengembalian ref readonly ke ref pada metode atau antarmuka virtual

  • TIDAK DIIZINKAN: Menambahkan atau menghapus abstrak dari anggota

  • TIDAK DIIZINKAN: Menghapus kata kunci virtual dari anggota

  • TIDAK DIIZINKAN: Menambahkan kata kunci virtual ke anggota

    Meskipun ini sering kali bukan perubahan yang merusak karena pengkompilasi C# cenderung menghasilkan instruksi callvirt Intermediate Language (IL) untuk memanggil metode non-virtual (callvirt melakukan pemeriksaan null, sementara panggilan normal tidak), perilaku ini tidak selalu demikian karena beberapa alasan:

    • Bahasa C# bukan satu-satunya yang menjadi sasaran .NET.
    • Pengompilasi C# semakin sering mencoba mengoptimalkan callvirt ke panggilan normal setiap kali metode target non-virtual dan mungkin tidak null (seperti metode yang diakses melalui operator penyebaran null ?. ).

    Membuat metode menjadi virtual berarti bahwa kode pengguna sering kali akan memanggil metode tersebut secara non-virtual.

  • TIDAK DIIZINKAN: Menjadikan anggota virtual bersifat abstrak

    Anggota virtual menyediakan implementasi metode yang dapat di-override oleh kelas turunan. Anggota abstrak tidak menyediakan implementasi dan harus dioverride.

  • TIDAK DIIZINKAN: Menambahkan kata kunci yang disegel ke anggota antarmuka

    sealed jika ditambahkan ke anggota antarmuka default akan membuatnya non-virtual, mencegah pemanggilan implementasi jenis turunan dari anggota tersebut.

  • TIDAK DIIZINKAN: Menambahkan anggota abstrak ke jenis publik yang memiliki konstruktor yang dapat diakses (publik atau dilindungi) dan yang tidak disegel

  • TIDAK DIIZINKAN: Menambahkan atau menghapus kata kunci statis dari anggota

  • TIDAK DIIZINKAN: Menambahkan kelebihan beban yang menghalangi kelebihan beban yang ada dan menentukan perilaku yang berbeda

    Ini memutus klien yang ada yang terikat pada kelebihan beban sebelumnya. Misalnya, jika kelas memiliki satu versi metode yang menerima UInt32, konsumen yang ada akan berhasil mengikat ke overload tersebut saat meneruskan nilai Int32. Namun, jika Anda menambahkan kelebihan beban yang menerima Int32, saat mengkompilasi ulang atau menggunakan pengikatan terlambat, pengkompilasi sekarang mengikat ke kelebihan beban baru. Jika perilaku yang berbeda terjadi, ini dapat menjadi perubahan yang signifikan.

  • MEMERLUKAN PENILAIAN: Menambahkan OverloadResolutionPriorityAttribute ke kelebihan beban yang ada atau mengubah nilai prioritasnya

    Mempengaruhi OverloadResolutionPriorityAttribute resolusi kelebihan beban pada tingkat sumber: penelepon yang kompilasi ulang mungkin mengatasi kelebihan beban yang berbeda dari sebelumnya. Penggunaan yang dimaksudkan adalah menambahkan atribut ke kelebihan beban baru yang lebih baik sehingga pengkompilasi lebih memilihnya daripada yang sudah ada. Menambahkannya ke kelebihan beban yang ada atau mengubah nilai prioritas pada kelebihan beban yang sudah diatribusikan dapat menjadi perubahan pemecah sumber karena penelepon yang mengkompilasi ulang mungkin mengubah perilaku.

  • ✔️ DIIZINKAN: Menambahkan allows ref struct anti-batasan ke parameter jenis generik

    Menambahkan allows ref struct memperluas tipe yang dapat digunakan sebagai argumen tipe dengan mengizinkan tipe ref struct. Penelepon yang sudah ada yang menggunakan argumen yang bukan tiperef struct tidak terpengaruh. Metode atau tipe generik harus mengikuti aturan keamanan ref pada semua instans dari parameter tipe tersebut.

  • TIDAK DIIZINKAN: Menghapus pembatas allows ref struct dari parameter tipe generik

    Menghapus allows ref struct membatasi jenis-jenis yang dapat digunakan pemanggil sebagai argumen jenis. Setiap pemanggil yang meneruskan ref struct sebagai argumen jenis tidak akan dapat dikompilasi lagi.

  • TIDAK DIIZINKAN: Menambahkan konstruktor ke kelas yang sebelumnya tidak memiliki konstruktor tanpa menambahkan konstruktor tanpa parameter

  • ❌️ TIDAK DIIZINKAN: Menambahkan readonly ke bidang

  • TIDAK DIIZINKAN: Mengurangi visibilitas anggota

    Ini termasuk mengurangi visibilitas anggota yang dilindungi ketika ada konstruktor yang dapat diakses (public atau protected) dan jenisnya tidakdisegel. Jika tidak demikian, mengurangi visibilitas anggota yang dilindungi diizinkan.

    Meningkatkan visibilitas anggota diizinkan.

  • TIDAK DIIZINKAN: Mengubah jenis anggota

    Nilai pengembalian metode atau jenis properti atau bidang tidak dapat dimodifikasi. Misalnya, tanda tangan metode yang mengembalikan Object tidak dapat diubah untuk mengembalikan String, atau sebaliknya.

  • TIDAK DIIZINKAN: Menambahkan bidang instans ke struktur yang tidak memiliki bidang nonpublik

    Jika struct hanya memiliki bidang publik atau tidak memiliki bidang sama sekali, penelepon dapat mendeklarasikan lokal dari jenis struct tersebut tanpa memanggil konstruktor struct atau terlebih dahulu menginisialisasi lokal ke default(T), selama semua bidang publik diatur pada struct sebelum pertama kali digunakan. Menambahkan bidang baru - publik atau nonpublik - ke dalam struktur semacam ini adalah perubahan yang merusak sumber bagi pemanggil ini, karena kompilator sekarang akan mengharuskan bidang tambahan untuk diinisialisasi.

    Selain itu, menambahkan bidang baru, baik yang publik maupun nonpublik, pada struktur yang tidak memiliki bidang atau hanya memiliki bidang publik akan menjadi perubahan mendasar dalam biner bagi pemanggil yang telah menerapkan [SkipLocalsInit] ke dalam kode mereka. Karena pengompilasi tidak mengetahui elemen-elemen ini pada waktu kompilasi, pengompilasi dapat menghasilkan IL yang tidak sepenuhnya menginisialisasi struktur, sehingga struktur tersebut dibuat dari data tumpukan yang belum diinisialisasi.

    Jika struktur memiliki bidang nonpublik, kompilator sudah memberlakukan inisialisasi melalui konstruktor atau default(T), dan penambahan bidang instans baru bukan merupakan perubahan yang merusak.

  • TIDAK DIIZINKAN: Mengaktifkan peristiwa yang sudah ada ketika tidak pernah terjadi sebelumnya

Perubahan perilaku

Perakitan

  • ✔️ DIIZINKAN: Membuat rakitan portabel ketika platform yang sama masih didukung

  • TIDAK DIIZINKAN: Mengubah nama komponen

  • TIDAK DIIZINKAN: Mengubah kunci publik rakitan

Properti, bidang, parameter, dan nilai pengembalian

  • ✔️ DIIZINKAN: Mengubah nilai properti, bidang, nilai pengembalian, atau parameter keluar ke jenis yang lebih turunan

    Misalnya, metode yang mengembalikan jenis Object dapat mengembalikan instans String. (Namun, tanda tangan metode tidak dapat berubah.)

  • ✔️ DIIZINKAN: Meningkatkan rentang nilai yang diterima untuk properti atau parameter jika anggota tidak virtual

    Meskipun rentang nilai yang dapat diteruskan ke metode atau dikembalikan oleh anggota dapat diperluas, parameter atau jenis anggota tidak dapat. Misalnya, sementara nilai yang diteruskan ke metode dapat diperluas dari 0-124 ke 0-255, jenis parameter tidak dapat berubah dari Byte ke Int32.

  • TIDAK DIIZINKAN: Meningkatkan rentang nilai yang diterima untuk properti atau parameter jika anggotanya virtual

    Perubahan ini merusak fungsi anggota yang sudah ditimpa, sehingga tidak akan berfungsi dengan benar untuk rentang nilai yang diperluas.

  • TIDAK DIIZINKAN: Mengurangi rentang nilai yang diterima untuk properti atau parameter

  • TIDAK DIIZINKAN: Meningkatkan rentang nilai yang dikembalikan untuk properti, bidang, nilai yang dikembalikan, atau parameter keluar

  • TIDAK DIIZINKAN: Mengubah nilai yang dikembalikan untuk properti, bidang, nilai pengembalian metode, atau parameter keluar

  • TIDAK DIIZINKAN: Mengubah nilai default properti, bidang, atau parameter

    Mengubah atau menghapus nilai default parameter bukanlah jeda biner. Menghapus nilai default parameter adalah pemisah sumber, dan mengubah nilai default parameter dapat mengakibatkan pemutusan perilaku setelah kompilasi ulang.

    Untuk alasan ini, menghapus nilai default parameter dapat diterima dalam kasus tertentu "memindahkan" nilai default tersebut ke metode baru yang kelebihan beban untuk menghilangkan ambiguitas. Misalnya, pertimbangkan metode MyMethod(int a = 1)yang ada . Jika Anda memperkenalkan kelebihan beban MyMethod dengan dua parameter a opsional dan b, Anda dapat mempertahankan kompatibilitas dengan memindahkan nilai a default ke kelebihan beban baru. Sekarang kedua kelebihan beban adalah MyMethod(int a) dan MyMethod(int a = 1, int b = 2). Pola ini memungkinkan MyMethod() untuk mengkompilasi.

  • TIDAK DIIZINKAN: Mengubah presisi nilai pengembalian numerik

  • MENGHARUSKAN PENILAIAN: Perubahan penguraian input dan melempar pengecualian baru (bahkan jika perilaku penguraian tidak ditentukan dalam dokumentasi

  • TIDAK DIIZINKAN: Menambahkan atau menghapus jenis kasus dari union deklarasi

    Menambahkan atau menghapus tipe kasus dari tipe union adalah pelanggaran biner dan pelanggaran sumber.

    Pengujian pencocokan pola tidak lagi lengkap setelah menambahkan jenis kasus. Pengkompilasi menandai ekspresi pencocokan pola sebagai non-lengkap. Pada runtime, nilai yang tidak terduga menyebabkan pengecualian runtime. Menghapus jenis kasus akan menghapus deklarasi konstruktor untuk jenis kasus tersebut.

Pengecualian

  • ✔️ DIIZINKAN: Melemparkan pengecualian yang lebih turunan daripada pengecualian yang ada

    Karena pengecualian baru adalah subkelas dari pengecualian yang ada, kode penanganan pengecualian sebelumnya terus menangani pengecualian. Misalnya, dalam .NET Framework 4, metode pembuatan dan pengambilan kultur akan melemparkan CultureNotFoundException alih-alih ArgumentException jika kultur tidak dapat ditemukan. Karena CultureNotFoundException berasal dari ArgumentException, ini adalah perubahan yang dapat diterima.

  • ✔️ DIIZINKAN: Melemparkan pengecualian yang lebih spesifik daripada NotSupportedException, , NotImplementedExceptionNullReferenceException

  • ✔️ DIIZINKAN: Melemparkan pengecualian yang dianggap tidak dapat dipulihkan

    Pengecualian yang tidak dapat dipulihkan tidak boleh ditangkap tetapi sebaliknya harus ditangani oleh handler catch-all tingkat tinggi. Oleh karena itu, pengguna tidak diharapkan memiliki kode yang menangkap pengecualian eksplisit ini. Pengecualian yang tidak dapat dipulihkan adalah:

  • ✔️ DIIZINKAN: Melemparkan pengecualian baru di jalur kode baru

    Pengecualian hanya boleh berlaku untuk jalur kode baru yang dijalankan dengan nilai atau status parameter baru dan yang tidak dapat dijalankan oleh kode yang ada yang menargetkan versi sebelumnya.

  • ✔️ DIIZINKAN: Menghapus pengecualian untuk mengaktifkan perilaku yang lebih kuat atau skenario baru

    Misalnya, sebuah Divide metode yang sebelumnya hanya menangani nilai positif dan melemparkan ArgumentOutOfRangeException jika sebaliknya dapat diubah untuk mendukung baik nilai negatif maupun positif tanpa menghasilkan pengecualian.

  • ✔️ DIIZINKAN: Mengubah teks pesan kesalahan

    Pengembang tidak boleh mengandalkan teks pesan kesalahan, yang juga berubah berdasarkan budaya pengguna.

  • TIDAK DIIZINKAN: Melemparkan pengecualian dalam kasus lain yang tidak tercantum di atas

  • TIDAK DIIZINKAN: Menghapus pengecualian dalam kasus lain yang tidak tercantum di atas

Atributs

  • ✔️ DIIZINKAN: Mengubah nilai atribut yang tidak dapat diamati

  • TIDAK DIIZINKAN: Mengubah nilai atribut yang dapat diamati

  • MEMERLUKAN PENILAIAN: Menghapus atribut

    Dalam kebanyakan kasus, menghapus atribut (seperti NonSerializedAttribute) adalah perubahan yang melanggar.

Dukungan platform

  • ✔️ DIIZINKAN: Mendukung operasi pada platform yang sebelumnya tidak didukung

  • TIDAK DIIZINKAN: Tidak mendukung atau sekarang memerlukan paket layanan tertentu untuk operasi yang sebelumnya didukung pada platform

Perubahan implementasi internal

  • MEMERLUKAN PENILAIAN: Mengubah area permukaan dari tipe internal

    Perubahan tersebut umumnya diizinkan, meskipun melanggar refleksi privat. Dalam beberapa kasus, di mana pustaka pihak ketiga populer atau sejumlah besar pengembang bergantung pada API internal, perubahan tersebut mungkin tidak diizinkan.

  • MEMERLUKAN PENILAIAN: Mengubah implementasi internal anggota

    Perubahan ini umumnya diizinkan, meskipun melanggar refleksi privat. Dalam beberapa kasus, di mana kode pelanggan sering bergantung pada refleksi privat atau di mana perubahan memperkenalkan efek samping yang tidak diinginkan, perubahan ini mungkin tidak diizinkan.

  • ✔️ DIIZINKAN: Meningkatkan performa operasi

    Kemampuan untuk memodifikasi performa operasi sangat penting, tetapi perubahan tersebut dapat merusak kode yang bergantung pada kecepatan operasi saat ini. Ini terutama berlaku untuk kode yang tergantung pada waktu operasi asinkron. Perubahan performa seharusnya tidak berpengaruh pada perilaku API lain yang dimaksud; jika tidak, perubahan akan melanggar.

  • ✔️ DIIZINKAN: Secara tidak langsung (dan sering merugikan) mengubah performa operasi

    Jika perubahan yang dimaksud tidak dikategorikan sebagai melanggar karena alasan lain, ini dapat diterima. Seringkali, tindakan perlu diambil yang mungkin mencakup operasi tambahan atau yang menambahkan fungsionalitas baru. Ini hampir akan selalu memengaruhi performa tetapi mungkin penting untuk membuat API yang dimaksud berfungsi seperti yang diharapkan.

  • TIDAK DIIZINKAN: Mengubah API sinkron menjadi asinkron (dan sebaliknya)

Perubahan kode

  • ✔️ DIIZINKAN: Menambahkan param ke parameter

  • TIDAK DIIZINKAN: Mengubah struktur ke kelas dan sebaliknya

  • TIDAK DIIZINKAN: Menambahkan pernyataan yang dicentang ke blok kode

    Perubahan ini dapat menyebabkan kode yang sebelumnya dijalankan untuk melempar OverflowException dan tidak dapat diterima.

  • TIDAK DIIZINKAN: Menghapus param dari parameter

  • TIDAK DIIZINKAN: Mengubah tipe koleksi dari parameter params

    Dimulai dengan C# 13, params parameter mendukung tipe koleksi non-array, termasuk Span<T>, ReadOnlySpan<T>, tipe struct atau kelas yang mengimplementasikan IEnumerable<T> dengan konstruktor tanpa parameter yang dapat diakses dan metode instance Add, serta tipe antarmuka tertentu seperti IList<T>. Mengubah jenis koleksi parameter yang ada params (misalnya, dari params T[] ke params ReadOnlySpan<T>) mengubah tanda tangan IL metode dan merupakan perubahan pemecahan biner. Pemanggil yang dikompilasi terhadap versi sebelumnya harus dikompilasi ulang.

  • ✔️ DIIZINKAN: Mengonversi metode ekstensi ke sintaks anggota blok ekstensi

    Dimulai dengan C# 14, Anda dapat mendeklarasikan anggota ekstensi dengan blok extension selain sintaksis parameter lama this. Kedua bentuk menghasilkan IL yang identik, sehingga penelepon tidak dapat membedakannya. Mengonversi metode ekstensi yang ada ke sintaks blok ekstensi baru kompatibel baik dengan biner maupun sumber.

  • TIDAK DIIZINKAN: Mengubah susunan urutan peristiwa dipicu

    Pengembang dapat secara wajar mengharapkan peristiwa terjadi dalam urutan yang sama, dan kode pengembang sering kali bergantung pada urutan peristiwa tersebut terjadi.

  • TIDAK DIIZINKAN: Menghapus pemicu peristiwa pada tindakan tertentu

  • TIDAK DIIZINKAN: Mengubah jumlah panggilan peristiwa tertentu

  • TIDAK DIIZINKAN: Menambahkan FlagsAttribute pada tipe enumerasi

Lihat juga