Felhantering i C# hanteras främst genom användningen av undantag (exceptions). Undantag är händelser som inträffar under programkörning och som bryter det normala exekveringsflödet. Genom att fånga och hantera undantag på rätt sätt kan du undvika att applikationen kraschar och istället hantera problemet på ett kontrollerat sätt.
try, catch, finally, och throwI C# används undantag främst genom följande strukturer:
try: Innesluter den kod där ett undantag potentiellt kan uppstå.catch: Fångar och hanterar undantaget om det inträffar.finally: Innesluter kod som alltid ska köras, oavsett om ett undantag inträffar eller inte. Detta är användbart för att städa upp resurser som filer eller nätverksanslutningar.throw: Används för att manuellt kasta ett undantag, antingen inom en metod eller återkasta ett fångat undantag.try {
// Kod som kan orsaka ett undantag
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]); // Detta orsakar ett undantag (index out of range)
} catch (IndexOutOfRangeException e) {
// Hantering av undantaget
Console.WriteLine("Ett undantag inträffade: " + e.Message);
} finally {
// Kod som alltid körs
Console.WriteLine("Rensning eller avslutande logik här.");
}
try-blocket körs, och om det inte uppstår något undantag, ignoreras catch-blocket.try, hoppar exekveringen direkt till motsvarande catch-block.finally-blocket körs oavsett om ett undantag inträffade eller inte. Detta är användbart för att frigöra resurser eller städa upp efter att programkoden har körts.throw:Du kan kasta egna undantag med throw-nyckelordet.
public void ValidateAge(int age) {
if (age < 18) {
throw new ArgumentException("Åldern måste vara minst 18.");
}
}
När throw används i koden ovan, kommer ett undantag att kastas om åldern är mindre än 18. Om detta undantag inte fångas någonstans i applikationen, kommer programmet att krascha.
C# har ett stort antal inbyggda undantagstyper som du kan fånga och hantera beroende på vilken typ av fel som uppstår. Här är några av de vanligaste:
Exception, fångar du alla typer av undantag. Det är dock en god praxis att vara så specifik som möjligt när du fångar undantag, för att inte dölja felaktiga undantag.null).Exempel på att fånga olika undantagstyper:
try {
// Kod som kan orsaka flera typer av undantag
int a = 10;
int b = 0;
int result = a / b; // Orsakar DivideByZeroException
} catch (DivideByZeroException ex) {
Console.WriteLine("Kan inte dela med noll: " + ex.Message);
} catch (Exception ex) {
// Fångar alla andra typer av undantag
Console.WriteLine("Ett annat undantag inträffade: " + ex.Message);
}
Det är viktigt att förstå skillnaden mellan fel (errors) och undantag (exceptions):
En annan viktig skillnad är att undantag är en kontrollerad mekanism som gör att du kan hantera fel på ett systematiskt sätt, medan fel ofta är okontrollerade och kan leda till att hela applikationen kraschar utan möjlighet till återhämtning.
Att hantera undantag på rätt sätt är viktigt för att skapa stabila och användarvänliga program. Här är några riktlinjer:
Fånga aldrig undantag bara för sakens skull. Om du inte kan göra något användbart för att hantera ett undantag, låt det bubbla upp till en högre nivå där det kan hanteras på ett meningsfullt sätt.
try {
// Kod som kan orsaka undantag
} catch (FileNotFoundException e) {
// Hantera specifikt fall
} catch (Exception e) {
// Återkasta om det inte går att hantera undantaget här
throw;
}
Om ditt program använder resurser som filer, databaskopplingar eller nätverksanslutningar, se till att dessa resurser alltid frigörs oavsett om ett undantag inträffar eller inte.
StreamReader reader = null;
try {
reader = new StreamReader("data.txt");
// Läs data från filen
} catch (FileNotFoundException e) {
Console.WriteLine("Filen hittades inte.");
} finally {
if (reader != null) {
reader.Close(); // Stäng filen, oavsett om ett undantag inträffade
}
}
I C# så har man förenklat detta sätt att skriva med ett reserverat ord using (som tar hand om stängning av nätverk, filer och databaskopplingar) för att slippa skriva finally. (using skapar finally-blocket utan att det syns i koden - "under huven"). Är det andra saker som behövs tas hand om så måste du skriva finally enligt ovanstående.
Så här sker felhantering med best practice (i C#) när det gäller just hantering av nätverk, filhantering och databashantering).
try {
using var reader = new StreamReader("data.txt");
} catch (FileNotFoundException) {
Console.WriteLine("Filen hittades inte.");
}
//Ingen 'finally' behövs, filen stängs automatiskt här (eftersom using används)
Ibland kan det vara meningsfullt att skapa egna undantag om du stöter på specifika fel i ditt program som inte täcks av de inbyggda undantagstyperna. Detta gör det enklare att identifiera och hantera specifika situationer.
public class InvalidAgeException : Exception {
public InvalidAgeException(string message) : base(message) {}
}
public void CheckAge(int age) {
if (age < 18) {
throw new InvalidAgeException("Åldern är för låg.");
}
}
Här är några förslag på övningar för att praktisera undantagshantering:
Fångning av inmatningsfel:
FormatException när ett tal förväntas men användaren skriver in en sträng) eller försöker dela med noll.Exempel:
try {
Console.WriteLine("Mata in ett tal:");
int num1 = int.Parse(Console.ReadLine());
Console.WriteLine("Mata in ett annat tal:");
int num2 = int.Parse(Console.ReadLine());
int result = num1 / num2;
Console.WriteLine($"Resultatet är: {result}");
} catch (FormatException e) {
Console.WriteLine("Felaktig inmatning, vänligen mata in ett heltal.");
} catch (DivideByZeroException e) {
Console.WriteLine("Kan inte dela med noll.");
} catch (Exception e) {
Console.WriteLine("Ett oväntat fel inträffade: " + e.Message);
}
Användning av using:
using.Skapa egna undantag:
OverdraftException.Efter Dag 4 kommer du ha en djup förståelse för hur undantag fungerar i C#, och du kommer att kunna skriva robust kod som kan hantera fel och undantag på ett kontrollerat sätt. Detta är en avgörande färdighet för att skapa applikationer som inte kraschar vid oväntade problem och som kan ge användaren informativa och användbara felmeddelanden.