Поделиться через


Типы (Руководство по программированию на C#)

Типы, переменные и значения

C# является строго типизированным языком.Каждая переменная и константа имеет тип, как и каждое выражение, результатом вычисления которого является значение.Каждая сигнатура метода задает тип для каждого входного параметра и для возвращаемого значения.Библиотека классов платформы .NET Framework определяет набор встроенных числовых типов, а также более сложных типов, представляющих широкое разнообразие логических конструкций, например, файловую систему, сетевые подключения, коллекции и массивы объектов и даты.Типичная программа C# использует типы из библиотеки классов, а также пользовательские типы, моделирующие принципы, относящиеся к проблемной области программы.

К сведениям, хранимым в типе, может относиться следующее:

  • Место для хранения, необходимое для переменной типа.

  • Максимальное и минимальное значения, которые могут быть представлены.

  • Содержащиеся члены (методы, поля, события и т. д.).

  • Базовый тип, которому он наследует.

  • Расположение, в котором будет выделена память для переменных во время выполнения.

  • Разрешенные виды операций.

Компилятор использует сведения о типе, чтобы убедиться, что все операции, выполняемые в коде, являются типобезопасными.Например, при объявлении переменной типа int, компилятор позволяет использовать в дополнение переменную и операции вычитания.При попытке выполнить эти же операции в переменной типа bool, компилятор вызовет ошибку, как показано в следующем примере:

int a = 5;             
int b = a + 2; //OK

bool test = true;

// Error. Operator '+' cannot be applied to operands of type 'int' and 'bool'.
int c = a + test;
ПримечаниеПримечание

Разработчикам, работающим с C и C++, следует обратить внимание на то, что в C# bool нельзя преобразовать в int.

Компилятор внедряет сведения о типе в исполняемый файл в качестве метаданных.Среда CLR использует эти метаданные во время выполнения для дальнейшего обеспечения безопасности типа при выделении и освобождении памяти.

ms173104.collapse_all(ru-ru,VS.110).gifЗадание типов в объявлениях переменных

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

// Declaration only:
float temperature;
string name;
MyClass myClass;

// Declaration with initializers (four examples):
char firstLetter = 'C';
var limit = 3;
int[] source = { 0, 1, 2, 3, 4, 5 };
var query = from item in source
            where item <= limit
            select item;

Типы параметров метода и возвращаемые значения задаются в сигнатуре метода.В следующей сигнатуре показан метод, который требует int в качестве входного аргумента, и который возвращает строку:

public string GetName(int ID)
{
    if (ID < names.Length)
        return names[ID];
    else
        return String.Empty;
}
private string[] names = { "Spencer", "Sally", "Doug" };

После объявления переменной она не может быть повторно объявлена с новым типом, и ей нельзя присвоить значение, несовместимое с ее объявленным типом.Например, нельзя объявить int и затем присвоить ему логическое значение true.Однако значения могут быть преобразованы в другие типы, например, при их присвоении новым переменным или при передаче в качестве аргументов метода.Преобразование типов, которое не приводит к потере данных, автоматически выполняется компилятором.Для преобразования, которое может привести к потере данных, необходимо приведение в исходном коде.

Дополнительные сведения см. в разделе Приведение и преобразование типов (Руководство по программированию на C#).

Встроенные типы

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

Пользовательские типы

Конструкции структура, класс, интерфейс и перечисление используются для создания собственных пользовательских типов.Сама библиотека классов платформы .NET Framework является коллекцией пользовательских типов, предоставленной корпорацией Microsoft, которую можно использовать в собственных приложениях.По умолчанию наиболее часто используемые типы в библиотеке классов доступны в любой программе C#.Другие становятся доступными только при явном добавлении ссылки проекта на сборку, в которой они определены.Если компилятор имеет ссылку на сборку, то можно объявить переменные (и константы) типов, объявленных в сборке в исходном коде.Дополнительные сведения см. в разделе Библиотека классов .NET Framework.

Система общих типов CTS

Важно понимать две фундаментальные точки о системе типов в .NET Framework:

  • Она поддерживает принцип наследования.Типы могут быть производными от других типов, которые называются базовыми типами.Производный тип наследует (с некоторыми ограничениями) методы, свойства и другие члены базового типа.Базовый тип, в свою очередь, может быть производным от какого-то другого типа, при этом производный тип наследует члены обоих базовых типов в иерархии наследования.Все типы, включая встроенные числовые типы, например, System.Int32 (ключевое слово C#: int), в конечном счете являются производными от одного базового типа, который является System.Object (ключевое слово C#: объектом).Эта унифицированная иерархия типов называется Система общих типов CTS (CTS).Дополнительные сведения о наследовании в C# см. в разделе Наследование (Руководство по программированию на C#).

  • Каждый тип в CTS определен либо как тип значения, либо как ссылочный тип.Сюда включены все пользовательские типы в библиотеке классов платформы .NET Framework, а также собственные пользовательские типы.Типы, определяемые с помощью ключевого слова struct, являются типами значений; все встроенные числовые типы являются structs.Типы, определяемые с помощью ключевого слова class, являются ссылочными типами.Правила времени компиляции и поведение времени выполнения ссылочных типов отличается от правил времени компиляции и поведения времени выполнения типов значений.

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

Типы значений и ссылочные типы в CTS

Типы значений и ссылочные типы

ПримечаниеПримечание

Можно увидеть, что наиболее часто используемые типы все организованы в пространстве имен System.Однако пространство имен, в котором содержится тип, не имеет отношения к тому, является ли этот тип типом значения или ссылочным типом.

ms173104.collapse_all(ru-ru,VS.110).gifТипы значений

Типы значений являются производными от System.ValueType, являющегося производным от System.Object.Типы, производные от System.ValueType, имеют особое поведение в среде CLR.Переменные типа значения напрямую содержат их значения, что означает, что память встроена в контекст, в котором объявлена переменная.Не существует отдельного размещения кучи или служебных данных сборки мусора для переменных типа значения.

Существует две категории типов значений: структура и перечисление.

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

// Static method on type Byte.
byte b = Byte.MaxValue;

Но значения объявляются и присваиваются им, как если бы они были простыми не статическими типами:

byte num = 0xA;
int i = 5;
char c = 'Z';

Типы значений являются запечатанными, что означает, например, что нельзя произвести тип от System.Int32, и нельзя определить структуру для наследования от любого пользовательского класса или структуры, поскольку структура может наследовать только от System.ValueType.Однако структура может реализовать один или несколько интерфейсов.Можно выполнить приведение типа структуры в тип интерфейса; это приведет к операции упаковки-преобразования для создания программы-оболочки структуры внутри объекта ссылочного типа в управляемой куче.Операции упаковки-преобразования возникают при передаче типа значения методу, принимающему System.Object в качестве входного параметра.Дополнительные сведения см. в разделе Упаковка-преобразование и распаковка-преобразование (Руководство по программированию на C#).

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

public struct CoOrds
{
    public int x, y;

    public CoOrds(int p1, int p2)
    {
        x = p1;
        y = p2;
    }
}

Дополнительные сведения о структурах см. в разделе Структуры (Руководство по программированию на C#).Дополнительные сведения о типах значений в .NET Framework см. в разделе Система общих типов CTS.

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

public enum FileMode
{
    CreateNew = 1,
    Create = 2,
    Open = 3,
    OpenOrCreate = 4,
    Truncate = 5,
    Append = 6,
}

Значение константы System.IO.FileMode.Create равно 2.Однако имя намного более значимо для пользователей, читающих исходный код, и по этой причине лучше использовать перечисления вместо литеральных номеров констант.Дополнительные сведения см. в разделе System.IO.FileMode.

Все перечисления наследуются от System.Enum, который наследуется от System.ValueType.Все правила, применимые к структурам, также применяются к перечислениям.Дополнительные сведения о перечислениях см. в разделе Типы перечислений (Руководство по программированию в C#).

ms173104.collapse_all(ru-ru,VS.110).gifСсылочные типы

Тип, определенный как класс, делегат, массив или интерфейс, является ссылочным типом.Во время выполнения при объявлении переменной ссылочного типа переменная содержит значение null до явного создания экземпляра объекта с помощью оператора new или назначения его объекту, который был создан в другом месте, с помощью new, as shown in the following example:.

MyClass mc = new MyClass();
MyClass mc2 = mc;

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

IMyInterface iface = new MyClass();

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

Все массивы являются ссылочными типами, даже если их члены являются типами значений.Массивы являются неявно производными от класса System.Array, но объявляются и используются они с упрощенным синтаксисом, предоставленным C#, как показано в следующем примере:

// Declare and initialize an array of integers.
int[] nums = { 1, 2, 3, 4, 5 };

// Access an instance property of System.Array.
int len = nums.Length;

Ссылочные типы полностью поддерживают наследование.При создании класса можно наследовать от любого другого интерфейса или класса, который не определен как запечатанный, а другие классы могут наследовать от этого класса и переопределять виртуальные методы.Дополнительные сведения о создании собственных классов см. в разделе Классы и структуры (Руководство по программированию в C#).Дополнительные сведения о наследовании и виртуальных методах см. в разделе Наследование (Руководство по программированию на C#).

Типы литеральных значений

В C# литеральные значения получают тип от компилятора.Можно задать, как числовой литерал должен быть типизирован, путем добавления буквы в конце номера.Например, чтобы задать, что значение 4,56 должно обрабатываться как число с плавающей запятой, добавьте после номера "f" или "F": 4.56f.При отсутствии добавленной буквы компилятор определит тип для литерала.Дополнительные сведения о том, какие типы могут быть заданы с буквенными суффиксами, см. на страницах справочника для отдельных типов в разделе Типы значений (Справочник по C#).

Поскольку литералы являются типизированными и все типы в конечном счете являются производными от System.Object, можно записать и скомпилировать код, например, следующий:

string s = "The answer is " + 5.ToString();
// Outputs: "The answer is 5"
Console.WriteLine(s);

Type type = 12345.GetType();
// Outputs: "System.Int32"
Console.WriteLine(type);

Универсальные типы

Тип может быть объявлен с одним или несколькими параметрами типа, служащими в качестве местозаполнителя для фактического типа (устойчивого типа), который клиентский код предоставит при создании экземпляра типа.Такие типы называются универсальными типами.Например, тип платформы .NET Framework System.Collections.Generic.List<T> имеет один параметр типа, которому в соответствии с соглашением предоставлено имя T.При создании экземпляра типа необходимо задать тип объектов, которые будут содержаться в списке, например, строку:

List<string> strings = new List<string>();

Использование параметра типа делает возможным повторное использование этого же класса для хранения любого типа элемента, не преобразовывая каждый элемент в объект.Универсальные классы коллекции называются строго типизированными коллекциями, поскольку компилятор знает определенный тип элементов коллекции и может вызвать ошибку во время компиляции, если, к примеру, будет произведена попытка добавить целое число к объекту strings в предыдущем примере.Дополнительные сведения см. в разделе Универсальные шаблоны (Руководство по программированию на C#).

Неявные типы, анонимные типы и типы, допускающие значение NULL

Как уже говорилось ранее, можно неявно типизировать локальную переменную (но не члены класса) с помощью ключевого слова var.Переменная все же получает тип во время компиляции, но тип предоставляется компилятором.Дополнительные сведения см. в разделе Неявно типизированные локальные переменные (Руководство по программированию в C#).

В некоторых случаях неудобно создавать именованный тип для простых наборов связанных значений, которые не будут сохранены или переданы за пределы метода.Для этой цели можно создать анонимные типы.Дополнительные сведения см. в разделе Анонимные типы (Руководство по программированию в C#).

Обычные типы значений не могут иметь значение null.Однако можно создать типы значений, допускающие значение NULL, путем привязки ? после типа.Например, int? является типом int, который также может иметь значение null.В CTS типы, допускающие значения NULL, являются экземплярами универсального типа структуры System.Nullable<T>.Типы, допускающие значение NULL, особенно полезны при передаче данных в базы данных и из них, в которых числовые значение могут быть равны NULL.Дополнительные сведения см. в разделе Типы, допускающие значения NULL (Руководство по программированию на C#).

Связанные разделы

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

Спецификация языка C#

Дополнительные сведения см в Спецификация языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

См. также

Ссылки

Сравнение типов данных в разных языках

Таблица целых типов (Справочник по C#)

Основные понятия

Руководство по программированию на C#

Conversion of XML Data Types

Другие ресурсы

Справочник по C#