Главная | Обратная связь
МегаЛекции

Catching Exceptions at the Most Appropriate Place





Using (reader)

{

int lineNumber = 0;

// Read first line from the text file

string line = reader.ReadLine();

// Read the other lines from the text file

while (line != null)

{

lineNumber++;

Console.WriteLine("Line {0}: {1}", lineNumber, line);

line = reader.ReadLine();

}

}

}

дирования символов и несколько схем кодирования символов, таких как UTF-8 и Windows-1251, из раздела «Схемы кодирования» главы «Системы счисления и представление данных», а также из раздела «Кодировки файлов в Visual Studio». главы "Определение классов". Теперь мы немного расширим эту концепцию и будем использовать кодировки символов для правильной работы с текстовыми файлами.

 

Reading a Cyrillic Content

You probably already guessed that if we want to read from a file that contains characters from the Cyrillic alphabet, we must use the correct encoding that "understands" correctly these special characters. Typically, in a Windows environment, text files, containing Cyrillic text, are stored in Windows-1251 encoding. To use it, we should set it as the encoding of the stream, which our StreamReader will process: Encoding win1251 = Encoding.GetEncoding("Windows-1251"); StreamReader reader = new StreamReader("test.txt", win1251);
Стандарт Юникода. Чтение в ЮникодеUnicode - это отраслевой стандарт, который позволяет компьютерам и другим электронным устройствам всегда представлять и манипулировать текстом, который был написан в большинстве мировых литературных источников. Он состоит из более чем 100 000 символов, а также различных схем кодирования (кодировок). Объединение различных символов, которые предлагает Unicode, приводит к его большему распространению. Как вы знаете, символы в C # (типы char и string) также представлены в Unicode.Чтобы читать символы, хранящиеся в Unicode, мы должны использовать одну из поддерживаемых схем кодирования для этого стандарта. Самым популярным и широко используемым является UTF-8. Мы можем установить его как схему кода уже знакомым способом:

Writing to a Text File

Text files are very convenient for storing various types of information. For example, we can record the results of a program. We can use text files to make something like a journal (log) for the program – a convenient way to monitor it at runtime.

Again, as with reading a text file, we will use a similar to the Console class when writing, called StreamWriter.

The StreamWriter Class

The class StreamWriter is part of the System.IO namespace and is used exclusively for working with text data. It resembles the class StreamReader, but instead of methods for reading, it offers similar methods for writing to a text file. Unlike other streams, before writing data to the desired destination, StreamWriter turns it into bytes. StreamWriter enables us to set a preferred character encoding at the time it is created. We can create an instance of the class the following way: StreamWriter writer = new StreamWriter("test.txt");



Предположим, файл находится на удаленном сервере, и в процессе его чтения соединение обрывается. Файл будет загружен только частично. Программа не сможет нормально работать и показывать содержимое файла на экране. В этом случае мы имеем исключение из нормального (и правильного) выполнения программы, и об этом исключении необходимо сообщить пользователю и / или администратору.Исключением является уведомление о том, что что-то прерывает нормальное выполнение программы. Исключения обеспечивают парадигму программирования для обнаружения и реагирования на неожиданные события. Когда возникает исключение, состояние программы сохраняется, нормальный поток прерывается, и управление передается обработчику исключения (если таковой существует в текущем контексте).Исключения вызываются или генерируются программным кодом, который должен послать исполняющей программе сигнал об ошибке или необычной ситуации. Например, если мы попытаемся открыть файл, который не существует, код, ответственный за открытие файла, обнаружит это и выдаст исключение с соответствующим сообщением об ошибке. Исключения являются одной из основных парадигм объектно-ориентированного программирования (ООП), которая подробно описана в главе «Принципы объектно-ориентированного программирования».Ловля и Обработка ИсключенийОбработка исключений - это механизм, который позволяет создавать и перехватывать исключения. Этот механизм предоставляется внутри CLR (Common Language Runtime). Части инфраструктуры обработки исключений - это языковые конструкции в C # для создания и перехвата исключений. CLR заботится о распространении каждого исключения в коде, который может его обработать.Исключения в объектно-ориентированном программированииВ объектно-ориентированном программировании (ООП) исключения являются мощным механизмом централизованной обработки ошибок и исключительных ситуаций. Этот механизм заменяет процедурно-ориентированный метод обработки ошибок, в котором каждая функция возвращает код, указывающий на ошибку или успешное выполнение.Обычно в ООП код, выполняющий какую-либо операцию, вызывает исключение, если есть проблема и операция не может быть успешно завершена. Метод, вызывающий операцию, может перехватить исключение (и обработать ошибку) или передать исключение вызывающему методу. Это позволяет делегировать обработку ошибок какому-либо верхнему уровню в стеке вызовов и в целом позволяет гибко управлять ошибками и непредвиденными ситуациями.Другое фундаментальное понятие - иерархия исключений. В ООП исключения являются классами, и они могут наследоваться для построения иерархий. Когда исключение обрабатывается (перехватывается), механизм обработки может перехватывать целый класс исключений, а не только конкретную ошибку (как в традиционном процедурном программировании).
о типе ошибки, месте в программе, где произошла ошибка, а также о состоянии программы в момент ошибки. Каждое исключение в .NET содержит так называемую трассировку стека, которая дает информацию о том, где именно произошла ошибка. Это будет обсуждаться более подробно позже в этой главе

