Exceptions (Изключения)
Exceptions в C# сигнализират за грешки по време на изпълнение. Те позволяват отделяне на кода за обработка на грешки от основната бизнес логика.
Основни видове изключения
// Често срещани изключения
ArgumentException // Невалиден аргумент
ArgumentNullException // Null аргумент
InvalidOperationException // Невалидна операция
NullReferenceException // Опит за достъп до null обект
IndexOutOfRangeException // Невалиден индекс в масив
FileNotFoundException // Файлът не е намерен
DivideByZeroException // Деление на нула
FormatException // Невалиден формат при конвертиране
Try-Catch-Finally блок
public class ExceptionHandling
{
public void ProcessFile(string path)
{
FileStream file = null;
try
{
file = File.OpenRead(path);
// Работа с файла
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"Файлът не е намерен: {ex.Message}");
}
catch (IOException ex)
{
Console.WriteLine($"Грешка при четене: {ex.Message}");
}
finally
{
file?.Dispose(); // Освобождаване на ресурси
}
}
}
Хвърляне на изключения
public class BankAccount
{
private decimal balance;
public void Withdraw(decimal amount)
{
if (amount <= 0)
{
throw new ArgumentException("Сумата трябва да е положителна");
}
if (amount > balance)
{
throw new InvalidOperationException("Недостатъчна наличност");
}
balance -= amount;
}
}
Собствени изключения
public class BusinessException : Exception
{
public int ErrorCode { get; }
public BusinessException(string message, int errorCode)
: base(message)
{
ErrorCode = errorCode;
}
public BusinessException(string message, int errorCode, Exception inner)
: base(message, inner)
{
ErrorCode = errorCode;
}
}
Exception филтри
public class ExceptionFilters
{
public void ProcessData(string data)
{
try
{
// Някаква обработка
}
catch (Exception ex) when (ex.Message.Contains("timeout"))
{
// Обработка само на timeout грешки
}
catch (Exception ex) when (IsRecoverable(ex))
{
// Обработка на поправими грешки
}
}
private bool IsRecoverable(Exception ex)
{
// Логика за определяне дали грешката е поправима
return true;
}
}
Using блок
public class ResourceManagement
{
public void ProcessFile(string path)
{
// Автоматично освобождаване на ресурси
using (var file = File.OpenRead(path))
{
// Работа с файла
} // Dispose се извиква автоматично
// C# 8.0+ синтаксис
using var reader = new StreamReader(path);
// Работа с reader
} // Dispose се извиква в края на метода
}
Async изключения
public class AsyncExceptions
{
public async Task ProcessAsync()
{
try
{
await Task.Delay(1000);
throw new Exception("Async error");
}
catch (Exception ex)
{
// Обработка на асинхронни грешки
}
}
}
Добри практики
- Специфични изключения
// Лошо
throw new Exception("Нещо се обърка");
// Добро
throw new ArgumentException("Невалидна стойност", nameof(parameter));
- Прихващане на специфични изключения
// Лошо
try { /* код */ }
catch (Exception ex) { /* всичко */ }
// Добро
try { /* код */ }
catch (FileNotFoundException ex) { /* специфична обработка */ }
catch (IOException ex) { /* специфична обработка */ }
- Запазване на stack trace
try
{
// код
}
catch (Exception ex)
{
// Запазва оригиналния stack trace
throw;
// Губи оригиналния stack trace
// throw ex; // Не правете това!
}
- Документиране на изключения
/// <summary>
/// Изтегля файл от сървъра.
/// </summary>
/// <param name="url">URL адрес на файла</param>
/// <exception cref="ArgumentNullException">Когато url е null</exception>
/// <exception cref="WebException">При проблем с мрежата</exception>
public async Task DownloadFileAsync(string url)
{
if (url == null) throw new ArgumentNullException(nameof(url));
// Код за изтегляне
}