Необходимость в преобразовании типов возникает в выражениях, присваиваниях, замене формальных аргументов
Если при вычислении выражения операнды операции имеют разные типы, то возникает необходимость приведения их к одному типу. Такая необходимость возникает и тогда, когда операнды имеют один тип, но он несогласован с типом операции. Например, при выполнении сложения операнды типа byte должны быть приведены к типу int, поскольку сложение не определено над байтами. При выполнении присваивания x=e тип e и тип x должны быть
Поскольку операции над ссылочными типами не определены (
Коротко повторю основные положения, связанные с преобразованиями ссылочных типов. При присваиваниях (замене аргументов) тип Parent и Child.
Продолжая тему преобразований типов, рассмотрим привычные для программистов
В C# такие преобразования делятся на byte в тип int относится к byte является подмножеством диапазона int. Это преобразование всегда успешно и не может приводить к потере точности. Заметьте, преобразования из целочисленных типов к типам с плавающей точкой относятся к long в double порядок значения остается неизменным.
К int в тип byte относится к
Арифметический тип, как показано в таблице 3.1, распадается на 11 подтипов. На рис. 4.1 показана схема преобразований внутри арифметического типа.
(рис 4.1) Иерархия преобразований внутри арифметического типаДиаграмма, приведенная на рисунке, позволяет ответить на ряд важных вопросов, связанных с существованием преобразований между типами. Если на диаграмме задан путь (стрелками) от типа А к типу В, то это означает существование А в тип В. Все остальные преобразования между подтипами арифметического типа существуют, но являются
Путь, указанный на диаграмме, может быть достаточно длинным, но это вовсе не означает, что выполняется вся последовательность преобразований на данном пути. Наличие пути говорит лишь о существовании А в тип назначения В.
Иногда возникает ситуация, при которой для одного типа
Понятие перегрузки |
Диаграмма, приведенная на рис. 4.1, и в этом случае помогает понять, как делается выбор. Пусть существует две или более реализации перегруженного T может возникнуть проблема, какую реализацию выбрать, поскольку для нескольких реализаций может быть допустимым преобразование аргумента типа T в тип, заданный формальным аргументом данной реализации
Давайте рассмотрим еще один тестовый пример. В класс Testing включена группа перегруженных OLoad с одним и двумя аргументами. Вот эти
/// <summary>
/// Группа перегруженных методов OLoad
/// с одним или двумя аргументами арифметического типа.
/// Если фактический аргумент один, то будет вызван один из
/// методов, наиболее близко подходящий по типу аргумента.
/// При вызове метода с двумя аргументами возможен
/// конфликт выбора подходящего метода, приводящий
/// к ошибке периода компиляции.
/// </summary>
void OLoad(float par)
{
Console.WriteLine("float value {0}", par);
}
/// <summary>
/// Перегруженный метод OLoad с одним параметром типа long
/// </summary>
/// <param name="par"></param>
void OLoad(long par)
{
Console.WriteLine("long value {0}", par);
}
/// <summary>
/// Перегруженный метод OLoad с одним параметром типа ulong
/// </summary>
/// <param name="par"></param>
void OLoad(ulong par)
{
Console.WriteLine("ulong value {0}", par);
}
/// <summary>
/// Перегруженный метод OLoad с одним параметром типа double
/// </summary>
/// <param name="par"></param>
void OLoad(double par)
{
Console.WriteLine("double value {0}", par);
}
/// <summary>
/// Перегруженный метод OLoad с двумя параметрами типа long и long
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
void OLoad(long par1, long par2)
{
Console.WriteLine("long par1 {0}, long par2 {1}", par1, par2);
}
/// <summary>
/// Перегруженный метод OLoad с двумя параметрами типа
/// double и double
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
void OLoad(double par1, double par2)
{
Console.WriteLine("double par1 {0}, double par2 {1}",par1, par2);
}
/// <summary>
/// Перегруженный метод OLoad с двумя параметрами типа
/// int и float
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
void OLoad(int par1, float par2)
{
Console.WriteLine("int par1 {0}, float par2 {1}",par1, par2);
}
Все эти OLoad с разным числом и типами аргументов:
/// <summary>
/// Вызов перегруженного метода OLoad. В зависимости от
/// типа и числа аргументов вызывается один из методов группы.
/// </summary>
public void OLoadTest()
{
OLoad(x); OLoad(ux);
OLoad(y); OLoad(dy);
// OLoad(x,ux);
// conflict: (int, float) и (long,long)
OLoad(x,(float)ux);
OLoad(y,dy); OLoad(x,dy);
}
Заметьте, один из вызовов закомментирован, так как он приводит к конфликту на этапе трансляции. Для устранения конфликта при вызове
(рис 4.2) Вывод на печать результатов теста OLoadTestПрежде чем посмотреть на результаты работы тестирующей процедуры, попробуйте понять, какой из перегруженных
Приведу все-таки некоторые комментарии. При первом вызове int, а тип аргумента у четырех возможных реализаций соответственно float, long, ulong, double. Явного соответствия нет, поэтому нужно искать самый короткий путь на схеме. Так как не существует int в тип ulong (на диаграмме нет пути), то остаются возможными три реализации. Но путь из int в long короче, чем остальные пути, поэтому будет выбрана long-реализация
Следующий вызов демонстрирует еще одну возможную ситуацию. Для типа uint существуют две возможные реализации, и пути преобразований для них имеют одинаковую длину. В этом случае выбирается та реализация, для которой на диаграмме путь показан сплошной, а не пунктирной стрелкой, потому будет выбрана реализация с параметром long.
Рассмотрим еще ситуацию, приводящую к конфликту. Первый аргумент в соответствии с правилами требует вызова одной реализации, а второй аргумент будет настаивать на вызове другой реализации. Возникнет коллизия, не разрешимая правилами C# и приводящая к ошибке периода компиляции. Коллизию требуется устранить, например, как это сделано в примере. Обратите внимание - обе реализации допустимы, и существуй даже только одна из них, ошибки бы не возникало.
Как уже говорилось,
Важным классом преобразований являются преобразования в строковый тип и наоборот. Преобразования в строковый тип всегда определены, поскольку, напомню, все типы являются ToString(). Для встроенных типов определена подходящая реализация этого ToString() возвращает в подходящей форме строку, задающую соответствующее значение арифметического типа. Заметьте, ToString можно вызывать явно, но, если явный вызов не указан, то он будет вызываться неявно, всякий раз, когда по контексту требуется преобразование к строковому типу. Вот соответствующий пример:
/// <summary>
/// Демонстрация преобразования в строку данных различного типа.
/// </summary>
public void ToStringTest()
{
s ="Владимир Петров ";
s1 =" Возраст: "; ux = 27;
s = s + s1 + ux.ToString();
s1 =" Зарплата: "; dy = 2700.50;
s = s + s1 + dy;
WhoIsWho("s",s);
}
(рис 4.3) Вывод на печать результатов теста ToStringTestЗдесь для переменной ux dy он вызывается автоматически. Результат работы этой процедуры показан на рис. 4.3.
Преобразования из строкового типа в другие типы, например, в арифметический, должны выполняться явно. Но System. Приведу соответствующий пример:
/// <summary>
/// Демонстрация преобразования строки в данные различного типа.
/// </summary>
public void FromStringTest()
{
s ="Введите возраст ";
Console.WriteLine(s);
s1 = Console.ReadLine();
ux = Convert.ToUInt32(s1);
WhoIsWho("Возраст: ",ux);
s ="Введите зарплату ";
Console.WriteLine(s);
s1 = Console.ReadLine();
dy = Convert.ToDouble(s1);
WhoIsWho("Зарплата: ",dy);
}
Этот пример демонстрирует ввод с консоли данных разных типов. Данные, читаемые с консоли ReadLine или Read, всегда представляют собой строку, которую затем необходимо преобразовать в нужный тип. Тут-то и вызываются соответствующие
На рис. 4.4 показаны результаты вывода и ввода данных с консоли при работе этой процедуры.
(рис 4.4) Вывод на печать результатов теста FromStringTestSystem, играет важную роль, обеспечивая необходимые преобразования между различными типами. Напомню, что внутри арифметического типа можно использовать более простой, скобочный способ приведения к нужному типу. Но таким способом нельзя привести, например, переменную типа string к типу int, оператор присваивания: ux = (int)s1; приведет к ошибке периода компиляции. Здесь необходим вызов ToInt32
To <Type> (ToBoolean(),...ToUInt64()), где Type может принимать значения от Boolean до UInt64 для всех встроенных типов, перечисленных в таблице 3.1. Единственным object, - ToObject нет по понятным причинам, поскольку для всех типов существует object. Среди других ChangeType, позволяющий преобразование объекта к некоторому заданному типу.
Существует возможность преобразования к системному типу DateTime, который хотя и не является встроенным типом языка C#, но допустим в программах, как и любой другой системный тип. Приведу простейший пример работы с этим типом:
// System type: DateTime
System.DateTime dat = Convert.ToDateTime("15.03.2003");
Console.WriteLine("Date = {0}", dat);
Результатом вывода будет строка:
Date = 15.03.2003 0:00:00
Все To <Type>
Кроме
Уже упоминалось о том, что при выполнении
Язык C# позволяет создать
Синтаксически checked. В теле такого блока unchecked. Замечу еще, что и в
/// <summary>
/// Демонстрация проверяемых и непроверяемых преобразований.
/// Опасные проверяемые преобразования приводят к исключениям.
/// Опасные непроверяемые преобразования приводят к неверным
/// результатам, что совсем плохо.
/// </summary>
public void CheckUncheckTest()
{
x = -25^2;
WhoIsWho ("x", x);
b= 255;
WhoIsWho("b",b);
// Проверяемые опасные преобразования.
// Возникают исключения, перехватываемые catch-блоком.
checked
{
try
{
b += 1;
}
catch (Exception e)
{
Console.WriteLine("Переполнение при вычислении b");
Console.WriteLine(e);
}
try
{
b = (byte)x;
}
catch (Exception e)
{
Console.WriteLine("Переполнение при преобразовании к byte");
Console.WriteLine(e);
}
// непроверяемые опасные преобразования
unchecked
{
try
{
b +=1;
WhoIsWho ("b", b);
b = (byte)x;
WhoIsWho ("b", b);
ux= (uint)x;
WhoIsWho ("ux", ux);
Console.WriteLine("Исключений нет, но результаты не верны!");
}
catch (Exception e)
{
Console.WriteLine("Этот текст не должен появляться");
Console.WriteLine(e);
}
// автоматическая проверка преобразований в Convert
// исключения возникают, несмотря на unchecked
try
{
b = Convert.ToByte(x);
}
catch (Exception e)
{
Console.WriteLine("Переполнение при
преобразовании к byte!");
Console.WriteLine(e);
}
try
{
ux= Convert.ToUInt32(x);
}
catch (Exception e)
{
Console.WriteLine("Потеря знака при
преобразовании к uint!");
Console.WriteLine(e);
}
}
}
}
В этом примере мы впервые встречаемся с
Заметьте, рекомендуемый стиль программирования в C# отличается от стиля, принятого в языках С/C++, где функция, в которой возникла ошибка, завершается нормальным образом, уведомляя об ошибке в возвращаемом значении результата. Вызывающая программа должна анализировать результат, чтобы понять, была ли ошибка в работе вызванной функции и какова ее природа. При программировании в стиле C# ответственность за обнаружение ошибок лежит на вызванной программе. Она должна не только обнаружить ошибку, но и явно сообщить о ней, выбрасывая |
В состав
Если в некотором модуле предполагается возможность появления try. Вслед за этим блоком следуют один или несколько блоков, обрабатывающих T, то catch-блоки начинают конкурировать в борьбе за перехват T - совпадает с ним или является его T. Универсальный обработчик, если он есть, стоит последним, поскольку захватывает
Конечно, плохо, когда в процессе работы той или иной процедуры возникает
Вернемся к обсуждению нашего примера. Здесь как в
Такая ситуация возникает в первых двух try-блоках нашего примера. Эти блоки встроены в b+1 из-за переполнения переменная b получает значение 0, а не 256. Поскольку вычисление находится в
Такую ситуацию демонстрирует третий try-блок нашего примера, встроенный в
Заметьте, проверку переполнения в арифметических вычислениях можно включить не только с помощью создания checked-блоков, но и задав
Область действия проверки или ее отключения можно распространить и на отдельное выражение. В этом случае спецификаторы checked и unchecked предшествуют выражению, заключенному в круглые скобки. Такое выражение называется checked и unchecked рассматриваются как операции, допустимые в выражениях.
Явно выполняемые преобразования по определению относятся к опасным.
В нашем примере четвертый и пятый try-блоки встроены в
На рис. 4.5 показаны результаты работы процедуры CheckUncheckTest. Их анализ способствует лучшему пониманию рассмотренных нами ситуаций.
(рис 4.5) Вывод на печать результатов теста CheckUncheckTestНа этом, пожалуй, пора поставить точку в обсуждении системы типов языка C#. За получением тех или иных подробностей, как всегда, следует обращаться к справочной системе.
Необходимость в преобразовании типов возникает в выражениях, присваиваниях, замене формальных аргументов
Если при вычислении выражения операнды операции имеют разные типы, то возникает необходимость приведения их к одному типу. Такая необходимость возникает и тогда, когда операнды имеют один тип, но он несогласован с типом операции. Например, при выполнении сложения операнды типа byte должны быть приведены к типу int, поскольку сложение не определено над байтами. При выполнении присваивания x=e тип e и тип x должны быть
Поскольку операции над ссылочными типами не определены (
Коротко повторю основные положения, связанные с преобразованиями ссылочных типов. При присваиваниях (замене аргументов) тип Parent и Child.
Продолжая тему преобразований типов, рассмотрим привычные для программистов
В C# такие преобразования делятся на byte в тип int относится к byte является подмножеством диапазона int. Это преобразование всегда успешно и не может приводить к потере точности. Заметьте, преобразования из целочисленных типов к типам с плавающей точкой относятся к long в double порядок значения остается неизменным.
К int в тип byte относится к
Арифметический тип, как показано в таблице 3.1, распадается на 11 подтипов. На рис. 4.1 показана схема преобразований внутри арифметического типа.
(рис 4.1) Иерархия преобразований внутри арифметического типаДиаграмма, приведенная на рисунке, позволяет ответить на ряд важных вопросов, связанных с существованием преобразований между типами. Если на диаграмме задан путь (стрелками) от типа А к типу В, то это означает существование А в тип В. Все остальные преобразования между подтипами арифметического типа существуют, но являются
Путь, указанный на диаграмме, может быть достаточно длинным, но это вовсе не означает, что выполняется вся последовательность преобразований на данном пути. Наличие пути говорит лишь о существовании А в тип назначения В.
Иногда возникает ситуация, при которой для одного типа
Понятие перегрузки |
Диаграмма, приведенная на рис. 4.1, и в этом случае помогает понять, как делается выбор. Пусть существует две или более реализации перегруженного T может возникнуть проблема, какую реализацию выбрать, поскольку для нескольких реализаций может быть допустимым преобразование аргумента типа T в тип, заданный формальным аргументом данной реализации
Давайте рассмотрим еще один тестовый пример. В класс Testing включена группа перегруженных OLoad с одним и двумя аргументами. Вот эти
/// <summary>
/// Группа перегруженных методов OLoad
/// с одним или двумя аргументами арифметического типа.
/// Если фактический аргумент один, то будет вызван один из
/// методов, наиболее близко подходящий по типу аргумента.
/// При вызове метода с двумя аргументами возможен
/// конфликт выбора подходящего метода, приводящий
/// к ошибке периода компиляции.
/// </summary>
void OLoad(float par)
{
Console.WriteLine("float value {0}", par);
}
/// <summary>
/// Перегруженный метод OLoad с одним параметром типа long
/// </summary>
/// <param name="par"></param>
void OLoad(long par)
{
Console.WriteLine("long value {0}", par);
}
/// <summary>
/// Перегруженный метод OLoad с одним параметром типа ulong
/// </summary>
/// <param name="par"></param>
void OLoad(ulong par)
{
Console.WriteLine("ulong value {0}", par);
}
/// <summary>
/// Перегруженный метод OLoad с одним параметром типа double
/// </summary>
/// <param name="par"></param>
void OLoad(double par)
{
Console.WriteLine("double value {0}", par);
}
/// <summary>
/// Перегруженный метод OLoad с двумя параметрами типа long и long
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
void OLoad(long par1, long par2)
{
Console.WriteLine("long par1 {0}, long par2 {1}", par1, par2);
}
/// <summary>
/// Перегруженный метод OLoad с двумя параметрами типа
/// double и double
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
void OLoad(double par1, double par2)
{
Console.WriteLine("double par1 {0}, double par2 {1}",par1, par2);
}
/// <summary>
/// Перегруженный метод OLoad с двумя параметрами типа
/// int и float
/// </summary>
/// <param name="par1"></param>
/// <param name="par2"></param>
void OLoad(int par1, float par2)
{
Console.WriteLine("int par1 {0}, float par2 {1}",par1, par2);
}
Все эти OLoad с разным числом и типами аргументов:
/// <summary>
/// Вызов перегруженного метода OLoad. В зависимости от
/// типа и числа аргументов вызывается один из методов группы.
/// </summary>
public void OLoadTest()
{
OLoad(x); OLoad(ux);
OLoad(y); OLoad(dy);
// OLoad(x,ux);
// conflict: (int, float) и (long,long)
OLoad(x,(float)ux);
OLoad(y,dy); OLoad(x,dy);
}
Заметьте, один из вызовов закомментирован, так как он приводит к конфликту на этапе трансляции. Для устранения конфликта при вызове
(рис 4.2) Вывод на печать результатов теста OLoadTestПрежде чем посмотреть на результаты работы тестирующей процедуры, попробуйте понять, какой из перегруженных
Приведу все-таки некоторые комментарии. При первом вызове int, а тип аргумента у четырех возможных реализаций соответственно float, long, ulong, double. Явного соответствия нет, поэтому нужно искать самый короткий путь на схеме. Так как не существует int в тип ulong (на диаграмме нет пути), то остаются возможными три реализации. Но путь из int в long короче, чем остальные пути, поэтому будет выбрана long-реализация
Следующий вызов демонстрирует еще одну возможную ситуацию. Для типа uint существуют две возможные реализации, и пути преобразований для них имеют одинаковую длину. В этом случае выбирается та реализация, для которой на диаграмме путь показан сплошной, а не пунктирной стрелкой, потому будет выбрана реализация с параметром long.
Рассмотрим еще ситуацию, приводящую к конфликту. Первый аргумент в соответствии с правилами требует вызова одной реализации, а второй аргумент будет настаивать на вызове другой реализации. Возникнет коллизия, не разрешимая правилами C# и приводящая к ошибке периода компиляции. Коллизию требуется устранить, например, как это сделано в примере. Обратите внимание - обе реализации допустимы, и существуй даже только одна из них, ошибки бы не возникало.
Как уже говорилось,
Важным классом преобразований являются преобразования в строковый тип и наоборот. Преобразования в строковый тип всегда определены, поскольку, напомню, все типы являются ToString(). Для встроенных типов определена подходящая реализация этого ToString() возвращает в подходящей форме строку, задающую соответствующее значение арифметического типа. Заметьте, ToString можно вызывать явно, но, если явный вызов не указан, то он будет вызываться неявно, всякий раз, когда по контексту требуется преобразование к строковому типу. Вот соответствующий пример:
/// <summary>
/// Демонстрация преобразования в строку данных различного типа.
/// </summary>
public void ToStringTest()
{
s ="Владимир Петров ";
s1 =" Возраст: "; ux = 27;
s = s + s1 + ux.ToString();
s1 =" Зарплата: "; dy = 2700.50;
s = s + s1 + dy;
WhoIsWho("s",s);
}
(рис 4.3) Вывод на печать результатов теста ToStringTestЗдесь для переменной ux dy он вызывается автоматически. Результат работы этой процедуры показан на рис. 4.3.
Преобразования из строкового типа в другие типы, например, в арифметический, должны выполняться явно. Но System. Приведу соответствующий пример:
/// <summary>
/// Демонстрация преобразования строки в данные различного типа.
/// </summary>
public void FromStringTest()
{
s ="Введите возраст ";
Console.WriteLine(s);
s1 = Console.ReadLine();
ux = Convert.ToUInt32(s1);
WhoIsWho("Возраст: ",ux);
s ="Введите зарплату ";
Console.WriteLine(s);
s1 = Console.ReadLine();
dy = Convert.ToDouble(s1);
WhoIsWho("Зарплата: ",dy);
}
Этот пример демонстрирует ввод с консоли данных разных типов. Данные, читаемые с консоли ReadLine или Read, всегда представляют собой строку, которую затем необходимо преобразовать в нужный тип. Тут-то и вызываются соответствующие
На рис. 4.4 показаны результаты вывода и ввода данных с консоли при работе этой процедуры.
(рис 4.4) Вывод на печать результатов теста FromStringTestSystem, играет важную роль, обеспечивая необходимые преобразования между различными типами. Напомню, что внутри арифметического типа можно использовать более простой, скобочный способ приведения к нужному типу. Но таким способом нельзя привести, например, переменную типа string к типу int, оператор присваивания: ux = (int)s1; приведет к ошибке периода компиляции. Здесь необходим вызов ToInt32
To <Type> (ToBoolean(),...ToUInt64()), где Type может принимать значения от Boolean до UInt64 для всех встроенных типов, перечисленных в таблице 3.1. Единственным object, - ToObject нет по понятным причинам, поскольку для всех типов существует object. Среди других ChangeType, позволяющий преобразование объекта к некоторому заданному типу.
Существует возможность преобразования к системному типу DateTime, который хотя и не является встроенным типом языка C#, но допустим в программах, как и любой другой системный тип. Приведу простейший пример работы с этим типом:
// System type: DateTime
System.DateTime dat = Convert.ToDateTime("15.03.2003");
Console.WriteLine("Date = {0}", dat);
Результатом вывода будет строка:
Date = 15.03.2003 0:00:00
Все To <Type>
Кроме
Уже упоминалось о том, что при выполнении
Язык C# позволяет создать
Синтаксически checked. В теле такого блока unchecked. Замечу еще, что и в
/// <summary>
/// Демонстрация проверяемых и непроверяемых преобразований.
/// Опасные проверяемые преобразования приводят к исключениям.
/// Опасные непроверяемые преобразования приводят к неверным
/// результатам, что совсем плохо.
/// </summary>
public void CheckUncheckTest()
{
x = -25^2;
WhoIsWho ("x", x);
b= 255;
WhoIsWho("b",b);
// Проверяемые опасные преобразования.
// Возникают исключения, перехватываемые catch-блоком.
checked
{
try
{
b += 1;
}
catch (Exception e)
{
Console.WriteLine("Переполнение при вычислении b");
Console.WriteLine(e);
}
try
{
b = (byte)x;
}
catch (Exception e)
{
Console.WriteLine("Переполнение при преобразовании к byte");
Console.WriteLine(e);
}
// непроверяемые опасные преобразования
unchecked
{
try
{
b +=1;
WhoIsWho ("b", b);
b = (byte)x;
WhoIsWho ("b", b);
ux= (uint)x;
WhoIsWho ("ux", ux);
Console.WriteLine("Исключений нет, но результаты не верны!");
}
catch (Exception e)
{
Console.WriteLine("Этот текст не должен появляться");
Console.WriteLine(e);
}
// автоматическая проверка преобразований в Convert
// исключения возникают, несмотря на unchecked
try
{
b = Convert.ToByte(x);
}
catch (Exception e)
{
Console.WriteLine("Переполнение при
преобразовании к byte!");
Console.WriteLine(e);
}
try
{
ux= Convert.ToUInt32(x);
}
catch (Exception e)
{
Console.WriteLine("Потеря знака при
преобразовании к uint!");
Console.WriteLine(e);
}
}
}
}
В этом примере мы впервые встречаемся с
Заметьте, рекомендуемый стиль программирования в C# отличается от стиля, принятого в языках С/C++, где функция, в которой возникла ошибка, завершается нормальным образом, уведомляя об ошибке в возвращаемом значении результата. Вызывающая программа должна анализировать результат, чтобы понять, была ли ошибка в работе вызванной функции и какова ее природа. При программировании в стиле C# ответственность за обнаружение ошибок лежит на вызванной программе. Она должна не только обнаружить ошибку, но и явно сообщить о ней, выбрасывая |
В состав
Если в некотором модуле предполагается возможность появления try. Вслед за этим блоком следуют один или несколько блоков, обрабатывающих T, то catch-блоки начинают конкурировать в борьбе за перехват T - совпадает с ним или является его T. Универсальный обработчик, если он есть, стоит последним, поскольку захватывает
Конечно, плохо, когда в процессе работы той или иной процедуры возникает
Вернемся к обсуждению нашего примера. Здесь как в
Такая ситуация возникает в первых двух try-блоках нашего примера. Эти блоки встроены в b+1 из-за переполнения переменная b получает значение 0, а не 256. Поскольку вычисление находится в
Такую ситуацию демонстрирует третий try-блок нашего примера, встроенный в
Заметьте, проверку переполнения в арифметических вычислениях можно включить не только с помощью создания checked-блоков, но и задав
Область действия проверки или ее отключения можно распространить и на отдельное выражение. В этом случае спецификаторы checked и unchecked предшествуют выражению, заключенному в круглые скобки. Такое выражение называется checked и unchecked рассматриваются как операции, допустимые в выражениях.
Явно выполняемые преобразования по определению относятся к опасным.
В нашем примере четвертый и пятый try-блоки встроены в
На рис. 4.5 показаны результаты работы процедуры CheckUncheckTest. Их анализ способствует лучшему пониманию рассмотренных нами ситуаций.
(рис 4.5) Вывод на печать результатов теста CheckUncheckTestНа этом, пожалуй, пора поставить точку в обсуждении системы типов языка C#. За получением тех или иных подробностей, как всегда, следует обращаться к справочной системе.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.