Sdílet prostřednictvím


Doporučené postupy pro zpracování výjimek

Sada dobře navržených bloků kódu pro zpracování chyb může vytvořit program více robustní a méně náchylný k selhání, protože aplikace takové chyby zpracuje. Následující seznam obsahuje návrhy doporučených postupů pro zpracování výjimek:

  • Rozhodněte, kdy nastavit blok try/catch. Můžete například programově zkontrolovat podmínku, která by mohla nastat bez použití zpracování výjimek. V jiných situacích je vhodné použít zpracování výjimek pro zachycení chybové podmínky.

    Následující příklad používá příkaz if ke kontrole, zda je připojení ukončeno. Pokud není připojení uzavřeno, můžete tuto metodu použít namísto vyvolání výjimky.

If conn.State <> ConnectionState.Closed Then
    conn.Close()
End IF
if (conn.State != ConnectionState.Closed)
{
    conn.Close();
}
if (conn->State != ConnectionState::Closed)
{
    conn->Close();
}

V následujícím příkladu je vyvolána výjimka, pokud nejsou připojení uzavřena.

Try
    conn.Close()
Catch ex As InvalidOperationException
    Console.WriteLine(ex.GetType().FullName)
    Console.WriteLine(ex.Message)
End Try
try
{
    conn.Close();
}
catch (InvalidOperationException ex)
{
    Console.WriteLine(ex.GetType().FullName);
    Console.WriteLine(ex.Message);
}
try
{
    conn->Close();
}
catch (InvalidOperationException^ ex)
{
    Console::WriteLine(ex->GetType()->FullName);
    Console::WriteLine(ex->Message);
}

Metoda, kterou zvolíte závisí na četnosti očekávané události. Pokud je událost skutečně výjimečná a je chybou (například neočekávané ukončení souboru), použití zpracování výjimek je lepší, protože v normálním případě je vykonána menší část kódu. Pokud se událost stává pravidelně, je ke kontrole chyb lepší použít programové metody. V tomto případě, pokud dojde k výjimce, zpracování výjimky bude trvat déle.

  • Použijte bloky try/finally kolem kódu, který může potencionálně generovat výjimku a centralizujte příkazy catch na jednom místě. Výpis try generuje tímto způsobem výjimku, příkaz finally zavře nebo odstraní zdroje a příkaz catch zpracuje výjimku z centrálního umístění.

  • Vždy řaďte výjimky v blocích catch od nejvíce specifické, po nejméně specifickou. Tato technika zpracovává specifické výjimky dříve, než jsou předány do obecnějšího bloku catch.

  • Ukončete názvy tříd výjimek slovem Výjimka. Příklad:

Public Class MyFileNotFoundException
    Inherits Exception
End Class
public class MyFileNotFoundException : Exception
{
}
public ref class MyFileNotFoundException : public Exception
{
};
  • Při vytváření výjimek definovaných uživatelem musíte zajistit, že jsou metadata pro výjimky k dispozici pro kód, který je prováděn vzdáleně, a také při výskytu výjimek mezi doménami aplikace. Předpokládejme například, že doména aplikace A vytvoří doménu aplikace B, která spustí kód, který vyvolá výjimku. Doména aplikace A musí být schopna najít sestavení obsahující výjimku domény aplikace B, aby správně zachytila a zpracovala výjimku. Pokud aplikační doména B vyvolá výjimku, která je obsažena v sestavení pod jeho základem aplikace, ale není pod základem aplikace aplikační domény A, pak aplikační doména A nebude moci najít výjimku v modulu CLR (Common Language Runtime) a vyvolá FileNotFoundException. Této situaci se vyhnete nasazením sestavení obsahujícího informace o výjimce dvěma způsoby:

    • Umístěte sestavení do společného základu aplikace sdíleného oběma doménami aplikace.

      -nebo-

    • Pokud domény nesdílejí společný základ aplikace, podepište sestavení obsahující informace o výjimce silným názvem a nasaďte sestavení do globální mezipaměti setavení (GAC).

  • Při vytváření vlastních tříd výjimky v jazyce C# a C++ použijte alespoň tři společné konstruktory. Příklad naleznete v tématu Postupy: Vytvořit uživatelem definované výjimky.

  • Ve většině případů použijte předdefinované typy výjimek. Definujte nové typy výjimek pouze pro programové scénáře. Zaveďte novou třídu výjimky, aby mohl programátor provádět různé akce v kódu, který je založen na třídě výjimky.

  • Pro většinu aplikací odvodíte vlastní výjimky z třídy Exception. Původně bylo zamýšleno, že by vlastní výjimky měly být odvozeny ze třídy ApplicationException. Avšak v praxi nebylo shledáno, že by to přidávalo významné výhody.

  • Zahrněte lokalizované řetězce popisu v každé výjimce. Pokud se uživateli objeví chybová zpráva, je odvozená z řetězce popisu výjimky, která byla vyvolána, a nikoli z třídy výjimky.

  • Použijte gramaticky správné chybové zprávy zahrnující koncovou interpunkci. Jednotlivé věty v řetězci popisu výjimky by měly končit tečkou.

  • Poskytněte vlastnosti Exception pro programový přístup. Zahrněte další informace ve výjimce (navíc k řetězci popisu) pouze v případě, kdy existuje programový scénář, kde jsou další informace užitečné.

  • Vraťte null pro extrémně běžné chybové případy. Například Open vrátí null, pokud není soubor nalezen, ale vyvolá výjimku, pokud je soubor uzamčený.

  • Navrhněte třídy tak, aby nebyla výjimka při normálním použití vyvolána. Například, třída FileStream zpřístupní další způsob zjištění, zda bylo dosaženo konce souboru. Tím je zabráněno výjimce, která je vyvolána, pokud čtete za koncem souboru. Následující příklad ukazuje, jak číst do konce souboru.

