netlib.narod.ru< Назад | Оглавление | Далее >

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

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


Целочисленные типы данных C#



Количество бит Со знаком Без знака

8 sbyte byte
16 short ushort
32 int uint
64 long ulong


Кроме того, в С# поддерживаются два типа данных с плавающей точкой, float и double, соответствующие стандарту ANSI/IEEE 754-1985 — IEEE Standard for Binary Floating-Point Arithmetic (стандарт IEEE двоичной арифметики с плавающей точкой). Количество бит, используемое порядком и мантиссой типов float и double, таково:


Количество бит, используемое типами данных С# с плавающей точкой



Тип С# Порядок Мантисса Всего бит

float 8 24 32
double 11 53 64


Кроме того, в С# поддерживается тип decimal, использующий 128 бит для хранения данных. В состав числа этого типа входят 96-битная мантисса и десятичный масштабирующий множитель от 0 до 28. Тип данных decimal обеспечивает точность около 28 десятичных знаков. Он удобен для хранения и выполнения вычислений над числами с фиксированным количеством десятичных знаков, например, денежных сумм или процентных ставок. Я подробней рассмотрю тип decimal, работу с числами и математические вычисления в С# в приложении Б.

Если в тексте программы на С# попадется число 3.14, компилятор будет считать, что оно имеет тип double. Чтобы указать, что его тип float или decimal, используйте для типа float суффикс f а для decimal — суффикс m.

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

MinAndMax.cs

  //-------------------------------------------
  // MinAndMax.cs (C) 2001 by Charles Petzold
  //-------------------------------------------
  using System;

  class MinAndMax
  {
      public static void Main()
      {
          Console.WriteLine("sbyte:   {0} to {1}", sbyte.MinValue,
                                                          sbyte.MaxValue);
          Console.WriteLine("byte:    {0} to {1}", byte.MinValue,
                                                          byte.MaxValue);
          Console.WriteLine("short:   {0} to {1}", short.MinValue,
                                                          short.MaxValue);
          Console.WriteLine("ushort:  {0} to {1}", ushort.MinValue,
                                                          ushort.MaxValue);
          Console.WriteLine("int:     {0} to {1}", int.MinValue,
                                                          int.MaxValue);
          Console.WriteLine("uint:    {0} to {1}", uint.MinValue,
                                                          uint.MaxValue);
          Console.WriteLine("long:    {0} to {1}", long.MinValue,
                                                          long.MaxValue);
          Console.WriteLine("ulong:   {0} to {1}", ulong.MinValue,
                                                          ulong.MaxValue);
          Console.WriteLine("float:   {0} to {1}", float.MinValue,
                                                          float.MaxValue);
          Console.WriteLine("double:  {0} to {1}", double.MinValue,
                                                          double.MaxValue);
          Console.WriteLine("decimal: {0} to {1}", decimal.MinValue,
                                                          decimal.MaxValue);
      }
  }

Как вы заметили, я поставил после каждого типа данных точку и слова MinValue или MaxValue. Эти два идентификатора являются полями структуры. К концу главы все, что делает эта программа, станет для вас понятным, а пока что просто взглянем на результаты ее выполнения:

  sbyte:   -128 to 127
  byte:    0 to 255
  short:   -32768 to 32767
  ushort:  0 to 65535
  int:     -2147483648 to 2147483647
  uint:    0 to 4294967295
  long:    -9223372036854775808 to 9223372036854775807
  ulong:   0 to 18446744073709551615
  float:   -3.402823E+38 to 3.402823E+38
  double:  -1.79769313486232E+308 to 1.79769313486232Е+308
  decimal: -79228162514264337593543950335 to 79228162514264337593543950335

В С# поддерживается также тип bool, который может принимать только одно из двух значений: true или false, являющихся ключевыми словами С#. Результаты операций сравнения (==, !=, <, >, <= и >=) — значения типа bool. Можно также описать данные типа bool явно. Приведение типа bool к целочисленным типам допускается (true преобразуется в 1, а false — в 0), но оно должно быть явно указано в коде.

Тип данных char служит для хранения одного символа, a string — для хранения строк из нескольких символов. Тип данных char отличается от целочисленных типов, и его не следует путать с типами sbyte или byte. К тому же переменные типа char занимают 16 бит (но это не значит, что его можно путать с short или ushort).

