Разработка приложений на C# в среде Visual Studio 2005

Типы данных C#

Разбить на страницы
Показывать лекцию целиком

Литералы

Литералами называются константы, содержащие явное значение соответствующего элементарного типа, не обозначенное идентификатором. Это могут быть:

  • Целые знаковые числа (11 - int )
  • Целые беззнаковые числа (11u, 11U - uint )
  • Целые длинные
  • Вещественные числа с плавающей точкой одинарной точности (11.0f, 11.0F - float )
  • Вещественные числа с плавающей точкой удвоенной точности (11.0d, 11.0D - double )
  • Денежные вещественные числа (11.0m, 11.0M - decimal ). Длина 16 байт для уменьшения ошибок округления
  • Логические (булевы) константы ( true, True, false, False - bool )
  • Символьные ('a' - char )
  • Строковые ("Привет" - string )
  • Строковые замороженные-буквальные (@"Привет" - string )
  • По сути, все элементарные типы имеют литералы для явного задания значений

    Элементарные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    void + Void Пусто Применяется для соблюдения синтаксиса
    sbyte - SByte -128 - 127 Знаковое 8 бит
    byte + Byte 0 - 255 Беззнаковое 8 бит
    short + Int16 -32'768 - 32'767 Знаковое 16 бит
    ushort - UInt16 0 - 65'535 Беззнаковое 16 бит
    int + Int32 -2'147'483'648 - 2'147'483'647 Знаковое 32 бит (4 байта)
    uint - UInt32 0 - 4'294'967'295 Беззнаковое 32 бит
    long + Int64 -9'223'372'036'854'775'808 - 9'223'372'036'854'775'807 Знаковое 64 бит (8 байт)
    ulong - UInt64 0 - 18'446'774'073'709'551'615 Беззнаковое 64 бит (8 байт)
    char + Char U+0000 - U+FFFF Для описания только одного символа Unicode 16 бит
    float + Single 1.5x10-45 - 3.4x1038 Знаковое с плавающей точкой 32 бит (4 байта)
    double + Double 5.0x10-324 - 1.7x10308 Знаковое с плавающей точкой 64 бит (8 байт)
    bool + Boolean true или false Логическое
    decimal + Decimal 100 - 1028 Знаковое целое (16 байт)
    string + String Ограничено только системной памятью Для описания строки символов Unicode любой длины
    object + Object Практически все что угодно. Все типы происходят от System.Object, поэтому объектом является все Класс, базовый для всех типов в . NET

    Вот простая программа, характеризующая литералы и элементарные типы

    using System;
        
    namespace Test
    {
        class Program
        {
        static string str;// Инициализируется пустой строкой
        
        static void Main(string[] args)
        {
        // Настройка консоли
        Console.Title = "Литералы и элементарные типы в C#";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        // Печать типов
        Console.WriteLine("Тип(длина) \t{Min}  ~  {Max}"
                    + Environment.NewLine);
        str += String.Format("sbyte({0})  \t{1}  ~  {2}\r\n",
                    sizeof(sbyte), sbyte.MinValue, sbyte.MaxValue);
        str += String.Format("byte({0})  \t{1}  ~  {2}\r\n",
                    sizeof(byte), byte.MinValue, byte.MaxValue);
        str += String.Format("short({0})  \t{1}  ~  {2}\r\n",
                    sizeof(short), short.MinValue, short.MaxValue);
        str += String.Format("ushort({0})  \t{1}  ~  {2}\r\n",
                    sizeof(ushort), ushort.MinValue, ushort.MaxValue);
        str += String.Format("int({0})  \t{1}  ~  {2}\r\n",
                    sizeof(int), int.MinValue, int.MaxValue);
        str += String.Format("uint({0})  \t{1}  ~  {2}\r\n",
                    sizeof(uint), uint.MinValue, uint.MaxValue);
        str += String.Format("long({0})  \t{1}  ~  {2}\r\n",
                    sizeof(long), long.MinValue, long.MaxValue);
        str += String.Format("ulong({0})  \t{1}  ~  {2}\r\n",
                    sizeof(ulong), ulong.MinValue, ulong.MaxValue);
        str += String.Format("char({0})  \t{1:X}  ~  {2:X}\r\n",
                    sizeof(char), (int)char.MinValue, (int)char.MaxValue);
        str += String.Format("float({0})  \t{1}  ~  {2}\r\n",
                    sizeof(float), float.MinValue, float.MaxValue);
        str += String.Format("double({0})  \t{1}  ~  {2}\r\n",
                    sizeof(double), double.MinValue, double.MaxValue);
        str += String.Format("decimal({0})  \t{1}  ~  {2}\r\n",
                    sizeof(decimal), decimal.MinValue, decimal.MaxValue);
        
        Console.WriteLine(str);
        
        Console.ReadLine();
        }
        }
    }

    Рузультат выполнения будет таким

    Управляющие последовательности

    В строковых литералах применяются управляющие последовательности.

  • \a - звуковой сигнал
  • \b - возврат на одну позицию
  • \f - прогон страницы
  • \n - новая строка
  • \r - возврат каретки
  • \t - горизонтальная табуляция
  • \v - вертикальная табуляция
  • \0 - нуль-символ
  • \' - одинарная кавычка
  • \" - двойная кавычка
  • \\ - обратный слэш
  • Буквальный строковый литерал

    Строковый литерал можно сделать буквальным ( verbatim - дословный), если перед открывающей кавычкой поставить символ @. Содержимое строки не интерпретируется и может быть многострочным. Но если внутри строкового литерала используется символ ", то его нужно заэкранировать таким же символом. Управляющие символы в такой строке не действуют.

    using System;
        
    namespace Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                // Настройка консоли
                Console.Title = "Буквальный строковый литерал";
                Console.ForegroundColor = ConsoleColor.White;
                Console.CursorVisible = false;
        
                // Буквальный строковый литерал
                string str;// Локальная переменная не инициализируется
                str =
    @"Привет всем от \n
        Иванова
        Петрова
        Сидорова
        ""Фантомаса""
    \t...............
        
    и от многих других";
        
                Console.WriteLine(str);
        
                Console.ReadLine();
            }
        }
    }

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

    С литералами можно обращаться как с переменными соответствующих типов (не забывая, что это константы), например, приводить литерал к другому типу или использовать методы типов, наследуемые от ValueType/Object. При приведении типа литерала к родственному типу переменной соблюдаются те же правила, что и при приведении типов переменных. Если тип переменной имеет количество байт для хранения ее значений, способный уместить максимальное значение литерала без потери данных, то его можно приводить неявно. В противном случае нужно указать оператор явного приведения типов.

    using System;
        
    namespace Test
    {
        class Program
        {
            static void Main()
            {
                // Настройка консоли
                Console.Title = "Приведение простых типов";
                Console.ForegroundColor = ConsoleColor.White;
        
                double a = 11.1f;// Неявное приведение малого к большому
                float b = (float)11.1d; // Явное приведение большого к малому
                float c = (int)11;// Неявное приведение целого к вещественному
                long d = (short)11; // Неявное приведение короткого к длинному
        
                string str = "";// Локальная переменная
                str += a.ToString() + "\t"
                     + b.ToString() + "\t"
                     + c.ToString() + "\t"
                     + d.ToString() + Environment.NewLine
                // Литералы - те же простые типы
                // и имеют соответствующие методы
                + (11.1f).ToString() + "\t"
                + (11.1d).ToString() + "\t"
                + (11).ToString() + "\t"
                + ((short)11.1f).ToString();
                Console.WriteLine(str);
        
                Console.WriteLine("\nВведите вещественное число");
                Console.Write("(дробная часть через запятую): ");
                str = Console.ReadLine();
                try
                {
                    float f = Convert.ToSingle(str);// Преобразование к float
                    Console.WriteLine("Вы ввели число: {0}", f);
                    int x = (int)f;
                    float y = f - x;
                    Console.WriteLine("\nЦелая часть числа: {0}", x);
                    Console.WriteLine("Дробная часть числа: {0}", y);
                }
                catch
                {
                    Console.WriteLine("Вы ввели не число");
                }
        
                Console.ReadLine();
            }
        }
    }

    Ссылочные и значимые типы

    Экземпляры классов создаются методами налету в управляемой куче, а ссылки на них размещаются в стеке потока. Такие типы называются ссылочными, поскольку в программе представлены не самими данными, а ссылками на них. Их экземпляры еще называют неименованными данными. С другой стороны, простые (элементарные) типы, структуры и перечисления (перечни) выведены из класса System.ValueType и их экземпляры представлены переменными, которые являются самими данными. Такие типы называют значимыми, а представляющие их переменные называют именованными данными.

    При работе метода все его локальные переменные помещаются в стек потока. Если локальная переменная, помещенная в стек, представляет ссылочный тип, то сами данные находятся в управляемой куче в области размещения объекта-экземпляра. Если локальная переменная представляет значимый тип, то все представленные ею данные размещаются в стеке. Тем не менее, методы любого вида размещаются в объекте-типе управляемой кучи, как и статические данные этого типа.

    Объекты значимого типа поддерживают два вида синтаксиса:

  • Статическое объявление ( int x; Point point;)
  • Динамическое объявление ( int x = new int(); Point point = new Point(); )
  • Динамическое объявление значимого типа предполагает одновременно создание и инициализацию объекта. Поэтому его допустимо применять и внутри метода. Статическое объявление предполагает неявный вызов конструктора по умолчанию только при объявлении полей класса. В этом случае допустимо применять как статическое, так и динамическое объявление с явным вызовом конструктора по умолчанию или пользовательского конструктора.

    Объявление значимых переменных сложных типов внутри метода требует явного вызова конструктора, поскольку неявная инициализация не производится. Простые значимые типы, поскольку они имеют только одно общедоступное значение, внутри метода допустимо вначале объявлять, а затем инициализировать литералом. Чтобы применить статическое объявление к сложному значимому типу нужно, чтобы все поля были общедоступными для явной инициализации литералами. Все локальные переменные перед их использованием должны быть инициализированы.

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

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

    using System;
        
    namespace Test
    {
        class Program
        {
            static void Main()
            {
                new Some();
        
                Console.ReadLine();
            }
        }
        
        struct Point
        {
            int x, y;
        
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            public void Show()
            {
                Console.WriteLine("x={0}; y={1}", x, y);
            }
        }
        
        class Some
        {
            //Point point;
        
            public Some()
            {
                Point point = new Point();
                point.Show();
            }
        }
    }

    Упаковка и распаковка значимых типов

    Иногда может потребоваться хранить значимый тип в управляемой куче с сохранением его адреса в ссылочной переменной. Ссылка должна иметь тип object, поскольку класс object является порождающим для всех типов C#. Такой процесс называется упаковкой значимого объекта. Синтаксис упаковки такой

    object refValue = point;

    Среда выполнения сама зарезервирует место в динамической области памяти и скопирует туда все данные значимого типа.

    Упакованный объект можно передать как ссылочный параметр любому внешнему методу. Обратный процесс получения значимого объекта по его ссылке называется распаковкой. По ссылке упакованного объекта нельзя обратиться к его членам. Для этого объект нужно распаковать. Синтаксис распаковки такой

    Point point = (Point)refValue;

    Ссылка на упакованный объект приводится с помощью явного преобразования к самому объекту того же типа. Типы упакованного и распакованного объектов должны быть совместимы, т.е. иметь одинаковую структуру данных и функций (из чего упаковали, в то и распаковываем).

    Экземпляр класса (объект), размещенный при выполнении метода в управляемой куче и адресуемый в программе по ссылке, называется упакованным. Структура или перечисление, размещаемые при выполнении метода в стеке потока, называются распакованными. Здесь речь идет только о членах-данных этих программных единиц.

    Поскольку структуры производятся от класса Systcode.ValueType, который, в свою очередь произошел от класса Systcode.Object, то значимый тип можно привести к ссылке на базовый класс Systcode.Object. Такая процедура называется упаковкой.

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

    using System;
        
    namespace Test
    {
        struct Point
        {
            // Поля
            public int x, y;
        
            // Конструктор
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Функция доступа
            public void Set(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Печать
            public void Show(string message)
            {
                Console.WriteLine(message + "x={0}, y={1}", x, y);
            }
        }
        
        // Класс с функцией Main не может иметь экземпляр
        // Поэтому все функции в этом классе должны быть статическими
        class EntryPoint
        {
        static Point valPoint3; // Поле в объекте-типе
        
        static void Main(string[] args)
        {
        // Настройка консоли
        Console.Title = "";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        Point valPoint = new Point(5, 10);// Инициализировали и поместили в стек
        valPoint.Show("Исходный объект в стеке: ");
        object refPoint = valPoint;// Упаковка: ссылка в стеке, объект в куче
        ((Point)refPoint).Show("\nИсходный объект в куче: ");
        object refPoint1 = refPoint;// Еще одна ссылка на объект в куче
        CreatePackPoint(ref refPoint1);// Создали еще один объект в куче
        ((Point)refPoint1).Show("\nНовый объект в куче: ");
        
        Point valPoint1 = new Point();
        valPoint1.Show("\nЕще один локальный объект в стеке: ");
        
        Point valPoint2;// Статическое объявление локального объекта
        valPoint2.x = 50;// Обязательная инициализация
        valPoint2.y = 70;// Обязательная инициализация
        valPoint2.Show("\nИ еще один локальный объект в стеке: ");
        
        valPoint3.Show("\nОбъект-поле в типе: ");
        
        Console.ReadLine();// Для задержки окна
        }
        
            static void CreatePackPoint(ref object arg)
            {
                Point point = (Point)arg;// Распаковываем
                point.Set(20, 30);// Изменяем
                arg = point;//Опять упаковываем
            }
        }
    }

    Автоматическая упаковка аргумента метода

    Процесс упаковки выполняется автоматически при передачи объекта методу в случае, если метод ожидает упакованный объект, а ему в качестве аргумента передается распакованный объект.

    using System;
        
    namespace Test
    {
        // Значимый тип, данные размещаются в стеке
        struct Point    
        {
            // Закрытые поля
            int x, y;
        
            // Конструктор
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Функция доступа
            public void Set(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Печать
            public void Show(string message)
            {
                Console.WriteLine(message + "x={0}, y={1}", x, y);
            }
        }
        
        // Класс с функцией Main может иметь экземпляр
        // Необязательно все функции в этом классе должны быть статическими
        class EntryPoint
        {
        static void Main()
        {
        // Настройка консоли
        Console.Title = "Автоматическая упаковка аргумента метода";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        Point valPoint = new Point(5, 10);// Инициализировали и поместили в стек
        valPoint.Show("Распакованный объект вне метода: ");
        Program prg = new Program();//!!!!!
        prg.AutoPackPoint(valPoint);// Создали еще один объект в куче
        valPoint.Show("Распакованный объект вне метода: ");
            
        Console.ReadLine();// Для задержки окна
        }
        
        // Метод ожидает упакованный объект, поэтому
        // автоматически упаковывает распакованный аргумент
        void AutoPackPoint(object arg)
        {
        // Проверим тип для подстраховки, чтобы не вызвать исключение
        if (arg is Point)
        {
        Point point = (Point)arg;// Распаковываем
        point.Set(20, 30);// Изменяем
        point.Show("Распакованный объект внутри метода: "); // Печатаем
        }
        else
        Console.WriteLine("Вы прислали не Point!");
        }
        }
    }

    Ручная распаковка аргумента метода

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

    using System;
        
    namespace Test
    {
        // Класс с функцией Main не может иметь экземпляр
        // Поэтому все функции в этом классе должны быть статическими
        class EntryPoint
        {
        static void Main()
        {
        // Настройка консоли
        Console.Title = "Распаковка аргумента метода вручную";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        Point valPoint = new Point(5, 10);// Инициализировали и поместили в стек
        valPoint.Show("Распакованный объект вне метода: ");
        object refPoint = valPoint;// Упаковали значимый объект
        ManualUnPackPoint((Point)refPoint);// Распаковываем вручную
            
        Console.ReadLine();// Для задержки окна
        }
        
        // Метод ожидает распакованный объект, распаковка 
        // должна выполняться вручную для контроля типов
        static void ManualUnPackPoint(Point arg)
        {
        arg.Set(20, 30);// Изменяем распакованную копию
        arg.Show("Копия объекта внутри метода: "); // Печатаем
        }
        }
    }
        
    namespace Test
    {
        // Значимый тип, данные размещаются в стеке
        struct Point
        {
            // Закрытые поля
            int x, y;
        
            // Конструктор
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Функция доступа
            public void Set(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Печать
            public void Show(string message)
            {
                Console.WriteLine(message + "x={0}, y={1}", x, y);
            }
        }
    }

    Перечисления (перечни)

    Перечисления ( enumerations ) относятся к значимому типу данных. Они представляют собой набор именованных целочисленных констант, по умолчанию заданных типом Int32. Синтаксис объявления перечисления следующий:

    модификатор_доступа enum имя_типа{список_членов}

    Список членов представляет собой список идентификаторов, разделенных запятыми. Модификатор доступа по умолчанию является internal - в пределах сборки. Для использования во внешней сборке нужно объявлять public (как и классы).

    using System;
        
    namespace Test
    {
        // Значимый тип, данные размещаются в стеке
        enum Fruit  // Фрукты
        {
            Apples,     // Яблоки
            Plums,      // Сливы
            Cherries,   // Вишни
            Grapes,     // Виноград
            Pears       // Груши
        }
        
        // Класс с функцией Main не может иметь экземпляр
        // Поэтому все функции в этом классе должны быть статическими
        class EntryPoint
        {
            static void Main()
            {
                // Настройка консоли
                Console.Title = "Использование перечислений";
                Console.ForegroundColor = ConsoleColor.White;
                Console.CursorVisible = false;
        
                string[] colorFruit = { // Массив цветов
                    "Красный",
                    "Синий",
                    "Вишневый",
                    "Зеленый",
                    "Черный"
                };
        
                string[] nameFruit = {  // Массив имен
                    "Яблоки",
                    "Сливы",
                    "Вишни",
                    "Виноград",
                    "Груши"
                };
        
                // Объявляем переменную перечислимого типа
                Fruit fruit;
        
                // Используем переменную перечисления для обхода всех членов
                for (fruit = Fruit.Apples; fruit <= Fruit.Pears; fruit++)
                    Console.WriteLine(fruit + " имеет 
                      значение " + (int)fruit);
        
                // Используем переменную перечисления для индексации массива
                Console.WriteLine();// Прогон строки
                for (fruit = Fruit.Apples; fruit <= Fruit.Pears; fruit++)
                    Console.WriteLine("Цвет фрукта " + fruit 
                        + " (" + nameFruit[(int)fruit] + 
                        ") - " + colorFruit[(int)fruit]);
        
                Console.ReadLine();// Для задержки окна
            }
        }
    }

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

    enum Fruit  // Фрукты
        {
            Apples,         // = 0
            Plums,          // = 1
            Cherries = 100,
            Grapes,         // = 101
            Pears           // = 102
        }

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

    enum Fruit  // Фрукты
        {
            Apples = 21,       
            Plums = 101,         
            Cherries = 100, 
            Grapes = 12,
            //Grapes = 3,
            Pears = 12 
        }

    Управление объемом памяти элементов перечисления

    Элементы перечисления, как значимого типа, загружаются в стек потока, и каждый по умолчанию имеет тип Int3 2 и занимает 4 байта. Ситуацию можно изменить, задав другой целочисленный тип (например, byte ) для всех элементов перечисления по следующему синтаксису

    enum Fruit : byte  // Фрукты
        {
            Apples = 21,       
            Plums = 101,         
            Cherries = 100, 
            Grapes = 12,
            Pears = 2 
        }
    using System;
        
    namespace Test
    {
        enum Fruit  // Фрукты
        {
            Apples,
            Plums,
            Cherries,
            Grapes,
            Pears
        }
        
        enum Fruit1 : byte  // Фрукты
        {
            Apples,
            Plums,
            Cherries,
            Grapes,
            Pears
        }
        
        enum Fruit2 : long  // Фрукты
        {
            Apples,
            Plums,
            Cherries,
            Grapes,
            Pears
        }
            
        class EntryPoint
        {
            static void Main()
            {
                // Настройка консоли
                Console.Title = "Использование перечислений";
                Console.ForegroundColor = ConsoleColor.White;
                Console.CursorVisible = false;
        
                Console.WriteLine("Члены Fruit имеют размер по "
                    + sizeof(Fruit) + " байта");
                Console.WriteLine("Члены Fruit1 имеют размер по "
                    + sizeof(Fruit1) + " байту");
                Console.WriteLine("Члены Fruit2 имеют размер по "
                    + sizeof(Fruit2) + " байт");
       
                Console.ReadLine();// Для задержки окна
            }
        }
    }

    Перечисления как члены класса

    Перечисления могут быть и членами класса

    using System;
        
    namespace Test
    {
        class EntryPoint
        {
            enum Fruit // Фрукты
            {
                Apples,
                Plums,
                Cherries,
                Grapes,
                Pears
            }
        
            static void Main()
            {
            // Настройка консоли
            Console.Title = "Использование перечислений";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
        
            // Объявляем переменную перечислимого типа
            Fruit fruit;
        
            // Используем переменную перечисления для обхода всех членов
            for (fruit = Fruit.Apples; fruit <= Fruit.Pears; fruit++)
              Console.WriteLine(fruit + " имеет 
                  значение " + (int)fruit);
        
            Console.ReadLine();// Для задержки окна
            }
        }
    }

    Использование библиотечного перечисления Keys для распознавания клавиш

    Приведенные способы применения перечислений встречаются очень редко, чаще используется прямое назначение перечислений как набора именованных целочисленных констант, упакованных в одном блоке кода. Библиотека .NET Framework содержит множество полезных перечислений, облегчающих программисту жизнь. Одно из таких перечислений System.Windows.Forms.Keys, содержащееся в одноименной библиотечной сборке System.Windows.Forms.dll.

    using System;
    using System.Windows.Forms;
    using System.Drawing;
        
    // Подключить через оболочку соответствующие сборки!!!!!!!!!!!
    namespace Test
    {
        class MyClass : Form
        {
            // Сообщение в окне
            string messageKey = "Нажимайте клавиши";
        
            public MyClass()    // Конструктор формы
            {
                // Настройка формы
        
                try // Безопасный код загрузки иконки
                {
                    this.Icon = new Icon("1.ICO");
                }
                catch { /* На исключения не реагировать */ }
        
                this.Text = "Перечисление Keys";
                this.Font = new Font("Arial", 14, FontStyle.Bold);
            }
        
            // Перегрузка метода OnPaint(), наследуемого от класса Control
            protected override void OnPaint(PaintEventArgs e)
            {
            Form frm = this;
            Graphics gr = e.Graphics;// Контекст экрана
            // Создаем и настраиваем точку привязки текстового блока
            StringFormat strfrm = new StringFormat();
            strfrm.Alignment = StringAlignment.Center;// Центр по горизонтали
            strfrm.LineAlignment = StringAlignment.Center;// Центр по вертикали
        
            // Точка привязки на форме
            PointF point = new PointF(frm.ClientSize.Width / 2,
                    frm.ClientSize.Height / 2);
        
            // Выводим содержимое строки поля класса
            gr.DrawString(messageKey,
            frm.Font, // Применяется шрифт окна
            new SolidBrush(Color.Red),  // Цвет шрифта
            point, // Точка привязки на форме
            strfrm); // Передаем точку привязки текстового блока
        
            // Выполняем обработчик события до полной глубины наследования
            base.OnPaint(e);
            }
        
            // Перегрузка метода OnKeyUp(), наследуемого от класса Control
            protected override void OnKeyUp(KeyEventArgs e)
            {
            // Временно сохраняем подсказку
            string mess = messageKey;
        
            // Анализируем нажатую клавишу
            switch (e.KeyCode)
            {
            case Keys.X:
            case Keys.Enter:
            case Keys.Escape:
              messageKey = "Нажата клавиша " + e.KeyCode
                + "\nAscii-код клавиши " + (byte)(e.KeyCode)
                + "\nЧто-то делаем...";
                break;
            case Keys.Space:
              messageKey = "Нажата клавиша " + Keys.Space
                + "\nAscii-код клавиши " + (byte)(Keys.Space)
                + "\nЧто-то делаем...";
                break;
            default:
              messageKey = "Нажата " + e.KeyCode
                + "\nAscii-код клавиши " + (byte)(e.KeyCode)
                + "\nОна нам не нужна!";
                break;
            }
            // Инициируем немедленную перерисовку формы
            // для вывода нового сообщения
            this.Refresh();
            //this.Invalidate(); // Удаляется из очереди при задержке потока
        
            // Усыпляем текущий поток на две секунды
            System.Threading.Thread.Sleep(2000);
        
            // Восстанавливаем подсказку
            messageKey = mess;
            // Инициируем перерисовку формы
            // для вывода восстановленной подсказки
            this.Invalidate();
        
            // Выполняем обработчик события до полной глубины наследования
            base.OnKeyUp(e);
            }
        }
    }
        
    namespace Test
    {
        class EntryPoint
        {
            static void Main()
            {
                // Настройка стиля формы
                Application.EnableVisualStyles();
                // Цикл сообщений Windows
                Application.Run(new MyClass());
            }
        }
    }

    Базовый класс System.Enum для работы с перечислениями

    Как только в приложении объявляется перечисление, тем самым неявно объявляется тип, производный от абстрактного класса System.Enum. Например, даже вот такой пустой код

    internal enum MyEnum
    {
    }
        
    internal class EntryPoint
    {
        static void Main()
        {
        }
    }

    дает следующую диаграмму в панели Class View оболочки

    Базовый класс System.Enum является абстрактным, поэтому не может напрямую иметь экземпляры (объекты), а может использоваться только как базовый в цепочке наследования. Тем не менее он определяет ряд статических методов, позволяющих обрабатывать созданные перечисления. Вот некоторые из этих методов.

    Некоторые статические методы класса Enum
    Метод Описание
    public static string Format(System.Type enumType, object value, string format) Преобразует значение данного типа перечисления в эквивалентное строковое представление в соответствии с указанным форматом
    public static string GetName(System.Type enumType, object value) Возвращает имя для константы с указанным значением
    public static string[] GetNames(System.Type enumType) Возвращает массив имен для константы с указанным значением
    public static System.Type GetUnderlyingType(System.Type enumType) Возвращает численный тип данных, используемый для хранения значений данного перечисления
    public static System.Array GetValues(System.Type enumType) Возвращает массив элементов указанного перечисления
    public static bool IsDefined(System.Type enumType, object value) Возвращает флаг существования в указанном перечислении заданного элемента
    public static object Parse(System.Type enumType, string value, bool ignoreCase) Упаковывает в объектную ссылку один или несколько элементов перечисления по их именам, заданным в строке
    public static object Parse(System.Type enumType, string value) Упаковывает в объектную ссылку один или несколько элементов перечисления по их именам, заданным в строке

    Приведем пример программы, использующей статические методы класса System.Enum.

    using System;
        
    namespace CHETKOB.Test
    {
        internal enum Fruit // Фрукты
        {
            Apples = 102,     // Яблоки
            Plums = 12,      // Сливы
            Cherries = 50,   // Вишни
            Grapes = 11,     // Виноград
            Pears = 211      // Груши
        }
        
        internal class MyClass
        {
        static void Main()
        {
        // Настройка консоли
        Console.Title = "Методы библиотечного класса Enum";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        // Анализируем перечисление Fruit
        Array fruitArray = Enum.GetValues(typeof(Fruit));
        Console.WriteLine("Определяем количество 
          членов перечисления:");
        Console.WriteLine("Перечисление содержит {0} 
          членов", fruitArray.Length);
        
        // Обходим все члены перечисления
        // и выводим пары "ключ-значение"
        Console.WriteLine("\nВыводим элементы перечисления:");
        foreach (Fruit fruit in fruitArray)
        {
        Console.Write("{0, -8} = {1, -3} ",// Количество знакомест
          fruit.ToString(),
          Enum.Format(typeof(Fruit), fruit, "D")); // Decimal - десятичный
        Console.WriteLine("(= 0x{0})",
          Enum.Format(typeof(Fruit), fruit, "X"));// Hex - шестнадцатиричный
        }
        
        // Ищем элемент по значению
        Console.WriteLine();
        Console.WriteLine("Ищем элемент по значению:");
        foreach (Fruit fruit in fruitArray)
          {
          int value = (int)fruit;
          Console.WriteLine("Значение {0, -3} 
              имеет элемент {1}", value,
            Enum.GetName(typeof(Fruit), value));
          }
        
        // Проверяем, есть ли элемент в указанном перечислении
        Console.WriteLine();
        Console.WriteLine("Проверяем существование 
          элемента в перечислении:");
        string element = "Apples";
        if (Enum.IsDefined(typeof(Fruit), element))
          Console.WriteLine("Элемент {0} в 
            перечислении есть", element);
        else
          Console.WriteLine("Элемента {0} в 
            перечислении нет", element);
        
        // Печатаем еще одно перечисление
        Console.WriteLine();
        Console.WriteLine("Печатаем еще одно перечисление:");
        Type weekdays = typeof(Days);
        foreach (string str in Enum.GetNames(weekdays))
          Console.WriteLine("{0,-11} = {1}", 
            str,// Резервирует 11 знакомест 
        Enum.Format(weekdays, Enum.Parse(weekdays, str), "d"));
        
        Console.ReadLine();
        }
        
        // Перечисление в классе. Доступ из других класов
        // сборки будет составным: MyClass.Days 
        internal enum Days
        {
        Понедельник, Вторник, Среда, Четверг,
        Пятница, Суббота, Воскресенье
        };
        }
    }

    Приложение. Типы данных в С#

    Целочисленные типы

    Целочисленные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    sbyte - SByte -128 - 127 Знаковое 8 бит
    byte + Byte 0 - 255 Беззнаковое 8 бит
    short + Int16 -32'768 - 32'767 Знаковое 16 бит
    ushort - UInt16 0 - 65'535 Беззнаковое 16 бит
    int + Int32 -2'147'483'648 - 2'147'483'647 Знаковое 32 бит
    uint - UInt32 0 - 4'294'967'295 Беззнаковое 32 бит
    long + Int64 -9'223'372'036'854'775'808 - 9'223'372'036'854'775'807 Знаковое 64 бит
    ulong - UInt64 0 - 18'446'774'073'709'551'615 Беззнаковое 64 бит

    Префикс s означает " signed " - знаковый; u - " unsigned " - беззнаковый

    Тип int

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

    using System;
      
    namespace Test
    {
      class Inches
      {
        static void Main()
        {
        long inches;
        long miles = 93000000; // Миль до Солнца
      
        // 5280 футов в миле, 12 дюймов в футе
        inches = miles * 5280 * 12;
        Console.WriteLine("Расстояние до Солнца: "
          + inches
          + " дюймов.");
      
        Console.Read();
        }
      }
    }

    Тип byte

    Тип byte предназначен для хранения чисел без знака от 0 до 255 размером 8 битов и полезен при обработке двоичных данных.

    Системные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    sbyte - SByte -128 - 127 Знаковое 8 бит
    byte + Byte 0 - 255 Беззнаковое 8 бит
    using System;
      
    namespace Test
    {
      class UseByte
      {
        static void Main()
        {
        byte x;
        int sum = 0;
      
        for(x = 1; x <= 100; x++)
          sum += x;
      
        Console.WriteLine("Сумма чисел от 
          1 до 100 равна " + sum);
      
        Console.Read();
        }
      }
    }

    Типы для представления чисел с плавающей точкой (вещественные типы)

    Вещественные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    float + Single 1.5x10-45 - 3.4x1038 Знаковое с плавающей точкой 32 бит
    double + Double 5.0x10-324 - 1.7x10308 Знаковое с плавающей точкой 64 бит

    Чаще всего используется тип double, поскольку он поддерживается множеством математических функций библиотеки .NET Framework. Большинство математических функций сосредоточено в классе System.Math

    using System;
      
    namespace Test
    {
      // Нахождение радиуса круга по его площади
      class FindRadius
      {
        static void Main()
        {
        double radius, area = 10.0;  
      
        radius = Math.Sqrt(area / Math.PI);
        Console.WriteLine("Площадь круга: 
          {0};", area);
        Console.WriteLine("Радиус круга: 
          {0};", radius);
      
        Console.Read();
        }
      }
    }
    using System;
      
    namespace Test
    {
      // Использование тригонометрических методов
      class Trigonometry
      {
        static void Main()
        {
        for(int i = 0; i < 3; i++) // Внешний цикл
        {
        // alpha - угол в градусах
        for(double alpha = 0D; alpha <= 180; alpha = alpha + 10)
        {
        switch(i + 1)
          {
          case 1: Console.WriteLine("Sin({0})={1}", 
            alpha, Math.Sin(alpha / 180 * Math.PI));
            break;
      case 2: Console.WriteLine("Cos({0})={1}", 
        alpha, Math.Cos(alpha / 180 * Math.PI));
            break;
          case 3: Console.WriteLine("Tan({0})={1}",
             alpha, Math.Tan(alpha / 180 * Math.PI));
            break;
          }
        }
        Console.WriteLine();
        }
      
        Console.Read();
      }
      }
    }

    Тип decimal

    Предназначен для выполнения вычислений, связанных с денежными единицами.

    Тип decimal в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    decimal + Decimal 10-28 —1028 Знаковое 128 бит

    Применение обычной арифметики с плавающей точкой чревато ошибками округления. Во избежании этих ошибок и предназначен тип decimal.

    using System;
      
    namespace Test
    {
      // Использование типа decimal для вычисления скидки
      class UseDecimal
      {
      static void Main()
      {
      decimal price; // Цена
      decimal discount; // Скидка
      decimal discounted_price; // Цена со скидкой
      
      // Вычисляем цену со скидкой
      price = 19.95M; // Цена товара
      discount = 0.15m; // Ставка дисконта равна 15%
      discounted_price = price - (price * discount);// Скобки не обязательны
      
      Console.WriteLine("Цена со скидкой: $"
        + discounted_price);
      
      Console.Read();
      }
      }
    }
    using System;
      
    namespace Test
    {
      /* 
       * Использование типа decimal для вычисления
       * будущей стоимости капиталовложений
       */
      class UseDecimal
      {
      static void Main()
      {
      decimal amount; // Исходный вклад
      decimal rate_of_return; // Норма прибыли
      int years; // Количество лет
      
      amount = 1000M;
      rate_of_return = .07m;
      years = 10;
      
      Console.WriteLine("Исходный вклад: 
        $" + amount);
      Console.WriteLine("Норма прибыли: 
        " + rate_of_return);
      Console.Write("Через " + years + 
        " лет будет $");
      
      for(int i = 0; i < years; i++)
        amount += amount * rate_of_return;
      
      Console.WriteLine(amount);
      
      Console.Read();
      }
      }
    }

    Символьный тип

    В C# исмволы представлются не в однобайтном коде ASCII, а в двухбайтном коде Unicode. Это позволяет представлять алфавиты всех существующих в мире языков. Это 16 - разрядный тип без знака.

    Системные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    char + Char U+0000 - U+FFFF Для описания только одного символа Unicode 16 бит

    Символьной переменной можно присвоить значение, заключив соответствующий символ в одинарные кавычки. Например

    char ch;
    ch = 'X';
    using System;
      
    namespace Test
    {
      class UseDecimal
      {
      static void Main()
      {
      char ch0 = 'П', ch1 = 'р', 
          ch2 = 'и', ch3 = 'в', 
          ch4 = 'е', ch5 = 'т';
      
      Console.WriteLine((int)ch0);
      Console.WriteLine((int)ch1);
      Console.WriteLine((int)ch2);
      Console.WriteLine((int)ch3);
      Console.WriteLine((int)ch4);
      Console.WriteLine((int)ch5 + "\n");
      
      Console.WriteLine(ch0 + ch1 + ch2 + ch3 + ch4 + ch5);
      Console.WriteLine();
      
      Console.WriteLine(ch0);
      Console.WriteLine(ch1);
      Console.WriteLine(ch2);
      Console.WriteLine(ch3);
      Console.WriteLine(ch4);
      Console.WriteLine(ch5 + "\n");
      
      Console.WriteLine("{0}{1}{2}{3}{4}{5}\n", 
          ch0, ch1, ch2, ch3, ch4, ch5);
      
      string str = Convert.ToString(ch0) 
          + Convert.ToString(ch1) 
          + Convert.ToString(ch2) 
          + Convert.ToString(ch3) 
          + Convert.ToString(ch4) 
          + Convert.ToString(ch5);
      Console.WriteLine(str);
      
      Console.Read();
      }
      }
    }

    Логический тип bool

    Тип bool в C# представляет логические значения true или false ( ИСТИНА/ЛОЖЬ ), которые можно использовать в операторах управления (условия, циклы).

    using System;
      
    namespace Test
    {
      class UseBool
      {
      static void Main()
      {
      bool logical;
      logical = false;
      
      int i;
      for(i = 0; i < 2; i++)
      {
      logical = !logical;
      Console.Write("logical={0}: ", logical);
      if(logical)
        Console.WriteLine("Привет от Иванова!");
      else
        Console.WriteLine("Привет от Петрова!");
      }
      Console.WriteLine("10 > 9 равно " + (10 > 9));
      
      Console.Read();
      }
      }
    }
    Страницы:

    Литералы

    Литералами называются константы, содержащие явное значение соответствующего элементарного типа, не обозначенное идентификатором. Это могут быть:

  • Целые знаковые числа (11 - int )
  • Целые беззнаковые числа (11u, 11U - uint )
  • Целые длинные
  • Вещественные числа с плавающей точкой одинарной точности (11.0f, 11.0F - float )
  • Вещественные числа с плавающей точкой удвоенной точности (11.0d, 11.0D - double )
  • Денежные вещественные числа (11.0m, 11.0M - decimal ). Длина 16 байт для уменьшения ошибок округления
  • Логические (булевы) константы ( true, True, false, False - bool )
  • Символьные ('a' - char )
  • Строковые ("Привет" - string )
  • Строковые замороженные-буквальные (@"Привет" - string )
  • По сути, все элементарные типы имеют литералы для явного задания значений

    Элементарные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    void + Void Пусто Применяется для соблюдения синтаксиса
    sbyte - SByte -128 - 127 Знаковое 8 бит
    byte + Byte 0 - 255 Беззнаковое 8 бит
    short + Int16 -32'768 - 32'767 Знаковое 16 бит
    ushort - UInt16 0 - 65'535 Беззнаковое 16 бит
    int + Int32 -2'147'483'648 - 2'147'483'647 Знаковое 32 бит (4 байта)
    uint - UInt32 0 - 4'294'967'295 Беззнаковое 32 бит
    long + Int64 -9'223'372'036'854'775'808 - 9'223'372'036'854'775'807 Знаковое 64 бит (8 байт)
    ulong - UInt64 0 - 18'446'774'073'709'551'615 Беззнаковое 64 бит (8 байт)
    char + Char U+0000 - U+FFFF Для описания только одного символа Unicode 16 бит
    float + Single 1.5x10-45 - 3.4x1038 Знаковое с плавающей точкой 32 бит (4 байта)
    double + Double 5.0x10-324 - 1.7x10308 Знаковое с плавающей точкой 64 бит (8 байт)
    bool + Boolean true или false Логическое
    decimal + Decimal 100 - 1028 Знаковое целое (16 байт)
    string + String Ограничено только системной памятью Для описания строки символов Unicode любой длины
    object + Object Практически все что угодно. Все типы происходят от System.Object, поэтому объектом является все Класс, базовый для всех типов в . NET

    Вот простая программа, характеризующая литералы и элементарные типы

    using System;
        
    namespace Test
    {
        class Program
        {
        static string str;// Инициализируется пустой строкой
        
        static void Main(string[] args)
        {
        // Настройка консоли
        Console.Title = "Литералы и элементарные типы в C#";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        // Печать типов
        Console.WriteLine("Тип(длина) \t{Min}  ~  {Max}"
                    + Environment.NewLine);
        str += String.Format("sbyte({0})  \t{1}  ~  {2}\r\n",
                    sizeof(sbyte), sbyte.MinValue, sbyte.MaxValue);
        str += String.Format("byte({0})  \t{1}  ~  {2}\r\n",
                    sizeof(byte), byte.MinValue, byte.MaxValue);
        str += String.Format("short({0})  \t{1}  ~  {2}\r\n",
                    sizeof(short), short.MinValue, short.MaxValue);
        str += String.Format("ushort({0})  \t{1}  ~  {2}\r\n",
                    sizeof(ushort), ushort.MinValue, ushort.MaxValue);
        str += String.Format("int({0})  \t{1}  ~  {2}\r\n",
                    sizeof(int), int.MinValue, int.MaxValue);
        str += String.Format("uint({0})  \t{1}  ~  {2}\r\n",
                    sizeof(uint), uint.MinValue, uint.MaxValue);
        str += String.Format("long({0})  \t{1}  ~  {2}\r\n",
                    sizeof(long), long.MinValue, long.MaxValue);
        str += String.Format("ulong({0})  \t{1}  ~  {2}\r\n",
                    sizeof(ulong), ulong.MinValue, ulong.MaxValue);
        str += String.Format("char({0})  \t{1:X}  ~  {2:X}\r\n",
                    sizeof(char), (int)char.MinValue, (int)char.MaxValue);
        str += String.Format("float({0})  \t{1}  ~  {2}\r\n",
                    sizeof(float), float.MinValue, float.MaxValue);
        str += String.Format("double({0})  \t{1}  ~  {2}\r\n",
                    sizeof(double), double.MinValue, double.MaxValue);
        str += String.Format("decimal({0})  \t{1}  ~  {2}\r\n",
                    sizeof(decimal), decimal.MinValue, decimal.MaxValue);
        
        Console.WriteLine(str);
        
        Console.ReadLine();
        }
        }
    }

    Рузультат выполнения будет таким

    Управляющие последовательности

    В строковых литералах применяются управляющие последовательности.

  • \a - звуковой сигнал
  • \b - возврат на одну позицию
  • \f - прогон страницы
  • \n - новая строка
  • \r - возврат каретки
  • \t - горизонтальная табуляция
  • \v - вертикальная табуляция
  • \0 - нуль-символ
  • \' - одинарная кавычка
  • \" - двойная кавычка
  • \\ - обратный слэш
  • Буквальный строковый литерал

    Строковый литерал можно сделать буквальным ( verbatim - дословный), если перед открывающей кавычкой поставить символ @. Содержимое строки не интерпретируется и может быть многострочным. Но если внутри строкового литерала используется символ ", то его нужно заэкранировать таким же символом. Управляющие символы в такой строке не действуют.

    using System;
        
    namespace Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                // Настройка консоли
                Console.Title = "Буквальный строковый литерал";
                Console.ForegroundColor = ConsoleColor.White;
                Console.CursorVisible = false;
        
                // Буквальный строковый литерал
                string str;// Локальная переменная не инициализируется
                str =
    @"Привет всем от \n
        Иванова
        Петрова
        Сидорова
        ""Фантомаса""
    \t...............
        
    и от многих других";
        
                Console.WriteLine(str);
        
                Console.ReadLine();
            }
        }
    }

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

    С литералами можно обращаться как с переменными соответствующих типов (не забывая, что это константы), например, приводить литерал к другому типу или использовать методы типов, наследуемые от ValueType/Object. При приведении типа литерала к родственному типу переменной соблюдаются те же правила, что и при приведении типов переменных. Если тип переменной имеет количество байт для хранения ее значений, способный уместить максимальное значение литерала без потери данных, то его можно приводить неявно. В противном случае нужно указать оператор явного приведения типов.

    using System;
        
    namespace Test
    {
        class Program
        {
            static void Main()
            {
                // Настройка консоли
                Console.Title = "Приведение простых типов";
                Console.ForegroundColor = ConsoleColor.White;
        
                double a = 11.1f;// Неявное приведение малого к большому
                float b = (float)11.1d; // Явное приведение большого к малому
                float c = (int)11;// Неявное приведение целого к вещественному
                long d = (short)11; // Неявное приведение короткого к длинному
        
                string str = "";// Локальная переменная
                str += a.ToString() + "\t"
                     + b.ToString() + "\t"
                     + c.ToString() + "\t"
                     + d.ToString() + Environment.NewLine
                // Литералы - те же простые типы
                // и имеют соответствующие методы
                + (11.1f).ToString() + "\t"
                + (11.1d).ToString() + "\t"
                + (11).ToString() + "\t"
                + ((short)11.1f).ToString();
                Console.WriteLine(str);
        
                Console.WriteLine("\nВведите вещественное число");
                Console.Write("(дробная часть через запятую): ");
                str = Console.ReadLine();
                try
                {
                    float f = Convert.ToSingle(str);// Преобразование к float
                    Console.WriteLine("Вы ввели число: {0}", f);
                    int x = (int)f;
                    float y = f - x;
                    Console.WriteLine("\nЦелая часть числа: {0}", x);
                    Console.WriteLine("Дробная часть числа: {0}", y);
                }
                catch
                {
                    Console.WriteLine("Вы ввели не число");
                }
        
                Console.ReadLine();
            }
        }
    }

    Ссылочные и значимые типы

    Экземпляры классов создаются методами налету в управляемой куче, а ссылки на них размещаются в стеке потока. Такие типы называются ссылочными, поскольку в программе представлены не самими данными, а ссылками на них. Их экземпляры еще называют неименованными данными. С другой стороны, простые (элементарные) типы, структуры и перечисления (перечни) выведены из класса System.ValueType и их экземпляры представлены переменными, которые являются самими данными. Такие типы называют значимыми, а представляющие их переменные называют именованными данными.

    При работе метода все его локальные переменные помещаются в стек потока. Если локальная переменная, помещенная в стек, представляет ссылочный тип, то сами данные находятся в управляемой куче в области размещения объекта-экземпляра. Если локальная переменная представляет значимый тип, то все представленные ею данные размещаются в стеке. Тем не менее, методы любого вида размещаются в объекте-типе управляемой кучи, как и статические данные этого типа.

    Объекты значимого типа поддерживают два вида синтаксиса:

  • Статическое объявление ( int x; Point point;)
  • Динамическое объявление ( int x = new int(); Point point = new Point(); )
  • Динамическое объявление значимого типа предполагает одновременно создание и инициализацию объекта. Поэтому его допустимо применять и внутри метода. Статическое объявление предполагает неявный вызов конструктора по умолчанию только при объявлении полей класса. В этом случае допустимо применять как статическое, так и динамическое объявление с явным вызовом конструктора по умолчанию или пользовательского конструктора.

    Объявление значимых переменных сложных типов внутри метода требует явного вызова конструктора, поскольку неявная инициализация не производится. Простые значимые типы, поскольку они имеют только одно общедоступное значение, внутри метода допустимо вначале объявлять, а затем инициализировать литералом. Чтобы применить статическое объявление к сложному значимому типу нужно, чтобы все поля были общедоступными для явной инициализации литералами. Все локальные переменные перед их использованием должны быть инициализированы.

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

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

    using System;
        
    namespace Test
    {
        class Program
        {
            static void Main()
            {
                new Some();
        
                Console.ReadLine();
            }
        }
        
        struct Point
        {
            int x, y;
        
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            public void Show()
            {
                Console.WriteLine("x={0}; y={1}", x, y);
            }
        }
        
        class Some
        {
            //Point point;
        
            public Some()
            {
                Point point = new Point();
                point.Show();
            }
        }
    }

    Упаковка и распаковка значимых типов

    Иногда может потребоваться хранить значимый тип в управляемой куче с сохранением его адреса в ссылочной переменной. Ссылка должна иметь тип object, поскольку класс object является порождающим для всех типов C#. Такой процесс называется упаковкой значимого объекта. Синтаксис упаковки такой

    object refValue = point;

    Среда выполнения сама зарезервирует место в динамической области памяти и скопирует туда все данные значимого типа.

    Упакованный объект можно передать как ссылочный параметр любому внешнему методу. Обратный процесс получения значимого объекта по его ссылке называется распаковкой. По ссылке упакованного объекта нельзя обратиться к его членам. Для этого объект нужно распаковать. Синтаксис распаковки такой

    Point point = (Point)refValue;

    Ссылка на упакованный объект приводится с помощью явного преобразования к самому объекту того же типа. Типы упакованного и распакованного объектов должны быть совместимы, т.е. иметь одинаковую структуру данных и функций (из чего упаковали, в то и распаковываем).

    Экземпляр класса (объект), размещенный при выполнении метода в управляемой куче и адресуемый в программе по ссылке, называется упакованным. Структура или перечисление, размещаемые при выполнении метода в стеке потока, называются распакованными. Здесь речь идет только о членах-данных этих программных единиц.

    Поскольку структуры производятся от класса Systcode.ValueType, который, в свою очередь произошел от класса Systcode.Object, то значимый тип можно привести к ссылке на базовый класс Systcode.Object. Такая процедура называется упаковкой.

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

    using System;
        
    namespace Test
    {
        struct Point
        {
            // Поля
            public int x, y;
        
            // Конструктор
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Функция доступа
            public void Set(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Печать
            public void Show(string message)
            {
                Console.WriteLine(message + "x={0}, y={1}", x, y);
            }
        }
        
        // Класс с функцией Main не может иметь экземпляр
        // Поэтому все функции в этом классе должны быть статическими
        class EntryPoint
        {
        static Point valPoint3; // Поле в объекте-типе
        
        static void Main(string[] args)
        {
        // Настройка консоли
        Console.Title = "";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        Point valPoint = new Point(5, 10);// Инициализировали и поместили в стек
        valPoint.Show("Исходный объект в стеке: ");
        object refPoint = valPoint;// Упаковка: ссылка в стеке, объект в куче
        ((Point)refPoint).Show("\nИсходный объект в куче: ");
        object refPoint1 = refPoint;// Еще одна ссылка на объект в куче
        CreatePackPoint(ref refPoint1);// Создали еще один объект в куче
        ((Point)refPoint1).Show("\nНовый объект в куче: ");
        
        Point valPoint1 = new Point();
        valPoint1.Show("\nЕще один локальный объект в стеке: ");
        
        Point valPoint2;// Статическое объявление локального объекта
        valPoint2.x = 50;// Обязательная инициализация
        valPoint2.y = 70;// Обязательная инициализация
        valPoint2.Show("\nИ еще один локальный объект в стеке: ");
        
        valPoint3.Show("\nОбъект-поле в типе: ");
        
        Console.ReadLine();// Для задержки окна
        }
        
            static void CreatePackPoint(ref object arg)
            {
                Point point = (Point)arg;// Распаковываем
                point.Set(20, 30);// Изменяем
                arg = point;//Опять упаковываем
            }
        }
    }

    Автоматическая упаковка аргумента метода

    Процесс упаковки выполняется автоматически при передачи объекта методу в случае, если метод ожидает упакованный объект, а ему в качестве аргумента передается распакованный объект.

    using System;
        
    namespace Test
    {
        // Значимый тип, данные размещаются в стеке
        struct Point    
        {
            // Закрытые поля
            int x, y;
        
            // Конструктор
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Функция доступа
            public void Set(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Печать
            public void Show(string message)
            {
                Console.WriteLine(message + "x={0}, y={1}", x, y);
            }
        }
        
        // Класс с функцией Main может иметь экземпляр
        // Необязательно все функции в этом классе должны быть статическими
        class EntryPoint
        {
        static void Main()
        {
        // Настройка консоли
        Console.Title = "Автоматическая упаковка аргумента метода";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        Point valPoint = new Point(5, 10);// Инициализировали и поместили в стек
        valPoint.Show("Распакованный объект вне метода: ");
        Program prg = new Program();//!!!!!
        prg.AutoPackPoint(valPoint);// Создали еще один объект в куче
        valPoint.Show("Распакованный объект вне метода: ");
            
        Console.ReadLine();// Для задержки окна
        }
        
        // Метод ожидает упакованный объект, поэтому
        // автоматически упаковывает распакованный аргумент
        void AutoPackPoint(object arg)
        {
        // Проверим тип для подстраховки, чтобы не вызвать исключение
        if (arg is Point)
        {
        Point point = (Point)arg;// Распаковываем
        point.Set(20, 30);// Изменяем
        point.Show("Распакованный объект внутри метода: "); // Печатаем
        }
        else
        Console.WriteLine("Вы прислали не Point!");
        }
        }
    }

    Ручная распаковка аргумента метода

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

    using System;
        
    namespace Test
    {
        // Класс с функцией Main не может иметь экземпляр
        // Поэтому все функции в этом классе должны быть статическими
        class EntryPoint
        {
        static void Main()
        {
        // Настройка консоли
        Console.Title = "Распаковка аргумента метода вручную";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        Point valPoint = new Point(5, 10);// Инициализировали и поместили в стек
        valPoint.Show("Распакованный объект вне метода: ");
        object refPoint = valPoint;// Упаковали значимый объект
        ManualUnPackPoint((Point)refPoint);// Распаковываем вручную
            
        Console.ReadLine();// Для задержки окна
        }
        
        // Метод ожидает распакованный объект, распаковка 
        // должна выполняться вручную для контроля типов
        static void ManualUnPackPoint(Point arg)
        {
        arg.Set(20, 30);// Изменяем распакованную копию
        arg.Show("Копия объекта внутри метода: "); // Печатаем
        }
        }
    }
        
    namespace Test
    {
        // Значимый тип, данные размещаются в стеке
        struct Point
        {
            // Закрытые поля
            int x, y;
        
            // Конструктор
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Функция доступа
            public void Set(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        
            // Печать
            public void Show(string message)
            {
                Console.WriteLine(message + "x={0}, y={1}", x, y);
            }
        }
    }

    Перечисления (перечни)

    Перечисления ( enumerations ) относятся к значимому типу данных. Они представляют собой набор именованных целочисленных констант, по умолчанию заданных типом Int32. Синтаксис объявления перечисления следующий:

    модификатор_доступа enum имя_типа{список_членов}

    Список членов представляет собой список идентификаторов, разделенных запятыми. Модификатор доступа по умолчанию является internal - в пределах сборки. Для использования во внешней сборке нужно объявлять public (как и классы).

    using System;
        
    namespace Test
    {
        // Значимый тип, данные размещаются в стеке
        enum Fruit  // Фрукты
        {
            Apples,     // Яблоки
            Plums,      // Сливы
            Cherries,   // Вишни
            Grapes,     // Виноград
            Pears       // Груши
        }
        
        // Класс с функцией Main не может иметь экземпляр
        // Поэтому все функции в этом классе должны быть статическими
        class EntryPoint
        {
            static void Main()
            {
                // Настройка консоли
                Console.Title = "Использование перечислений";
                Console.ForegroundColor = ConsoleColor.White;
                Console.CursorVisible = false;
        
                string[] colorFruit = { // Массив цветов
                    "Красный",
                    "Синий",
                    "Вишневый",
                    "Зеленый",
                    "Черный"
                };
        
                string[] nameFruit = {  // Массив имен
                    "Яблоки",
                    "Сливы",
                    "Вишни",
                    "Виноград",
                    "Груши"
                };
        
                // Объявляем переменную перечислимого типа
                Fruit fruit;
        
                // Используем переменную перечисления для обхода всех членов
                for (fruit = Fruit.Apples; fruit <= Fruit.Pears; fruit++)
                    Console.WriteLine(fruit + " имеет 
                      значение " + (int)fruit);
        
                // Используем переменную перечисления для индексации массива
                Console.WriteLine();// Прогон строки
                for (fruit = Fruit.Apples; fruit <= Fruit.Pears; fruit++)
                    Console.WriteLine("Цвет фрукта " + fruit 
                        + " (" + nameFruit[(int)fruit] + 
                        ") - " + colorFruit[(int)fruit]);
        
                Console.ReadLine();// Для задержки окна
            }
        }
    }

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

    enum Fruit  // Фрукты
        {
            Apples,         // = 0
            Plums,          // = 1
            Cherries = 100,
            Grapes,         // = 101
            Pears           // = 102
        }

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

    enum Fruit  // Фрукты
        {
            Apples = 21,       
            Plums = 101,         
            Cherries = 100, 
            Grapes = 12,
            //Grapes = 3,
            Pears = 12 
        }

    Управление объемом памяти элементов перечисления

    Элементы перечисления, как значимого типа, загружаются в стек потока, и каждый по умолчанию имеет тип Int3 2 и занимает 4 байта. Ситуацию можно изменить, задав другой целочисленный тип (например, byte ) для всех элементов перечисления по следующему синтаксису

    enum Fruit : byte  // Фрукты
        {
            Apples = 21,       
            Plums = 101,         
            Cherries = 100, 
            Grapes = 12,
            Pears = 2 
        }
    using System;
        
    namespace Test
    {
        enum Fruit  // Фрукты
        {
            Apples,
            Plums,
            Cherries,
            Grapes,
            Pears
        }
        
        enum Fruit1 : byte  // Фрукты
        {
            Apples,
            Plums,
            Cherries,
            Grapes,
            Pears
        }
        
        enum Fruit2 : long  // Фрукты
        {
            Apples,
            Plums,
            Cherries,
            Grapes,
            Pears
        }
            
        class EntryPoint
        {
            static void Main()
            {
                // Настройка консоли
                Console.Title = "Использование перечислений";
                Console.ForegroundColor = ConsoleColor.White;
                Console.CursorVisible = false;
        
                Console.WriteLine("Члены Fruit имеют размер по "
                    + sizeof(Fruit) + " байта");
                Console.WriteLine("Члены Fruit1 имеют размер по "
                    + sizeof(Fruit1) + " байту");
                Console.WriteLine("Члены Fruit2 имеют размер по "
                    + sizeof(Fruit2) + " байт");
       
                Console.ReadLine();// Для задержки окна
            }
        }
    }

    Перечисления как члены класса

    Перечисления могут быть и членами класса

    using System;
        
    namespace Test
    {
        class EntryPoint
        {
            enum Fruit // Фрукты
            {
                Apples,
                Plums,
                Cherries,
                Grapes,
                Pears
            }
        
            static void Main()
            {
            // Настройка консоли
            Console.Title = "Использование перечислений";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
        
            // Объявляем переменную перечислимого типа
            Fruit fruit;
        
            // Используем переменную перечисления для обхода всех членов
            for (fruit = Fruit.Apples; fruit <= Fruit.Pears; fruit++)
              Console.WriteLine(fruit + " имеет 
                  значение " + (int)fruit);
        
            Console.ReadLine();// Для задержки окна
            }
        }
    }

    Использование библиотечного перечисления Keys для распознавания клавиш

    Приведенные способы применения перечислений встречаются очень редко, чаще используется прямое назначение перечислений как набора именованных целочисленных констант, упакованных в одном блоке кода. Библиотека .NET Framework содержит множество полезных перечислений, облегчающих программисту жизнь. Одно из таких перечислений System.Windows.Forms.Keys, содержащееся в одноименной библиотечной сборке System.Windows.Forms.dll.

    using System;
    using System.Windows.Forms;
    using System.Drawing;
        
    // Подключить через оболочку соответствующие сборки!!!!!!!!!!!
    namespace Test
    {
        class MyClass : Form
        {
            // Сообщение в окне
            string messageKey = "Нажимайте клавиши";
        
            public MyClass()    // Конструктор формы
            {
                // Настройка формы
        
                try // Безопасный код загрузки иконки
                {
                    this.Icon = new Icon("1.ICO");
                }
                catch { /* На исключения не реагировать */ }
        
                this.Text = "Перечисление Keys";
                this.Font = new Font("Arial", 14, FontStyle.Bold);
            }
        
            // Перегрузка метода OnPaint(), наследуемого от класса Control
            protected override void OnPaint(PaintEventArgs e)
            {
            Form frm = this;
            Graphics gr = e.Graphics;// Контекст экрана
            // Создаем и настраиваем точку привязки текстового блока
            StringFormat strfrm = new StringFormat();
            strfrm.Alignment = StringAlignment.Center;// Центр по горизонтали
            strfrm.LineAlignment = StringAlignment.Center;// Центр по вертикали
        
            // Точка привязки на форме
            PointF point = new PointF(frm.ClientSize.Width / 2,
                    frm.ClientSize.Height / 2);
        
            // Выводим содержимое строки поля класса
            gr.DrawString(messageKey,
            frm.Font, // Применяется шрифт окна
            new SolidBrush(Color.Red),  // Цвет шрифта
            point, // Точка привязки на форме
            strfrm); // Передаем точку привязки текстового блока
        
            // Выполняем обработчик события до полной глубины наследования
            base.OnPaint(e);
            }
        
            // Перегрузка метода OnKeyUp(), наследуемого от класса Control
            protected override void OnKeyUp(KeyEventArgs e)
            {
            // Временно сохраняем подсказку
            string mess = messageKey;
        
            // Анализируем нажатую клавишу
            switch (e.KeyCode)
            {
            case Keys.X:
            case Keys.Enter:
            case Keys.Escape:
              messageKey = "Нажата клавиша " + e.KeyCode
                + "\nAscii-код клавиши " + (byte)(e.KeyCode)
                + "\nЧто-то делаем...";
                break;
            case Keys.Space:
              messageKey = "Нажата клавиша " + Keys.Space
                + "\nAscii-код клавиши " + (byte)(Keys.Space)
                + "\nЧто-то делаем...";
                break;
            default:
              messageKey = "Нажата " + e.KeyCode
                + "\nAscii-код клавиши " + (byte)(e.KeyCode)
                + "\nОна нам не нужна!";
                break;
            }
            // Инициируем немедленную перерисовку формы
            // для вывода нового сообщения
            this.Refresh();
            //this.Invalidate(); // Удаляется из очереди при задержке потока
        
            // Усыпляем текущий поток на две секунды
            System.Threading.Thread.Sleep(2000);
        
            // Восстанавливаем подсказку
            messageKey = mess;
            // Инициируем перерисовку формы
            // для вывода восстановленной подсказки
            this.Invalidate();
        
            // Выполняем обработчик события до полной глубины наследования
            base.OnKeyUp(e);
            }
        }
    }
        
    namespace Test
    {
        class EntryPoint
        {
            static void Main()
            {
                // Настройка стиля формы
                Application.EnableVisualStyles();
                // Цикл сообщений Windows
                Application.Run(new MyClass());
            }
        }
    }

    Базовый класс System.Enum для работы с перечислениями

    Как только в приложении объявляется перечисление, тем самым неявно объявляется тип, производный от абстрактного класса System.Enum. Например, даже вот такой пустой код

    internal enum MyEnum
    {
    }
        
    internal class EntryPoint
    {
        static void Main()
        {
        }
    }

    дает следующую диаграмму в панели Class View оболочки

    Базовый класс System.Enum является абстрактным, поэтому не может напрямую иметь экземпляры (объекты), а может использоваться только как базовый в цепочке наследования. Тем не менее он определяет ряд статических методов, позволяющих обрабатывать созданные перечисления. Вот некоторые из этих методов.

    Некоторые статические методы класса Enum
    Метод Описание
    public static string Format(System.Type enumType, object value, string format) Преобразует значение данного типа перечисления в эквивалентное строковое представление в соответствии с указанным форматом
    public static string GetName(System.Type enumType, object value) Возвращает имя для константы с указанным значением
    public static string[] GetNames(System.Type enumType) Возвращает массив имен для константы с указанным значением
    public static System.Type GetUnderlyingType(System.Type enumType) Возвращает численный тип данных, используемый для хранения значений данного перечисления
    public static System.Array GetValues(System.Type enumType) Возвращает массив элементов указанного перечисления
    public static bool IsDefined(System.Type enumType, object value) Возвращает флаг существования в указанном перечислении заданного элемента
    public static object Parse(System.Type enumType, string value, bool ignoreCase) Упаковывает в объектную ссылку один или несколько элементов перечисления по их именам, заданным в строке
    public static object Parse(System.Type enumType, string value) Упаковывает в объектную ссылку один или несколько элементов перечисления по их именам, заданным в строке

    Приведем пример программы, использующей статические методы класса System.Enum.

    using System;
        
    namespace CHETKOB.Test
    {
        internal enum Fruit // Фрукты
        {
            Apples = 102,     // Яблоки
            Plums = 12,      // Сливы
            Cherries = 50,   // Вишни
            Grapes = 11,     // Виноград
            Pears = 211      // Груши
        }
        
        internal class MyClass
        {
        static void Main()
        {
        // Настройка консоли
        Console.Title = "Методы библиотечного класса Enum";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
        
        // Анализируем перечисление Fruit
        Array fruitArray = Enum.GetValues(typeof(Fruit));
        Console.WriteLine("Определяем количество 
          членов перечисления:");
        Console.WriteLine("Перечисление содержит {0} 
          членов", fruitArray.Length);
        
        // Обходим все члены перечисления
        // и выводим пары "ключ-значение"
        Console.WriteLine("\nВыводим элементы перечисления:");
        foreach (Fruit fruit in fruitArray)
        {
        Console.Write("{0, -8} = {1, -3} ",// Количество знакомест
          fruit.ToString(),
          Enum.Format(typeof(Fruit), fruit, "D")); // Decimal - десятичный
        Console.WriteLine("(= 0x{0})",
          Enum.Format(typeof(Fruit), fruit, "X"));// Hex - шестнадцатиричный
        }
        
        // Ищем элемент по значению
        Console.WriteLine();
        Console.WriteLine("Ищем элемент по значению:");
        foreach (Fruit fruit in fruitArray)
          {
          int value = (int)fruit;
          Console.WriteLine("Значение {0, -3} 
              имеет элемент {1}", value,
            Enum.GetName(typeof(Fruit), value));
          }
        
        // Проверяем, есть ли элемент в указанном перечислении
        Console.WriteLine();
        Console.WriteLine("Проверяем существование 
          элемента в перечислении:");
        string element = "Apples";
        if (Enum.IsDefined(typeof(Fruit), element))
          Console.WriteLine("Элемент {0} в 
            перечислении есть", element);
        else
          Console.WriteLine("Элемента {0} в 
            перечислении нет", element);
        
        // Печатаем еще одно перечисление
        Console.WriteLine();
        Console.WriteLine("Печатаем еще одно перечисление:");
        Type weekdays = typeof(Days);
        foreach (string str in Enum.GetNames(weekdays))
          Console.WriteLine("{0,-11} = {1}", 
            str,// Резервирует 11 знакомест 
        Enum.Format(weekdays, Enum.Parse(weekdays, str), "d"));
        
        Console.ReadLine();
        }
        
        // Перечисление в классе. Доступ из других класов
        // сборки будет составным: MyClass.Days 
        internal enum Days
        {
        Понедельник, Вторник, Среда, Четверг,
        Пятница, Суббота, Воскресенье
        };
        }
    }

    Приложение. Типы данных в С#

    Целочисленные типы

    Целочисленные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    sbyte - SByte -128 - 127 Знаковое 8 бит
    byte + Byte 0 - 255 Беззнаковое 8 бит
    short + Int16 -32'768 - 32'767 Знаковое 16 бит
    ushort - UInt16 0 - 65'535 Беззнаковое 16 бит
    int + Int32 -2'147'483'648 - 2'147'483'647 Знаковое 32 бит
    uint - UInt32 0 - 4'294'967'295 Беззнаковое 32 бит
    long + Int64 -9'223'372'036'854'775'808 - 9'223'372'036'854'775'807 Знаковое 64 бит
    ulong - UInt64 0 - 18'446'774'073'709'551'615 Беззнаковое 64 бит

    Префикс s означает " signed " - знаковый; u - " unsigned " - беззнаковый

    Тип int

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

    using System;
      
    namespace Test
    {
      class Inches
      {
        static void Main()
        {
        long inches;
        long miles = 93000000; // Миль до Солнца
      
        // 5280 футов в миле, 12 дюймов в футе
        inches = miles * 5280 * 12;
        Console.WriteLine("Расстояние до Солнца: "
          + inches
          + " дюймов.");
      
        Console.Read();
        }
      }
    }

    Тип byte

    Тип byte предназначен для хранения чисел без знака от 0 до 255 размером 8 битов и полезен при обработке двоичных данных.

    Системные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    sbyte - SByte -128 - 127 Знаковое 8 бит
    byte + Byte 0 - 255 Беззнаковое 8 бит
    using System;
      
    namespace Test
    {
      class UseByte
      {
        static void Main()
        {
        byte x;
        int sum = 0;
      
        for(x = 1; x <= 100; x++)
          sum += x;
      
        Console.WriteLine("Сумма чисел от 
          1 до 100 равна " + sum);
      
        Console.Read();
        }
      }
    }

    Типы для представления чисел с плавающей точкой (вещественные типы)

    Вещественные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    float + Single 1.5x10-45 - 3.4x1038 Знаковое с плавающей точкой 32 бит
    double + Double 5.0x10-324 - 1.7x10308 Знаковое с плавающей точкой 64 бит

    Чаще всего используется тип double, поскольку он поддерживается множеством математических функций библиотеки .NET Framework. Большинство математических функций сосредоточено в классе System.Math

    using System;
      
    namespace Test
    {
      // Нахождение радиуса круга по его площади
      class FindRadius
      {
        static void Main()
        {
        double radius, area = 10.0;  
      
        radius = Math.Sqrt(area / Math.PI);
        Console.WriteLine("Площадь круга: 
          {0};", area);
        Console.WriteLine("Радиус круга: 
          {0};", radius);
      
        Console.Read();
        }
      }
    }
    using System;
      
    namespace Test
    {
      // Использование тригонометрических методов
      class Trigonometry
      {
        static void Main()
        {
        for(int i = 0; i < 3; i++) // Внешний цикл
        {
        // alpha - угол в градусах
        for(double alpha = 0D; alpha <= 180; alpha = alpha + 10)
        {
        switch(i + 1)
          {
          case 1: Console.WriteLine("Sin({0})={1}", 
            alpha, Math.Sin(alpha / 180 * Math.PI));
            break;
      case 2: Console.WriteLine("Cos({0})={1}", 
        alpha, Math.Cos(alpha / 180 * Math.PI));
            break;
          case 3: Console.WriteLine("Tan({0})={1}",
             alpha, Math.Tan(alpha / 180 * Math.PI));
            break;
          }
        }
        Console.WriteLine();
        }
      
        Console.Read();
      }
      }
    }

    Тип decimal

    Предназначен для выполнения вычислений, связанных с денежными единицами.

    Тип decimal в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    decimal + Decimal 10-28 —1028 Знаковое 128 бит

    Применение обычной арифметики с плавающей точкой чревато ошибками округления. Во избежании этих ошибок и предназначен тип decimal.

    using System;
      
    namespace Test
    {
      // Использование типа decimal для вычисления скидки
      class UseDecimal
      {
      static void Main()
      {
      decimal price; // Цена
      decimal discount; // Скидка
      decimal discounted_price; // Цена со скидкой
      
      // Вычисляем цену со скидкой
      price = 19.95M; // Цена товара
      discount = 0.15m; // Ставка дисконта равна 15%
      discounted_price = price - (price * discount);// Скобки не обязательны
      
      Console.WriteLine("Цена со скидкой: $"
        + discounted_price);
      
      Console.Read();
      }
      }
    }
    using System;
      
    namespace Test
    {
      /* 
       * Использование типа decimal для вычисления
       * будущей стоимости капиталовложений
       */
      class UseDecimal
      {
      static void Main()
      {
      decimal amount; // Исходный вклад
      decimal rate_of_return; // Норма прибыли
      int years; // Количество лет
      
      amount = 1000M;
      rate_of_return = .07m;
      years = 10;
      
      Console.WriteLine("Исходный вклад: 
        $" + amount);
      Console.WriteLine("Норма прибыли: 
        " + rate_of_return);
      Console.Write("Через " + years + 
        " лет будет $");
      
      for(int i = 0; i < years; i++)
        amount += amount * rate_of_return;
      
      Console.WriteLine(amount);
      
      Console.Read();
      }
      }
    }

    Символьный тип

    В C# исмволы представлются не в однобайтном коде ASCII, а в двухбайтном коде Unicode. Это позволяет представлять алфавиты всех существующих в мире языков. Это 16 - разрядный тип без знака.

    Системные типы данных и их псевдонимы в C#
    Псевдоним C# Соответствие CLS Системный тип Диапазон Пояснения
    char + Char U+0000 - U+FFFF Для описания только одного символа Unicode 16 бит

    Символьной переменной можно присвоить значение, заключив соответствующий символ в одинарные кавычки. Например

    char ch;
    ch = 'X';
    using System;
      
    namespace Test
    {
      class UseDecimal
      {
      static void Main()
      {
      char ch0 = 'П', ch1 = 'р', 
          ch2 = 'и', ch3 = 'в', 
          ch4 = 'е', ch5 = 'т';
      
      Console.WriteLine((int)ch0);
      Console.WriteLine((int)ch1);
      Console.WriteLine((int)ch2);
      Console.WriteLine((int)ch3);
      Console.WriteLine((int)ch4);
      Console.WriteLine((int)ch5 + "\n");
      
      Console.WriteLine(ch0 + ch1 + ch2 + ch3 + ch4 + ch5);
      Console.WriteLine();
      
      Console.WriteLine(ch0);
      Console.WriteLine(ch1);
      Console.WriteLine(ch2);
      Console.WriteLine(ch3);
      Console.WriteLine(ch4);
      Console.WriteLine(ch5 + "\n");
      
      Console.WriteLine("{0}{1}{2}{3}{4}{5}\n", 
          ch0, ch1, ch2, ch3, ch4, ch5);
      
      string str = Convert.ToString(ch0) 
          + Convert.ToString(ch1) 
          + Convert.ToString(ch2) 
          + Convert.ToString(ch3) 
          + Convert.ToString(ch4) 
          + Convert.ToString(ch5);
      Console.WriteLine(str);
      
      Console.Read();
      }
      }
    }

    Логический тип bool

    Тип bool в C# представляет логические значения true или false ( ИСТИНА/ЛОЖЬ ), которые можно использовать в операторах управления (условия, циклы).

    using System;
      
    namespace Test
    {
      class UseBool
      {
      static void Main()
      {
      bool logical;
      logical = false;
      
      int i;
      for(i = 0; i < 2; i++)
      {
      logical = !logical;
      Console.Write("logical={0}: ", logical);
      if(logical)
        Console.WriteLine("Привет от Иванова!");
      else
        Console.WriteLine("Привет от Петрова!");
      }
      Console.WriteLine("10 > 9 равно " + (10 > 9));
      
      Console.Read();
      }
      }
    }
    Вернуться к учебному плану