С какими классами я должен использовать оператор использования C #? - PullRequest
3 голосов
/ 07 июля 2010

Я прочитал, и мне кажется, что я понимаю, что делает оператор C # using (пожалуйста, исправьте меня, если я ошибаюсь): Инициализирует объект IDisposable как доступный только для чтения в ограниченной области (блок using) Я знаю, что вы можете инициализировать до using, и это не ограничивает область действия, но это рекомендуется здесь:

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

Я не всегда обращаю внимание на то, какие классы являются подклассами чего. Я не слишком уверен, какие классы наследуют от IDisposable. Мне не просто интересно, какие классы можно использовать в операторе using, но какие классы мои коллеги ожидают найти в блоке using? Какие классы должны быть в блоке using? Кроме того, действительно ли что-то не так с тем, что вы не используете блок using и не вызываете Dispose? Это просто память или стабильность?

Ответы [ 10 ]

16 голосов
/ 07 июля 2010

Строго говоря, любой объект, реализующий IDisposable и область действия которого ограничена этой функцией, должен находиться внутри блока using.Интерфейс IDisposable существует для того, чтобы классы, которые имеют дело с неуправляемыми ресурсами (соединениями с базой данных, файловыми дескрипторами, оконными дескрипторами и т. Д.), Могли своевременно и детерминировать эти ресурсы.

В общем, естьтри способа использования объекта IDisposable в классе:

  1. Объект создан и больше не нужен в рамках одного вызова метода.Это довольно распространенное явление, когда using можно (и нужно) использовать.
  2. Объект создается классом (или передается классу), и его время жизни выходит за рамки области действия.одиночный вызов метода, но не за пределами жизни класса.Например, ваш класс создает Stream и должен использовать его в течение всего времени жизни объекта.В этом случае ваш класс должен реализовать сам IDisposable и избавиться от объектов, которые вам принадлежат, когда вызывается ваш собственный метод Dispose.Примером этого может быть что-то вроде System.IO.StreamWriter
  3. Объект передается классу, но класс не «владеет» им.Это означает, что полезное время жизни объекта IDisposable выходит за рамки одного вызова метода и может превышать время жизни вашего объекта.В этом случае кто-то другой должен нести ответственность за вызов Dispose.

Первый случай является наиболее распространенным, с которым вы можете столкнуться, поэтому существует блок using.Он обеспечивает удаление объекта, даже в случае исключения.

Некоторые примеры:

  • Потоковые классы
  • Соединения с базой данных /команды
  • Элементы управления

Нет исчерпывающего списка классов, которые реализуют IDisposable, так как этот список будет довольно большим и заполнен классами, которые вы, вероятно, никогда не встретите.Подумайте о том, что делает класс ;это открывает какое-то соединение или файл, который должен быть закрыт?В общем, получает ли он какой-то ресурс, который должен быть освобожден ?Если это так, он, вероятно, реализует это.На базовом уровне, если компилятор позволяет вам заключить его в using, он реализует IDisposable.

Что касается последствий , а не , вызывающих Dispose, don 'не считаю это. Call Dispose .Правда, защитный стандарт состоит в том, что если ваш класс использует неуправляемые ресурсы напрямую , то вы должны определить финализатор, который будет вызывать dispose в случае, если ваш объект собран и кто-то не смог его вызвать, но это должноНе будь дизайнерским выбором.Насколько я знаю.

13 голосов
/ 07 июля 2010

Дело не в памяти.Речь идет о других ресурсах, таких как файловые дескрипторы, соединения с базой данных и т. Д.

Обычно, если класс реализует IDisposable, это сигнал о том, что вы должны избавиться от него, когда закончите, потому что он может иметь неуправляемые ресурсы,было бы дорого оставить вокруг.(например, в вашем пуле соединений могут не хватить соединений, или дескриптор файла останется открытым, что не позволит другому куску кода снова открыть тот же файл).

2 голосов
/ 07 июля 2010

Вы должны всегда вызывать Dispose для любого класса, который реализует IDisposable, и это легче всего сделать с помощью блока using.

Это не только память,Это также не только ресурсы.Это о правильности.

StreamWriter - известный пример.Microsoft даже разработала MDA , чтобы поймать некоторые случаи, когда программисты забывали вызывать Dispose.Это больше, чем просто память или ресурсы: в примере StreamWriter записываемый файл может быть обрезан.

Мне пришлось один раз отследить неприятную ошибку (на самом деле в коде моего босса),когда транзакция базы данных откатывалась ... выясняется, что причина была в том, что Dispose не вызывался, поэтому он пытался зафиксировать слишком много данных на диске при выходе из процесса (для завершения процесса есть время ожидания для финализаторов),Исправление было всего лишь несколькими using блоками.

