
Bukan rahasia lagi bahwa Microsoft telah bekerja pada rilis versi kedelapan C # untuk beberapa waktu. Dalam rilis Visual Studio 2019 baru-baru ini, versi bahasa baru (C # 8.0) sudah tersedia, tetapi sejauh ini hanya sebagai rilis beta. Paket versi baru ini memiliki beberapa fitur, yang implementasinya mungkin tidak terlalu jelas, atau lebih tepatnya, tidak terlalu diharapkan. Salah satu inovasi ini adalah kemampuan untuk menggunakan tipe Referensi Nullable. Arti yang dinyatakan dari inovasi ini adalah perang melawan Null Reference Exception (NRE).
Kami senang bahasanya berkembang dan fitur-fitur baru akan membantu pengembang. Secara kebetulan, dalam penganalisis PVS-Studio kami untuk C #, kemampuan untuk mendeteksi NRE yang persis sama dalam kode relatif baru saja diperluas. Dan kami bertanya pada diri sendiri - apakah ada gunanya sekarang untuk analisis statis pada umumnya, dan untuk PVS-Studio pada khususnya, untuk mencoba mencari dereferencing referensi nol, jika, setidaknya dalam kode baru menggunakan Referensi Nullable, dereferencing seperti itu akan menjadi "mustahil" ? Mari kita coba jawab pertanyaan ini.
Pro dan Kontra Inovasi
Untuk memulainya, perlu diingat bahwa dalam versi beta terbaru dari C # 8.0, tersedia pada saat penulisan ini, Referensi Nullable dimatikan secara default, mis. perilaku tipe referensi tidak akan berubah.
Apa jenis referensi yang dapat dibatalkan dalam C # 8.0 jika Anda memasukkannya? Ini adalah tipe referensi lama yang baik yang sama dengan perbedaan yang variabel-variabel dari tipe ini sekarang harus ditandai dengan '?' (mis.
string? ), mirip dengan yang sudah dilakukan untuk
Nullable <T> , mis. jenis signifikan yang dapat dibatalkan (mis.
int? ). Namun, sekarang
string yang sama tanpa '?' sudah mulai ditafsirkan sebagai referensi yang tidak dapat dibatalkan, mis. ini adalah tipe referensi yang variabelnya tidak dapat berisi nilai
nol .
Null Reference Exception adalah salah satu pengecualian yang paling menjengkelkan karena tidak banyak menyebutkan sumber masalahnya, terutama jika ada beberapa referensi dalam satu baris dalam metode yang melempar pengecualian. Kemampuan untuk melarang lewat
nol ke variabel referensi tipe terlihat baik-baik saja, tetapi jika
nol sebelumnya diteruskan ke metode, dan beberapa logika eksekusi lebih lanjut terkait dengan ini, lalu apa yang harus saya lakukan sekarang? Tentu saja, Anda dapat melewatkan nilai literal, konstanta, atau hanya โtidak mungkinโ alih-alih
nol , yang, menurut logika program, tidak dapat ditugaskan ke variabel ini di tempat lain. Namun, jatuhnya seluruh program dapat diganti dengan eksekusi salah "diam" lebih lanjut. Ini tidak selalu lebih baik daripada melihat kesalahan segera.
Dan jika bukan melemparkan pengecualian? Pengecualian yang berarti di tempat di mana terjadi kesalahan selalu lebih baik daripada
NRE di tempat yang lebih tinggi atau lebih rendah di tumpukan. Tapi itu baik jika kita berbicara tentang proyek kita sendiri, di mana kita dapat memperbaiki konsumen dan memasukkan
blok uji coba, dan ketika mengembangkan perpustakaan menggunakan Referensi (non) Nullable, kami bertanggung jawab bahwa beberapa metode selalu mengembalikan nilai. Dan itu tidak selalu bahkan dalam kode asli yang akan (setidaknya sederhana) untuk menggantikan kembali
nol untuk melempar pengecualian (terlalu banyak kode dapat dipengaruhi).
Anda dapat mengaktifkan Referensi Nullable di seluruh tingkat proyek dengan menambahkan properti
NullableContextOptions dengan nilai
aktifkan padanya, atau pada tingkat file menggunakan arahan preprocessor:
#nullable enable string cantBeNull = string.Empty; string? canBeNull = null; cantBeNull = canBeNull!;
Jenis sekarang akan lebih visual. Dengan tanda tangan metode, adalah mungkin untuk menentukan perilakunya, apakah mengandung cek untuk
nol atau tidak, itu bisa mengembalikan
nol atau tidak bisa. Sekarang, jika Anda mencoba mengakses variabel referensi yang dapat dibatalkan tanpa memeriksa, kompiler akan menghasilkan peringatan.
Cukup nyaman saat menggunakan perpustakaan pihak ketiga, tetapi ada situasi dengan kemungkinan kesalahan informasi. Faktanya adalah bahwa melewati
null masih dimungkinkan, misalnya, menggunakan operator null-forgiving baru (!). Yaitu hanya saja dengan bantuan satu tanda seru, Anda dapat mematahkan semua asumsi lebih lanjut yang akan dibuat tentang antarmuka menggunakan variabel-variabel ini:
#nullable enable String GetStr() { return _count > 0 ? _str : null!; } String str = GetStr(); var len = str.Length;
Ya, dapat dikatakan bahwa menulis dengan cara ini salah, dan tidak ada yang akan melakukan itu, tetapi selama kesempatan ini tetap ada, tidak mungkin lagi untuk sepenuhnya bergantung hanya pada kontrak yang diberlakukan oleh antarmuka metode ini (tidak dapat mengembalikan nol).
Dan Anda dapat, dengan cara, menulis hal yang sama dengan bantuan beberapa operator!, Karena C # sekarang memungkinkan Anda untuk menulis seperti ini (dan kode ini dikompilasi sepenuhnya):
cantBeNull = canBeNull!!!!!!!;
Yaitu kami ingin menekankan lebih lanjut: perhatikan - ini bisa menjadi
nol !!! (kami di tim menyebutnya pemrograman "emosional"). Bahkan, kompiler (dari Roslyn), ketika membangun sintaksis kode, menafsirkan operator! mirip dengan tanda kurung sederhana, sehingga jumlah mereka, seperti halnya dengan tanda kurung, tidak terbatas. Meskipun, jika Anda menulis banyak dari mereka, kompiler dapat "dibuang". Mungkin ini akan berubah di versi final C # 8.0.
Dengan cara yang sama, Anda dapat mem-bypass peringatan kompiler ketika mengakses variabel referensi yang dapat dibatalkan tanpa memeriksa:
canBeNull!.ToString();
Anda dapat menulis lebih emosional:
canBeNull!!!?.ToString();
Sintaks ini sebenarnya sulit dibayangkan dalam proyek nyata, menempatkan operator
null-maaf kepada kompiler: semuanya baik-baik saja di sini, tidak diperlukan verifikasi. Menambahkan operator elvis kami katakan: tetapi secara umum mungkin tidak normal, mari kita periksa.
Dan sekarang muncul pertanyaan yang sah - mengapa, jika konsep tipe referensi yang tidak dapat
dibatalkan menyiratkan bahwa variabel jenis ini tidak dapat mengandung
nol , dapatkah kita masih menulisnya dengan mudah di sana? Faktanya adalah bahwa "di bawah tenda", pada tingkat kode IL, jenis referensi kami yang tidak dapat dibatalkan tetap ... semua jenis referensi "biasa" yang sama. Dan seluruh sintaks nullability sebenarnya hanya merupakan anotasi untuk penganalisa statis yang dibangun ke dalam kompiler (dan, menurut pendapat kami, bukan penganalisa yang paling nyaman, tetapi lebih pada nanti) Menurut pendapat kami, memasukkan sintaks baru dalam bahasa hanya sebagai anotasi untuk alat pihak ketiga (bahkan jika itu dibangun ke dalam kompiler) bukan solusi yang paling "indah", karena untuk seorang programmer yang menggunakan bahasa ini bahwa ini hanya sebuah anotasi mungkin tidak jelas sama sekali - lagipula, sintaks yang sangat mirip untuk struktur nullable bekerja dengan cara yang sangat berbeda.
Kembali ke bagaimana masih mungkin untuk "mematahkan" jenis Referensi Nullable. Pada saat penulisan, jika ada beberapa proyek dalam solusi, ketika melewati dari metode yang dinyatakan dalam satu proyek variabel referensi, misalnya dari tipe
String, ke metode dari proyek lain di mana
NullableContextOptions diaktifkan
, kompiler akan memutuskan bahwa itu sudah menjadi String yang tidak dapat dibatalkan, dan tidak akan memberi peringatan. Dan ini terlepas dari sejumlah besar atribut
[Nullable (1)] yang ditambahkan ke setiap metode bidang dan kelas dalam kode IL ketika Referensi Nullable dihidupkan
. Ngomong-ngomong, atribut-atribut ini harus diperhitungkan jika Anda bekerja dengan daftar atribut melalui refleksi, mengandalkan keberadaan hanya atribut-atribut yang Anda tambahkan sendiri.
Situasi ini dapat menimbulkan masalah tambahan saat mengonversi basis kode besar ke Referensi Nullable. Kemungkinan besar proses ini akan bertahap, proyek per proyek. Tentu saja, dengan pendekatan perubahan yang kompeten, Anda dapat secara bertahap beralih ke fungsional baru, tetapi jika Anda sudah memiliki konsep kerja, setiap perubahan di dalamnya berbahaya dan tidak diinginkan (berfungsi - jangan disentuh!). Itu sebabnya ketika menggunakan penganalisa PVS-Studio tidak perlu mengedit kode sumber atau entah bagaimana menandainya untuk mendeteksi
NRE potensial. Untuk memeriksa tempat-tempat di mana
NullReferenceException dapat terjadi
, Anda hanya perlu memulai penganalisis dan melihat peringatan V3080. Tidak perlu mengubah properti proyek atau kode sumber. Tidak perlu menambahkan arahan, atribut, atau operator. Tidak perlu mengubah kode Anda.
Dengan dukungan tipe Referensi Nullable dalam penganalisa PVS-Studio, kami menghadapi pilihan - haruskah penganalisa menafsirkan variabel referensi yang tidak dapat dibatalkan sebagai nilai yang selalu tidak nol? Setelah mempelajari masalah kemungkinan untuk "memecah" jaminan ini, kami sampai pada kesimpulan bahwa tidak ada - penganalisa seharusnya tidak membuat asumsi seperti itu. Memang, bahkan jika tipe referensi non-nullable digunakan di mana-mana dalam proyek, penganalisa dapat melengkapi penggunaannya dengan hanya menemukan situasi di mana nilai
nol dapat muncul dalam variabel seperti itu.
Bagaimana PVS-Studio mencari Pengecualian Referensi Null
Mekanisme aliran data dalam C # analyzer PVS-Studio memantau nilai-nilai variabel yang mungkin selama analisis. Secara khusus, PVS-Studio juga melakukan analisis antar prosedur, yaitu Mencoba menentukan nilai yang mungkin dikembalikan oleh metode, serta metode yang dipanggil dalam metode ini, dll. Antara lain, penganalisa mengingat variabel yang berpotensi menjadi
nol . Jika di masa depan penganalisa melihat dereferencing tanpa memeriksa variabel seperti itu, sekali lagi, baik dalam kode saat ini sedang diperiksa atau di dalam metode yang disebut dalam kode ini, peringatan V3080 tentang potensi Pengecualian Referensi Null akan dikeluarkan.
Pada saat yang sama, ide utama yang mendasari diagnosis ini adalah bahwa penganalisa hanya akan bersumpah jika melihat suatu tempat penugasan
nol ke variabel. Ini adalah perbedaan utama antara perilaku diagnostik ini dan penganalisa yang dibangun ke dalam kompiler yang bekerja dengan tipe Referensi Nullable. Alat analisis yang dibangun ke dalam kompiler akan bersumpah pada setiap referensi variabel variabel nullable yang tidak diverifikasi dari jenisnya, kecuali, tentu saja, alat analisis ini โditipuโ oleh operator! dengan cara lain, benar-benar alat analisis apa pun dapat digunakan, terutama jika Anda menetapkan sendiri tujuan tersebut, dan PVS-Studio tidak terkecuali).
PVS-Studio bersumpah hanya jika melihat
nol (dalam konteks lokal, atau berasal dari suatu metode). Pada saat yang sama, bahkan jika variabel tersebut adalah variabel referensi yang tidak dapat dibatalkan, perilaku penganalisa tidak akan berubah - itu masih akan bersumpah jika melihat bahwa nol ditulis untuk itu. Menurut kami, pendekatan ini lebih tepat (atau, paling tidak, nyaman bagi pengguna penganalisa) itu tidak memerlukan "mencakup" seluruh kode dengan cek
nol untuk menemukan referensi potensial - ini bisa dilakukan sebelumnya, tanpa Referensi Nullable, misalnya, dengan kontrak yang sama. Selain itu, penganalisa sekarang dapat digunakan untuk kontrol tambahan atas variabel referensi yang tidak dapat dibatalkan. Jika mereka digunakan "dengan jujur", dan mereka tidak pernah ditugaskan nol - analis akan tetap diam. Jika null ditugaskan dan variabel ditereferensi tanpa memeriksa, penganalisis memperingatkan tentang hal ini dengan pesan V3080:
#nullable enable String GetStr() { return _count > 0 ? _str : null!; } String str = GetStr(); var len = str.Length; <== V3080: Possible null dereference. Consider inspecting 'str'
Mari kita perhatikan beberapa contoh pemicu seperti diagnostik V3080 dalam kode Roslyn itu sendiri. Kami telah
memeriksa proyek ini belum lama ini, tetapi kali ini kami akan mempertimbangkan hanya pemicu Null Reference Exception potensial yang tidak ada dalam artikel sebelumnya. Mari kita lihat bagaimana penganalisa PVS-Studio dapat menemukan potensi referensi referensi nol, dan bagaimana tempat-tempat ini dapat diperbaiki menggunakan sintaks Referensi Nullable baru.
V3080 [CWE-476] Kemungkinan null dereference di dalam metode. Pertimbangkan memeriksa argumen 2: chainedTupleType. Microsoft.CodeAnalysis.CSharp TupleTypeSymbol.cs 244 NamedTypeSymbol chainedTupleType; if (_underlyingType.Arity < TupleTypeSymbol.RestPosition) { .... chainedTupleType = null; } else { .... } return Create(ConstructTupleUnderlyingType(firstTupleType, chainedTupleType, newElementTypes), elementNames: _elementNames);
Seperti yang Anda lihat, variabel
chainedTupleType bisa nol di salah satu cabang eksekusi kode. Kemudian
chainedTupleType dilewatkan di dalam metode
ConstructTupleUnderlyingType, dan digunakan di sana dengan verifikasi melalui
Debug.Assert . Situasi ini sangat umum di Roslyn, namun, perlu diingat bahwa
Debug.Assert dihapus dalam versi rilis majelis. Oleh karena itu, penganalisa masih menganggap dereferencing di dalam metode
ConstructTupleUnderlyingType berbahaya. Selanjutnya, kami memberikan tubuh metode ini, di mana dereferencing terjadi:
internal static NamedTypeSymbol ConstructTupleUnderlyingType( NamedTypeSymbol firstTupleType, NamedTypeSymbol chainedTupleTypeOpt, ImmutableArray<TypeWithAnnotations> elementTypes) { Debug.Assert (chainedTupleTypeOpt is null == elementTypes.Length < RestPosition); .... while (loop > 0) { .... currentSymbol = chainedTupleTypeOpt.Construct(chainedTypes); loop--; } return currentSymbol; }
Apakah penganalisa harus mempertimbangkan Assert seperti itu sebenarnya merupakan poin yang dapat diperdebatkan (beberapa pengguna kami menginginkannya melakukan ini), karena kontrak dari System.Diagnostics.Contracts, misalnya, penganalisa sekarang mempertimbangkan. Saya hanya akan memberi tahu Anda sebuah contoh kecil dari penggunaan Roslyn yang sama di penganalisa kami. Baru-baru ini,
kami mendukung versi baru Visual Studio , dan pada saat yang sama memperbarui penganalisis Roslyn ke versi 3. Setelah itu, penganalisa mulai jatuh ketika memeriksa kode tertentu yang sebelumnya tidak pernah crash. Pada saat yang sama, penganalisa mulai tidak berada dalam kode kita, tetapi di dalam kode Roslyn itu sendiri - untuk jatuh dengan Null Reference Exception. Dan debugging lebih lanjut menunjukkan bahwa di tempat Roslyn sekarang jatuh, tepat beberapa baris di atas, ada pemeriksaan
nol yang sama melalui
Debug.Assert . Dan dia, seperti yang kita lihat, tidak menyelamatkan.
Ini adalah contoh masalah yang sangat bagus dengan Referensi Nullable
, karena kompilator menganggap
Debug. Masukkan cek yang valid dalam konfigurasi apa pun. Yaitu, jika Anda cukup mengaktifkan
#nullable aktifkan dan tandai argumen
chainedTupleTypeOpt sebagai referensi yang dapat
dibatalkan , tidak akan ada peringatan kompiler di lokasi dereferensi di metode
ConstructTupleUnderlyingType .
Pertimbangkan contoh pemicu PVS-Studio berikut ini.
V3080 Kemungkinan null dereference. Pertimbangkan untuk memeriksa 'efektifRuleset'. RuleSet.cs 146 var effectiveRuleset = ruleSet.GetEffectiveRuleSet(includedRulesetPaths); effectiveRuleset = effectiveRuleset.WithEffectiveAction(ruleSetInclude.Action); if (IsStricterThan(effectiveRuleset.GeneralDiagnosticOption, ....)) effectiveGeneralOption = effectiveRuleset.GeneralDiagnosticOption;
Peringatan ini mencatat bahwa memanggil metode
WithEffectiveAction dapat mengembalikan
nol , tetapi hasilnya digunakan tanpa memeriksa (
efektifRuleset.GeneralDiagnosticOption ). Badan metode
WithEffectiveAction , yang dapat mengembalikan nol, ditulis ke variabel
efektifRuleset :
public RuleSet WithEffectiveAction(ReportDiagnostic action) { if (!_includes.IsEmpty) throw new ArgumentException(....); switch (action) { case ReportDiagnostic.Default: return this; case ReportDiagnostic.Suppress: return null; .... return new RuleSet(....); default: return null; } }
Jika Anda mengaktifkan mode Referensi Nullable untuk metode
GetEffectiveRuleSet , kita akan memiliki dua tempat di mana kita perlu mengubah perilaku. Karena ada pengecualian melempar dalam metode di atas, logis untuk menganggap bahwa pemanggilan metode dibungkus dalam
blok try-catch dan itu akan benar menulis ulang metode, melemparkan pengecualian bukannya mengembalikan nol. Tetapi memanjat tantangan, kita melihat bahwa intersepsi itu tinggi dan konsekuensinya bisa sangat tidak terduga. Mari kita lihat variabel consumer
efektifRuleset - metode
IsStricterThan private static bool IsStricterThan(ReportDiagnostic action1, ReportDiagnostic action2) { switch (action2) { case ReportDiagnostic.Suppress: ....; case ReportDiagnostic.Warn: return action1 == ReportDiagnostic.Error; case ReportDiagnostic.Error: return false; default: return false; } }
Seperti yang Anda lihat, ini adalah saklar sederhana untuk dua enumerasi dengan kemungkinan nilai enumerasi
ReportDiagnostic.Default . Jadi yang terbaik adalah menulis ulang panggilan sebagai berikut:
Tanda tangan
WithEffectiveAction akan berubah:
#nullable enable public RuleSet? WithEffectiveAction(ReportDiagnostic action)
panggilan akan terlihat seperti ini:
RuleSet? effectiveRuleset = ruleSet.GetEffectiveRuleSet(includedRulesetPaths); effectiveRuleset = effectiveRuleset?.WithEffectiveAction(ruleSetInclude.Action); if (IsStricterThan(effectiveRuleset?.GeneralDiagnosticOption ?? ReportDiagnostic.Default, effectiveGeneralOption)) effectiveGeneralOption = effectiveRuleset.GeneralDiagnosticOption;
mengetahui bahwa
IsStricterThan hanya melakukan perbandingan - kondisinya dapat ditulis ulang, misalnya seperti ini:
if (effectiveRuleset == null || IsStricterThan(effectiveRuleset.GeneralDiagnosticOption, effectiveGeneralOption))
Mari kita beralih ke pesan berikutnya dari penganalisa.
V3080 Kemungkinan null dereference. Pertimbangkan untuk memeriksa 'propertySymbol'. BinderFactory.BinderFactoryVisitor.cs 372 var propertySymbol = GetPropertySymbol(parent, resultBinder); var accessor = propertySymbol.GetMethod; if ((object)accessor != null) resultBinder = new InMethodBinder(accessor, resultBinder);
Penggunaan lebih lanjut dari variabel
propertySymbol harus diperhitungkan ketika mengoreksi peringatan penganalisa.
private SourcePropertySymbol GetPropertySymbol( BasePropertyDeclarationSyntax basePropertyDeclarationSyntax, Binder outerBinder) { .... NamedTypeSymbol container = GetContainerType(outerBinder, basePropertyDeclarationSyntax); if ((object)container == null) return null; .... return (SourcePropertySymbol)GetMemberSymbol(propertyName, basePropertyDeclarationSyntax.Span, container, SymbolKind.Property); }
Metode
GetMemberSymbol juga dapat mengembalikan
nol dalam beberapa kasus.
private Symbol GetMemberSymbol( string memberName, TextSpan memberSpan, NamedTypeSymbol container, SymbolKind kind) { foreach (Symbol sym in container.GetMembers(memberName)) { if (sym.Kind != kind) continue; if (sym.Kind == SymbolKind.Method) { .... var implementation = ((MethodSymbol)sym).PartialImplementationPart; if ((object)implementation != null) if (InSpan(implementation.Locations[0], this.syntaxTree, memberSpan)) return implementation; } else if (InSpan(sym.Locations, this.syntaxTree, memberSpan)) return sym; } return null; }
Menggunakan jenis referensi yang dapat dibatalkan, panggilan akan berubah seperti ini:
#nullable enable SourcePropertySymbol? propertySymbol = GetPropertySymbol(parent, resultBinder); MethodSymbol? accessor = propertySymbol?.GetMethod; if ((object)accessor != null) resultBinder = new InMethodBinder(accessor, resultBinder);
Cukup sederhana ketika Anda tahu di mana harus memperbaikinya. Analisis statis dengan mudah menemukan potensi kesalahan ini dengan mendapatkan semua nilai bidang yang mungkin di semua rantai panggilan prosedur.
V3080 Kemungkinan null dereference. Pertimbangkan untuk memeriksa 'simpleName'. CSharpCommandLineParser.cs 1556 string simpleName; simpleName = PathUtilities.RemoveExtension( PathUtilities.GetFileName(sourceFiles.FirstOrDefault().Path)); outputFileName = simpleName + outputKind.GetDefaultExtension(); if (simpleName.Length == 0 && !outputKind.IsNetModule()) ....
Masalahnya ada di baris dengan memeriksa
simpleName. Panjang. simpleName adalah hasil dari seluruh rangkaian metode dan mungkin
nol . Ngomong-ngomong, demi rasa ingin tahu, Anda dapat melihat metode
RemoveExtension dan menemukan perbedaan dari
Path.GetFileNameWithoutExtension. Di sini kita dapat membatasi diri untuk memeriksa
simpleName! = Null , tetapi dalam konteks tautan bukan nol, kode akan terlihat seperti ini:
#nullable enable public static string? RemoveExtension(string path) { .... } string simpleName;
Panggilan akan terlihat seperti ini:
simpleName = PathUtilities.RemoveExtension( PathUtilities.GetFileName(sourceFiles.FirstOrDefault().Path)) ?? String.Empty;
Kesimpulan
Jenis referensi Nullable dapat sangat membantu dalam perencanaan arsitektur yang dibangun dari awal, tetapi pengerjaan ulang kode yang ada berpotensi membutuhkan banyak waktu dan perawatan, karena dapat menyebabkan banyak kesalahan halus. Dalam artikel ini, kami tidak bermaksud untuk mencegah siapa pun dari menggunakan jenis Referensi Nullable di proyek kami. Kami percaya bahwa inovasi ini umumnya bermanfaat untuk bahasa, meskipun bagaimana penerapannya dapat menimbulkan pertanyaan.
Anda harus selalu mengingat keterbatasan yang melekat dalam pendekatan ini, dan bahwa mode Referensi Nullable yang dihidupkan tidak melindungi terhadap kesalahan dengan dereferencing tautan nol, dan jika digunakan secara tidak benar, itu bahkan dapat menyebabkan mereka. Sebaiknya pertimbangkan penggunaan penganalisa statis modern, misalnya PVS-Studio, yang mendukung analisis antar-prosedur, sebagai alat tambahan yang, bersama-sama dengan Referensi Nullable, dapat melindungi Anda dari referensi referensi nol yang kosong. Masing-masing pendekatan ini - baik analisis inter-prosedural mendalam dan anotasi tanda tangan metode (yang pada dasarnya membuat Referensi Nullable), memiliki kelebihan dan kekurangan. Penganalisa akan memungkinkan Anda untuk mendapatkan daftar tempat-tempat yang berpotensi berbahaya, dan juga, ketika mengubah kode yang ada, melihat semua konsekuensi dari perubahan tersebut. Jika Anda menetapkan
nol dalam hal apa pun, penganalisa harus segera menunjukkan semua konsumen variabel, yang tidak diperiksa sebelum dereferencing.
Anda dapat secara independen mencari beberapa kesalahan lain baik di proyek yang dipertimbangkan, dan di Anda sendiri. Untuk melakukan ini, Anda hanya perlu
mengunduh dan mencoba penganalisa PVS-Studio.

Jika Anda ingin berbagi artikel ini dengan audiens yang berbahasa Inggris, silakan gunakan tautan ke terjemahan: Paul Eremeev, Alexander Senichkin.
Jenis referensi yang dapat dihapus dalam C # 8.0 dan analisis statis