Подтвердить что ты не робот

Использование оператора и IDisposable.Dispose()

Насколько я понимаю, оператор using в .NET вызывает метод IDisposable object Dispose() после кода выходит из блока.

Делает ли оператор using что-то еще? Если нет, кажется, что следующие два примера кода достигают той же самой вещи:

Using Con as New Connection()
    Con.Open()
    'do whatever '
End Using

Dim Con as New Connection()
Con.Open()
'do whatever '
Con.Dispose()

Я дам лучший ответ тому, кто подтверждает, что я прав, или указывает, что я ошибаюсь и объясняю почему. Имейте в виду, что я знаю, что некоторые классы могут делать разные вещи в своих методах Dispose(). Этот вопрос касается того, выполняет ли оператор using тот же результат, что и вызов метода Dispose().

4b9b3361

Ответ 1

using в основном эквивалентен:

try
{
  // code
}
finally
{
  obj.Dispose();
}

Таким образом, также имеет смысл вызывать Dispose(), даже если необработанное исключение выбрано в коде внутри блока.

Ответ 2

Как сказал Брайан Варшов в здесь, это просто импотент блоков try и finally, чтобы убедиться, что объект удален. Добавляя к его ответу; Блок using также гарантирует, что объект будет удален, даже если вы вернете внутри с помощью области

Мне когда-то было любопытно об этом и проверил его, используя следующий подход:

Пользовательский тестовый класс IDisposable и главный

private class DisposableTest : IDisposable
{
    public string Name { get; set; }

    public void Dispose() { Console.WriteLine("{0}.Dispose() is called !", Name); }
}

public static void Main(string[] args)
{
    try
    {
        UsingReturnTest();
        UsingExceptionTest();                
    }
    catch { }

    try
    {
        DisposeReturnTest();
        DisposeExceptionTest();                
    }
    catch { }

    DisposeExtraTest();

    Console.ReadLine();
}        

Реализация тестовых примеров

private static string UsingReturnTest()
{
    using (DisposableTest usingReturn = new DisposableTest() { Name = "UsingReturn" })
    {
        return usingReturn.Name;
    }
}

private static void UsingExceptionTest()
{
    using (DisposableTest usingException = new DisposableTest() { Name = "UsingException" })
    {
        int x = int.Parse("NaN");
    }
}

private static string DisposeReturnTest()
{        
    DisposableTest disposeReturn = new DisposableTest() { Name = "DisposeReturn" };
    return disposeReturn.Name;
    disposeReturn.Dispose(); // # IDE Warning; Unreachable code detected
}

private static void DisposeExceptionTest()
{
    DisposableTest disposeException = new DisposableTest() { Name = "DisposeException" };
    int x = int.Parse("NaN");
    disposeException.Dispose();
}

private static void DisposeExtraTest()
{
    DisposableTest disposeExtra = null;
    try
    {
        disposeExtra = new DisposableTest() { Name = "DisposeExtra" };
        return;
    }
    catch { }
    finally
    {
        if (disposeExtra != null) { disposeExtra.Dispose(); }
    }
}

И вывод:

  • Вызывается методReturn.Dispose()!
  • Вызывается использованиеException.Dispose()!
  • DisposeExtra.Dispose() вызывается!

Ответ 3

//preceeding code
using (con = new Connection()) {
    con.Open()
    //do whatever
}
//following code

эквивалентно следующему (обратите внимание на ограниченный объем для con):

//preceeding code
{
    var con = new Connection();
    try {
        con.Open()
        //do whatever
    } finally {
        if (con != null) con.Dispose();
    }
}
//following code

Это описано здесь: http://msdn.microsoft.com/en-us/library/yh598w02.aspx

Оператор using гарантирует, что Dispose вызывается, даже если Исключение возникает, когда вы вызываете методы на объекте. Вы можете добиться того же результата, поставив объект внутри блока try и затем вызов Dispose в блоке finally; на самом деле, именно так using оператор переводится компилятором.

Ответ 4

Разница между ними заключается в том, что если исключение выбрано в

Con.Open()
'do whatever

Con.Dispose не будет вызываться.

Я не в синтаксисе VB, но в С# эквивалентный код будет

try
{
    con = new Connection();
    // Do whatever
}
finally
{
    if (con != null) con.Dispose();
}

Ответ 5

Оператор

A using более ясен и более кратким, чем конструктор try...finally{Dispose()}, и должен использоваться почти во всех случаях, когда вы не хотите разрешать вывод блока без вызова Dispose. Единственными распространенными ситуациями, когда "ручное" удаление было бы лучше, было бы:

  • Метод вызывает метод factory, который возвращает что-то, что может или не может реализовывать `IDisposable`, но которое должно быть` Dispose`d, если оно существует (сценарий, который встречается с не-generic `IEnumerable.GetEnumerator() `). Хорошо спроектированные интерфейсы factory должны либо возвращать тип, который реализует `IDisposable` (возможно, с реализацией do-nothing, как это обычно бывает в случае с IEnumerator), либо указать, что вызывающие объекты не должны "Dispose" возвращать объект, К сожалению, некоторые интерфейсы, такие как не общий "IEnumerable", не удовлетворяют ни одному критерию. Обратите внимание, что в таких случаях нельзя использовать `use`, поскольку он работает только с местами хранения, чей объявленный тип реализует` IDisposable`.
  • Ожидается, что объект `IDisposable` будет жить даже после выхода блока (как это часто бывает при установке поля` IDisposable` или возврата `IDisposable` из метода factory).

Обратите внимание, что при возврате IDisposable из метода factory следует использовать что-то вроде следующего:

  bool ok = false;
  DisposableClass myThing;
  try
  {
    myThing = new DisposableClass();
    ...
    ok = true;
    return myThing;
  }
  finally
  {
    if (!ok)
    {
      if (myThing != null)
        myThing.Dispose();
    }
  }

чтобы myThing получал Dispose d, если он не возвращается. Хотелось бы использовать метод using наряду с некоторым методом "cancel Dispose", но такой вещи не существует.

Ответ 6

Оператор using гарантирует, что объект будет удален в случае возникновения исключения. Это эквивалент вызова dispose в блоке finally.

Ответ 7

Используемый блок гарантирует, что Dispose() вызывается, если генерируется исключение.

Ваш второй образец этого не делает.

Если Con.Open() выбрасывает исключение, в первом случае вам гарантируется вызов Con.Dispose(). Во втором случае исключение распространяется вверх и Con.Dispose() не будет вызываться.

Ответ 8

Использование обертки вложенного блока в try/finally, который вызывает Dispose в блоке finally. Это гарантирует, что Dispose будет вызываться, даже если возникает исключение.

Вам следует использовать практически во всех случаях по соображениям безопасности

Ответ 9

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

try
{
  var myDisposable = new DisposableObject();
  myDisposable.DoSomething();
}
finally
{
  if (myDisposable != null)
    ((IDisposable)myDisposable).Dispose();
}