共用方式為


使用實作 IDisposable 的物件

公用語言執行平台的垃圾收集器(GC)會回收受管理物件所使用的記憶體。 一般而言,使用非管理資源的類型會實作 IDisposableIAsyncDisposable 介面,以允許回收這些非管理資源。 當您完成使用實作 IDisposable的物件時,會呼叫 物件的 DisposeDisposeAsync 實作,以明確執行清除。 您可以使用下列兩種方式之一來執行此動作:

  • 使用 C# using 語句或宣告 (Using 在 Visual Basic 中)。
  • 藉由實作 try/finally 區塊,並在 Dispose 中呼叫 DisposeAsyncfinally 方法。

這很重要

GC 不會 處置您的物件,因為它不知道 IDisposable.Dispose()IAsyncDisposable.DisposeAsync()。 GC 只知道物件是否可完成(也就是它定義 Object.Finalize() 方法),以及何時需要呼叫物件的完成項。 如需詳細資訊,請參閱 最終處理的運作方式。 如需實作 DisposeDisposeAsync的其他詳細數據,請參閱:

實作System.IDisposableSystem.IAsyncDisposable的物件,不論變數範圍如何,一律應該妥善處置,除非另有明確說明。 定義完成項以釋放非受控資源的型別,通常會從其GC.SuppressFinalizeDispose實作中呼叫DisposeAsync。 呼叫 SuppressFinalize 告訴 GC 已執行完成子,對象不應被提升進行最終化。

using 語句

C# 中的 語句和 using Visual Basic 中的 語句會簡化您必須撰寫以清除物件的程式代碼。Using using語句會取得一或多個資源、執行您指定的語句,並自動處置 物件。 不過, using 語句只適用於在建構物件之方法範圍內使用的物件。

下列範例會使用 using 語句來建立及釋放 System.IO.StreamReader 物件。

using System.IO;

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

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

using宣告是一種替代語法,在這種語法中大括號被移除,且範圍界定是隱含的。

using System.IO;

class UsingDeclaration
{
    static void Main()
    {
        var buffer = new char[50];
        using StreamReader streamReader = new("file1.txt");

        int charsRead = 0;
        while (streamReader.Peek() != -1)
        {
            charsRead = streamReader.Read(buffer, 0, buffer.Length);
            //
            // Process characters read.
            //
        }
    }
}

雖然 類別 StreamReader 會實作 IDisposable 介面,指出其使用 Unmanaged 資源,但此範例不會明確呼叫 StreamReader.Dispose 方法。 當 C# 或 Visual Basic 編譯程式遇到 using 語句時,它會發出相當於下列明確包含 try/finally 區塊的程式碼的中繼語言 (IL)。

using System.IO;

class TryFinallyGenerated
{
    static void Main()
    {
        var buffer = new char[50];
        StreamReader? streamReader = null;
        try
        {
            streamReader = new StreamReader("file1.txt");
            int charsRead = 0;
            while (streamReader.Peek() != -1)
            {
                charsRead = streamReader.Read(buffer, 0, buffer.Length);
                //
                // Process characters read.
                //
            }
        }
        finally
        {
            // If non-null, call the object's Dispose method.
            streamReader?.Dispose();
        }
    }
}
Imports System.IO

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

C# using 語句也可讓您在單一語句中取得多個資源,這在內部相當於巢狀 using 語句。 下列範例會具現化兩個 StreamReader 物件,以讀取兩個不同的檔案的內容。

using System.IO;

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

        using StreamReader version1 = new("file1.txt"),
                           version2 = new("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.
            //
        }
    }
}

Try/finally 區塊

您可以選擇直接實作try/finally區塊,而不是將using區塊包裝在try/finally語句中。 這可能是您的個人程式代碼撰寫樣式,或基於下列其中一個原因而想要這麼做:

  • 若要包含 catch 區塊來處理在 try 區塊中擲回的例外狀況。 否則,語句內 using 擲回的任何例外狀況都不會被處理。
  • 若要實例化一個實作 IDisposable 的物件,而其範圍不侷限於宣告該物件的區塊之內。

下列範例類似於之前的範例,但不同之處在於它使用 try/catch/finally 區塊來具現化、使用和處理 StreamReader 物件,並處理由 StreamReader 建構函式及其 ReadToEnd 方法所拋出的任何例外狀況。 在finally區塊中的代碼會檢查實作IDisposable的物件是否不是null,然後才會呼叫Dispose方法。 若無法這麼做,可能會導致運行時間發生 NullReferenceException 例外狀況。

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

class TryExplicitCatchFinally
{
    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 TryExplicitCatchFinally
    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

如果您選擇實作 或必須實 try/finally 作 區塊,則可以遵循此基本模式,因為您的程式設計語言不支援 using 語句,但允許直接呼叫 Dispose 方法。

IDisposable 實例成員

如果類別擁有實體欄位或屬性,且其型別實作IDisposable,則該類別也應該實作IDisposable。 如需詳細資訊,請參閱 實作串聯處置

另請參閱