C # распоряжение объектами - PullRequest
       10

C # распоряжение объектами

2 голосов
/ 15 октября 2010

Я знаю, что метод Dispose () вызывается для объекта StreamReader, когда у вас есть следующий код:

//Sample 1
using (StreamReader sr1 = new StreamReader(@"C:\Data.txt"))
{
    string s1 = sr1.ReadToEnd();
    //Do something with s1...
}

Но если вы напишите такой код (Пример 2), будет ли метод Dispose ()Вам тоже позвонили?

//Sample 2
StreamReader sr2 = new StreamReader(@"C:\Data.txt");
using (sr2)
{
    string s2 = sr2.ReadToEnd();
    //Do something with s2...
}

Ответы [ 6 ]

9 голосов
/ 15 октября 2010

Да, Dispose() будет вызываться в обоих примерах. Они функционально эквивалентны, за исключением того, что во втором примере удаленный StreamReader все еще будет находиться в области видимости. Поэтому предпочтителен первый метод, поскольку использование удаленного объекта обычно является плохой идеей.

Однако, как отмечали другие, иногда можно использовать удаленный объект. В таких случаях вы можете использовать второй пример. Но вы должны знать, что вы делаете, и я бы избегал этого, если это вообще возможно.

9 голосов
/ 15 октября 2010

Да, абсолютно.Подробности в разделе 8.13.Нет точного изложения вашего точного вопроса, но:

Оператор использования вида

using (expression) statement

имеет те же три возможных расширения, но в этом случае ResourceType неявно является типом выражения времени компиляции, а переменная ресурса недоступна и невидима для встроенного оператора.

«Три возможных расширения», о которых идет речь, охватывают более распространенноеслучай объявления переменной одновременно.В основном важно то, что он ведет себя одинаково, за исключением области видимости переменной.Dispose будет по-прежнему вызываться - в противном случае не было бы никакого смысла вставлять оператор using вообще:)

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

// Warning but no error
MemoryStream ms = new MemoryStream();
using (ms)
{
    ms = null;
}

, но это не так:

using (MemoryStream ms = new MemoryStream())
{
    // error CS1656: Cannot assign to 'ms' because it is a 'using variable'
    ms = null;
}

Обратите внимание, что даже в случае, если оно действительно, это оригинальное значениеms который используется для утилизации.Компилятор проясняет это:

предупреждение CS0728: Возможно, неправильное присвоение локальной переменной «ms», которая является аргументом оператора using или lock.Вызов или разблокировка Dispose произойдет с исходным локальным значением.

Обратите внимание, что эта форма не генерирует предупреждение:

// No warning
MemoryStream ms;
using (ms = new MemoryStream())
{
    ms = null;
}

С другой стороны, кроме этого, они действительно будут вести себя одинаково.

РЕДАКТИРОВАТЬ: Как отмечает bzlm, тот факт, что переменная остается в области видимости после оператора using, означает, что обычно не очень хорошая идея.Тем не менее, объекты, которые были удалены, не всегда непригодны для использования.Например:

MemoryStream ms = new MemoryStream();
using (ms) 
{
    // Do stuff
}
byte[] data = ms.ToArray();

Это будет прекрасно работать - MemoryStream сохраняет данные, даже когда они утилизируются.Мне все еще кажется, что это неправильно.

0 голосов
/ 15 октября 2010

MSDN говорит, что не совсем равны в отношении исключений во время инициализации. Также рассмотрим следующий сценарий определения объема:

//Sample 1
using (StreamReader sr1 = new StreamReader(@"C:\Data.txt"))
{
    string s1 = sr1.ReadToEnd();
    //Do something with s1...
}
sr1.ReadToEnd() // sr1 not in scope.

Не компилируется, но

//Sample 2
StreamReader sr2 = new StreamReader(@"C:\Data.txt");
using (sr2)
{
    string s2 = sr2.ReadToEnd();
    //Do something with s2...
}

sr2.ReadToEnd() // possible to write, but accessing a disposed object.

компилирует, но получает доступ к удаленному объекту.

0 голосов
/ 15 октября 2010

Хороший вопрос.Я бы сказал да, потому что кодовый блок using немного больше, чем синтаксический сахар для следующего:

try
{
   var myObj = <parameter from using>
   <using block code>
}
finally
{
   myObj.Dispose();
}

Обратите внимание, что при замене вашего блока using переменная, которую вы в конечном итоге располагаетедругой дескриптор, который виден вне блока кода (sr2).Эта ссылка предотвратит сборку мусора экземпляра после оператора using, но поскольку он был удален, если только он не достаточно умен для восстановления после Dispose () среднего уровня, он будет бесполезен.

0 голосов
/ 15 октября 2010

using принимает объект, который реализует IDisposable. Как и где создается этот объект, не учитывается, когда компилятор генерирует код для вызова Dispose в конце для блока using.

0 голосов
/ 15 октября 2010

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

Использует ли C # оператор, безопасный от прерывания?

Подобное обсуждение сосредоточено на взаимодействии с прерыванием потока.

...