Catching Exceptions in C#

After a method throws an exception, CLR is looking for an exception handler that can process the error. To understand how this works, we will take a closer look on the concept of a call-stack. The program call-stack is a stack structure that holds information about method calls, their local variables, method parameters and the memory for value types.

.NET programs start from the Main(…) method, which is the entry point of the program. Another method, let’s name it "Method 1" could be called from Main. Let "Method 1" call "Method 2" and so on until "Method N" is called.

When "Method N" finishes, the program flow returns back to its calling method (in our example it would be "Method N-1"), then back to its calling method and so on. This goes on until the Main(…) method is reached. Once Main(…) finishes, the entire program exits.

The general principle is that when a new method is called, it is pushed on top of the stack. When the method finishes, it is pulled back from the stack. At any given point in time, the call-stack contains all the methods called during the execution – from the starting method Main(…) to the last В разработке программного обеспечения хорошей практикой для каждого программного компонента является определение небольшого числа конкретных исключений приложений. В этом случае компонент будет генерировать только эти конкретные исключения приложения, а не стандартные исключения .NET. Таким образом, пользователи компонента программного обеспечения будут знать, что могут ожидать от него исключения.Например, если у нас есть банковское программное обеспечение и у нас есть компонент, связанный с интересами, этот компонент будет определять (и выбрасывать) исключения, такие как InterestCalculationException и InvalidPeriodException. Компонент интереса не должен генерировать исключения, такие как FileNotFoundException, DivideByZeroException и NullReferenceException. При возникновении ошибки, которая не имеет прямого отношения к расчету процентов, соответствующая акие исключения нужно обрабатывать, а какие нет?Существует одно универсальное правило, касающееся обработки исключений:Метод должен обрабатывать только те исключения, которые он ожидает и которые он знает, как обрабатывать. Все остальные исключения должны быть оставлены вызывающему методу.Если мы следуем этому правилу и каждый метод оставляет исключения, которые он не может обработать, вызывающему методу, в конце концов мы бы достигли метода Main () (или метода запуска соответствующего потока выполнения), и если этот метод не перехватывает исключение, CLR будет отображать ошибку Каждый блок try может содержать соответствующий блок finally. Код в блоке finally всегда выполняется независимо от того, как поток программы покидает блок try. Это гарантирует, что блок finally будет выполнен, даже если выдается исключение или в блоке try выполняется оператор return.Код в блоке finally не будет выполнен, если во время выполнения блока try CLR неожиданно завершится, например, если мы остановим программу через диспетчер задач Windows.Основная форма блока finally приведена ниже:

 

огда мы должны использовать try-finally?Во многих приложениях нам приходится работать с внешними для наших программ ресурсами. Примерами внешних ресурсов являются файлы, сетевые подключения, графические элементы, каналы и потоки к различным аппаратным устройствам (например, к принтерам, карт-ридерам и т. Д.). Когда мы имеем дело с такими внешними ресурсами, крайне важно высвободить ресурсы как можно раньше, когда ресурс больше не нужен. Например, когда мы открываем файл для чтения его содержимого (скажем, для загрузки изображения JPG), мы должны закрыть файл сразу после того, как прочитали содержимое. Если мы оставим файл открытым, операционная система не позволит другим пользователям и приложениям выполнять определенные операции с файлом. Возможно, вы столкнулись с такой ситуацией, когда вы не можете удалить какой-либо каталог или файл, потому что он используется запущенным процессом.


Блок finally бесценен, когда нам нужно освободить внешний ресурс или выполнить любую другую очистку. Блок finally гарантирует, что операции очистки не будут случайно пропущены из-за непредвиденного исключения или из-за выполнения return, continue или break. Поскольку правильное управление ресурсами является важной концепцией в программировании, мы рассмотрим его более подробно. Очистка ресурса - определение проблемы В нашем примере мы хотим прочитать файл. Для этого у нас есть читатель, который должен быть закрыт, когда файл был прочитан. Лучший способ сделать это - окружить линии, используя ридер в блоке try-finally. Вот обновление того, как выглядит наш пример:

The hierarchical nature of exceptions allows us to catch and handle whole groups of exceptions at one time. When using catch we are not only catching the given type of exception but the whole hierarchy of exception types that are inheritors of the declared type.

catch (IOException e)

{

// Handle IOException and all its descendants

}

The example above will catch not only the IOException, but all of its descendants including FileNotFoundException

