Używanie obiektów implementujących interfejs IDisposableUsing objects that implement IDisposable

Moduł zbierający elementy bezużyteczne środowiska uruchomieniowego języka wspólnego ponownie przejmuje pamięć używaną przez zarządzane obiekty, ale typy korzystające z zasobów niezarządzanych implementują IDisposable interfejs w celu zezwalania na odzyskiwanie zasobów wymaganych przez te niezarządzane zasoby.The common language runtime's garbage collector reclaims the memory used by managed objects, but types that use unmanaged resources implement the IDisposable interface to allow the resources needed by these unmanaged resources to be reclaimed. Po zakończeniu korzystania z obiektu, który implementuje IDisposable , należy wywołać IDisposable.Dispose implementację obiektu.When you finish using an object that implements IDisposable, you should call the object's IDisposable.Dispose implementation. Można to zrobić na jeden z dwóch sposobów:You can do this in one of two ways:

  • Za pomocą instrukcji języka C# using ( Using w Visual Basic).With the C# using statement (Using in Visual Basic).
  • Przez implementację try/finally bloku i wywołanie elementu IDisposable.Dispose w finally .By implementing a try/finally block, and calling the IDisposable.Dispose in the finally.

Instrukcja usingThe using statement

using Instrukcja w języku C# i Using instrukcja w Visual Basic upraszczają kod, który należy napisać, aby oczyścić obiekt.The using statement in C# and the Using statement in Visual Basic simplify the code that you must write to cleanup an object. usingInstrukcja uzyskuje jeden lub więcej zasobów, wykonuje określone instrukcje i automatycznie usuwa obiekt.The using statement obtains one or more resources, executes the statements that you specify, and automatically disposes of the object. Jednak using instrukcja jest przydatna tylko w przypadku obiektów, które są używane w zakresie metody, w której są zbudowane.However, the using statement is useful only for objects that are used within the scope of the method in which they are constructed.

Poniższy przykład używa using instrukcji w celu utworzenia i zwolnienia System.IO.StreamReader obiektu.The following example uses the using statement to create and release a System.IO.StreamReader object.

using System;
using System.IO;

class Example
{
   static void Main()
   {
      char[] buffer = new char[50];
      using var streamReader = new StreamReader("file1.txt");
      
      int charsRead = 0;
      while (streamReader.Peek() != -1)
      {
         charsRead = streamReader.Read(buffer, 0, buffer.Length);
         //
         // Process characters read.
         //
      }
   }
}
Imports System.IO

Module Example
    Public Sub Main()
        Dim buffer(49) As Char
        Using s As New StreamReader("File1.txt")
            Dim charsRead As Integer
            Do While s.Peek() <> -1
                charsRead = s.Read(buffer, 0, buffer.Length)
                ' 
                ' Process characters read.
                '
            Loop
        End Using
    End Sub
End Module

Mimo że StreamReader Klasa implementuje IDisposable interfejs, który wskazuje, że używa niezarządzanego zasobu, przykład nie wywołuje jawnie StreamReader.Dispose metody.Although the StreamReader class implements the IDisposable interface, which indicates that it uses an unmanaged resource, the example doesn't explicitly call the StreamReader.Dispose method. Gdy kompilator języka C# lub Visual Basic napotka using instrukcję, emituje język pośredni (IL), który jest odpowiednikiem poniższego kodu, który jawnie zawiera try/finally blok.When the C# or Visual Basic compiler encounters the using statement, it emits intermediate language (IL) that is equivalent to the following code that explicitly contains a try/finally block.

using System;
using System.IO;

class Example
{
    static void Main()
    {
        char[] buffer = new char[50];
        var streamReader = new StreamReader("file1.txt");
        try
        {
            int charsRead = 0;
            while (streamReader.Peek() != -1)
            {
                charsRead = streamReader.Read(buffer, 0, buffer.Length);
                //
                // Process characters read.
                //
            }
        }
        finally
        {
            if (streamReader != null)
            {
                ((IDisposable)streamReader).Dispose();
            }
        }
    }
}
Imports System.IO

Module Example
    Public Sub Main()
        Dim buffer(49) As Char
        ''      Dim s As New StreamReader("File1.txt")
        With s As New StreamReader("File1.txt")
      Try
                Dim charsRead As Integer
                Do While s.Peek() <> -1
                    charsRead = s.Read(buffer, 0, buffer.Length)
                    ' 
                    ' Process characters read.
                    '
                Loop
            Finally
                If s IsNot Nothing Then DirectCast(s, IDisposable).Dispose()
            End Try
        End With
    End Sub
End Module

Instrukcja języka C# using umożliwia także uzyskanie wielu zasobów w pojedynczej instrukcji, która jest wewnętrznie odpowiednikiem zagnieżdżonych using instrukcji.The C# using statement also allows you to acquire multiple resources in a single statement, which is internally equivalent to nested using statements. Poniższy przykład tworzy wystąpienie dwóch StreamReader obiektów w celu odczytania zawartości dwóch różnych plików.The following example instantiates two StreamReader objects to read the contents of two different files.

