소스 검색

исключения

Евгений Колесников 1 년 전
부모
커밋
d16868ec1d
1개의 변경된 파일32개의 추가작업 그리고 31개의 파일을 삭제
  1. 32 31
      articles/5_3_1_6_exceptions.md

+ 32 - 31
articles/5_3_1_6_exceptions.md

@@ -390,9 +390,9 @@ static void Main(string[] args)
 }
 ```
 
-В данном случае в блоке try генерируется исключение типа InvalidCastException, однако соответствующего блока catch для обработки данного исключения нет. Поэтому программа аварийно завершит свое выполнение.
+В данном случае в блоке **try** генерируется исключение типа **InvalidCastException**, однако соответствующего блока **catch** для обработки данного исключения нет. Поэтому программа аварийно завершит свое выполнение.
 
-Мы также можем определить для InvalidCastException свой блок catch, однако суть в том, что теоретически в коде могут быть сгенерированы сами различные типы исключений. А определять для всех типов исключений блоки catch, если обработка исключений однотипна, не имеет смысла. И в этом случае мы можем определить блок catch для базового типа Exception:
+Мы также можем определить для **InvalidCastException** свой блок **catch**, однако суть в том, что теоретически в коде могут быть сгенерированы сами различные типы исключений. А определять для всех типов исключений блоки **catch**, если обработка исключений однотипна, не имеет смысла. И в этом случае мы можем определить блок **catch** для базового типа **Exception**:
 
 ```cs
 static void Main(string[] args)
@@ -419,11 +419,11 @@ static void Main(string[] args)
 }
 ```
 
-И в данном случае блок `catch (Exception ex){}` будет обрабатывать все исключения кроме DivideByZeroException и IndexOutOfRangeException. При этом блоки catch для более общих, более базовых исключений следует помещать в конце - после блоков catch для более конкретный, специализированных типов. Так как CLR выбирает для обработки исключения первый блок catch, который соответствует типу сгенерированного исключения. Поэтому в данном случае сначала обрабатывается исключение DivideByZeroException и IndexOutOfRangeException, и только потом Exception (так как DivideByZeroException и IndexOutOfRangeException наследуется от класса Exception).
+И в данном случае блок `catch (Exception ex){}` будет обрабатывать все исключения кроме **DivideByZeroException** и **IndexOutOfRangeException**. При этом блоки **catch** для более общих, более базовых исключений следует помещать в конце - после блоков **catch** для более конкретный, специализированных типов. Так как CLR выбирает для обработки исключения первый блок **catch**, который соответствует типу сгенерированного исключения. Поэтому в данном случае сначала обрабатывается исключение **DivideByZeroException** и **IndexOutOfRangeException**, и только потом **Exception** (так как **DivideByZeroException** и **IndexOutOfRangeException** наследуется от класса **Exception**).
 
 ## Создание классов исключений
 
-Если нас не устраивают встроенные типы исключений, то мы можем создать свои типы. Базовым классом для всех исключений является класс Exception, соответственно для создания своих типов мы можем унаследовать данный класс.
+Если нас не устраивают встроенные типы исключений, то мы можем создать свои типы. Базовым классом для всех исключений является класс **Exception**, соответственно для создания своих типов мы можем унаследовать данный класс.
 
 Допустим, у нас в программе будет ограничение по возрасту:
 
@@ -465,9 +465,9 @@ class Person
 }
 ```
 
-В классе Person при установке возраста происходит проверка, и если возраст меньше 18, то выбрасывается исключение. Класс Exception принимает в конструкторе в качестве параметра строку, которое затем передается в его свойство Message.
+В классе **Person** при установке возраста происходит проверка, и если возраст меньше `18`, то выбрасывается исключение. Класс **Exception** принимает в конструкторе в качестве параметра строку, которое затем передается в его свойство Message.
 
-Но иногда удобнее использовать свои классы исключений. Например, в какой-то ситуации мы хотим обработать определенным образом только те исключения, которые относятся к классу Person. Для этих целей мы можем сделать специальный класс PersonException:
+Но иногда удобнее использовать свои классы исключений. Например, в какой-то ситуации мы хотим обработать определенным образом только те исключения, которые относятся к классу **Person**. Для этих целей мы можем сделать специальный класс **PersonException**:
 
 ```cs
 class PersonException : Exception
@@ -478,7 +478,7 @@ class PersonException : Exception
 }
 ```
 
-По сути класс кроме пустого конструктора ничего не имеет, и то в конструкторе мы просто обращаемся к конструктору базового класса Exception, передавая в него строку message. Но теперь мы можем изменить класс Person, чтобы он выбрасывал исключение именно этого типа и соответственно в основной программе обрабатывать это исключение:
+По сути класс кроме пустого конструктора ничего не имеет, и то в конструкторе мы просто обращаемся к конструктору базового класса **Exception**, передавая в него строку _message_. Но теперь мы можем изменить класс **Person**, чтобы он выбрасывал исключение именно этого типа и соответственно в основной программе обрабатывать это исключение:
 
 ```cs
 class Program
@@ -513,7 +513,7 @@ class Person
 }
 ```
 
