Главная · Карта сайта · Поиск · Статьи · Компьютерные курсы · Обучающие программы · Открытые проекты · Веб-программирование · Создание интернет-сайта · Полезные ссылки · Глоссарий · Контакты · Декабрь 09 2016 20:21:44
Последнее опубликованное

Что такое Model-View-Controller
Pattern Model-View-Controller

Как создать свой веб-сайт
Как создать свой сайт в интернете

Разное
Статистика

Программирование на C#. Преобразование и приведение типов


Перейти к обзору всех тем

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

Довольно часто в программировании приходится осуществлять преобразование одних типов в другие. Для всех элементарных типов .NET Framework реализованы общие “правила игры”: если преобразование типа можно выполнить без потери точности, то это можно сделать неявно. Если преобразование типа требует расстаться с частью информации, то согласиться на это компилятор может только в том случае, если программист даст на это свое явное согласие. Например, преобразовать вещественный тип в целочисленный тип с потерей знаков после запятой компилятор добровольно откажется. Пример явного и неудачной попытки неявного преобразования демонстрирует следующий пример:

namespace CSharpQuickGuide
{
    static class TypeConversionSample01
    {
        static void Main()
        {
            //Объявление вещественной переменной
            double d = 5.74;
            //Ошибка: попытка неявного преобразования типа с потерей точности
            int i = d;
            //Явное преобразование с потерей точности разрешено
            int di = (int)d;
            //Неявное преобразование без потери точности разрешено
            double id = di;
        }
    }
}

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

namespace CSharpQuickGuide
{
    internal class MyInt
    {
        internal int value { get; set; }
        internal MyInt(int i) { value = i; }
    }

    class MyDouble
    {
        internal double value { get; set; }
        internal MyDouble(double d) { value = d; }
        //Определение явного преобразования MyDouble к MyInt
        public static explicit operator MyInt(MyDouble d)
        { return new MyInt((int)d.value); }
    }

    static class TypeConversionSample02
    {
        static void Main()
        {
            MyDouble d = new MyDouble(5.74);
            //Ошибка: неявное преобразование MyDouble к MyInt не определено
            MyInt i = d;
            //Явное преобразование типа MyDouble к MyInt определено
            MyInt di = (MyInt)d;
            //Ошибка: неявное преобразование MyInt к MyDouble не определено
            MyDouble id = di;
        }
    }
}

В примере определено только явное, без потери точности преобразование вещественного типа к целочисленному типу, поэтому любые попытки неявного преобразования типов по-прежнему компилятором отвергаются. Для решения этой проблемы в классе MyInt нужно разрешить неявное преобразование, как показано в следующем примере. Заодно разрешим компилятору производить неявно преобразования с потерей точности: в классе MyDouble ключевое слово explicit заменим на implicit.

namespace CSharpQuickGuide
{
    internal class MyInt
    {
        internal int value { get; set; }
        internal MyInt(int i) { value = i; }
        //Определение неявного преобразования MyInt к MyDouble
        public static implicit operator MyDouble(MyInt i)
        { return new MyDouble((double)i.value); }
    }

    class MyDouble
    {
        internal double value { get; set; }
        internal MyDouble(double d) { value = d; }
        //Определение неявного преобразования MyDouble к MyInt
        public static implicit operator MyInt(MyDouble d)
        { return new MyInt((int)d.value); }
    }

    static class TypeConversionSample03
    {
        static void Main()
        {
            MyDouble d = new MyDouble(5.74);
            //Неявное преобразование MyDouble к MyInt определено
            MyInt i = d;
            //Явное преобразование типа MyDouble к MyInt разрешено,
            //поскольку определено неявное преобразование
            MyInt di = (MyInt)d;
            //Неявное преобразование MyInt к MyDouble определено
            MyDouble id = di;
        }
    }
}

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

И еще одно замечание: если у вас определено неявное преобразование для конкретных двух типов, то определять для них явное преобразование необходимости нет - это лишнее, да и компилятор не позволит вам этого сделать.

Для классов, связанных “семейными узам” – отношением наследования – пользовательские операции преобразования типов запрещены категорически, поскольку это может привести к тому, что компилятор просто не поймет, чего от него хотят: выполнить преобразование типа или приведение экземпляра производного класса к базовому. О приведении типов чуть дальше, а следующий пример иллюстрирует реакцию компилятора на подобные провокации.

namespace CSharpQuickGuide
{
    class MyBaseClass
    {
        //Ошибка: определение преобразования типов между классами
        //одной иерархии запрещено. Попытка преобразования производного
        //класса к базовому
        //user-defined conversions to or from a derived class are not allowed!
        public static explicit operator MyBaseClass(MyInheritedClass c)
        { return new MyBaseClass(); }
    }

    class MyInheritedClass : MyBaseClass
    {
        //Ошибка: попытка преобразования базового класса к производному
        public static explicit operator MyInheritedClass(MyBaseClass c)
        { return new MyInheritedClass(); }
    }
}

Приведение типов

Если преобразование типов связано с заменой экземпляра одного типа на экземпляр другого типа, то их приведение используется только для того, чтобы работать с тем же экземпляром, но в ином поведенческом контексте. Используется приведение типов в двух случаях: для приведения экземпляров производных классов к их базовому классу, например, для осуществления единообразной их обработки; и для получения ссылки на интерфейс с аналогичными целями.

namespace CSharpQuickGuide
{
    interface MyInterface { }
    class MyBaseClass : MyInterface { }
    class MyInheritedClass : MyBaseClass { }

    static class TypeConversionSample04
    {
        static void Main()
        {
            //Приведение производного типа к базовому разрешено.
            MyBaseClass bc = new MyInheritedClass();
            //Ошибка: Приведение базового класса к производному запрещено.
            MyInheritedClass ic = new MyBaseClass();
            //Получение интерфейса у базового класса;
            MyInterface i1 = bc;
            //Получение интерфейса у производного класса;
            MyInterface i2 = ic;
        }
    }
}

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



Компьютерные курсы и курсы программирования
Основы программирования

Курс для начинающих программистов на C# и VB.NET.

SQL 25™

Построение SQL запросов и работа с базой данных.

C# Quick Guide™

Программирование на C#. Краткое руководство.

RegEx

Применение регулярных выражений.

Plug-in архитектура

Примеры программной Plug-in архитектуры.

XML и его расширения

Язык разметки XML и его расширения с примерами.

HTML и разметка гипертекста

Языки HTML, XHTML и CSS с примерами разметки.

Основы веб-дизайна

Основы веб-дизайна: решения типовых задач верстки.

Программирование на PHP

Руководство по программированию на PHP для начинающих.

Справочные материалы

Шаблоны проектирования
Каталог шаблонов проектирования программных компонентов.

Рефакторинг кода
Каталог приемов рефакторинга программного кода.

Гость
Имя

Пароль



Забыли пароль?
Запросите новый здесь
.
Coding Craft. Все права защищены © 2011. Проект Инициативного Народного Фронта Образования - ИНФО-проект.