Третий пример: классы-оболочки Microsoft Managed ESENT имеют «трехуровневую» схему удаления, для которой требуется Dispose для вызова вправильный порядок (последние «внешние» классы).

Итак, есть три реальных примера, где неправильное поведение приведет к неправильному вызову Dispose.Другие классы могут проявлять подобное поведение.

Как правило, вы должны всегда звонить Dispose.

1 голос
/ 07 июля 2010

Цель IDisposable - дать возможность объектам, которые взаимодействуют с неуправляемыми ресурсами (такими как файлы, базы данных или графические контексты), выполнять очистку после себя. Оператор using - это удобное сокращение для следующей конструкции

var disposable = new MemoryStream();
try
{
  //do some work with the disposable object
}
finally
{
  if (disposable!=null)
     disposable.Dispose();  
}

Конечно, проблема в том, чтобы знать, какие объекты реализуют IDisposable ... к сожалению, нет никакого автоматизированного способа узнать, кроме документации. Хотя я полагаю, что есть настройка Fxcop, которая проверяет IDisposables, используемые вне использования.

1 голос
/ 07 июля 2010

Основная причина, по которой класс реализует IDisposable, - освобождение неуправляемых ресурсов. Сборщик мусора высвободит управляемые ресурсы, когда они выйдут из области видимости, и сочтет нужным, но не знает о неуправляемых ресурсах. Вызов метода Dispose явно освободит ресурсы.

Если вы не используете блок using или не вызываете метод Dispose, то у вас возникнет проблема с утечкой памяти, которая, в свою очередь, может вызвать проблемы со стабильностью.

Вы должны всегда использовать блок using при работе с классами, которые реализуют IDisposable. Хотя вы можете предпочесть Try.. Catch.. Finally, чтобы вы вызывали Dispose в блоке finally, чтобы иметь дело с исключениями.

1 голос
/ 07 июля 2010

Что касается того, какие классы являются одноразовыми, вы можете исследовать intellisense самостоятельно, или вы просто будете учиться на собственном опыте. Некоторые из них включают Image и его дочерние элементы, фактически большую часть пространства имен System.Drawing, множество файловых потоков, соединений с базой данных и т. Д.

Насколько это должно быть вызвано - как можно скорее. Если вы знаете, что он одноразовый, и знаете, что с ним покончено, позвоните в компанию Dispose.

Я полагаю, что многие базовые классы .NET, которые реализуют IDisposable, реализуют одноразовый шаблон, что означает, что они будут утилизироваться надлежащим образом, когда сборщик мусора придет за ними. Но даже в этом случае вы все равно должны распоряжаться вещами, когда закончите, потому что

  1. Вы можете оставить ссылку, висящую вокруг (утечка), и она не будет ликвидирована, или
  2. ГК не может прийти в себя некоторое время.

Кроме того, для классов, которые вы пишете самостоятельно, сборка мусора НЕ приравнивается к правильному удалению неуправляемых ресурсов - распространенная путаница. Одноразовый шаблон должен быть реализован самостоятельно.

1 голос
/ 07 июля 2010

Совершенно много ошибок в том, что вы не используете блок using и не вызываете Dispose, скорее всего, вы потеряете память и / или ресурсы. Использовать удобно, но вам действительно следует вызывать Dispose для любого объекта, класс которого является производным от IDisposable.

1 голос
/ 07 июля 2010

По крайней мере, все классы, которые использовали неуправляемые ресурсы

0 голосов
/ 07 июля 2010

Готовый счетчик классов для вызова с using:

  • Streams
  • Соединения с базой данных, команды и устройства чтения данных
  • Читатели и писатели

Существует еще много классов, которые вы также должны утилизировать, но те, что указаны выше, часто используются, часто в узких рамках.

Да - существуют проблемы с тем, что вы не используете using и не звоните dispose. Классическим является веб-приложение, которое не закрывает свои соединения с базой данных, эффективно высасывая ресурсы из сервера базы данных, поскольку оно поддерживает соединения открытыми.

0 голосов
/ 07 июля 2010

вам не нужно беспокоиться об использовании классов при использовании блоков. Если оператор, который вы использовали в операторе using, не реализует IDisposbale, он покажет вам красно-синюю волну. Так что вы можете прийти к knwo, что его не хватает однозначного интерфейса. И поскольку я использовал почти все классы фреймворка, реализован Idisposable. но в пользовательском классе необходимо реализовать

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...