using System.IO;

class Example
{
    static void Main()
    {
        char[] buffer1 = new char[50];
        char[] buffer2 = new char[50];

        using StreamReader version1 = new StreamReader("file1.txt"),
                           version2 = new StreamReader("file2.txt");

        int charsRead1, charsRead2 = 0;
        while (version1.Peek() != -1 && version2.Peek() != -1)
        {
            charsRead1 = version1.Read(buffer1, 0, buffer1.Length);
            charsRead2 = version2.Read(buffer2, 0, buffer2.Length);
            //
            // Process characters read.
            //
        }
    }
}

Blok try/finallyTry/finally block

Zamiast zawijać try/finally blok w using instrukcji, możesz wybrać opcję try/finally bezpośredniego wdrożenia bloku.Instead of wrapping a try/finally block in a using statement, you may choose to implement the try/finally block directly. Może to być osobisty styl kodowania lub można to zrobić z jednego z następujących powodów:It may be your personal coding style, or you might want to do this for one of the following reasons:

  • Aby dołączyć catch blok obsługujący wyjątki zgłoszone w try bloku.To include a catch block to handle exceptions thrown in the try block. W przeciwnym razie wyjątki zgłaszane w using instrukcji są nieobsługiwane.Otherwise, any exceptions thrown within the using statement are unhandled.

  • Aby utworzyć wystąpienie obiektu, który implementuje, IDisposable którego zakres nie jest lokalny dla bloku, w którym jest zadeklarowany.To instantiate an object that implements IDisposable whose scope is not local to the block within which it is declared.

Poniższy przykład jest podobny do poprzedniego przykładu, z tą różnicą, że używa try/catch/finally bloku do tworzenia wystąpienia, używania i usuwania StreamReader obiektu oraz do obsługi wszelkich wyjątków zgłoszonych przez StreamReader konstruktora i jego ReadToEnd metodę.The following example is similar to the previous example, except that it uses a try/catch/finally block to instantiate, use, and dispose of a StreamReader object, and to handle any exceptions thrown by the StreamReader constructor and its ReadToEnd method. Kod w finally bloku sprawdza, czy obiekt, który implementuje IDisposable nie null przed wywołaniem Dispose metody.The code in the finally block checks that the object that implements IDisposable isn't null before it calls the Dispose method. Niewykonanie tej czynności może spowodować wyjątek w NullReferenceException czasie wykonywania.Failure to do this can result in a NullReferenceException exception at run time.

using System;
using System.Globalization;
using System.IO;

class Example
{
    static void Main()
    {
        StreamReader? streamReader = null;
        try
        {
            streamReader = new StreamReader("file1.txt");
            string contents = streamReader.ReadToEnd();
            var info = new StringInfo(contents);
            Console.WriteLine($"The file has {info.LengthInTextElements} text elements.");
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("The file cannot be found.");
        }
        catch (IOException)
        {
            Console.WriteLine("An I/O error has occurred.");
        }
        catch (OutOfMemoryException)
        {
            Console.WriteLine("There is insufficient memory to read the file.");
        }
        finally
        {
            streamReader?.Dispose();
        }
    }
}
Imports System.Globalization
Imports System.IO

Module Example
    Sub Main()
        Dim streamReader As StreamReader = Nothing
        Try
            streamReader = New StreamReader("file1.txt")
            Dim contents As String = streamReader.ReadToEnd()
            Dim info As StringInfo = New StringInfo(contents)
            Console.WriteLine($"The file has {info.LengthInTextElements} text elements.")
        Catch e As FileNotFoundException
            Console.WriteLine("The file cannot be found.")
        Catch e As IOException
            Console.WriteLine("An I/O error has occurred.")
        Catch e As OutOfMemoryException
            Console.WriteLine("There is insufficient memory to read the file.")
        Finally
            If streamReader IsNot Nothing Then streamReader.Dispose()
        End Try
    End Sub
End Module

Możesz użyć tego podstawowego wzorca, jeśli zdecydujesz się zaimplementować lub musi zaimplementować try/finally blok, ponieważ język programowania nie obsługuje using instrukcji, ale zezwala na bezpośrednie wywołania Dispose metody.You can follow this basic pattern if you choose to implement or must implement a try/finally block, because your programming language doesn't support a using statement but does allow direct calls to the Dispose method.

Elementy członkowskie wystąpienia IDisposableIDisposable instance members

Jeśli klasa przechowuje IDisposable implementację jako element członkowski wystąpienia, pole lub właściwość, należy również zaimplementować klasę IDisposable .If a class holds an IDisposable implementation as an instance member, either a field or a property, the class should also implement IDisposable. Aby uzyskać więcej informacji, zobacz implementacja kaskadowego usuwania.For more information, see implement a cascade dispose.

Zobacz takżeSee also