Catching Exceptions at the Most Appropriate Place

The ability to catch exceptions at multiple locations is extremely comfortable. It allows us to handle the exception at the most appropriate place. Let’s demonstrate this with a simple comparison with the old approach using error codes. Let’s have the following method structure

Method3()

{

Method2();

}

Method2()

{

Method1();

}

Method1()

{

ReadFile();

}

The method Method3() calls Method2(), which calls Method1() where ReadFile() is called. Let’s suppose that Method3() is the method interested in eventual error in the ReadFile() method. If such error occurs in ReadFile() it wouldn’t be easy to transfer the error to Method3() using the traditional approach with error codes:

int Method2()

{

errorCode = Method1();

if (errorCode != 0)

return errorCode;

else

DoTheActualWork();

}

int Method1()

{

errorCode = ReadFile();

if (errorCode != 0)

return errorCode;

else

DoTheActualWork();

}

First in Method1() we have to analyze the error code returned by ReadFile() method and eventually pass it to Method2(). In Method2() we have to analyze the error code returned by Method1() and eventually pass it to Method3() where to handle the error itself.

How can we avoid all this? Let’s remember that that the CLR searches for exceptions back in the call stack of the methods and lets each of them to define catching and handling of the exceptions. If the method is not interested in catching some exception it is simply sent back in the stack:

 

void Method3()

{

try

{

Method2();

}

catch (Exception e)

{

process the exception;

}

}

void Method2()

{

Method1();

}

void Method1()

{

ReadFile();

}

Лучшие практики при использовании исключений

В этом разделе мы дадим некоторые рекомендации и рекомендации по правильному использованию исключений для обработки ошибок и непредвиденных ситуаций. Это важные правила, которые следует запомнить и соблюдать.

Когда полагаться на исключения?

Чтобы понять, когда стоит полагаться на исключения, давайте рассмотрим следующий пример: у нас есть программа, которая открывает файл по заданному пути и имени файла. Во время записи пользователь может написать неправильное имя файла. Это скорее следует считать нормальным, а не исключительным.

Мы можем подготовиться и сначала проверить, существует ли файл, прежде чем пытаться открыть его:

static void ReadFile(string fileName)

{

if (!File.Exists(fileName))

{

Console.WriteLine(

"The file '{0}' does not exist.", fileName);

return;

}

StreamReader reader = new StreamReader(fileName);

using (reader)

{

while (!reader.EndOfStream)

{

string line = reader.ReadLine();

Console.WriteLine(line);

}

}

}


Бросать исключения для конечного пользователя? Исключения сбивают с толку для большинства пользователей. Они создают впечатление плохо написанной программы, в которой «есть ошибки». Что подумает пользователь нашего приложения, вводящего счета, если вдруг программа покажет этот диалог?

Это хороший способ показать сообщение об ошибке конечному пользователю. Сообщение легко понять от пользователя, а также содержит технические детали, которые могут быть использованы при необходимости, но не видны в начале.Рекомендуется, чтобы исключения были никем не перехвачены (такие исключения могут быть только ошибками времени выполнения), чтобы их перехватывал глобальный обработчик исключений, который сохраняет их на диске и показывает удобное для пользователя сообщение, такое как «Произошла ошибка, повторите попытку позже» , Хорошей практикой является показ не только удобного для пользователя сообщения, но и технической информации (трассировки стека), доступной по запросу (например, через дополнительную кнопку или ссылку).

Бросайте исключения на соответствующем уровне абстракции!

Когда мы бросаем наши собственные исключения, мы должны помнить об абстракциях в контексте наших методов. Например, если наш метод работает с массивами, мы можем выбросить IndexOutOfRangeException или NullReferenceException, поскольку наш метод работает на низком уровне и напрямую работает с памятью и элементами массива. Но если наш метод осуществляет накопление процентов на всех счетах в банке, он не должен генерировать исключение IndexOutOfRangeException, поскольку это исключение не относится к бизнес-сфере банковского сектора. Нормальным накоплением процентов в банковском программном обеспечении было бы генерировать исключение InvalidInterestException с соответствующим сообщением об ошибке, в которое должно быть добавлено исходное исключение IndexOutOfRangeException.

Давайте приведем другой пример: мы вызываем метод, который сортирует массив целых чисел и выдает исключение TransactionAbortedException. Это также неуместное исключение, так же как NullReferenceException при накоплении интересов в банковском программном обеспечении. Вот почему мы должны учитывать уровень абстракции, на котором работает наш метод, когда мы генерируем наше исключение.

 

Всегда выдавайте адекватное, подробное и правильное сообщение об ошибке при выдаче исключений! Пользователь вашего кода должен быть в состоянии сказать, что и где проблема, и что вызвало ее при чтении сообщения об ошибке.





Рекомендуемые страницы:

Воспользуйтесь поиском по сайту:
©2015- 2019 megalektsii.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.