2009-04-03 3 views
7

Я немного новичок в C#, больше привык к скриптовым языкам. Мне нравится идея «использования», вы создаете экземпляр объекта, а затем вы работаете в пределах своего объема, если вам это нужно, тогда вы позволяете ему распоряжаться собой, когда это делается для его цели.Как узнать лучшее место для использования 'using'?

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

Как я могу узнать хорошие места для использования using и как использовать его в сочетании с блоками try-catch. Они идут внутри блока или обычно вы хотите заключить оператор using в блок try?

ответ

9

Я редко пишу попробовать/уловах блоки - большинство исключений вышвырнут до (около) в верхней части стека. Если у меня есть do, вам нужен блок try/catch, я не уверен, что я особенно согласен с тем, чтобы положить его в оператор using и вне его. Это зависит от того, хотите ли вы, чтобы ресурс был удален до того, как будет запущен ваш код обработки исключений.

Если вы спрашиваете о когда вы должны писать using заявления - в любое время вы «свой» объект, который реализует IDisposable (либо непосредственно, либо косвенно, через наследование) и контролировать его жизнь. Обычно это объект, который использует неуправляемый ресурс, такой как дескриптор файла или сетевое соединение. Это не всегда очень очевидно, но вы учитесь на собственном опыте. Почти что-нибудь сделать с IO будет одноразовым, а дескрипторы Windows (для шрифтов и т. Д.) Похожи.

+0

Чтобы прояснить объекты, реализующие IDisposable напрямую или через наследование (поскольку danieltalsky является «несколько новым для C#»). –

+0

Спасибо Джонатан - отредактирован соответствующим образом. –

+0

Ну, «несколько нового для C#», я имею в виду, «писал коммерческий код на C# менее 8 месяцев». Я, например, уже знаком с подключением «использования» к «IDisposable», о котором я упоминаю в вопросе. Это была часть управления «пожизненного контроля», которую я отсутствовал. – danieltalsky

18

using может использоваться только с типами, которые реализуют IDisposable; он гарантирует, что метод Dispose() будет вызываться, даже если возникает ошибка.

Этот код:

using (MyDisposableType x = new MyDisposableType()) 
{ 
    // use x 
} 

эквивалентно следующему:

MyDisposableType x = new MyDisposableType(); 
try 
{ 
    // use x 
} 
finally 
{ 
    x.Dispose(); 
} 
+0

Итак ... используйте его на любом объекте, который реализует IDisposable? Всегда? – danieltalsky

+0

А как насчет обработки исключений? – danieltalsky

+0

, пожалуйста, оставьте комментарий. Благодарю. –

1

КАКИЕ сказал Митч, плюс ..

Вы можете использовать, используя заявление снаружи или внутри блока try..catch это действительно будет зависеть от того, что вы пытаетесь достичь, то ли разумно ожидать, что-то бросаться исключение, в то время как с использованием определенного объекта, который вы планируете восстановить, например.

К тому же вы также можете удалить объект, который реализует IDisposable в блоке finally, если вам нужно.

3

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

1

Использование с использованием, когда вам нужно детерминированное удаление объекта. Например, если вы открываете файл, файл заблокирован. Вы часто захотите, чтобы файл был закрыт как можно скорее, чтобы другие программы могли получить к нему доступ. Если вы не используете с помощью и писать, как л:

System.IO.FileStream writeStream = new System.IO.FileStream(fileName, System.IO.FileMode.OpenOrCreate)); 
System.IO.BinaryWriter writer = new System.IO.BinaryWriter(writeStream)); 
//do smth 

и исключение происходит во время «делать что-л» вы не знаете, когда объекты, работающие на файле, на самом деле расположены и файл закрывается.С помощью вы знаете наверняка, что как только вы покинули с помощью операторного блока - либо непосредственно, либо через исключение объект в использованияКонтактной заявления расположен по телефону IDisposable :: Dispose:

using(System.IO.FileStream writeStream = new System.IO.FileStream(fileName, System.IO.FileMode.OpenOrCreate)) { 
    using(System.IO.BinaryWriter writer = new System.IO.BinaryWriter(writeStream)) { 
     //do stmth 
    } 
} 
+0

Нет, объект * не * финализирован. Это только утилизировано. Завершение и удаление очень разные. Обычно утилизация подавляет финализатор (если таковой есть), но это не одно и то же. –

+0

