Adakah yang bisa memberi tahu saya cara menghapus semua peringatan CA2202 dari kode berikut?
public static byte[] Encrypt(string data, byte[] key, byte[] iv)
{
using(MemoryStream memoryStream = new MemoryStream())
{
using (DESCryptoServiceProvider cryptograph = new DESCryptoServiceProvider())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptograph.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
using(StreamWriter streamWriter = new StreamWriter(cryptoStream))
{
streamWriter.Write(data);
}
}
}
return memoryStream.ToArray();
}
}
Peringatan 7 CA2202: Microsoft.Usage: Objek 'cryptoStream' dapat dibuang lebih dari sekali dalam metode 'CryptoServices.Encrypt (string, byte [], byte [])'. Untuk menghindari pembuatan System.ObjectDisposedException, Anda tidak boleh memanggil Buang lebih dari satu kali pada suatu objek .: Garis: 34
Peringatan 8 CA2202: Microsoft.Usage: Object 'memoryStream' dapat dibuang lebih dari sekali dalam metode 'CryptoServices.Encrypt (string, byte [], byte [])'. Untuk menghindari pembuatan System.ObjectDisposedException, Anda tidak boleh memanggil Buang lebih dari satu kali pada suatu objek .: Baris: 34, 37
Anda memerlukan Visual Studio Code Analysis untuk melihat peringatan ini (ini bukan peringatan compiler c #).
sumber
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification="BrainSlugs83 said so.")]
" - pastikan Anda memilikiusing System.Diagnostics.CodeAnalysis;
pernyataan " " di blok penggunaan Anda.Jawaban:
Ini mengkompilasi tanpa peringatan:
Edit sebagai tanggapan atas komentar: Saya baru saja memverifikasi lagi bahwa kode ini tidak menghasilkan peringatan, sedangkan yang asli tidak. Dalam kode asli,
CryptoStream.Dispose()
danMemoryStream().Dispose(
) sebenarnya dipanggil dua kali (yang mungkin menjadi masalah atau tidak).Kode yang dimodifikasi bekerja sebagai berikut: referensi ditetapkan
null
, segera setelah tanggung jawab untuk membuang dipindahkan ke objek lain. Misalnya,memoryStream
disetel kenull
setelah panggilan keCryptoStream
konstruktor berhasil.cryptoStream
disetel kenull
, setelah panggilan keStreamWriter
konstruktor berhasil. Jika tidak ada pengecualian yang terjadi,streamWriter
dibuang difinally
blok dan pada gilirannya akan membuangCryptoStream
danMemoryStream
.sumber
Anda harus menyembunyikan peringatan dalam kasus ini. Kode yang berhubungan dengan sekali pakai harus konsisten, dan Anda tidak perlu peduli bahwa kelas lain mengambil kepemilikan atas barang sekali pakai yang Anda buat dan juga memanggilnya
Dispose
.UPDATE: Dalam dokumentasi IDisposable.Dispose Anda dapat membaca ini:
Dapat dikatakan bahwa aturan ini ada sehingga pengembang dapat menggunakan
using
pernyataan secara masuk akal dalam rangkaian sekali pakai, seperti yang saya tunjukkan di atas (atau mungkin ini hanya efek samping yang bagus). Dengan cara yang sama, maka CA2202 tidak memiliki tujuan yang berguna, dan harus disembunyikan dari segi proyek. Pelaku sebenarnya adalah implementasi yang salahDispose
, dan CA1065 harus membereskannya (jika itu di bawah tanggung jawab Anda).sumber
Memang akurat, metode Dispose () pada aliran ini akan dipanggil lebih dari sekali. Kelas StreamReader akan mengambil 'kepemilikan' dari cryptoStream sehingga membuang streamWriter juga akan membuang cryptoStream. Demikian pula, kelas CryptoStream mengambil alih tanggung jawab untuk memoryStream.
Ini bukan bug yang sebenarnya, kelas .NET ini tahan terhadap beberapa panggilan Dispose (). Tetapi jika Anda ingin menghilangkan peringatan tersebut maka Anda harus menghilangkan pernyataan using untuk objek-objek ini. Dan sakiti diri Anda sedikit ketika memikirkan apa yang akan terjadi jika kode tersebut membuat pengecualian. Atau tutup peringatan dengan atribut. Atau abaikan saja peringatan itu karena itu konyol.
sumber
using
pernyataan itu harus tetap ada. Peringatan ini sangat konyol.using
pernyataan itu. Rasanya salah jika mengandalkan objek lain untuk membuang objek yang saya buat. Untuk kode ini, tidak apa-apa, tetapi ada banyak implementasi di dalamStream
dan diTextWriter
luar sana (tidak hanya di BCL). Kode untuk menggunakan semuanya harus konsisten.XmlDocument.Save()
metode akan memanggilDispose
parameter yang disediakan? saya tidak melihatnya di dokumentasiSave(XmlWriter)
(di mana saya mengalami bug FxCop), atau dalamSave()
metode itu sendiri, atau dalam dokumentasiXmlDocument
itu sendiri.Saat StreamWriter dibuang, StreamWriter akan secara otomatis membuang Stream yang dibungkus (di sini: CryptoStream ). CryptoStream juga secara otomatis membuang Stream yang dibungkus (di sini: MemoryStream ).
Jadi MemoryStream Anda dibuang oleh CryptoStream dan pernyataan menggunakan . Dan CryptoStream Anda dibuang oleh StreamWriter dan pernyataan penggunaan luar .
Setelah beberapa percobaan, tampaknya tidak mungkin untuk menghilangkan peringatan sepenuhnya. Secara teoritis, MemoryStream perlu dibuang, tetapi Anda secara teoritis tidak dapat mengakses metode ToArray lagi. Praktisnya, MemoryStream tidak perlu dibuang, jadi saya akan menggunakan solusi ini dan menekan peringatan CA2000.
sumber
Saya akan melakukan ini dengan menggunakan
#pragma warning disable
.Panduan .NET Framework merekomendasikan untuk mengimplementasikan IDisposable. Buang sedemikian rupa sehingga dapat dipanggil beberapa kali. Dari deskripsi MSDN tentang IDisposable. Buang :
Oleh karena itu peringatan itu tampaknya hampir tidak ada artinya:
Saya kira itu bisa dikatakan bahwa peringatan mungkin berguna jika Anda menggunakan objek IDisposable yang diterapkan dengan buruk yang tidak mengikuti pedoman implementasi standar. Tetapi ketika menggunakan kelas dari .NET Framework seperti yang Anda lakukan, menurut saya aman untuk menekan peringatan menggunakan #pragma. Dan IMHO ini lebih disukai daripada melalui rintangan seperti yang disarankan dalam dokumentasi MSDN untuk peringatan ini .
sumber
#pragma warning disable
hanya dapat digunakan untuk menyembunyikan peringatan kompilator. Untuk menekan peringatan Analisis Kode Anda perlu menggunakan atribut.Saya dihadapkan dengan masalah serupa dalam kode saya.
Sepertinya seluruh hal CA2202 dipicu karena
MemoryStream
dapat dibuang jika pengecualian terjadi pada konstruktor (CA2000).Ini bisa diselesaikan seperti ini:
Perhatikan bahwa kita harus mengembalikan bagian
memoryStream
dalamusing
pernyataan terakhir (baris 10) karenacryptoStream
dibuang pada baris 11 (karena digunakan dalamstreamWriter
using
pernyataan), yang mengarahmemoryStream
ke juga dibuang pada baris 11 (karenamemoryStream
digunakan untuk membuatcryptoStream
).Setidaknya kode ini berhasil untuk saya.
EDIT:
Meskipun terdengar lucu, saya menemukan bahwa jika Anda mengganti
GetMemoryStream
metode dengan kode berikut,Anda mendapatkan hasil yang sama.
sumber
Cryptostream didasarkan pada aliran memori.
Apa yang tampaknya terjadi adalah ketika crypostream dibuang (pada akhir penggunaan) aliran memori juga dibuang, kemudian aliran memori dibuang lagi.
sumber
Saya ingin menyelesaikan ini dengan cara yang benar - yaitu tanpa menekan peringatan dan membuang semua objek sekali pakai dengan benar.
Saya menarik 2 dari 3 aliran sebagai ladang dan membuangnya ke dalam
Dispose()
metode kelas saya. Ya, mengimplementasikanIDisposable
antarmuka mungkin tidak selalu menjadi apa yang Anda cari, tetapi solusinya terlihat cukup bersih dibandingkan dengandispose()
panggilan dari semua tempat acak dalam kode.sumber
Di luar topik tetapi saya menyarankan Anda untuk menggunakan teknik pemformatan yang berbeda untuk pengelompokan
using
:Saya juga menganjurkan penggunaan
var
s di sini untuk menghindari pengulangan nama kelas yang sangat panjang.PS Terima kasih kepada @ShellShock karena telah menunjukkan bahwa saya tidak dapat menghilangkan kawat gigi untuk pertama kali
using
karena akan membuat pernyataanmemoryStream
direturn
luar ruang lingkup.sumber
if
s (meskipun saya tidak akan menyarankan teknik ini untuk hal lain selainusing
s).return
pernyataan yang Anda maksudkan . Benar sekali. Saya mengedit jawaban untuk mencerminkan ini.using
tanpa kurung kurawal membuat kode lebih rapuh (pikirkan tahun-tahun diff dan penggabungan). joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong & imperialviolet.org/2014/02/22/applebug.htmlHindari semua penggunaan dan gunakan Dispose-Calls bersarang!
sumber
using
dalam kasus ini.Saya hanya ingin membuka kodenya sehingga kita bisa melihat beberapa panggilan ke
Dispose
objek:Meskipun sebagian besar kelas .NET (mudah-mudahan) tahan terhadap kesalahan beberapa panggilan ke
.Dispose
, tidak semua kelas bersifat defensif terhadap penyalahgunaan programmer.FX Cop mengetahui hal ini, dan memperingatkan Anda.
Anda punya beberapa pilihan;
Dispose
sekali pada objek apa pun; jangan gunakanusing
sumber
Saya menggunakan jenis kode ini yang mengambil byte [] dan mengembalikan byte [] tanpa menggunakan aliran
Dengan cara ini yang harus Anda lakukan adalah konversi dari string ke byte [] menggunakan pengkodean.
sumber