<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=385961&amp;view=findpost&amp;p=3400090</guid>
        <pubDate>Sat, 18 Jan 2014 19:05:09 +0000</pubDate>
        <title>Обработка ошибок в C#</title>
        <link>https://forum.sources.ru/index.php?showtopic=385961&amp;view=findpost&amp;p=3400090</link>
        <description><![CDATA[Craft: Статья посвящена способам обработки ошибок, а также превентировании некоторых видов ошибок при программировании на языке C#. Первой ошибкой рассмотрим пример, в котором генерации ошибки происходит в цепочке событий. Рассмотрим пример подписки нескольких обработчиков событий, один из которых генерирует исключение.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">class Program</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;static void Main(string[] args)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;var p = new Program();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;p.CreatePublisher();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.ReadLine();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;public void CreatePublisher()</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var publisher = new Publisher();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.OnPublish += (sender, args) =&#62; Console.WriteLine(&quot;Publisher 1&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.OnPublish += (sender, args) =&#62; Console.WriteLine(&quot;Publisher 2&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.OnPublish += (sender, args) =&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new Exception(&quot;Throw publisher exception&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;};</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.OnPublish += (sender, args) =&#62; Console.WriteLine(&quot;Publisher 3&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.Raise();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;catch (Exception exception)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(exception);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">}</div><div class="code_line">public class Publisher</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;public event EventHandler OnPublish = delegate { };</div><div class="code_line">&nbsp;&nbsp; &nbsp;public void Raise()</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;OnPublish(this, new EventArgs());</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">}</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
Выше приведен пример кода, в котором в одном из цепочки событий генерируется exception. Возникает вопрос: будет ли продолжено выполнение кода после того, как мы перехватим это исключение? Если Вы предполагали, что будет вызвано три подписчика событий, один из которых перехвачен и вызывает исключение, то у меня для вас плохая новость. Если вызванный метод выбрасывает исключение, выполнение этого метода прекращается, исключение передается обратно коду, вызвавшему делегат, – и оставшиеся в списке вызовов методы не вызываются. Перехват исключения в вызывающем коде не меняет этого поведения. Чтобы как-то изменить это поведение, есть несколько вариантов: поискать готовое решение, которое может основываться на замене событий, например, использование паттерна &quot;Publisher-&gt;Subscriber&quot;, либо использование классического паттерна &quot;Наблюдатель&quot; (Observer). <br>
К счастью, решение без использования паттернов, позволяющее решить данную проблему (правда, не столь элегантное), существует. Решение данной проблемы основано на использовании метода <a class='tag-url' href='http://msdn.microsoft.com/ru-ru/library/system.delegate.getinvocationlist(v=vs.110).aspx' target='_blank'>Delegate.GetInvocationList</a>, который возвращает массив делегатов, представляющих список вызовов текущего делегата. Поскольку событие (event) – это обертка над MulticastDelegate, благодаря ключевому слову event, у события имеются некоторые дополнительные возможности. Рассмотрим, как будет выглядеть наше решение.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">class Program</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;static void Main(string[] args)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;var p = new Program();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;p.CreatePublisher();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.ReadLine();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;public void CreatePublisher()</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var publisher = new Publisher();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.OnPublish += (sender, args) =&#62; Console.WriteLine(&quot;Publisher 1&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.OnPublish += (sender, args) =&#62; Console.WriteLine(&quot;Publisher 2&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.OnPublish += (sender, args) =&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new Exception(&quot;Throw publisher exception&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;};</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.OnPublish += (sender, args) =&#62; Console.WriteLine(&quot;Publisher 3&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;publisher.Raise();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;catch (Exception exception)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(exception);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">}</div><div class="code_line">public class Publisher</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;public event EventHandler OnPublish = delegate { };</div><div class="code_line">&nbsp;&nbsp; &nbsp;public void Raise()</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;var exceptions = new List&#60;Exception&#62;();</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;foreach (var handler in OnPublish.GetInvocationList())</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;handler.DynamicInvoke(this, new EventArgs());</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;catch (Exception ex)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;exceptions.Add(ex);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (exceptions.Any())</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new AggregateException(exceptions);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">}</div></ol></div></div></div></div><br>
Это способ обработки всех событий без прерывания цепочки событий.<br>
<br>
<span class='tag-size' data-value='14' style='font-size:14pt;'><strong class='tag-b'>Try/finally block</strong></span><br>
Наверное, все знают об использовании блока try/catch для перехвата ошибок при выполнении программы. Еще одной важной особенностью обработки исключений является возможность указать, что определенный код всегда должен быть запущен в случае исключения. Это может быть сделано с помощью блока <em class='tag-i'>finally</em> вместе с блоками <em class='tag-i'>try</em> или <em class='tag-i'>try/catch</em>. Можем ли мы быть уверены в том, что блок <em class='tag-i'>finally</em> выполнится всегда? Рассмотрим пример использования данного блока.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">private static void Main(string[] args)</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;var zero = 0;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;var a = 2/zero;</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;catch (DivideByZeroException exception)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(exception);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;finally</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(&quot;Finally block&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Console.ReadLine();</div><div class="code_line">}</div></ol></div></div></div></div><br>
Это слишком надуманный пример. Обычно блок finally используют, чтобы освободить ресурсы, используемые программой, сделать отписку от событий и т.д. Рассмотрим пример, который Вы, вероятно, встречали не раз или видели похожий способ очистки ресурсов.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">private static void Main(string[] args)</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;FileStream fs = null;</div><div class="code_line">&nbsp;&nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;fs = new FileStream(Path.Combine(Directory.GetCurrentDirectory(), &quot;test.txt&quot;), FileMode.OpenOrCreate);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;fs.Write(new byte[] {1, 2, 3, 4}, 0, 4);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;catch (IOException exception)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(exception);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;finally</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if(fs != null)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fs.Close();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Console.ReadLine();</div><div class="code_line">}</div></ol></div></div></div></div><br>
Вы могли видеть подобный код для выгрузки отдельного домена, отписки от событий, обнуления ссылок и т.д. Если Ваш класс реализует интерфейс <em class='tag-i'>IDisposable</em>, то вызов метода <em class='tag-i'>try/finally</em> можно переписать, заменив конструкцией <em class='tag-i'>using</em>. Рассмотрим, как изменится код, приведенный выше.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">private static void Main(string[] args)</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;var file = Path.Combine(Directory.GetCurrentDirectory(), &quot;test.txt&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;using (var fs = new FileStream(file, FileMode.OpenOrCreate))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fs.Write(new byte[] {1, 2, 3, 4}, 0, 4);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;catch (IOException exception)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(exception);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;Console.ReadLine();</div><div class="code_line">}</div></ol></div></div></div></div><br>
В оригинале конструкция приобрела такой вид:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">try</div><div class="code_line">&nbsp;&nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp;finally</div><div class="code_line">catch</div></ol></div></div></div></div><br>
Как видим, блок finally позволяет почистить мусор и освободить ресурсы.  Но всё ещё остается открытым вопрос, всегда ли будет гарантирован вызов блока finally. К сожалению, вызов блока <em class='tag-i'>finally</em> не всегда гарантирован. Одной из таких ситуаций является та, в которой в блоке <em class='tag-i'>try</em> происходит вызов бесконечного цикла. Иногда нужно иметь возможность корректно завершить приложение самому, записав при этом информацию в event log. В .NET 4.0 появился метод <a class='tag-url' href='http://msdn.microsoft.com/ru-ru/library/ms131100(v=vs.100).aspx' target='_blank'>Environment.FailFast</a>, который позволяет завершить процесс сразу после записи сообщения в журнал событий Windows, после чего включает сообщение в отчет об ошибках, отправляемый в корпорацию Майкрософт. Этот метод завершает процесс, минуя активные блоки <em class='tag-i'>try/finally</em> и методы-финализаторы. Метод <a class='tag-url' href='http://msdn.microsoft.com/ru-ru/library/ms131100(v=vs.100).aspx' target='_blank'>FailFast</a> записывает строку message в журнале событий Windows-приложения, создает дамп приложения и затем завершает текущий процесс. Строка message также включена в отчет об ошибках для корпорации Майкрософт. Метод <a class='tag-url' href='http://msdn.microsoft.com/ru-ru/library/ms131100(v=vs.100).aspx' target='_blank'>FailFast</a> используется для завершения работы приложения вместо метода Exit, если повреждение состояния приложения не подлежит восстановлению, а выполнение блоков <em class='tag-i'>try/finally</em> и методов завершения для этого приложения приведет повреждению ресурсов программы.<br>
<strong class='tag-b'>Примечание:</strong> довольно интересный метод для записи информации в event log добавила компания Microsoft в .NET 4.0. Сама компания рекомендует использовать этот метод для отладки приложения. К сожалению, я так и не смог представить, где может понадобиться такое чудо и чем эта новая фишка лучше старого доброго метода Exit, в который можно передать код выхода и при необходимости его обработать.<br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='14' style='font-size:14pt;'>ApplicationException vs Exception</span></strong><br>
Если в своих приложениях Вы используете для ошибок класс ApplicationException, задумайтесь о том, чтобы от него отказаться. Использование создания  такого типа ошибок в приложении бессмысленно и не несет никакой смысловой нагрузки. Вот что говорится об этом в Framework Design Guidelines:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Do not throw or derive from System.ApplicationException.<br>
JEFFREY RICHTER: System.ApplicationException is a class that should not be part of the .NET Framework. The original idea was that classes derived from SystemException would indicate exceptions thrown from the CLR (or system) itself, whereas non-CLR exceptions would be derived from ApplicationException. However, a lot of exception classes didn’t follow this pattern. For example, TargetInvocationException (which is thrown by the CLR) is derived from ApplicationException. So, the ApplicationException class lost all meaning. The reason to derive from this base class is to allow some code higher up the call stack to catch the base class. It was no longer possible to catch all application exceptions.</div></div><br>
Джефри Рихтер рекомендует исключить этот класс с .NET, так как он не выполняет своей основной роли: разделить ошибки, которые бросаются исполняющей средой CLR, от ошибок несистемных (non-clr). Ошибки, которые генерируются средой CLR, должны наследоваться от SystemException; все остальные – от ApplicationException. Но поскольку в самом .NET Framework такого принципа не поддерживается, например, класс TargetInvocationException, то попытка словить ApplicationException потеряла всякий смысл. Вот что об этом пишет компания Microsoft:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>&quot;При разработке приложения, которому требуется создать свои собственные исключения, необходимо создать пользовательские исключения из класса Exception. Изначально предполагалось, что пользовательские исключения должны наследовать от класса ApplicationException, однако на практике это не имеет особого значения. Для получения дополнительной информации см. <a class='tag-url' href='http://msdn.microsoft.com/ru-ru/library/seyhszts(v=vs.110).aspx' target='_blank'>Лучшие методики обработки исключений</a> &quot;.</div></div><br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='14' style='font-size:14pt;'>NullReferenceException vs ArgumentNullException</span></strong><br>
Избегайте использования в коде явного вызова NullReferenceException. Если аргумент пустой и контракт метода запрещает пустые аргументы, бросайте исключение ArgumentNullException. Так Вы сможете отделить те ошибки, которые бросаете от системных ошибок. Например, если в какой-то метод Вы передали null, сами того не подозревая, и пытались его использовать. Понять, кто бросил такой тип ошибки – Вы или система – порой бывает очень трудно. Но при использовании ArgumentNullException такой проблемы не возникнет.<br>
<br>
<strong class='tag-b'><span class='tag-size' data-value='14' style='font-size:14pt;'>Обработка ошибок при использовании тасков</span></strong><br>
Если Вы знакомы с классом Task и моделью TPL (Task Parallel Library) при проектировании и разработке приложений, то Вы, наверное, уже сталкивались с обработкой ошибок в ней. Если Вам не приходилось обрабатывать возникшие ошибки при некорректном завершении задания или если оно не выполнилось по какой-то причине, то Вам очень повезло. Но для готовности к разным неожиданностям рекомендую посмотреть, как обрабатывать такие ошибки.<br>
Если таск бросил ошибку, то его выполнение прекращено. Ошибка таска сохраняется как часть <strong class='tag-b'>AggregateException</strong> (AE) и хранится в объекте таска Exception (E) проперти. AE пробрасывается на функции.Wait, .Result или .WaitAll. Рассмотрим пример обработки ошибок.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">internal class Program</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;private static void Main(string[] args)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;try</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var task1 = Task.Factory.StartNew&#60;int&#62;(Method1);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var result = task1.Result;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;catch (AggregateException ae)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(ae.InnerException.Message);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.ReadLine();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private static int Method1()</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;throw new NotImplementedException();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">}</div></ol></div></div></div></div><br>
Чтобы отобразить все ошибки, которые привели к выбросу ошибки, нужно вызвать метод <strong class='tag-b'>Flatten()</strong>.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">try</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;var task1 = Task.Factory.StartNew&#60;int&#62;(Method1);</div><div class="code_line">&nbsp;&nbsp; &nbsp;var result = task1.Result;</div><div class="code_line">}</div><div class="code_line">catch (AggregateException ae)</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;var exceptions = ae.Flatten();</div><div class="code_line">&nbsp;&nbsp; &nbsp;foreach (var exception in exceptions.InnerExceptions)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(exception.Message);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">}</div></ol></div></div></div></div><br>
Правила работы с ошибками при использовании тасков (Exception handling design):<ul class="tag-list"><li>при использовании методов .Wait, .Result или .WaitAll нужно обрамлять в блок try/catch;</li><li>чтобы отловить необработанные критические ошибки при вызове тасков, выполнить подписку на TaskScheduler.UnobservedTaskException.</li></ul>Но при работе с тасками существует еще один подход к обработке ошибок. Если нужно выполнить какую-то логику именно для тасков, которые прокинули ошибки, можно воспользоваться другим подходом на основе метода <strong class='tag-b'>.ContinueWith</strong>. Рассмотрим, как можно использовать такой подход.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">var task1 = Task.Factory.StartNew&#60;int&#62;(Method1);</div><div class="code_line">var failedTask = task1.ContinueWith(task =&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(&quot;Call failed task&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;//TODO Write some logic</div><div class="code_line">&nbsp;&nbsp; &nbsp;}, TaskContinuationOptions.OnlyOnFaulted);</div><div class="code_line">var successTask = task1.ContinueWith(task =&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;var result = task.Result;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(result);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}, TaskContinuationOptions.NotOnFaulted);</div></ol></div></div></div></div><br>
В данном подходе наблюдается явное разделение тех функций, выполненных успешно, от тех, которые бросили ошибку. Но есть один тип ошибок, который, по сути, ошибкой не является. Это exception OperationCanceledException. Этот тип ошибки вызывается в том случае, если пользователь отменил выполнение таска. Более детально с этим можно ознакомиться в статье <a class='tag-url' href='http://sonyks2007.blogspot.com/2013/11/c_11.html' target='_blank'>Отмена задач (Taskcancellation)</a>, в которой речь идет об использовании класса Task и об отмене операций пользователем. Рассмотрим небольшой пример с обработкой OperationCanceledException.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">var tokenSource = new CancellationTokenSource();</div><div class="code_line">CancellationToken ct = tokenSource.Token;</div><div class="code_line">var task = Task.Factory.StartNew(() =&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;//TODO write some code in loop</div><div class="code_line">&nbsp;&nbsp; &nbsp;if (ct.IsCancellationRequested)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ct.ThrowIfCancellationRequested();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">}, tokenSource.Token); // Pass same token to StartNew.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; </div><div class="code_line">//Cancel method</div><div class="code_line">tokenSource.Cancel();</div><div class="code_line">&nbsp;</div><div class="code_line">// Just continue on this thread, or Wait/WaitAll with try-catch:</div><div class="code_line">try</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;task.Wait();</div><div class="code_line">}</div><div class="code_line">catch (AggregateException ae)</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;var exceptions = ae.Flatten();</div><div class="code_line">&nbsp;&nbsp; &nbsp;foreach (var exception in exceptions.InnerExceptions)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (exception is OperationCanceledException)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//ignore cancel</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Console.WriteLine(exception.Message);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">}</div></ol></div></div></div></div><br>
<a class='tag-url' href='http://msdn.microsoft.com/en-us/library/system.threading.cancellationtokensource.aspx' target='_blank'>CancellationTokenSource</a> создаёт маркёры отмены (свойство Token) и обрабатывает запросы на отмену операции.<br>
<a class='tag-url' href='http://msdn.microsoft.com/en-us/library/system.threading.cancellationtoken.aspx' target='_blank'>CancellationToken</a> - маркёр отмены, позволяющий несколькими способами отслеживать запросы на отмену операции: опросом свойства IsCancellationRequested, регистрацией callback-функции (через перегруженный метод Register), ожиданием на объекте синхронизации (свойство WaitHandle).<br>
<a class='tag-url' href='http://msdn.microsoft.com/en-us/library/system.operationcanceledexception.aspx' target='_blank'>OperationCanceledException</a> - исключение, выброс которого по соглашению означает, что запрос на отмену операции был обработан и операция должна считаться отменённой. Предпочтительный способ генерации исключения - вызов метода ThrowIfCancellationRequested.<br>
<br>
Ссылка на полную статью: <a class='tag-url' href='http://sonyks2007.blogspot.com/2014/01/c.html' target='_blank'>Обработка ошибок в C#</a> в блоге.]]></description>
        <author>Craft</author>
        <category>.NET FAQ</category>
      </item>
	
      </channel>
      </rss>
	