Delen via


Afhandeling van uitzonderingen (C#-programmeerhandleiding)

Een try-blok wordt door C#-programmeurs gebruikt om code te partitioneren die mogelijk wordt beïnvloed door een uitzondering. Gekoppelde catch-blokken worden gebruikt om eventuele resulterende uitzonderingen af te handelen. Een definitief blok bevat code die wordt uitgevoerd of er al dan niet een uitzondering wordt gegenereerd in het try blok, zoals het vrijgeven van resources die in het try blok zijn toegewezen. Een try blok vereist een of meer gekoppelde catch blokken, of een finally blok, of beide.

In de volgende voorbeelden ziet u een try-catch instructie, een try-finally instructie en een try-catch-finally instructie.

try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
    // Only catch exceptions that you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}
try
{
    // Code to try goes here.
}
finally
{
    // Code to execute after the try block goes here.
}
try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
}
finally
{
    // Code to execute after the try (and possibly catch) blocks
    // goes here.
}

Een try blok zonder of catchfinally blok veroorzaakt een compilerfout.

Catch Blocks

Een catch blok kan het type uitzondering opgeven dat moet worden onderschept. De typespecificatie wordt een uitzonderingsfilter genoemd. Het uitzonderingstype moet worden afgeleid van Exception. Geef in het algemeen niet op Exception als uitzonderingsfilter, tenzij u weet hoe u alle uitzonderingen moet verwerken die in het try blok kunnen worden gegenereerd, of als u een throw instructie aan het einde van het catch blok hebt opgenomen.

Meerdere catch blokken met verschillende uitzonderingsklassen kunnen aan elkaar worden gekoppeld. De catch blokken worden van boven naar beneden geëvalueerd in uw code, maar er wordt slechts één catch blok uitgevoerd voor elke uitzondering die wordt gegenereerd. Het eerste catch blok dat het exacte type of een basisklasse van de gegenereerde uitzondering aangeeft, wordt uitgevoerd. Als er geen catch blok een overeenkomende uitzonderingsklasse aangeeft, wordt er een catch blok geselecteerd waarvoor geen type is geselecteerd, als deze aanwezig is in de instructie. Het is belangrijk om blokken te positioneren catch met de meest specifieke (dat wil gezegd, de meest afgeleide) uitzonderingsklassen eerst.

Uitzonderingen vangen wanneer aan de volgende voorwaarden wordt voldaan:

  • U hebt een goed begrip van de reden waarom de uitzondering kan worden gegenereerd en u kunt een specifiek herstel implementeren, zoals het vragen van de gebruiker om een nieuwe bestandsnaam in te voeren wanneer u een FileNotFoundException object ondervangt.
  • U kunt een nieuwe, specifiekere uitzondering maken en genereren.
    int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    
  • U wilt een uitzondering gedeeltelijk afhandelen voordat u deze doorgeeft voor meer verwerking. In het volgende voorbeeld wordt een catch blok gebruikt om een vermelding toe te voegen aan een foutenlogboek voordat de uitzondering opnieuw wordt beperkt.
    try
    {
        // Try to access a resource.
    }
    catch (UnauthorizedAccessException e)
    {
        // Call a custom error logging procedure.
        LogError(e);
        // Re-throw the error.
        throw;
    }
    

U kunt ook uitzonderingsfilters opgeven om een Booleaanse expressie toe te voegen aan een catch-component. Uitzonderingsfilters geven aan dat een specifieke catch-component alleen overeenkomt wanneer aan die voorwaarde wordt voldaan. In het volgende voorbeeld gebruiken beide catch-componenten dezelfde uitzonderingsklasse, maar er wordt een extra voorwaarde gecontroleerd om een ander foutbericht te maken:

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e) when (index < 0) 
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be negative.", e);
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be greater than the array size.", e);
    }
}

Een uitzonderingsfilter false dat altijd wordt geretourneerd, kan worden gebruikt om alle uitzonderingen te onderzoeken, maar ze niet te verwerken. Een typisch gebruik is het vastleggen van uitzonderingen:

public class ExceptionFilter
{
    public static void Main()
    {
        try
        {
            string? s = null;
            Console.WriteLine(s.Length);
        }
        catch (Exception e) when (LogException(e))
        {
        }
        Console.WriteLine("Exception must have been handled");
    }

    private static bool LogException(Exception e)
    {
        Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
        Console.WriteLine($"\tMessage: {e.Message}");
        return false;
    }
}

De LogException methode retourneert altijd, geen catch component die gebruikmaakt van dit uitzonderingsfilterfalse. De catch-component kan algemeen zijn, met behulp van System.Exceptionen latere componenten kunnen specifiekere uitzonderingsklassen verwerken.

Ten slotte blokken

Met een finally blok kunt u acties opschonen die in een try blok worden uitgevoerd. Indien aanwezig, wordt het finally blok als laatste uitgevoerd, na het try blok en een overeenkomend catch blok. Er finally wordt altijd een blok uitgevoerd, ongeacht of er een uitzondering wordt gegenereerd of een catch blok dat overeenkomt met het uitzonderingstype wordt gevonden.

Het finally blok kan worden gebruikt om resources, zoals bestandsstromen, databaseverbindingen en grafische ingangen, vrij te geven zonder te wachten tot de garbagecollector in de runtime de objecten heeft voltooid.

In het volgende voorbeeld wordt het finally blok gebruikt om een bestand te sluiten dat in het try blok wordt geopend. U ziet dat de status van de bestandsgreep is gecontroleerd voordat het bestand wordt gesloten. Als het blok het try bestand niet kan openen, heeft de bestandsgreep nog steeds de waarde null en probeert het blok het finally niet te sluiten. Als het bestand in plaats daarvan is geopend in het try blok, wordt het finally geopende bestand gesloten.

FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // Check for null because OpenWrite might have failed.
    file?.Close();
}

C#-taalspecificatie

Zie Uitzonderingen en de instructie Try in de C#-taalspecificatie voor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik.

Zie ook