A System.ArgumentNullException
occurs when an invalid argument is passed to a method in C#. In this case, it refers to the passing of a null object when the method expects a non-null object or a value. Similar to other exceptions raised as a result of arguments, System.ArgumentNullException
is not generally raised by the .NET
framework itself or the Common Language Runtime (CLR). Instead, it is thrown by an application or a library as an indication of improper null arguments.
Syntax of ArgumentNullException
Similar to any class or method, exceptions also have their own syntax.
Below is the syntax for ArgumentNullException:
public class ArgumentNullException : ArgumentException
The ArgumentNullException
comes under the class of ArgumentException
, which is inherited from the SystemException
class. The SystemException
class is in turn inherited from the Exception
class, which is inherited from the Object
class.
Object -> Exception -> SystemException -> IOException -> FileNotFoundException
When does the ArgumentNullException occur in C#?
Generally, there are two major circumstances when an ArgumentNullException
is thrown, both of which reflect developer errors:
- An object returned from a method call is then passed as an argument to a second method, but the value of the original returned object is null. To prevent the error, check for a return value that is null and call the second method only if the return value is not null.
- An uninstantiated object is passed to a method. To prevent the error, instantiate the object.
Example One: Working with an Inbuilt Function like Parse()
In the below code, we are trying to parse and convert a string value to an integer value, assuming that the string is valid and contains only numbers.
class Program
{
static void Main(string[] args)
{
string id = null;
int ans = int.Parse(id); // error is thrown
}
}
Output of Example 1
We can see that StringToNumber
is causing the error because its parameter should not be null.
Unhandled Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: String
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.Int32.Parse(String s)
at ConsoleApp1.Program.Main(String[] args) in C:ConsoleApp1ConsoleApp1Program.cs:line 50
Example Two: Dealing with Custom Classes
In the below code we have created a class Books
, two private strings, author
and title
, and used them for the public properties of Author
and Title
respectively. Then we wrote custom Title.set ()
and Author.set ()
functions that checked whether or not the passed argument value was null.
If true, we throw in a new System.ArgumentNullException
instead of passing the entire message, as is frequently the case, System.ArgumentNullException
expects just the name of the argument, which should not be null.
namespace ConsoleApp1
{
public class Books
{
private string authors;
private string titles;
public string Author
{
get { return authors; }
set {
if (value is null)
throw new System.ArgumentNullException("Author");
authors = value;
}
}
public string Title
{
get { return titles; }
set {
if (value is null)
throw new System.ArgumentNullException("Title");
titles = value; }
}
public Books(string title, string author)
{
Author = author;
Title = title;
}
}
class Program
{
static void Main(string[] args)
{
var obj = new Books("Harry potter", null);
}
}
}
Output of Example Two
When the above code is run we get the following output:
Unhandled Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: Author
at ConsoleApp1.Books.set_Author(String value) in C:ConsoleApp1ConsoleApp1Program.cs:line 21
at ConsoleApp1.Books..ctor(String title, String author) in C:ConsoleApp1ConsoleApp1Program.cs:line 39
at ConsoleApp1.Program.Main(String[] args) in C:ConsoleApp1ConsoleApp1Program.cs:line 49
The parameter Author
is causing this exception as its value should not be null.
How to Handle ArgumentNullException in C#
Now let’s see how to debug and handle this exception in C#. The best approach is to use try-catch
block and perform a simple check before passing the values. Let’s see how to fix both examples discussed earlier.
How to Fix Example One:
On observing the first few lines of the output from the bottom to the top, it is quite evident that when parsing a string to convert the string to a number, System.ArgumentNullException
occurs as the argument of int.Parse()
cannot be null.
Unhandled Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: String
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
Working Code:
class Program
{
static void Main(string[] args)
{
try
{
string id = null;
if (id is null)
{
throw new ArgumentNullException("Id Argument cannot be null");
}
else {
int ans = int.Parse(id);
}
}catch (ArgumentNullException e)
{
Console.WriteLine(e.Message);
}
}
}
Output:
Value cannot be null.
Parameter name: Id Argument cannot be null
How to Fix Example Two:
Implement a try-catch
block in this case because the value is being checked in the set()
method.
Working Code:
namespace ConsoleApp1
{
public class Books
{
private string authors;
private string titles;
public string Author
{
get { return authors; }
set {
if (value is null)
throw new System.ArgumentNullException("Author");
authors = value; }
}
public string Title
{
get { return titles; }
set {
if (value is null)
throw new System.ArgumentNullException("Title");
titles = value; }
}
public Books(string title, string author)
{
Author = author;
Title = title;
}
}
class Program
{
static void Main(string[] args)
{
try
{
var obj = new Books("Harry potter", null);
}catch(ArgumentNullException e)
{
Console.WriteLine(e.Message);
}
}
}
}
Output:
Value cannot be null.
Parameter name: Author
Avoiding ArgumentNullExceptions
To summarize, an ArgumentNullException
comes from ArgumentExceptions
when an invalid argument is passed to a method. In this case, it refers to passing a null object when the method expects a non-null object or a value. Furthermore, whenever dealing with strings
, it’s always good practice to perform a null check
and then pass any arguments.
Track, Analyze and Manage Errors With Rollbar
Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing C# errors easier than ever. Sign Up Today!
- Remove From My Forums
-
Question
-
We have a project “A” which is a C# DLL project. This DLL is consumed in a windows forms C# project.
Currently we are facing problem of “Null Exception” in the below scenario.
An windows application (project X ) is written including Project “A” 1.1 version DLL. This works fine with Project “A” 1.1 version DLL.Project “A” version 1.0 DLL is installed on a Machine X, and the above project X executable and Project”A” 1.1 version DLL is copied into the Installation directory of Project”A” version 1.0 on machine X..
While running the project it is expected to return “version mismatch or File not found error” but below error message is thrown.System.ArgumentNullException: Value cannot be null.
Parameter name: format
at System.String.Format(IFormatProvider provider, String format, Object[] args)
at ProjectA.ctor(IntPtr windowHandle)
at TestDT.frmScan.frmScan_Load(Object sender, EventArgs e)
at System.Windows.Forms.Form.OnLoad(EventArgs e)
at System.Windows.Forms.Form.OnCreateControl()
at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
at System.Windows.Forms.Control.CreateControl()
at System.Windows.Forms.Control.WmShowWindow(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.Form.WmShowWindow(Message& m)
at System.Windows.Forms.Form.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)I know that the user is not suppose to do this, but still let me know why Null Exception is thrown instead of Version mismatch or file not found exception.
sarvanan
-
Moved by
Monday, August 9, 2010 11:33 AM
C# issue (From:.NET Framework Setup)
-
Moved by
Answers
-
Hi,
I have resolved the Issue, it was problem with a string variable in the resource file which was not present.
Here I would like to ask or highlight something that I noticed. My Project is in VS2005. Here there is no particular resource variable to which we were pointing in the Code, the surprise here is when the project was built using VS2005 no error was thrown.
But when I converted the same project to VS2008 there was an compilation error for referring to an non-existence resource variable. It looks like VS2005 during compilation If no resource variable is present it creates one with NULL value ? Please
let me know the reason behind this.Any way thanks for your kind response. This forum is very much useful to me all through my career.
sarvanan
-
Proposed as answer by
s3rvy
Tuesday, August 10, 2010 7:31 PM -
Marked as answer by
Alan_chen
Wednesday, August 11, 2010 3:04 AM
-
Proposed as answer by
1 / 1 / 0 Регистрация: 20.01.2019 Сообщений: 18 |
|
1 |
|
.NET 4.x 17.11.2021, 11:04. Показов 3561. Ответов 6
Здравствуйте. В ноябре 20-го года делал программу-тест с простым графическим интерфейсом, считывающую вопросы из txt-файла (полный проект во вложении). Точно помню, что она работала, зачёт по ней сдан. Сейчас она мне понадобилась для другой работы, но при решении 7-го вопроса теста из 10 Visual Studio выдаёт ошибку: System.ArgumentNullException: «Значение не может быть неопределенным. Имя параметра: String» (скрин во вложениях). Миниатюры
__________________
0 |
2656 / 1591 / 850 Регистрация: 14.04.2015 Сообщений: 5,494 |
|
17.11.2021, 11:43 |
2 |
Решениеmetalphoenix, лишние пустые строки из файла уберите
1 |
1 / 1 / 0 Регистрация: 20.01.2019 Сообщений: 18 |
|
17.11.2021, 12:18 [ТС] |
3 |
AndreyVorobey, вы имеете в виду пустые строки в конце текстового файла с вопросами «t.txt»? Убрал, не помогло. Добавлено через 5 минут
0 |
1 / 1 / 0 Регистрация: 20.01.2019 Сообщений: 18 |
|
17.11.2021, 12:19 [ТС] |
4 |
Скрин Миниатюры
0 |
1 / 1 / 0 Регистрация: 20.01.2019 Сообщений: 18 |
|
17.11.2021, 12:26 [ТС] |
5 |
AndreyVorobey, Благодарю. Оказывается, в каталоге был дубль текстового файла, строки надо было убирать в нём.
0 |
2656 / 1591 / 850 Регистрация: 14.04.2015 Сообщений: 5,494 |
|
17.11.2021, 12:28 |
6 |
metalphoenix, ну так это не дубль, а тот файл, с которого считываются данные. нет? в первом файле было 10 вопросов, а во втором 7, и на нем ошибка была. мне казалось, это и так было понятно
0 |
1 / 1 / 0 Регистрация: 20.01.2019 Сообщений: 18 |
|
17.11.2021, 12:33 [ТС] |
7 |
AndreyVorobey, да, именно так. Пустые строки были в обоих. Видимо, файл с 10 вопросами я ранее сделал как резерв для изменения вопросов в будущем, а сейчас не сразу понял, что данные считываются не с него, а из того, в котором 7 вопросов. Ещё раз благодарю вас за оперативную помощь, хорошего вам дня)
0 |
Содержание
- Исключения (Exceptions) и инструкция try
- Оговорка catch
- Блок finally
- Инструкция using
- Выбрасывание исключений
- Основные свойства System.Exception
- Основные типы исключений
- Директивы препроцессора
- Pragma Warning
- Атрибут Conditional
- Классы Debug и Trace
- TraceListener
- Fail и Assert
Исключения, их обработка, и некоторые другие моменты, связанные с ошибками в приложении на C#.
Исключения (Exceptions) и инструкция try
Инструкция try
отмечает блок кода как объект для обработки ошибок или очистки. После блока try
обязательно должен идти либо блок catch
, либо блок finally
, либо они оба. Блок catch
выполняется, когда внутри блока try возникает ошибка. Блок finally
выполняется после того, как прекращает выполнять блок try
(или, если присутствует, блок catch
), независимо от того, выполнился ли он до конца или был прерван ошибкой, что позволяет выполнить так называемый код очистки.
Блок catch
имеет доступ к объекту исключения (Exception
), который содержит информацию об ошибке. Блок catch
позволяет обработать исключительную ситуацию и как-либо скорректировать ошибку или выбросить новое исключение. Повторное выбрасывание исключения в блоке catch
обычно применяется с целью логирования ошибок или чтобы выбросить новое, более специфическое исключение.
Блок finally
добавляет в программу прогнозируемость, позволяя выполнить определенный код при любых обстоятельствах. Это может быть полезно для выполнения операций очистки, например, закрытия сетевого подключения и т.д.
В целом конструкция try выглядит следующим образом:
try { ... // в пределах этого блока может быть выброшено исключение } catch (ExceptionA ex) { ... // обработчик исключений типа ExceptionA } catch (ExceptionB ex) { ... // обработчик исключений типа ExceptionB } finally { ... // код очистки } |
Например, следующий код выбросит ошибку DivideByZeroException
(поскольку делить на ноль нельзя) и наша программа завершить досрочно:
int x = 3, y = 0; Console.WriteLine (x / y); |
Чтобы этого избежать можно использовать конструкцию try
:
try { int x = 3, y = 0; Console.WriteLine (x / y); } catch (DivideByZeroException ex) { Console.Write («y cannot be zero. «); } // выполнение программы продолжится отсюда |
Обработка исключений довольно ресурсоёмкая операция, поэтому на практике для таких случаев как в примере ее лучше не использовать (лучше непосредственно перед делением проверить делить на равенство нулю).
Когда выбрасывается исключение, CLR проверяет выброшено ли оно непосредственно внутри блока try
, который может обработать данное исключение. Если да, выполнение переходит в соответствующий блок catch
. Если блок catch
успешно завершается, выполнение переходит к следующей после блока try
инструкции (если имеется блок finally
, то сначала выполняется он). Если же исключение выброшено не внутри блока try
или конструкция try
не содержит соответствующего блока catch
, выполнение переходит в точку вызова метода (при этом сначала выполняется блок finally
), и проверка повторяется снова.
Если не одна функция в стэке вызовов не способна обработать исключение, ошибка выводиться пользователю и программа завершается досрочно.
Оговорка catch
В оговорке catch указывается какой тип исключения она должна перехватывать. Это может быть либо System.Exception
, либо его производный класс. Перехватывая непосредственно System.Exception
, мы перехватим все возможные ошибки. Это может быть полезно в нескольких случаях:
- программа потенциально должна и может продолжить работать несмотря на ошибки любых типов
- исключение будет выброшено повторно в блоке
catch
, например, после логирования ошибок - блок
catch
является последним в очереди, способным предотвратить аварийное завершение программы
Однако обычно перехватываются исключения более специфического типа, чтобы избежать ситуации, когда обработчику ошибки придется иметь дело с исключением, для которого он не предназначен (например, OutOfMemoryException
).
Можно обработать несколько типов исключений с помощью нескольких оговорок catch:
try { DoSomething(); } catch (IndexOutOfRangeException ex) { ... } catch (FormatException ex) { ... } catch (OverflowException ex) { ... } |
Каждая оговорка способна обработать только то исключение, которое точно совпадает с ее типом. Для одного выброшенного исключения может быть выполнена только одна оговорка catch. Обрабатываются блоки catch в том порядке, в котором они идут в коде. В этой связи более специфические исключения должны перехватываться раньше чем более общие.
Исключение может быть перехвачено и без указания переменной, если не нужен доступ к ее членам:
catch (StackOverflowException) // без переменной { ... } |
Более того, в оговорке catch можно опустить и переменную и тип исключения — такая оговрка будет перехватывать все исключения:
Блок finally
Блок finally
выполняется всегда, независимо от того выброшено исключение или нет. Блок finally
обычно содержит код очистки.
Блок finally
выполняется в следующих случаях:
- после завершения блока
catch
- если выполнение блока
try
прервано jump-инструкциями:return
,goto
и т.д. - после выполнения блока
try
полностью, если исключений так и не было выброшено
Блок finally
делает программу более прогнозируемой. Например, в следующем примере открываемый файл в итоге всегда будет закрыт, независимо от того, завершиться ли блок try
без ошибок, или будет прерван выброшенным исключением, или сработает инструкция return
если файл окажется пустым:
static void ReadFile() { StreamReader reader = null; try { reader = File.OpenText («file.txt»); if (reader.EndOfStream) return; Console.WriteLine (reader.ReadToEnd()); } finally { if (reader != null) reader.Dispose(); } } |
В пример для закрытия файла вызывается метод Dispose
. Использование этого метода внутри блока finally
является стандартной практикой. C# даже позволяет заменить всю конструкцию инструкцией using
.
Инструкция using
Многие классы инкапсулируют неуправляемые ресурсы, такие как дескриптор файла, соединение с базой данных и т.д. Эти классы реализуют интерфейс System.IDisposable
, который содержит единственный метод без параметров Dispose
, освобождающий соответствующие машинные ресурсы. Инструкция using
предусматривает удобный синтаксис вызова метода Dispose
для объектов реализующих IDisposable
внутри блока finally
:
using (StreamReader reader = File.OpenText («file.txt»)) { ... } |
Что эквивалентно следующей конструкции:
StreamReader reader = File.OpenText («file.txt»); try { ... } finally { if (reader != null) ((IDisposable)reader).Dispose(); } |
Выбрасывание исключений
Исключение может быть выброшено автоматически во время выполнения программы либо явно в коде программы с помощью ключевого слова throw
:
static void Display (string name) { if (name == null) throw new ArgumentNullException («name»); Console.WriteLine (name); } |
Также исключение может быть выброшено повторно внутри блока catch
:
try { ... } catch (Exception ex) { // логирование ошибки ... throw; // повторное выбрасывание того же самого исключения } |
Такой подход позволяет заносить ошибки в лог без их дальнейшего поглощения. Также это позволяет уклониться от обработки неожиданных исключений.
Если throw
заменить на throw ex
, то пример по прежнему будет работать, но свойство исключения StackTrace
не будет отражать исходную ошибку.
Другой распространенный сценарий использования повторного выбрасывания исключения — повторное выбрасывание более специфического и конкретного типа исключения, чем было перехвачено ранее:
try { ... // парсинг даты рождения из xml-данных } catch (FormatException ex) { throw new XmlException («Неправильная дата рождения», ex); } |
В таких случаях необходимо передать исходное исключение в качестве первого параметра конструктора нового исключения, ссылка на объект исходного исключения позже будет доступна через свойство InnerException
внутреннего исключения.
Основные свойства System.Exception
К наиболее важным свойствам класса System.Exception
можно отнести:
StackTrace
— строка, представляющая все методы, которые были вызваны, начиная с того, в котором было выброшено исключение, и заканчивая тем, в котором содержится блокcatch
, перехвативший исключение;Message
— строка с описанием ошибки;InnerException
— содержит ссылку на объектExeption
, который вызвал текущее исключение (например, при повторном выбрасывании исключения).
Основные типы исключений
Следующие типы исключений являются наиболее распространенными в среде CLR и .NET Framework. Их можно выбрасывать непосредственно или использовать как базовые классы для пользовательских типов исключений.
System.ArgumentException
— выбрасывается при вызове функции с неправильным аргументом.System.ArgumentNullException
— производный отArgumentException
класс, выбрасывается если один из аргументов функции неожиданно равенnull
.System.ArgumentOutOfRangeException
— производный отArgumentException
класс, выбрасывается когда аргумент функции имеет слишком большое или слишком маленькое значение для данного типа (обычно касается числовых типов). Например, такое исключение будет выброшено если попытаться передать отрицательное число в функцию, которая ожидает только положительные числа.System.InvalidOperationException
— выбрасывается когда состояние объекта является неподходящим для нормального выполнения метода, например, при попытке прочесть не открытый файл.System.NotSupportedException
— выбрасывается, когда запрошенный функционал не поддерживается, например, если попытаться вызвать методAdd
для коллекции доступной только для чтения (свойство коллекцииIsReadOnly
возвращаетtrue
).System.NotImplementedException
— выбрасывается, когда запрошенный функционал еще не реализован.System.ObjectDisposedException
— выбрасывается при попытке вызвать метод объекта, который уже был уничтожен (disposed).
Директивы препроцессора
Директивы препроцессора снабжают компилятор дополнительной информацией об областях кода. Самые распространенные директивы препроцессора — условные директивы, позволяющие включить или исключить области кода из компиляции.
#define DEBUG class MyClass { int x; void Foo() { # if DEBUG Console.WriteLine («Testing: x = {0}», x); # endif } } |
В этом классе инструкции в методе Foo
скомпилируются если определен символ DEBUG
, а если его удалить — инструкции не скомпилируются. Символы препроцессора могут быть определены в исходном коде (как в примере), а могут быть переданы компилятору в командной строке с помощью параметра /define:symbol
.
С директивами #if
и #elif
можно использовать операторы ||
, &&
и !
с несколькими символами:
Директивы #error
и #warning
предотвращают некорректное использование условных директив, заставляя компилятор генерировать предупреждение или ошибку при передаче неверного набора символов.
Директивы препроцессора схожи с условными конструкциями и статическими переменными, однако дают возможности, недоступные для последних:
- условное включение атрибута
- изменение типа, объявляемого для переменной
- переключение между разными пространствами имен или псевдонимами типа в директиве using:
using TestType =
#if V2
MyCompany.Widgets.GadgetV2;
#else
MyCompany.Widgets.Gadget;
#endif
- создавать новые версии кода и быстро переключаться между ними при компиляции
- создавать библиотеки, компилируемые для разных версий .NET Framework
Полный список директив препроцессора:
#define symbol
— определяет символ#undef symbol
— удаляет символ#if symbol [оператор symbol2]...
— условная компиляция; допустимые операторы==
,!=
,&&
и||
#else
— выполняет код после#endif
#elif symbol [оператор symbol2]
— объединяет#else
и#if
#endif
— конец условных директив#warning text
— текст предупреждения, которое появится в выдаче компилятора#error text
— текст ошибки, которая появится в выдаче компилятора#line [число["файл"] | hidden]
— число указывает номер строки в исходном коде; файл — имя файла, которое появится в выдаче компилятора; hidden — дает указание дебагеру пропустить код от этой точки до следующей директивы#line
#region name
— отмечает начало области#endregion
— отмечает конец области#pragma warning
Pragma Warning
Компилятор генерирует предупреждения, когда что-то в коде ему кажется неуместным (но корректным). В отличии от ошибок предупреждения не препятствуют компиляции программы. Предупреждения компилятора могут быть очень полезны при поиске багов в программе. Однако часто предупреждения оказываются ложными, поэтому целесообразно иметь возможность получать предупреждения только о действительных багах. С этой целью компилятор дает возможность выборочно подавить предупреждения с помощью директивы #pragma warning
.
public class Foo { static void Main() { } #pragma warning disable 414 static string Message = «Hello»; #pragma warning restore 414 } |
В примере мы указываем компилятору не выдавать предупреждения о том, что поле Message
не используется.
Если не указывать номер директива #pragma warning
отменит или восстановит вывод всех предупреждений.
Если скомпилировать программу с параметром /warnaserror
, то все не отмененные директивой #pragma warning
предупреждения будут расцениваться компилятором как ошибки.
Атрибут Conditional
Атрибут Conditional
указывает компилятору на необходимость игнорировать все обращения к определенному классу или методу, если заданный символ не был определен:
[Conditional («LOGGINGMODE»)] static void LogStatus (string msg) { ... } |
Это равносильно тому, что каждый вызов метода будет окружен условными директивами:
#if LOGGINGMODE LogStatus («Message Headers: « + GetMsgHeaders()); #endif |
Классы Debug и Trace
Статические классы Debug
и Trace
предлагают базовые возможности логирования. Оба класса схожи, отличие заключается в их назанчении. Класс Debug
предназначен для отладочных сборок, класс Trace
— для отладочных и финальных. В связи с этим все методы класса Debug
определены с атрибутом [Conditional("DEBUG")]
, а методы класса Trace
— с атрибутом [Conditional("TRACE")]
. Это значит, что все обращения к Debug
и Trace
будут подавляться компилятором, пока не определен символ DEBUG
или TRACE
.
Класс Debug
и Trace
определяют методы Write
, WriteLine
и WriteIf
. По умолчанию они отправляют сообщения в окно вывода отладчика:
Debug.Write («Data»); Debug.WriteLine (23 * 34); int x = 5, y = 3; Debug.WriteIf (x > y, «x is greater than y»); |
Класс Trace
также содержит методы TraceInformation
, TraceWarning
и TraceError
. Их действия зависят от зарегистрированных прослушивателей.
TraceListener
Классы Debug
и Trace
имеют свойство Listeners
, которое представляет собой статическую коллекцию экземпляров TraceListener
. Они отвечают за обработку данных, возвращаемых методами Write
, Fail
и Trace
.
По умолчанию коллекция Listeners
обоих классов включает единственный прослушиватель — DefaultTraceListener
— стандартный прослушиватель, имеющий две ключевые возможности:
- при подключении к отладчику (например, Visual Studio) сообщения записываются в окно вывода отладчика, во всех остальных случаях сообщения игнорируются
- при вызове метода
Fail
отображается диалоговое окно, запрашивающее у пользователя дальнейшие действия: продолжить, прервать или повторить отладку (независимо от того, подключен ли отладчик)
Это поведение можно изменить или дополнить, удалив (на обязательно) стандартный прослушиватель и/или добавив один или более собственных прослушивателей.
Прослушиваетли трассировки можно написать с нуля (создав производный класс от TraceListener
) или воспользоваться готовыми классами:
TextWriterTraceListener
записывает вStream
илиTextWriter
или добавляет в файл; имеет четыре подкласса:ConsoleTraceListener
,DelimitedListTraceListener
,XmlWriterTraceListener
иEventSchemaTraceListener
EventLogTraceListener
записывает в журнал событий WindowsEventProviderTraceListener
записывает в систему трассировки событий Windows (Event Tracing for Windows — ETW)WebPageTraceListener
выводит на веб-страницу ASP.NET
Ни один из этих прослушивателе не отображает диалоговое окно при вызове Fail
, это делает только DefaultTraceListener
.
// Удалить стандартный прослушиватель, очистив коллекцию прослушивателей: Trace.Listeners.Clear(); // Добавить средство записи в файл trace.txt: Trace.Listeners.Add (new TextWriterTraceListener («trace.txt»)); // Добавит средство записи в консоль: System.IO.TextWriter tw = Console.Out; Trace.Listeners.Add (new TextWriterTraceListener (tw)); // Добавить средство записи в журнал событий Windows: if (!EventLog.SourceExists («DemoApp»)) EventLog.CreateEventSource («DemoApp», «Application»); Trace.Listeners.Add (new EventLogTraceListener («DemoApp»)); |
В случае журнала событий Windows сообщения, отправляемые с помощью Write
, Fail
или Assert
, записываются как сведения, а сообщения методов TraceWarning
и TraceError
записываются как предупреждения или ошибки.
Каждый экземпляр TraceListener
имеет свойство Filter
и TraceFilter
, с помощью которых можно управлять, будет ли сообщение записано в этот прослушиватель. Для этого необходимо создать экземпляр классов EventTypeFilter
или SourceFilter
(производных от TraceFilter
) или создать свой класс, наследующий от TraceFilter
и переопределить в нем метод ShouldTrace
.
В TraceListener
также определены свойства IndentLevel
и IndentSize
для управления отступами и свойство TraceOutputOptions
для записи дополнительных данных:
TextWriterTraceListener tl = new TextWriterTraceListener (Console.Out); tl.TraceOutputOptions = TraceOptions.DateTime | TraceOptions.Callstack; // Это применяется при использовании метода Trace: Trace.TraceWarning («Orange alert»); DiagTest.vshost.exe Warning: 0 : Orange alert DateTime=2007—03—08T05:57:13.6250000Z Callstack= at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo) at System.Environment.get_StackTrace() at ... |
Прослушиватели, которые записывают данные в поток, кэшируются. По этой причине данные не появляются в потоке немедленно, а также поток перед завершением приложения должен быть закрыт, или хотя бы сброшен, чтоб не потерять данные в кэше. Для этой цели классы Trace
и Debug
содержат статические методы Close
и Flush
, которые вызывают Close
и Flush
во всех прослушивателях (а они в свою очередь закрывают или сбрасывают все потоки). Метод Close
вызывает метод Flush
, закрывает файловые дескрипторы и предотвращает дальнейшую запись.
Классы Trace
и Debug
также определяют свойство AutoFlush
, которое если равно true
вызывает Flush
после каждого сообщения.
Fail и Assert
Классы Debug
и Trace
содержат методы Fail
и Assert
.
Метод Fail
отправляет сообщения каждому TraceListener
:
Debug.Fail («File data.txt does not exist!»); |
Метод Assert
вызывает Fail
если аргумент типа bool
равен false
. Это называется созданием утверждения и указывает на ошибку, если оно нарушено. Можно также создать необязательное сообщение об ошибке:
Debug.Assert (File.Exists («data.txt»), «File data.txt does not exist!»); var result = ... Debug.Assert (result != null); |
Методы Write
, Fail
и Assert
также могут принимать категорию в виде строки ,которая может быть использована при обработке вывода.
These C# examples show the ArgumentException being thrown. ArgumentOutOfRangeException and ArgumentNullException help validate arguments.
ArgumentException. A method can be called with invalid arguments.
An ArgumentException may be thrown in this case. Exceptions use derived types to indicate their meaning. But this does not give them extra abilities.
Note: Semantically, ArgumentException indicates that a method was called with an invalid argument.
Example. This method receives one formal parameter, a string type with the identifier «argument». In the method A, we perform two checks on the value of the variable argument, detecting when it is null or has zero characters in its buffer.
NullEmpty Strings
Constructor. When using the ArgumentNullException constructor, you can pass a string literal that is equal to the variable name that was null. This affects the debug output and will aid debugging.
Tip: You can use the same pattern on ArgumentException, which indicates a general argument-related exception.
Based on: .NET 4.5 C# program that uses ArgumentException using System; class Program { static void Main() { // Demonstrate the argument null exception. try { A(null); } catch (Exception ex) { Console.WriteLine(ex); } // Demonstrate the general argument exception. try { A(""); } catch (Exception ex) { Console.WriteLine(ex); } // Flow path without exception. Console.WriteLine(A("test")); } static int A(string argument) { // Handle null argument. if (argument == null) { throw new ArgumentNullException("argument"); } // Handle invalid argument. if (argument.Length == 0) { throw new ArgumentException("Zero-length string invalid", "argument"); } return argument.Length; } } Output: truncated System.ArgumentNullException: Value cannot be null. Parameter name: argument at Program.A(String argument)... System.ArgumentException: Zero-length string invalid Parameter name: argument at Program.A(String argument)... 4
An interesting part of this example. The parameter name, which is specified as the string literal in both exception constructors, is written to the output. The argument name is important as a debugging aid.
Example: Maybe the method A would receive two strings, and neither of them could be validly null—the argument name would be helpful.
Discussion. There are some cases where you should validate arguments with more care. If you have a method that is called in many different places or any external places written by external developers, then validating arguments is more important.
But: With an internal method, the arguments may not need to be carefully validated because they may never be invalid.
So: For truly performance-critical methods, do not validate arguments in most cases.
ArgumentNullException is thrown by code that checks arguments for null and then throws it explicitly. Usually, the method would fail with a NullReferenceException if the check was removed. Here, we use null on the Dictionary indexer.
DictionaryIndexer
And: The indexer compiles to the get_Item method. Internally, get_Item eventually uses the statement «throw new ArgumentNullException».
C# program that causes ArgumentNullException using System.Collections.Generic; class Program { static void Main() { var dictionary = new Dictionary<string, int>(); int value = dictionary[null]; } } Output Unhandled Exception: System.ArgumentNullException: Value cannot be null. Parameter name: key
User code. The ArgumentNullException can be understood as an exception that is thrown by user code, not the runtime. It thus represents an error that was carefully added to help the users of the library better understand what is wrong.
Tip: In many cases, avoiding the null check and allowing the runtime itself to detect a NullReferenceException would be faster.
ArgumentOutOfRangeException. This program causes an ArgumentOutOfRangeException to be thrown by the Substring method. The Substring method requires its argument to be greater than or equal to zero. In this program, this requirement is not met.
Substring
Tip: Internally, Substring checks its argument for a negative value. With this exception, it alerts you to an invalid value.
And: This error is helpful. It makes your program easier to fix. It pinpoints the nature of your logical error.
C# program that causes ArgumentOutOfRangeException class Program { static void Main() { string value = "test".Substring(-1); } } Output Unhandled Exception: System.ArgumentOutOfRangeException: StartIndex cannot be less than zero. Parameter name: startIndex
In this example, the ArgumentOutOfRangeException is thrown explicitly, with a throw statement, not by the runtime. This makes it useful because it indicates a specific cause of what happened. The message helps you pinpoint the cause.
Throw
Summary. We looked at the ArgumentException and ArgumentNullException types. In the exception type hierarchy, the type names are a way to encode the meaning of the exception’s cause. These exceptions indicate an argument problem.
Review: The ArgumentException and ArgumentNullException types are semantically rich and aid in efficient debugging.
Related Links
Adjectives
Ado
Ai
Android
Angular
Antonyms
Apache
Articles
Asp
Autocad
Automata
Aws
Azure
Basic
Binary
Bitcoin
Blockchain
C
Cassandra
Change
Coa
Computer
Control
Cpp
Create
Creating
C-Sharp
Cyber
Daa
Data
Dbms
Deletion
Devops
Difference
Discrete
Es6
Ethical
Examples
Features
Firebase
Flutter
Fs
Git
Go
Hbase
History
Hive
Hiveql
How
Html
Idioms
Insertion
Installing
Ios
Java
Joomla
Js
Kafka
Kali
Laravel
Logical
Machine
Matlab
Matrix
Mongodb
Mysql
One
Opencv
Oracle
Ordering
Os
Pandas
Php
Pig
Pl
Postgresql
Powershell
Prepositions
Program
Python
React
Ruby
Scala
Selecting
Selenium
Sentence
Seo
Sharepoint
Software
Spellings
Spotting
Spring
Sql
Sqlite
Sqoop
Svn
Swift
Synonyms
Talend
Testng
Types
Uml
Unity
Vbnet
Verbal
Webdriver
What
Wpf