Кто-нибудь может сказать мне, как удалить все предупреждения CA2202 из следующего кода?
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();
}
}
Предупреждение 7 CA2202: Microsoft.Usage: объект «cryptoStream» можно удалить более одного раза в методе «CryptoServices.Encrypt (string, byte [], byte [])». Чтобы избежать генерации исключения System.ObjectDisposedException, не следует вызывать Dispose более одного раза для объекта .: Строки: 34
Предупреждение 8 CA2202: Microsoft.Usage: объект memoryStream может быть удален более одного раза в методе CryptoServices.Encrypt (string, byte [], byte []) ». Чтобы избежать генерации исключения System.ObjectDisposedException, не следует вызывать Dispose более одного раза для объекта .: Строки: 34, 37
Чтобы увидеть эти предупреждения, вам потребуется Visual Studio Code Analysis (это не предупреждения компилятора C #).
источник
[SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification="BrainSlugs83 said so.")]
» - убедитесь, что у вас есть оператор «using System.Diagnostics.CodeAnalysis;
» в вашем блоке использования.Ответы:
Это компилируется без предупреждения:
Изменить в ответ на комментарии: я только что еще раз подтвердил, что этот код не генерирует предупреждение, в то время как исходный. В исходном коде
CryptoStream.Dispose()
иMemoryStream().Dispose(
) фактически вызываются дважды (что может быть проблемой, а может и не быть).Модифицированный код работает следующим образом: ссылки устанавливаются
null
, как только ответственность за удаление передается другому объекту. НапримерmemoryStream
, устанавливается значениеnull
после успешного вызоваCryptoStream
конструктора.cryptoStream
установлен вnull
, после успешного вызоваStreamWriter
конструктора. Если не возникает исключения,streamWriter
помещается вfinally
блок и, в свою очередь, удаляетCryptoStream
иMemoryStream
.источник
В этом случае вы должны подавить предупреждения. Код, который имеет дело с одноразовыми предметами, должен быть согласованным, и вам не нужно заботиться о том, чтобы другие классы владели созданными вами одноразовыми предметами, а также обращались
Dispose
к ним.ОБНОВЛЕНИЕ: в документации IDisposable.Dispose вы можете прочитать это:
Можно утверждать, что это правило существует для того, чтобы разработчики могли
using
разумно использовать это утверждение в каскаде одноразовых предметов, как я показал выше (или, может быть, это просто приятный побочный эффект). Таким же образом, CA2202 бесполезен, и его следует подавлять в рамках проекта. Настоящим виновником может быть неправильная реализацияDispose
, и CA1065 должен позаботиться об этом (если это находится в вашей ответственности).источник
Что ж, это точно, метод Dispose () для этих потоков будет вызываться более одного раза. Класс StreamReader станет «владельцем» cryptoStream, поэтому при удалении streamWriter также будет удален cryptoStream. Точно так же класс CryptoStream берет на себя ответственность за memoryStream.
Это не совсем настоящие ошибки, эти классы .NET устойчивы к множественным вызовам Dispose (). Но если вы хотите избавиться от предупреждения, вам следует отказаться от оператора using для этих объектов. И немного огорчите себя, рассуждая о том, что произойдет, если код выдаст исключение. Или отключите предупреждение с помощью атрибута. Или просто проигнорируйте предупреждение, потому что это глупо.
источник
using
заявления следует оставить. Эти предупреждения действительно глупы.using
заявлений. Просто кажется неправильным полагаться на другой объект, чтобы избавиться от объекта, который я создал. Для этого кода, это нормально, но вы много реализацийStream
иTextWriter
там (не только на BCL). Код для их использования должен быть согласованным.XmlDocument.Save()
метод будет вызыватьDispose
указанный параметр? я не вижу этого ни в документацииSave(XmlWriter)
(где я столкнулся с ошибкой FxCop), ни в самомSave()
методе, ни в самой документацииXmlDocument
.Когда StreamWriter удаляется , он автоматически удаляет упакованный Stream (здесь: CryptoStream ). CryptoStream также автоматически удаляет упакованный Stream (здесь: MemoryStream ).
Таким образом, ваш MemoryStream удаляется как CryptoStream, так и оператором using . И ваш CryptoStream расположен в StreamWriter и внешней помощи заявления.
После некоторых экспериментов кажется, что полностью избавиться от предупреждений невозможно. Теоретически MemoryStream необходимо удалить, но тогда теоретически вы больше не сможете получить доступ к его методу ToArray. Практически, MemoryStream не нужно удалять, поэтому я бы выбрал это решение и подавил предупреждение CA2000.
источник
return
строку перед закрывающей скобкойusing
области.Я бы сделал это с помощью
#pragma warning disable
.Рекомендации .NET Framework рекомендуют реализовать IDisposable.Dispose таким образом, чтобы его можно было вызывать несколько раз. Из описания MSDN для IDisposable.Dispose :
Поэтому предупреждение кажется почти бессмысленным:
Думаю, можно было бы возразить, что предупреждение может быть полезно, если вы используете плохо реализованный объект IDisposable, который не соответствует стандартным рекомендациям по реализации. Но при использовании классов из .NET Framework, как это делаете вы, я бы сказал, что безопасно подавить предупреждение с помощью #pragma. И ИМХО, это предпочтительнее, чем проходить через обручи, как это предлагается в документации MSDN для этого предупреждения .
источник
#pragma warning disable
может использоваться только для подавления предупреждений компилятора. Чтобы подавить предупреждение анализа кода, вам необходимо использовать атрибут.Я столкнулся с аналогичными проблемами в своем коде.
Похоже, что все CA2202 запускается, потому что
MemoryStream
может быть удалено, если в конструкторе возникает исключение (CA2000).Это можно решить так:
Обратите внимание, что мы должны вернуть
memoryStream
внутри последнегоusing
оператора (строка 10), потому что онcryptoStream
удаляется в строке 11 (потому что он используется вstreamWriter
using
операторе), что приводитmemoryStream
к тому, что также удаляется в строке 11 (потому чтоmemoryStream
используется для созданияcryptoStream
).По крайней мере, этот код работал у меня.
РЕДАКТИРОВАТЬ:
Как бы забавно это ни звучало, я обнаружил, что если вы замените
GetMemoryStream
метод следующим кодом,вы получите тот же результат.
источник
Криптопоток основан на потоке памяти.
Похоже, что происходит то, что, когда крипопоток удаляется (в конце использования), поток памяти также удаляется, затем поток памяти удаляется снова.
источник
Я хотел решить эту проблему правильно - без подавления предупреждений и правильной утилизации всех одноразовых предметов.
Я извлек 2 из 3 потоков как поля и поместил их в
Dispose()
метод своего класса. Да, реализацияIDisposable
интерфейса не обязательно может быть тем, что вы ищете, но решение выглядит довольно чистым по сравнению сdispose()
вызовами из всех случайных мест в коде.источник
Не по теме, но я бы посоветовал вам использовать другую технику форматирования для группировки
using
:Я также рекомендую использовать
var
здесь s, чтобы избежать повторения действительно длинных имен классов.PS Спасибо @ShellShock за указание, что я не могу сначала опустить фигурные скобки,
using
как это было быmemoryStream
вreturn
заявлении за пределами области действия.источник
if
s (хотя я бы не советовал эту технику ни для чего, кромеusing
s).return
заявление. Это точно. Я отредактировал ответ, чтобы отразить это.using
отсутствие скобок делает код более хрупким (подумайте о годах различий и слияний). joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong & imperialviolet.org/2014/02/22/applebug.htmlИзбегайте любого использования и используйте вложенные вызовы Dispose!
источник
using
в этом случае.Я использовал такой код, который принимает byte [] и возвращает byte [] без использования потоков.
Таким образом, все, что вам нужно сделать, это преобразовать строку в byte [] с использованием кодировок.
источник
Я просто хотел развернуть код, чтобы мы могли видеть несколько вызовов
Dispose
объектов. Реальность такова , что вы являетесь вызовомDispose
на объектах дважды:Хотя большинство классов .NET (мы надеемся) устойчивы к ошибкам множественных вызовов
.Dispose
, не все классы так же защищают от неправильного использования программистами.FX Cop знает об этом и предупреждает вас.
У вас есть несколько вариантов;
Dispose
один раз для любого объекта; не использоватьusing
источник