Megosztás a következőn keresztül:


Az IDisposable-t implementáló objektumok használata

A közös nyelvi futtatókörnyezet szemétgyűjtője (GC) visszanyeri a felügyelt objektumok által használt memóriát. A nem felügyelt erőforrásokat használó típusok általában implementálják a IDisposable nem felügyelt erőforrások visszanyeréséhez szükséges felületet vagy IAsyncDisposable felületet. Amikor befejezi egy implementálást IDisposablevégző objektum használatát, meghívja Dispose az objektumot vagy DisposeAsync az implementációt, hogy explicit módon végezze el a törlést. Ezt a következő két módszer egyikével teheti meg:

  • A C# using utasítással vagy deklarációval (Using a Visual Basicben).
  • Egy blokk implementálásával try/finally és a Dispose metódus meghívásával DisposeAsync a finally.

Fontos

A GC nem dobja el az objektumokat, mivel nincs ismerete vagy .IDisposable.Dispose()IAsyncDisposable.DisposeAsync() A csoportházirend-objektum csak azt tudja, hogy egy objektum véglegesíthető-e (vagyis meghatároz egy metódust Object.Finalize() ), és mikor kell meghívni az objektum véglegesítőjét. További információ: A véglegesítés működése. A megvalósítással DisposeDisposeAsynckapcsolatos további részletekért lásd:

Azokat az objektumokat, amelyek implementálják System.IDisposable vagy System.IAsyncDisposable mindig megfelelően kell megsemmisíteni, függetlenül a változók hatókörétől, kivéve, ha másként kifejezetten meg van állítva. Azok a típusok, amelyek véglegesítőt határoznak meg a nem felügyelt erőforrások kiadásához, általában a saját vagy DisposeAsync az implementációjukból érkező hívásokat használják.GC.SuppressFinalizeDispose A hívás SuppressFinalize azt jelzi a csoportházirend-objektumnak, hogy a véglegesítő már lefutott, és az objektumot nem szabad előléptetni a véglegesítéshez.

A using utasítás

A using C# utasítása és a Using Visual Basic utasítása leegyszerűsíti az objektum törléséhez írandó kódot. Az using utasítás lekért egy vagy több erőforrást, végrehajtja a megadott utasításokat, és automatikusan megsemmisíti az objektumot. Az using utasítás azonban csak a metódus hatókörén belül használt objektumok esetében hasznos.

Az alábbi példa az using utasítással hoz létre és szabadít fel egy objektumot 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

A using deklaráció egy alternatív szintaxis, amely a zárójelek eltávolítására használható, a hatókörkezelés pedig implicit.

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.
            //
        }
    }
}

Bár az StreamReader osztály implementálja az IDisposable interfészt, amely azt jelzi, hogy nem felügyelt erőforrást használ, a példa nem hívja meg explicit módon a metódust StreamReader.Dispose . Amikor a C# vagy a Visual Basic fordító találkozik az using utasítással, olyan köztes nyelvet (IL) bocsát ki, amely egyenértékű az alábbi kóddal, amely kifejezetten tartalmaz egy blokkot try/finally .

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

A C# using utasítással több erőforrást is beszerezhet egyetlen utasításban, ami belsőleg egyenértékű a beágyazott using utasításokkal. Az alábbi példa két StreamReader objektumot példányosít két különböző fájl tartalmának olvasásához.

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.
            //
        }
    }
}

Kipróbálás/végül letiltás

A blokkok utasításban using való körbefuttatása try/finally helyett dönthet úgy, hogy közvetlenül implementálja a try/finally blokkot. Ez lehet a személyes kódolási stílusa, vagy az alábbi okok valamelyike miatt érdemes ezt megtennie:

  • Blokk hozzáadása catch a blokkban try szereplő kivételek kezeléséhez. Ellenkező esetben az using utasításban szereplő kivételeket a rendszer nem kezelte.
  • Olyan objektum példányosítása, amelynek IDisposable hatóköre nem helyi ahhoz a blokkhoz, amelyen belül deklarálva van.

Az alábbi példa az előző példához hasonló, azzal a kivétellel, hogy blokkot használ egy try/catch/finallyStreamReader objektum példányosítására, használatára és megsemmisítésére, valamint a StreamReader konstruktor és a ReadToEnd metódus által alkalmazott kivételek kezelésére. A blokkban lévő finally kód ellenőrzi, hogy a implementálható IDisposable objektum nem null a metódus meghívása Dispose előtt van-e. Ennek elmulasztása futásidőben kivételt NullReferenceException eredményezhet.

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

Ezt az alapszintű mintát követheti, ha egy blokk implementálása vagy implementálása try/finally mellett dönt, mert a programozási nyelv nem támogatja az utasítást using , de lehetővé teszi a Dispose metódus közvetlen hívását.

IDisposable-példányok tagjai

Ha egy osztály egy példánymező vagy tulajdonság tulajdonosa, és a típusa implementálva IDisposablevan, az osztálynak is implementálnia IDisposablekell. További információ: Kaszkádolt megsemmisítés implementálása.

Lásd még