-Однако необязательно наследовать свой класс исключений именно от типа Exception, можно взять какой-нибудь другой производный тип. Например, в данном случае мы можем взять тип ArgumentException, который представляет исключение, генерируемое в результате передачи аргументу метода некорректного значения:
+Однако необязательно наследовать свой класс исключений именно от типа **Exception**, можно взять какой-нибудь другой производный тип. Например, в данном случае мы можем взять тип **ArgumentException**, который представляет исключение, генерируемое в результате передачи аргументу метода некорректного значения:
 
 ```cs
 class PersonException : ArgumentException
@@ -577,7 +577,7 @@ class Program
 
 ## Поиск блока catch при обработке исключений
 
-Если код, который вызывает исключение, не размещен в блоке try или помещен в конструкцию try..catch, которая не содержит соответствующего блока catch для обработки возникшего исключения, то система производит поиск соответствующего обработчика исключения в стеке вызовов.
+Если код, который вызывает исключение, не размещен в блоке **try** или помещен в конструкцию `try...catch`, которая не содержит соответствующего блока **catch** для обработки возникшего исключения, то система производит поиск соответствующего обработчика исключения в стеке вызовов.
 
 Например, рассмотрим следующую программу:
 
@@ -641,17 +641,17 @@ namespace HelloApp
 }
 ```
 
-В данном случае стек вызовов выглядит следующим образом: метод Main вызывает метод Method1, который, в свою очередь, вызывает метод Method2. И в методе Method2 генерируется исключение DivideByZeroException. Визуально стек вызовов можно представить следующим образом:
+В данном случае стек вызовов выглядит следующим образом: метод _Main_ вызывает метод _Method1_, который, в свою очередь, вызывает метод _Method2_. И в методе _Method2_ генерируется исключение **DivideByZeroException**. Визуально стек вызовов можно представить следующим образом:
 
 ![](../img/050313.png)
 
-Внизу стека метод Main, с которого началось выполнение, и на самом верху метод Method2.
+Внизу стека метод _Main_, с которого началось выполнение, и на самом верху метод _Method2_.
 
 Что будет происходить в данном случае при генерации исключения?
 
-1. Метод Main вызывает метод Method1, а тот вызывает метод Method2, в котором генерируется исключение DivideByZeroException.
+1. Метод _Main_ вызывает метод _Method1_, а тот вызывает метод _Method2_, в котором генерируется исключение **DivideByZeroException**.
 
-2. Система видит, что код, который вызывал исключение, помещен в конструкцию try..catch
+1. Система видит, что код, который вызывал исключение, помещен в блок **try**
 
     ```cs
     try
@@ -664,9 +664,10 @@ namespace HelloApp
         Console.WriteLine("Блок finally в Method2");
     }
     ```
-    Система ищет в этой конструкции блок catch, который обрабатывает исключение DivideByZeroException. Однако такого блока catch нет.
 
-3. Система опускается в стеке вызовов в метод Method1, который вызывал Method2. Здесь вызов Method2 помещен в конструкцию try..catch
+    Система ищет в этой конструкции блок **catch**, который обрабатывает исключение **DivideByZeroException** (или базовый класс исключений **Exception**). Однако такого блока **catch** нет.
+
+1. Система опускается в стеке вызовов в метод _Method1_, который вызывал _Method2_. Здесь вызов _Method2_ помещен в блок **try**
 
     ```cs
     try
@@ -683,9 +684,9 @@ namespace HelloApp
     }
     ```
 
-    Система также ищет в этой конструкции блок catch, который обрабатывает исключение DivideByZeroException. Однако здесь также подобный блок catch отсутствует.
+    Система также ищет в этой конструкции блок **catch**, который обрабатывает исключение **DivideByZeroException**. Однако здесь также подобный блок **catch** отсутствует.
 
-4. Система далее опускается в стеке вызовов в метод Main, который вызывал Method1. Здесь вызов Method1 помещен в конструкцию try..catch
+1. Система далее опускается в стеке вызовов в метод _Main_, который вызывал _Method1_. Здесь вызов _Method1_ помещен в блок **try**
 
     ```cs
     try
@@ -701,9 +702,9 @@ namespace HelloApp
         Console.WriteLine("Блок finally в Main");
     }
     ```
-    Система снова ищет в этой конструкции блок catch, который обрабатывает исключение DivideByZeroException. И в данном случае ткой блок найден.
+    Система снова ищет в этой конструкции блок **catch**, который обрабатывает исключение **DivideByZeroException**. И в данном случае ткой блок найден.
 