Тип char — 16-битный, так как С# использует кодировку Unicode 1 вместо ASCII. Вместо 7-битного представления символов в базовом варианте ASCII и 8 бит на символ в расширенных наборах символов, ставших общепринятыми на компьютерах, в Unicode для кодировки одного символа используется целых 16 бит. Это позволяет отобразить все буквы, условные обозначения и другие символы всех письменностей мира, которые могут использоваться при работе с компьютером. Unicode является расширением кодировки ASCII. Его первые 128 символов совпадают с символами ASCII.

Типы данных не обязательно определять в начале метода. Как и в C++, можно определить типы данных в том месте метода, где они потребовались.

Переменную можно определить и сразу же инициализировать:

  string str = "Hello, World!";

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

  str.Length

Length является свойством типа данных string; концепцию свойств я опишу дальше в этой главе. В приложении В содержится подробная информация по работе со строками в С#.

Чтобы описать переменную-массив, поставьте после типа данных пустые квадратные скобки:

  float[] arr;

Тип данных переменной arr — массив чисел с плавающей точкой, но на самом деле arr — это указатель. В языке С# массив является ссылочным типом (reference type). Это относится и к строке. Другие типы, о которых я рассказывал ранее, являются размерными (value types).

Значение переменной arr при первоначальном определении — null. Для выделения памяти массиву нужно воспользоваться оператором new и указать количество элементов в массиве:

  arr = new float[3];

Можно также применить сочетание двух приведенных выше операторов:

  float[] arr = new float[3];

Кроме того, при описании массива можно инициализировать его элементы:

  float[] arr = new float[3] { 3.14f, 2.17f, 100 };

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

  float[] arr = new float[] { 3.14f, 2.17f, 100 };

и даже — оператор new.

  float[] arr = { 3.14f, 2.17f, 100 };

В дальнейшем в программе можно присвоить переменной arr массив типа float другого размера:

  arr = new float[5];

При этом выделяется память для хранения пяти значений типа float, каждое из этих значений первоначально равно 0.

Вы можете спросить: «А что случилось с первым блоком памяти, выделенным для трех значений типа float?» В С# нет оператора delete. Поскольку на исходный блок памяти больше не ссылается ни одна из переменных программы, он становится объектом сборки мусора (garbage collection). В какой-то момент Common Language Runtime освободит память, изначально выделенную массиву.

Как и в случае строк, количество элементов массива можно определить, используя выражение:

  arr.Length;

Кроме того, С# позволяет создавать многомерные и невыровненные (jagged) массивы, являющиеся массивами массивов.

Если не нужно взаимодействие с кодом, написанным на другом языке, указатели в программах на С# требуются редко. По умолчанию параметры передаются методам по значению. Это означает, что метод может как угодно изменять параметр, а значение параметра в вызывающем методе не изменится. Чтобы изменить такое поведение параметров, можно использовать ключевые слова ref (reference — ссылка) или out, Например, определить метод, изменяющий передаваемую в качестве параметра переменную, можно так:

  void AddFive(ref int i)
  {
      i += 5;
  }

А метод, присваивающий переменной значение, выглядит так:

  void SetToFive(out int i)
  {
      i = 5;
  }

В первом примере переменной i необходимо присвоить значение перед вызовом AddFive, тогда метод AddFive сможет изменить ее значение. Во втором — i при вызове метода может не иметь никакого значения.

Важную роль в С# и .NET Framework играют перечисления. Многие константы .NET Framework определены как перечисления. Приведем пример из пространства имен SystemIO:

  public enum FileAccess
  {
      Read = 1,
      Write,
      ReadWrite
  }

Перечисления всегда являются целочисленными типами данных, по умолчанию они имеют тип int. Если не указать значение явно (в данном примере для Read оно указано), первому элементу перечисления присваивается нулевое значение. Следующим элементам присваиваются значения в порядке возрастания.

FileAccess можно использовать при работе с несколькими классами файлового ввода-вывода. (Файловый ввод-вывод подробно рассмотрен в приложении А). Необходимо указывать имя перечисления, затем, через точку имя элемента:

  file.Open(FileMode.CreateNew, FileAccess.ReadWrite)

FileMode — это еще одно перечисление класса SystemIO. Если эти два перечисления в методе Open поменять местами, компилятор сообщит об ошибке. Перечисления помогают программисту избегать ошибок, связанных с константами.



1 Дополнительную информацию можно получить на Web-странице http://www.unicode.org или в The Unicode Consortium, The Unicode Standard Version 3.0 (Reading, Mass.: Addison-Wesley, 2000).


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz