vivanov 88f3d69b87 first commit | 10 mesiacov pred | |
---|---|---|
.gitignore.txt | 11 mesiacov pred | |
readme.md | 10 mesiacov pred |
Конспект лекции "Исключения"
Конструкция try..catch..finally, простыми словами - это замена if и else. Она подходит для записи больших условий при том условии, что код не будет выглядеть большим.
try
{
}
catch
{
}
finally
{
}
1)
Код выглядит следующим образом:
int x = 5;
int y = x / 0;
Console.WriteLine($"Результат: {y}");
Console.WriteLine("Конец программы");
Console.Read();
Код выводит следующую ошибку из-за неверного математического вычисления:
Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
at Program.<Main>$(String[] args) in C:\Users\шоумен\RiderProjects\lab8\lab8\Program.cs:line 2
Process finished with exit code -1,073,741,676.
Код выглядит следующим образом:
try
{
int x = 5;
int y = x / 0;
Console.WriteLine($"Результат: {y}");
}
catch
{
Console.WriteLine("Возникло исключение!");
}
finally
{
Console.WriteLine("Блок finally");
}
Console.WriteLine("Конец программы");
Console.Read();
Из-за неверного деления программа выведет следующее:
Возникло исключение!
Блок finally
Конец программы
Код выглядит следующим образом:
try
{
int x = 5;
int y = x / 0;
Console.WriteLine($"Результат: {y}");
}
catch
{
Console.WriteLine("Возникло исключение!");
}
Результат кода таков:
Возникло исключение!
Код выглядит следующим образом:
try
{
int x = 5;
int y = x / 0;
Console.WriteLine($"Результат: {y}");
}
finally
{
Console.WriteLine("Блок finally");
}
Результат кода таков:
Блок finally
Сейчас данная задача написана с условием, но ее можно написать и по другому для более приятного восприятия кода.
Console.WriteLine("Введите число");
int x;
string input = Console.ReadLine();
if (Int32.TryParse(input, out x))
{
x *= x;
Console.WriteLine("Квадрат числа: " + x);
}
else
{
Console.WriteLine("Некорректный ввод");
}
Console.Read();
По другому код можно записать таким образом:
Console.WriteLine("Введите число");
int x = Int32.Parse(Console.ReadLine());
x *= x;
Console.WriteLine("Квадрат числа: " + x);
Console.Read();
У блока catch есть 2 формы. Одна из них выглядит таким образом:
catch
{
// выполняемые инструкции
}
Оно обрабатывает любое исключение, которое появляется в блоке try.
Форая форма выглядит немного иначе:
catch (тип_исключения)
{
// выполняемые инструкции
}
Это блок обрабатывает только то исключение, которое соответсвтует типу, указанному в скобках. Так же если в блоке try будет другое исключение то оно не будет обработано.
Пример такой программы:
try
{
int x = 5;
int y = x / 0;
Console.WriteLine($"Результат: {y}");
}
catch(DivideByZeroException)
{
Console.WriteLine("Возникло исключение DivideByZeroException");
}
Так же есть еще один вариант, где обрабатывается только то исключение, которое соответствует типу указанных в скобках:
catch (тип_исключения имя_переменной)
{
// выполняемые инструкции
}
Пример такой программы:
try
{
int x = 5;
int y = x / 0;
Console.WriteLine($"Результат: {y}");
}
catch(DivideByZeroException ex)
{
Console.WriteLine($"Возникло исключение {ex.Message}");
}
Фильтры исключений
Фильтры, в которых после блока идет вырвжение с условием в свкобках.
catch when(условие)
{
}
Пример такой программы, которая выполняет исключение, если условие в выражении истинно:
int x = 1;
int y = 0;
try
{
int result = x / y;
}
catch(DivideByZeroException) when (y==0 && x == 0)
{
Console.WriteLine("y не должен быть равен 0");
}
catch(DivideByZeroException ex)
{
Console.WriteLine(ex.Message);
}
Типы исключений. Класс Exception
Базовый тип исключения - это тип Exception. С помощью этого типа можно получить информацию об исключении.
InnerException: хранит информацию об исключении, которое послужило причиной текущего исключения
Message: хранит сообщение об исключении, текст ошибки
Source: хранит имя объекта или сборки, которое вызвало исключение
StackTrace: возвращает строковое представление стека вызывов, которые привели к возникновению исключения
TargetSite: возвращает метод, в котором и было вызвано исключение
Пример обработки типа Exception.
try
{
int x = 5;
int y = x / 0;
Console.WriteLine($"Результат: {y}");
}
catch (Exception ex)
{
Console.WriteLine($"Исключение: {ex.Message}");
Console.WriteLine($"Метод: {ex.TargetSite}");
Console.WriteLine($"Трассировка стека: {ex.StackTrace}");
}
Console.Read();
Код выводит такой текст:
Исключение: Attempted to divide by zero.
Метод: Void <Main>$(System.String[])
Трассировка стека: at Program.<Main>$(String[] args) in C:\Users\шоумен\RiderProjects\lab8\lab8\Program.cs:line 4
Из-за того, что тип Exception является базовым типом для всех исключений, то выражение catch (Exception ex) будет обрабатывать все исключения, которые могут возникнуть:
Так же есть специализированные типы исключений, которые нужны для обработки определнных типов исключений:
DivideByZeroException: представляет исключение, которое генерируется при делении на ноль
ArgumentOutOfRangeException: генерируется, если значение аргумента находится вне диапазона допустимых значений
ArgumentException: генерируется, если в метод для параметра передается некорректное значение
IndexOutOfRangeException: генерируется, если индекс элемента массива или коллекции находится вне диапазона допустимых значений
InvalidCastException: генерируется при попытке произвести недопустимые преобразования типов
NullReferenceException: генерируется при попытке обращения к объекту, который равен null (то есть по сути неопределен)
Еще мы можем выключить дополительные блоки catch, это как else if.
Пример кода:
try
{
int[] numbers = new int[4];
numbers[7] = 9; // IndexOutOfRangeException
int x = 5;
int y = x / 0; // DivideByZeroException
Console.WriteLine($"Результат: {y}");
}
catch (DivideByZeroException)
{
Console.WriteLine("Возникло исключение DivideByZeroException");
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
В данном случае блоки catch обрабатывают исключения типов IndexOutOfRangeException и DivideByZeroException. Когда в блоке try возникнет исключение, то CLR будет искать нужный блок catch для обработки исключения. Так, в данном случае на строке
numbers[7] = 9;
происходит обращение к 7-му элементу массива. Однако поскольку в массиве только 4 элемента, то мы получим исключение типа IndexOutOfRangeException. CLR найдет блок catch, который обрабатывает данное исключение, и передаст ему управление.
Есть другая ситуация:
try
{
object obj = "you";
int num = (int)obj; // InvalidCastException
Console.WriteLine($"Результат: {num}");
}
catch (DivideByZeroException)
{
Console.WriteLine("Возникло исключение DivideByZeroException");
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("Возникло исключение IndexOutOfRangeException");
}
Console.Read();
В данном случае в блоке try генерируется исключение типа InvalidCastException, но такого блока catch не существует, поэтому программа принудительно завершится.
Мы также можем определить для InvalidCastException свой блок catch, однако суть в том, что теоретически в коде могут быть сгенерированы сами различные типы исключений. А определять для всех типов исключений блоки catch, если обработка исключений однотипна, не имеет смысла. И в этом случае мы можем определить блок catch для базового типа Exception:
try
{
object obj = "you";
int num = (int)obj; // InvalidCastException
Console.WriteLine($"Результат: {num}");
}
catch (DivideByZeroException)
{
Console.WriteLine("Возникло исключение DivideByZeroException");
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("Возникло исключение IndexOutOfRangeException");
}
catch (Exception ex)
{
Console.WriteLine($"Исключение: {ex.Message}");
}
Console.Read();
Создание классов исключений
Ограничение по возрасту
try
{
Person p = new Person { Name = "Tom", Age = 17 };
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка: {ex.Message}");
}
Console.Read();
class Person
{
private int age;
public string Name { get; set; }
public int Age
{
get { return age; }
set
{
if (value < 18)
{
throw new Exception("Лицам до 18 регистрация запрещена");
}
else
{
age = value;
}
}
}
}
Ошибка: Лицам до 18 регистрация запрещена
Поиск блока catch при обработке исключений
try
{
TestClass.Method1();
}
catch (DivideByZeroException ex)
{
Console.WriteLine($"Catch в Main : {ex.Message}");
}
finally
{
Console.WriteLine("Блок finally в Main");
}
Console.WriteLine("Конец метода Main");
Console.Read();
class TestClass
{
public static void Method1()
{
try
{
Method2();
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine($"Catch в Method1 : {ex.Message}");
}
finally
{
Console.WriteLine("Блок finally в Method1");
}
Console.WriteLine("Конец метода Method1");
}
static void Method2()
{
try
{
int x = 8;
int y = x / 0;
}
finally
{
Console.WriteLine("Блок finally в Method2");
}
Console.WriteLine("Конец метода Method2");
}
}
Блок finally в Method2
Блок finally в Method1
Catch в Main : Attempted to divide by zero.
Блок finally в Main
Конец метода Main
Генерация исключения и оператор throw
try
{
Console.Write("Введите строку: ");
string message = Console.ReadLine();
if (message.Length > 6)
{
throw new Exception(
"Длина строки больше 6 символов");
}
}
catch (Exception e)
{
Console.WriteLine($"Ошибка: {e.Message}");
}
Console.Read();
Введите строку: 1234567
Ошибка: Длина строки больше 6 символов
Проверка экземпляра типа значения, допускающего значение NULL
int? a = 42;
if (a is int valueOfA)
{
Console.WriteLine($"a is {valueOfA}");
}
else
{
Console.WriteLine("a does not have a value");
}
a is 42
int? a = 28;
int b = a ?? -1;
Console.WriteLine($"b is {b}"); // output: b is 28
int? c = null;
int d = c ?? -1;
Console.WriteLine($"d is {d}"); // output: d is -1
Операторы с нулификацией
int? a = 10;
int? b = null;
int? c = 10;
a++; // a is 11
a = a * c; // a is 110
a = a + b; // a is null
int? a = 10;
Console.WriteLine($"{a} >= null is {a >= null}");
Console.WriteLine($"{a} < null is {a < null}");
Console.WriteLine($"{a} == null is {a == null}");
// Output:
// 10 >= null is False
// 10 < null is False
// 10 == null is False
int? b = null;
int? c = null;
Console.WriteLine($"null >= null is {b >= c}");
Console.WriteLine($"null == null is {b == c}");
// Output:
// null >= null is False
// null == null is True
Упаковка-преобразование и распаковка-преобразование
Если HasValue возвращает false, создается пустая ссылка. Если HasValue возвращает true, упаковывается соответствующее значение базового типа T, а не экземпляр Nullable.
int a = 41;
object aBoxed = a;
int? aNullable = (int?)aBoxed;
Console.WriteLine($"Value of aNullable: {aNullable}");
object aNullableBoxed = aNullable;
if (aNullableBoxed is int valueOfA)
{
Console.WriteLine($"aNullableBoxed is boxed int: {valueOfA}");
}
// Output:
// Value of aNullable: 41
// aNullableBoxed is boxed int: 41
Оператор ??
object x = null;
object y = x ?? 100; // равно 100, так как x равен null
object z = 200;
object t = z ?? 44; // равно 200, так как z не равен null
Оператор условного null
class User
{
public Phone Phone { get; set; }
}
class Phone
{
public Company Company { get; set; }
}
class Company
{
public string Name { get; set; }
}
Объект User содержит ссылку на объект Phone, а объект Phone содержит ссылку на объект Company, поэтому теоретически мы можем получить из объекта User название компании, например, так:
User user = new User();
Console.WriteLine(user.Phone.Company.Name);