.NET Framework
undantag
Sök…
Anmärkningar
Relaterad:
Fånga ett undantag
Koden kan och bör kasta undantag under exceptionella omständigheter. Exempel på detta inkluderar:
- Försöker läsa förbi slutet av en ström
- Har inte nödvändiga behörigheter för att komma åt en fil
- Försök att utföra en ogiltig operation, till exempel att dela med noll
- En tidsgräns som inträffar när du laddar ner en fil från internet
Den som ringer kan hantera dessa undantag genom att "fånga" dem och bör bara göra det när:
- Det kan faktiskt lösa den exceptionella omständigheten eller återhämta sig på lämpligt sätt, eller;
- Det kan ge ytterligare sammanhang till undantaget som skulle vara användbart om undantaget behöver kastas om (omkastade undantag fångas av undantagshandlare längre upp i samtalstacken)
Det bör noteras att valet att inte fånga ett undantag är helt giltigt om avsikten är att det ska hanteras på en högre nivå.
Att fånga ett undantag görs genom att lägga in den potentiellt kasta koden i ett try { ... }
-block enligt följande och fånga de undantag som det kan hantera i en catch (ExceptionType) { ... }
-block:
Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();
Stream fileStream;
try
{
fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
Console.WriteLine("File '{0}' could not be found.", filename);
}
Med ett slutligt block
Det finally { ... }
blocket av en try-finally
eller try-catch-finally
kommer alltid att köras, oavsett om ett undantag inträffade eller inte (utom när en StackOverflowException
har kastats eller ett samtal har gjorts till Environment.FailFast()
).
Det kan användas för att frigöra eller rensa upp resurser som förvärvats i try { ... }
blockera säkert.
Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();
Stream fileStream = null;
try
{
fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
Console.WriteLine("File '{0}' could not be found.", filename);
}
finally
{
if (fileStream != null)
{
fileStream.Dispose();
}
}
Fånga och återupptagna fångade undantag
När du vill fånga ett undantag och göra något, men du inte kan fortsätta exekveringen av det aktuella kodblocket på grund av undantaget, kanske du vill flytta om undantaget till nästa undantagshanterare i samtalstacken. Det finns bra sätt och dåliga sätt att göra detta.
private static void AskTheUltimateQuestion()
{
try
{
var x = 42;
var y = x / (x - x); // will throw a DivideByZeroException
// IMPORTANT NOTE: the error in following string format IS intentional
// and exists to throw an exception to the FormatException catch, below
Console.WriteLine("The secret to life, the universe, and everything is {1}", y);
}
catch (DivideByZeroException)
{
// we do not need a reference to the exception
Console.WriteLine("Dividing by zero would destroy the universe.");
// do this to preserve the stack trace:
throw;
}
catch (FormatException ex)
{
// only do this if you need to change the type of the Exception to be thrown
// and wrap the inner Exception
// remember that the stack trace of the outer Exception will point to the
// next line
// you'll need to examine the InnerException property to get the stack trace
// to the line that actually started the problem
throw new InvalidOperationException("Watch your format string indexes.", ex);
}
catch (Exception ex)
{
Console.WriteLine("Something else horrible happened. The exception: " + ex.Message);
// do not do this, because the stack trace will be changed to point to
// this location instead of the location where the exception
// was originally thrown:
throw ex;
}
}
static void Main()
{
try
{
AskTheUltimateQuestion();
}
catch
{
// choose this kind of catch if you don't need any information about
// the exception that was caught
// this block "eats" all exceptions instead of rethrowing them
}
}
Du kan filtrera efter undantagstyp och till och med efter undantagsegenskaper (nya i C # 6.0, lite längre tillgängligt i VB.NET (citation behövs)):
Dokumentation / C # / nya funktioner
Undantagsfilter
Eftersom C # 6.0 kan undantag filtreras med operatören when
.
Detta liknar användning av en enkel if
men inte lossar bunten om villkoret inuti when
inte är uppfyllt.
Exempel
try
{
// ...
}
catch (Exception e) when (e.InnerException != null) // Any condition can go in here.
{
// ...
}
Samma information finns i C # 6.0-funktionerna här: Undantagsfilter
Återuppta ett undantag inom ett fångstblock
Inom ett catch
kan throw
nyckelordet användas på egen hand, utan att ange ett undantagsvärde, för att återkasta undantaget som just fångades. Genom att återta ett undantag kan det ursprungliga undantaget fortsätta uppåt undantagshanteringskedjan och bevara dess samtalstack eller tillhörande data:
try {...}
catch (Exception ex) {
// Note: the ex variable is *not* used
throw;
}
Ett vanligt antimönster är att istället throw ex
, vilket har effekten att begränsa nästa undantagshandlers syn på stackspåret:
try {...}
catch (Exception ex) {
// Note: the ex variable is thrown
// future stack traces of the exception will not see prior calls
throw ex;
}
I allmänhet är det inte önskvärt att använda throw ex
, eftersom framtida undantagshanterare som inspekterar stackspåret bara kan se samtal så långt tillbaka som throw ex
. Genom att utelämna ex
variabeln och bara använda throw
nyckelordet kommer det ursprungliga undantaget att "bubbla upp" .
Kasta ett undantag från en annan metod samtidigt som informationen bevaras
Ibland vill du fånga ett undantag och kasta det från en annan tråd eller metod medan du bevarar den ursprungliga undantagsbunten. Detta kan göras med ExceptionDispatchInfo
:
using System.Runtime.ExceptionServices;
void Main()
{
ExceptionDispatchInfo capturedException = null;
try
{
throw new Exception();
}
catch (Exception ex)
{
capturedException = ExceptionDispatchInfo.Capture(ex);
}
Foo(capturedException);
}
void Foo(ExceptionDispatchInfo exceptionDispatchInfo)
{
// Do stuff
if (capturedException != null)
{
// Exception stack trace will show it was thrown from Main() and not from Foo()
exceptionDispatchInfo.Throw();
}
}