-5. Система наконец нашла нужный блок catch в методе Main, для обработки исключения, которое возникло в методе Method2 - то есть к начальному методу, где непосредственно возникло исключение. Но пока данный блок catch НЕ выполняется. Система поднимается обратно по стеку вызовов в самый верх в метод Method2 и выполняет в нем блок finally:
+1. Система наконец нашла нужный блок **catch** в методе _Main_, для обработки исключения, которое возникло в методе _Method2_ - то есть к начальному методу, где непосредственно возникло исключение. Но пока данный блок **catch** НЕ выполняется. Система поднимается обратно по стеку вызовов в самый верх в метод _Method2_ и выполняет в нём блок **finally**:
 
     ```cs
     finally
@@ -712,7 +713,7 @@ namespace HelloApp
     }
     ```
 
-6. Далее система возвращается по стеку вызовов вниз в метод Method1 и выполняет в нем блок finally:
+1. Далее система возвращается по стеку вызовов вниз в метод _Method1_ и выполняет в нём блок **finally**:
 
     ```cs
     finally
@@ -721,7 +722,7 @@ namespace HelloApp
     }
     ```
 
-7. Затем система переходит по стеку вызовов вниз в метод Main и выполняет в нем найденный блок catch и последующий блок finally:
+1. Затем система переходит по стеку вызовов вниз в метод _Main_ и выполняет в нём найденный блок **catch** и последующий блок **finally**:
 
     ```cs
     catch (DivideByZeroException ex)
@@ -733,13 +734,14 @@ namespace HelloApp
         Console.WriteLine("Блок finally в Main");
     }
     ```
-8. Далее выполняется код, который идет в методе Main после конструкции try..catch:
+
+1. Далее выполняется код, который идет в методе _Main_ после конструкции `try...catch`:
 
     ```cs
     Console.WriteLine("Конец метода Main");
     ```
 
-    Стоит отметить, что код, который идет после конструкции try...catch в методах Method1 и Method2, не выполняется, потому что обработчик исключения найден именно в методе Main.
+    Стоит отметить, что код, который идет после конструкции `try...catch` в методах _Method1_ и _Method2_, не выполняется, потому что обработчик исключения найден именно в методе _Main_.
 
 Консольный вывод программы:
 
@@ -753,9 +755,9 @@ Catch в Main: Попытка деления на нуль.
 
 ## Генерация исключения и оператор throw
 
-Обычно система сама генерирует исключения при определенных ситуациях, например, при делении числа на ноль. Но язык C# также позволяет генерировать исключения вручную с помощью оператора throw. То есть с помощью этого оператора мы сами можем создать исключение и вызвать его в процессе выполнения.
+Обычно система сама генерирует исключения при определенных ситуациях, например, при делении числа на ноль. Но язык **C#** также позволяет генерировать исключения вручную с помощью оператора **throw**. То есть с помощью этого оператора мы сами можем создать исключение и вызвать его в процессе выполнения.
 
-Например, в нашей программе происходит ввод строки, и мы хотим, чтобы, если длина строки будет больше 6 символов, возникало исключение:
+Например, в нашей программе происходит ввод строки, и мы хотим, чтобы, если длина строки будет больше `6` символов, возникало исключение:
 
 ```cs
 static void Main(string[] args)
@@ -777,11 +779,11 @@ static void Main(string[] args)
 }
 ```
 
-После оператора throw указывается объект исключения, через конструктор которого мы можем передать сообщение об ошибке. Естественно вместо типа Exception мы можем использовать объект любого другого типа исключений.
+После оператора **throw** указывается объект исключения, через конструктор которого мы можем передать сообщение об ошибке. Естественно вместо типа **Exception** мы можем использовать объект любого другого типа исключений.
 
-Затем в блоке catch сгенерированное нами исключение будет обработано.
+Затем в блоке **catch** сгенерированное нами исключение будет обработано.
 
-Подобным образом мы можем генерировать исключения в любом месте программы. Но существует также и другая форма использования оператора throw, когда после данного оператора не указывается объект исключения. В подобном виде оператор throw может использоваться только в блоке catch:
+Подобным образом мы можем генерировать исключения в любом месте программы. Но существует также и другая форма использования оператора **throw**, когда после данного оператора не указывается объект исключения. В подобном виде оператор **throw** может использоваться только в блоке **catch**:
 
 ```cs
 try
@@ -807,10 +809,9 @@ catch (Exception ex)
 }
 ```
 
-В данном случае при вводе строки с длиной больше 6 символов возникнет исключение, которое будет обработано внутренним блоком catch. Однако поскольку в этом блоке используется оператор throw, то исключение будет передано дальше внешнему блоку catch.
-
+В данном случае при вводе строки с длиной больше `6` символов возникнет исключение, которое будет обработано внутренним блоком **catch**. Однако поскольку в этом блоке используется оператор **throw**, то исключение будет передано дальше (проброшено) внешнему блоку **catch**.
 
-# Методы поиска ошибок в программах
+## Методы поиска ошибок в программах
 
 Международный стандарт ANSI/IEEE-729-83 разделяет все ошибки в разработке программ на следующие типы.