«Используйте, когда вам нужно детерминированное удаление объектов». Мне кажется, что если объект реализует IDisposable, вы всегда должны его утилизировать, если объект больше не нужен. Внедряя IDisposable, объект говорит: «Я (могу) использовать ресурсы, которые нужно утилизировать». –

+0

Что делать, если реализация объекта, о котором идет речь, изменяется и удаляется сразу же? В чем преимущество неиспользования сразу после использования? –

1

Вы можете заключить использование внутри блока try/catch, и вы можете заключить блок try/catch внутри использования.

Одна из ситуаций, где использование хорошо, когда вы делаете операции с базами данных с использованием DBConnection и DBCommands:

using (SqlConnection conn = new SqlConnection(connectionString)) 
using (SqlCommand command = new SqlCommand(sql, conn)) 
{ 
    // do something here 
} 

Теперь, когда вы оставляете с помощью блоков вашей команды доброжелательности и соединение закрываются.

1

Что сказал Митч, является правильным. Таким образом, основное использование используется для обеспечения того, чтобы объекты IDisposable были удалены, без, чтобы закодировать команду try/catch или try/finally.

Теперь у вас есть более продвинутое использование, которое может показаться вам интересным. Когда вы используете оператор using, компилятор генерирует try/finally, а также генерирует вызов Dispose() для вас внутри окончательно созданного. Вы можете использовать этот метод Dispose() как «хук», чтобы делать все, что вы хотите ... не обязательно должны быть связаны с выпуском ресурсов.

Например, Джеффри Рихтер использует это в задаче таймера, который он написал. Вы можете сделать что-то подобное с ним (концептуальное только):

using(var x = new Timer()) 
{ 
    // Do the operation you want timed 
} 

// Now, the timer has been stopped, because the 
// compiler-generated call to Dispose() has already 
// occurred, and Jeffrey uses Dispose() to stop 
// the timer. 
+0

Кажется немного сложнее. После закрывающей скобки у вас нет доступа к x. Как вы можете воспользоваться остановленным таймером? –

+0

Да, это правда. В случае таймера Рихтера он выводит прошедшее время (и количество собранных сборок мусора) на консоль. Поэтому ему не нужно было ссылаться на объект после закрытия. –

+0

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

2

Если вы хотите знать, как творчески использовать его в ваших собственных конструкциях, просматривать некоторые из своего собственного кода для ситуаций, когда конкретный бит коды абсолютно необходимо выполнить до выхода закрывающего блока. Это ситуации, когда try/finally или using могут вам помочь.

В частности, если вы попытались достичь этого, воспользовавшись всеми исключениями, вы действительно должны изменить на try/finally или using вместо этого.

Если шаблон возникает несколько раз, вы можете создать класс, который реализует IDisposable, чтобы захватить шаблон и позволить вам вызывать шаблон с помощью оператора using. Но если у вас есть конкретный случай, который кажется одноразовым, просто используйте try/finally.

Два очень похожи, на самом деле - using определяется в терминах try/finally, но даже если мы только имели using, мы могли бы построить try/finally себя:

public class DisposeAnything : IDisposable 
{ 
    public Action Disposer; 

    public void Dispose() 
    { 
     Disposer(); 
    } 
} 

Теперь вы можете сказать:

using (new DisposeAnything 
     { 
      Disposer =() => File.Delete(tempFileName) 
     }) 
{ 
    // blah 
} 

Что такое же, как:

try 
{ 
    // blah 
} 
finally 
{ 
    File.Delete(tempFileName); 
} 

Просто подумайте об этом как о способе выполнения кода, выходящего из области действия.

+0

Эй, параметрирование логики удаления - интересная идея. Я предполагаю, что есть много способов сделать это. Круто. –

+0

Взятый к вышесказанному экстремуму, там не так много смысла! Но да, вероятно, есть много случаев на полпути. Вы можете найти это обсуждение интересным: http://incrediblejourneysintotheknown.blogspot.com/2009/02/functional-replacement-for-using.html –

1

Если класс реализует IDisposable, это, вероятно, не без оснований. Поэтому любой класс, который реализует IDisposable, должен быть удален.

1

Учитывая, что это то, что известно как «синтаксический сахар», и будет производить тот же ИЛ, что и конструкция try/finally dispose, это действительно просто хороший способ «короткого раздачи» такого кода.

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

0

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

Смежные вопросы