Class FileRead
    Public Sub ReadAll(fileToRead As FileStream)
        ' This if statement is optional
        ' as it is very unlikely that
        ' the stream would ever be null.
        If fileToRead Is Nothing Then
            Throw New System.ArgumentNullException()
        End If

        Dim b As Integer

        ' Set the stream position to the beginning of the file.
        fileToRead.Seek(0, SeekOrigin.Begin)

        ' Read each byte to the end of the file.
        For i As Integer = 0 To fileToRead.Length - 1
            b = fileToRead.ReadByte()
            Console.Write(b.ToString())
            ' Or do something else with the byte.
        Next i
    End Sub
End Class
class FileRead
{
    public void ReadAll(FileStream fileToRead)
    {
        // This if statement is optional
        // as it is very unlikely that
        // the stream would ever be null.
        if (fileToRead == null)
        {
            throw new System.ArgumentNullException();
        }

        int b;

        // Set the stream position to the beginning of the file.
        fileToRead.Seek(0, SeekOrigin.Begin);

        // Read each byte to the end of the file.
        for (int i = 0; i < fileToRead.Length; i++)
        {
            b = fileToRead.ReadByte();
            Console.Write(b.ToString());
            // Or do something else with the byte.
        }
    }
}
class FileRead
{
public:
    void ReadAll(FileStream^ fileToRead)
    {
        // This if statement is optional
        // as it is very unlikely that
        // the stream would ever be null.
        if (fileToRead == nullptr)
        {
            throw gcnew System::ArgumentNullException();
        }

        int b;

        // Set the stream position to the beginning of the file.
        fileToRead->Seek(0, SeekOrigin::Begin);

        // Read each byte to the end of the file.
        for (int i = 0; i < fileToRead->Length; i++)
        {
            b = fileToRead->ReadByte();
            Console::Write(b.ToString());
            // Or do something else with the byte.
        }
    }
};

Vyvolejte InvalidOperationException, není-li sada vlastností, nebo volání metody vhodně zadáno do současného stavu objektu.

Vyvolejte ArgumentException nebo třídu odvozenou z ArgumentException, pokud jsou předány neplatné parametry.

Trasování zásobníků začíná u příkazu, kde je vyvolána výjimka a končí u příkazu catch, který zachycuje výjimku. Pamatujte na tuto skutečnost při rozhodování, kam umístíte příkaz throw.

Použijte metody tvůrce výjimky. Pro třídu je běžné vyvolat stejnou výjimku z různých míst v rámci její implementace. Abyste zabránili nadbytečnému kódu, použijte pomocné metody k vytvoření výjimky a jejímu vrácení. Příklad:

Class FileReader
    Private fileName As String


    Public Sub New(path As String)
        fileName = path
    End Sub

    Public Function Read(bytes As Integer) As Byte()
        Dim results() As Byte = FileUtils.ReadFromFile(fileName, bytes)
        If results Is Nothing
            Throw NewFileIOException()
        End If
        Return results
    End Function

    Function NewFileIOException() As FileReaderException
        Dim description As String = "My NewFileIOException Description"

        Return New FileReaderException(description)
    End Function
End Class
class FileReader
{
    private string fileName;

    public FileReader(string path)
    {
        fileName = path;
    }

    public byte[] Read(int bytes)
    {
        byte[] results = FileUtils.ReadFromFile(fileName, bytes);
        if (results == null)
        {
            throw NewFileIOException();
        }
        return results;
    }

    FileReaderException NewFileIOException()
    {
        string description = "My NewFileIOException Description";

        return new FileReaderException(description);
    }
}
ref class FileReader
{
private:
    String^ fileName;

public:
    FileReader(String^ path)
    {
        fileName = path;
    }

    array<Byte>^ Read(int bytes)
    {
        array<Byte>^ results = FileUtils::ReadFromFile(fileName, bytes);
        if (results == nullptr)
        {
            throw NewFileIOException();
        }
        return results;
    }

    FileReaderException^ NewFileIOException()
    {
        String^ description = "My NewFileIOException Description";

        return gcnew FileReaderException(description);
    }
};

Alternativně použijte konstruktor výjimka vytvořit výjimku. Toto je vhodnější pro výjimku globální třídy jako ArgumentException.

  • Vyvoláním výjimky nevrací kód chyby nebo HRESULT.

  • Vyčistěte průběžné výsledky, když došlo k výjimce. Volající by měl předpokládat, že při vyvolání výjimky z metody neexistují žádné vedlejší účinky.

Viz také

Koncepty

Zpracování a vyvolání výjimek