Тверской государственный университет
Опубликован: 22.11.2005 | Доступ: свободный | Студентов: 30256 / 1759 | Оценка: 4.31 / 3.69 | Длительность: 28:26:00
ISBN: 978-5-9556-0050-5
Лекция 4:

Преобразования типов

< Лекция 3 || Лекция 4: 123 || Лекция 5 >

Явные преобразования

Как уже говорилось, явные преобразования могут быть опасными из-за потери точности. Поэтому они выполняются по указанию программиста, - на нем лежит вся ответственность за результаты.

Преобразования строкового типа

Важным классом преобразований являются преобразования в строковый тип и наоборот. Преобразования в строковый тип всегда определены, поскольку, напомню, все типы являются потомками базового класса Object, а, следовательно, обладают методом 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);
}
Вывод на печать результатов теста ToStringTest

Рис. 4.3. Вывод на печать результатов теста ToStringTest

Здесь для переменной ux метод был вызван явно, а для переменной dy он вызывается автоматически. Результат работы этой процедуры показан на рис. 4.3.

Преобразования из строкового типа в другие типы, например, в арифметический, должны выполняться явно. Но явных преобразований между арифметикой и строками не существует. Необходимы другие механизмы, и они в C# имеются. Для этой цели можно использовать соответствующие методы класса Convert библиотеки FCL, встроенного в пространство имен 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, всегда представляют собой строку, которую затем необходимо преобразовать в нужный тип. Тут-то и вызываются соответствующие методы класса Convert. Естественно, для успеха преобразования строка должна содержать значение в формате, допускающем подобное преобразование. Заметьте, например, что при записи значения числа для выделения дробной части должна использоваться запятая, а не точка; в противном случае возникнет ошибка периода выполнения.

В различных версиях Visual Studio возможны разные разделители целой и дробной частей, они также зависят от региональных настроек в ОС.

На рис. 4.4 показаны результаты вывода и ввода данных с консоли при работе этой процедуры.

Вывод на печать результатов теста FromStringTest

Рис. 4.4. Вывод на печать результатов теста FromStringTest

Преобразования и класс Convert

Класс Convert, определенный в пространстве имен System, играет важную роль, обеспечивая необходимые преобразования между различными типами. Напомню, что внутри арифметического типа можно использовать более простой, скобочный способ приведения к нужному типу. Но таким способом нельзя привести, например, переменную типа string к типу int, оператор присваивания: ux = (int)s1; приведет к ошибке периода компиляции. Здесь необходим вызов метода ToInt32 класса Convert, как это сделано в последнем примере предыдущего раздела.

Методы класса Convert поддерживают общий способ выполнения преобразований между типами. Класс Convert содержит 15 статических методов вида 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> класса Convert перегружены и каждый из них имеет, как правило, более десятка реализаций с аргументами разного типа. Так что фактически эти методы задают все возможные преобразования между всеми встроенными типами языка C#.

Кроме методов, задающих преобразования типов, в классе Convert имеются и другие методы, например, задающие преобразования символов Unicode в однобайтную кодировку ASCII, преобразования значений объектов и другие методы. Подробности можно посмотреть в справочной системе.

Проверяемые преобразования

Уже упоминалось о том, что при выполнении явных преобразований могут возникать нежелательные явления, например, потеря точности. Я говорил, что вся ответственность за это ложится на программиста, и легче ему от этого не становится. А какую часть этого бремени может взять на себя язык программирования? Что можно предусмотреть для обнаружения ситуаций, когда такие явления все-таки возникают? В языке C# имеются необходимые для этого средства.

Язык C# позволяет создать проверяемый блок, в котором будет осуществляться проверка результата вычисления арифметических выражений. Если результат вычисления значения источника выходит за диапазон возможных значений целевой переменной, то возникнет исключение (говорят также: "будет выброшено исключение ") соответствующего типа. Если предусмотрена обработка исключения, то дальнейшее зависит от обработчика исключения. В лучшем случае, программа сможет продолжить корректное выполнение. В худшем, - она остановится и выдаст информацию об ошибке. Заметьте, не произойдет самого опасного - продолжения работы программы с неверными данными.

Синтаксически проверяемый блок предваряется ключевым словом checked. В теле такого блока арифметические преобразования проверяются на допустимость. Естественно, подобная проверка требует дополнительных временных затрат. Если группа операторов в теле такого блока нам кажется безопасной, то их можно выделить в непроверяемый блок, используя ключевое слово unchecked. Замечу еще, что и в непроверяемом блоке при работе методов Convert все опасные преобразования проверяются и приводят к выбрасыванию исключений. Приведу пример, демонстрирующий все описанные ситуации:

/// <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);
			}
		}
	}
}
< Лекция 3 || Лекция 4: 123 || Лекция 5 >
Александр Галабудник
Александр Галабудник

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

Александра Гусева
Александра Гусева