Visual studio типы данных
bool : хранит значение true или false (логические литералы). Представлен системным типом System.Boolean
byte : хранит целое число от 0 до 255 и занимает 1 байт. Представлен системным типом System.Byte
sbyte : хранит целое число от -128 до 127 и занимает 1 байт. Представлен системным типом System.SByte
short : хранит целое число от -32768 до 32767 и занимает 2 байта. Представлен системным типом System.Int16
ushort : хранит целое число от 0 до 65535 и занимает 2 байта. Представлен системным типом System.UInt16
int : хранит целое число от -2147483648 до 2147483647 и занимает 4 байта. Представлен системным типом System.Int32 . Все целочисленные литералы по умолчанию представляют значения типа int:
uint : хранит целое число от 0 до 4294967295 и занимает 4 байта. Представлен системным типом System.UInt32
long : хранит целое число от –9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 и занимает 8 байт. Представлен системным типом System.Int64
ulong : хранит целое число от 0 до 18 446 744 073 709 551 615 и занимает 8 байт. Представлен системным типом System.UInt64
float : хранит число с плавающей точкой от -3.4*10 38 до 3.4*10 38 и занимает 4 байта. Представлен системным типом System.Single
double : хранит число с плавающей точкой от ±5.0*10 -324 до ±1.7*10 308 и занимает 8 байта. Представлен системным типом System.Double
decimal : хранит десятичное дробное число. Если употребляется без десятичной запятой, имеет значение от ±1.0*10 -28 до ±7.9228*10 28 , может хранить 28 знаков после запятой и занимает 16 байт. Представлен системным типом System.Decimal
string : хранит набор символов Unicode. Представлен системным типом System.String . Этому типу соответствуют строковые литералы.
Например, определим несколько переменных разных типов и выведем их значения на консоль:
Для вывода данных на консоль здесь применяется интерполяция: перед строкой ставится знак $ и после этого мы можем вводить в строку в фигурных скобках значения переменных. Консольный вывод программы:
Использование суффиксов
При присвоении значений надо иметь в виду следующую тонкость: все вещественные литералы (дробные числа) рассматриваются как значения типа double . И чтобы указать, что дробное число представляет тип float или тип decimal , необходимо к литералу добавлять суффикс: F/f - для float и M/m - для decimal.
Подобным образом все целочисленные литералы рассматриваются как значения типа int . Чтобы явным образом указать, что целочисленный литерал представляет значение типа uint, надо использовать суффикс U/u , для типа long - суффикс L/l , а для типа ulong - суффикс UL/ul :
Использование системных типов
Выше при перечислении всех базовых типов данных для каждого упоминался системный тип. Потому что название встроенного типа по сути представляет собой сокращенное обозначение системного типа. Например, следующие переменные будут эквивалентны по типу:
Неявная типизация
Ранее мы явным образом указывали тип переменных, например, int x; . И компилятор при запуске уже знал, что x хранит целочисленное значение.
Однако мы можем использовать и модель неявной типизации:
Для неявной типизации вместо названия типа данных используется ключевое слово var . Затем уже при компиляции компилятор сам выводит тип данных исходя из присвоенного значения. Так как по умолчанию все целочисленные значения рассматриваются как значения типа int , то поэтому в итоге переменная c будет иметь тип int . Аналогично переменной hello присваивается строка, поэтому эта переменная будет иметь тип string
Эти переменные подобны обычным, однако они имеют некоторые ограничения.
Во-первых, мы не можем сначала объявить неявно типизируемую переменную, а затем инициализировать:
Во-вторых, мы не можем указать в качестве значения неявно типизируемой переменной null :
The following table shows the Visual Basic data types, their supporting common language runtime types, their nominal storage allocation, and their value ranges.
† In scientific notation, "E" refers to a power of 10. So 3.56E+2 signifies 3.56 x 10 2 or 356, and 3.56E-2 signifies 3.56 / 10 2 or 0.0356.
For strings containing text, use the StrConv function to convert from one text format to another.
In addition to specifying a data type in a declaration statement, you can force the data type of some programming elements by using a type character. See Type Characters.
Memory Consumption
When you declare an elementary data type, it is not safe to assume that its memory consumption is the same as its nominal storage allocation. This is due to the following considerations:
Storage Assignment. The common language runtime can assign storage based on the current characteristics of the platform on which your application is executing. If memory is nearly full, it might pack your declared elements as closely together as possible. In other cases it might align their memory addresses to natural hardware boundaries to optimize performance.
Platform Width. Storage assignment on a 64-bit platform is different from assignment on a 32-bit platform.
Composite Data Types
The same considerations apply to each member of a composite data type, such as a structure or an array. You cannot rely on simply adding together the nominal storage allocations of the type's members. Furthermore, there are other considerations, such as the following:
Overhead. Some composite types have additional memory requirements. For example, an array uses extra memory for the array itself and also for each dimension. On a 32-bit platform, this overhead is currently 12 bytes plus 8 bytes for each dimension. On a 64-bit platform this requirement is doubled.
Storage Layout. You cannot safely assume that the order of storage in memory is the same as your order of declaration. You cannot even make assumptions about byte alignment, such as a 2-byte or 4-byte boundary. If you are defining a class or structure and you need to control the storage layout of its members, you can apply the StructLayoutAttribute attribute to the class or structure.
Object Overhead
An Object referring to any elementary or composite data type uses 4 bytes in addition to the data contained in the data type.
Концепция типа очень важна в C++. Каждая переменная, аргумент функции и возвращаемое значение функции должны иметь тип, чтобы их можно было скомпилировать. Кроме того, перед вычислением каждого выражения (включая литеральные значения) компилятор неявно назначает ему тип. Некоторые примеры типов включают int хранение целых значений, double хранение значений с плавающей запятой (также называемых скалярными типами данных) или класс стандартной библиотеки std::basic_string для хранения текста. Вы можете создать собственный тип, определив или class struct . Тип определяет объем памяти, выделяемой для переменной (или результата выражения), типы значений, которые могут храниться в этой переменной, способ интерпретации значений (например, битовые шаблоны), и операции, допустимые с переменной. Эта статья содержит неформальный обзор основных особенностей системы типов C++.
Терминология
Переменная: символьное имя количества данных, чтобы его можно было использовать для доступа к данным, на которые он ссылается, во всей области кода, в котором он определен. В C++ переменная обычно используется для ссылки на экземпляры скалярных типов данных, тогда как экземпляры других типов обычно называются объектами.
Объект. Для простоты и согласованности в этой статье используется объект терминов для ссылки на любой экземпляр класса или структуры, а когда он используется в общем смысле, включает все типы, даже скалярные переменные.
Тип POD (обычные старые данные): эта неформальная категория типов данных в C++ относится к типам, которые являются скалярными (см. раздел "Основные типы") или являются классами POD. Класс POD не содержит статических данных-членов, которые не являются типами POD, а также не содержит пользовательских конструкторов, пользовательских деструкторов или пользовательских операторов присваивания. Кроме того, класс POD не имеет виртуальных функций, базового класса и ни закрытых, ни защищенных нестатических данных-членов. Типы POD часто используются для внешнего обмена данными, например с модулем, написанным на языке С (в котором имеются только типы POD).
Указание типов переменных и функций
C++ — это строго типизированный язык, который также является статически типизированным; каждый объект имеет тип и этот тип никогда не изменяется (не следует путать со статическими объектами данных). При объявлении переменной в коде необходимо явно указать его тип или использовать auto ключевое слово, чтобы указать компилятору выводить тип из инициализатора. При объявлении функции в коде необходимо указать тип каждого аргумента и его возвращаемое значение, или void если значение не возвращается функцией. Исключением является использование шаблонов функции, которые допускают аргументы произвольных типов.
После объявления переменной изменить ее тип впоследствии уже невозможно. Однако можно скопировать значения переменной или возвращаемое значение функции в другую переменную другого типа. Такие операции называются преобразованиями типов, которые иногда необходимы, но также являются потенциальными источниками потери данных или неправильности.
При объявлении переменной типа POD настоятельно рекомендуется инициализировать ее, т. е. указать начальное значение. Пока переменная не инициализирована, она имеет "мусорное" значение, определяемое значениями битов, которые ранее были установлены в этом месте памяти. Необходимо учитывать эту особенность языка C++, особенно при переходе с другого языка, который обрабатывает инициализацию автоматически. При объявлении переменной типа, не являющегося классом POD, инициализация обрабатывается конструктором.
В следующем примере показано несколько простых объявлений переменных с небольшим описанием для каждого объявления. В примере также показано, как компилятор использует сведения о типе, чтобы разрешить или запретить некоторые последующие операции с переменной.
Базовые (встроенные) типы
В отличие от некоторых других языков, в C++ нет универсального базового типа, от которого наследуются все остальные типы. Язык включает множество фундаментальных типов, также известных как встроенные типы. Сюда входят числовые типы, такие как int , double , long bool , а также char типы и wchar_t типы для символов ASCII и ЮНИКОД соответственно. Большинство целочисленных фундаментальных типов (за исключением bool , double wchar_t и связанных типов) имеют unsigned версии, которые изменяют диапазон значений, которые может хранить переменная. Например, int 32-разрядное целое число со знаком может представлять значение от -2 147 483 648 до 2 147 483 647. Значение unsigned int , которое также хранится как 32-разрядные, может хранить значение от 0 до 4294 967 295. Общее количество возможных значений в каждом случае одинаково, отличается только диапазон.
Базовые типы распознаются компилятором, в котором предусмотрены встроенные правила, управляющие операциями, выполняемыми с такими типами, а также преобразованием в другие базовые типы. Полный список встроенных типов и их размеров и числовых ограничений см. в разделе "Встроенные типы".
На следующем рисунке показаны относительные размеры встроенных типов в реализации Microsoft C++:
В следующей таблице перечислены наиболее часто используемые фундаментальные типы и их размеры в реализации Microsoft C++:
Тип | Размер | Комментарий |
---|---|---|
int | 4 байта | Выбор по умолчанию для целочисленных значений. |
double | 8 байт | Выбор по умолчанию для значений с плавающей запятой. |
bool | 1 байт | Представляет значения, которые могут быть или true, или false. |
char | 1 байт | Используйте для символов ASCII в старых строках в стиле C или в объектах std::string, которые никогда не будут преобразовываться в Юникод. |
wchar_t | 2 байта | Представляет "расширенные" символы, которые могут быть представлены в формате Юникод (UTF-16 в Windows, в других операционных системах возможно другое представление). Это символьный тип, используемый в строках типа std::wstring . |
unsigned char | 1 байт | В C++ нет встроенного типа байтов. Используется unsigned char для представления байтового значения. |
unsigned int | 4 байта | Вариант по умолчанию для битовых флагов. |
long long | 8 байт | Представляет очень большие целочисленные значения. |
Другие реализации C++ могут использовать разные размеры для определенных числовых типов. Дополнительные сведения о размерах и связях размера, необходимых стандарту C++, см. в разделе "Встроенные типы".
Тип void
Тип void является особым типом. Переменная типа void не может объявляться, но можно объявить переменную типа void * (указатель на void ), что иногда необходимо при выделении необработанной (нетипизированной) памяти. Однако указатели не void являются типобезопасными и, как правило, их использование настоятельно не рекомендуется использовать в современном C++. В объявлении функции возвращаемое void значение означает, что функция не возвращает значение; это общее и допустимое использование void . Хотя язык C требует функций, имеющих нулевые параметры для объявления void в списке параметров, например, fou(void) эта практика не рекомендуется в современном C++ и должна быть объявлена fou() . Дополнительные сведения см. в разделе "Преобразования типов" и "Безопасность типов".
Квалификатор типа const
Любой встроенный или пользовательский тип может квалифицироваться ключевым словом const. Кроме того, функции-члены могут быть const квалифицированы и даже const перегружены. Значение const типа невозможно изменить после инициализации.
Квалификатор const широко используется в объявлениях функций и переменных, и "константная правильность" является важной концепцией в C++. По сути, это означает, const что во время компиляции значения не изменяются непреднамеренно. Дополнительные сведения см. в разделе const .
Тип const отличается от его версии, const int отличной от константной, например, является отдельным типом. int Оператор C++ const_cast можно использовать в тех редких случаях, когда необходимо удалить const-ness из переменной. Дополнительные сведения см. в разделе "Преобразования типов" и "Безопасность типов".
Строковые типы
Определяемые пользователем типы
При определении class , struct union или enum , эта конструкция используется в остальной части кода, как если бы это был фундаментальный тип. Он имеет известный размер в памяти, и в его отношении действуют определенные правила проверки во время компиляции и во время выполнения в течение срока использования программы. Основные различия между базовыми встроенными типами и пользовательскими типами указаны ниже:
Компилятор не имеет встроенных сведений о пользовательском типе. Он узнает о типе при первом обнаружении определения во время процесса компиляции.
Пользователь определяет, какие операции можно выполнять с типом и как его можно преобразовать в другие типы, задавая (через перегрузку) соответствующие операторы, либо в виде членов класса, либо в виде функций, не являющихся членами. Дополнительные сведения см. в разделе "Перегрузка функций"
типы указателей
Как и самые ранние версии языка C, язык C++ по-прежнему позволяет объявить переменную типа указателя с помощью специального декларатора * (звездочка). Тип указателя хранит адрес расположения в памяти, в котором хранится фактическое значение данных. В современном C++ они называются необработанными указателями и доступны в коде с помощью специальных операторов * (звездочка) или -> (дефис с большим числом). Это называется разыменовыванием, которое вы используете, зависит от того, выполняется ли разыменовывание указателя на скаляр или указатель на член в объекте. Работа с типами указателя долгое время была одним из наиболее трудных и непонятных аспектов разработки программ на языках C и C++. В этом разделе описываются некоторые факты и рекомендации по использованию необработанных указателей, если вы хотите, но в современном C++ больше не требуется (или рекомендуется) использовать необработанные указатели для владения объектами вообще из-за эволюции интеллектуального указателя (подробнее рассматривается в конце этого раздела). Все еще полезно и безопасно использовать необработанные указатели для отслеживания объектов, но если требуется использовать их для владения объектом, необходимо делать это с осторожностью и после тщательного анализа процедуры создания и уничтожения объектов, которые им принадлежат.
Первое, что необходимо знать, — это то, что при объявлении переменной необработанного указателя выделяется только память, необходимая для хранения адреса расположения памяти, на который будет ссылаться указатель при разыменовывании. Выделение памяти для самого значения данных (также называемого резервным хранилищем) еще не выделено. Другими словами, объявив переменную необработанного указателя, вы создаете переменную адреса памяти, а не фактическую переменную данных. Разыменовывание переменной указателя до проверки того, что она содержит действительный адрес в резервном хранилище, приведет к неопределенному поведению (обычно неустранимой ошибке) программы. В следующем примере демонстрируется подобная ошибка:
Пример разыменовывает тип указателя без выделения памяти для хранения фактических целочисленных данных или без выделенного допустимого адреса памяти. В следующем коде исправлены эти ошибки:
В исправленном примере кода используется локальной память стека для создания резервного хранилища, на который указывает указатель pNumber . Базовый тип используется для простоты. На практике резервное хранилище указателей — это наиболее часто определяемые пользователем типы, динамически выделяемые в области памяти, называемой кучей (или свободным хранилищем), с помощью new выражения ключевых слов (в программировании в стиле C была использована старая malloc() функция библиотеки среды выполнения C). После выделения эти переменные обычно называются объектами, особенно если они основаны на определении класса. Память, выделенная вместе с new ней, должна быть удалена соответствующим delete оператором (или, если для ее выделения использовалась malloc() функция free() среды выполнения C).
Однако легко забыть удалить динамически выделенный объект, особенно в сложном коде, что вызывает ошибку ресурса, называемую утечкой памяти. По этой причине в современном С++ настоятельно не рекомендуется использовать необработанные указатели. Почти всегда лучше упаковать необработанный указатель в интеллектуальный указатель, который автоматически освобождает память при вызове деструктора (когда код выходит за пределы области для интеллектуального указателя); используя интеллектуальные указатели, вы практически устраняете целый класс ошибок в программах C++. В следующем примере предположим, что MyClass — это пользовательский тип, который имеет открытый метод DoSomeWork();
Дополнительные сведения о смарт-указателях см. в разделе "Интеллектуальные указатели".
Дополнительные сведения о преобразованиях указателей см. в разделе "Преобразования типов" и "Безопасность типов".
Дополнительные сведения о указателях в целом см. в разделе "Указатели".
Типы данных Windows
Дополнительные сведения
Дополнительные сведения о системе типов C++ см. в следующих разделах.
Типы значений
Описывает типы значений вместе с проблемами, связанными с их использованием.
Преобразования типов и безопасность типов
Описание типовых проблем преобразования типов и способов их избежать.
в следующей таблице показаны типы данных Visual Basic, поддерживаемые типы среды clr, их номинальное выделение памяти и диапазоны значений.
† В экспоненциальном представлении"E" означает степень числа 10. Итак, 3.56 E + 2 означает 3,56 x 10 или 356, а 3.56 e-2 — 3,56/10 2 или 0,0356.
Для строк, содержащих текст, используйте StrConv функцию для преобразования одного текстового формата в другой.
Помимо указания типа данных в операторе объявления, можно принудительно задать тип данных некоторых элементов программирования с помощью символа типа. См. раздел символы типа.
Затраты памяти
При объявлении простейшего типа данных нельзя считать, что его потребление памяти совпадает с номинальным выделением хранилища. Это обусловлено следующими соображениями.
назначение служба хранилища. Среда CLR может назначать хранилище на основе текущих характеристик платформы, в которой выполняются приложения. Если память почти заполнена, она может упаковать объявленные элементы как можно ближе друг к другу. В других случаях адреса памяти могут быть согласованы с естественными аппаратными границами для оптимизации производительности.
Ширина платформы. назначение служба хранилища на 64-разрядной платформе отличается от назначения на 32-разрядной платформе.
Составные типы данных
Те же рекомендации применимы к каждому элементу составного типа данных, такому как структура или массив. Вы не можете полагаться на простое сложение номинальных выделений памяти для членов типа. Кроме того, существуют и другие рекомендации, например следующие:
За. Некоторые составные типы предъявляют дополнительные требования к памяти. Например, массив использует дополнительную память для самого массива, а также для каждого измерения. На 32-разрядной платформе этот объем накладных расходов в настоящее время составляет 12 байт плюс 8 байт для каждого измерения. На 64-разрядной платформе это требование удваивается.
макет служба хранилища. Нельзя безопасно предположить, что порядок хранения в памяти совпадает с порядком объявления. Вы даже не можете делать предположения относительно выравнивания байтов, например 2-байтовой или 4-байтовой границы. При определении класса или структуры и необходимости управления структурой хранения его элементов можно применить StructLayoutAttribute атрибут к классу или структуре.
Издержки объекта
При Object ссылке на любой простой или составной тип данных в дополнение к данным, содержащимся в типе данных, используется 4 байта.
В типах может храниться следующая информация:
- место, необходимое для хранения переменной этого типа;
- максимальное и минимальное значения, которые могут быть представлены;
- содержащиеся в типе члены (методы, поля, события и т. д.);
- базовый тип, от которого наследует этот тип;
- реализуемые им интерфейсы;
- разрешенные виды операций.
Компилятор использует сведения о типах, чтобы проверить, все ли операции, выполняемые в коде, являются типобезопасными. Например, при объявлении переменной типа int компилятор позволяет в дополнение использовать переменную и операции вычитания. При попытке выполнить эти же операции для переменной типа bool компилятор выдаст ошибку, как показано в следующем примере:
Компилятор внедряет сведения о типе в исполняемый файл в виде метаданных. Среда CLR использует эти метаданные во время выполнения для дальнейшего обеспечения безопасности типа при выделении и освобождении памяти.
Задание типов в объявлениях переменных
Когда вы объявляете в программе переменную или константу, для нее нужно задать тип либо использовать ключевое слово var , чтобы компилятор определил тип самостоятельно. В следующем примере показаны некоторые объявления переменных, использующие встроенные числовые типы и сложные пользовательские типы:
Типы параметров и возвращаемых значений метода задаются в объявлении метода. Далее представлена сигнатура метода, который требует значение int в качестве входного аргумента и возвращает строку:
После объявления переменной вы не можете повторно объявить ее с новым типом и назначить ей значение, несовместимое с объявленным типом. Например, нельзя объявить переменную типа int и затем присвоить ей логическое значение true . Но значения можно преобразовать в другие типы, например при сохранении в других переменных или передаче в качестве аргументов метода. Если преобразование типов не приводит к потере данных, оно выполняется компилятором автоматически. Для преобразования, которое может привести к потере данных, необходимо выполнить приведение в исходном коде.
Дополнительные сведения см. в разделе Приведение и преобразование типов.
Встроенные типы
Пользовательские типы
Система общих типов CTS
Ниже показаны взаимоотношения между типами значения и ссылочными типами в CTS.
Как видно, все наиболее часто используемые типы организованы в пространство имен System. Но само по себе пространство имен, в котором размещен тип, никак не зависит от того, является ли он типом значения или ссылочным типом.
Объявление класса, структуры или записи представляет собой своего рода чертеж, на основе которого создаются экземпляры или объекты во время выполнения. Если вы определите класс, структуру или запись с именем Person , то Person здесь обозначает имя типа. Если вы объявите и инициализируете переменную p типа Person , принято говорить, что p является объектом (или экземпляром) Person . Можно создать несколько экземпляров одного типа Person , и каждый экземпляр будет иметь разные значения свойств и полей.
Класс является ссылочным типом. Когда вы создаете объект типа и назначаете его переменной, эта переменная содержит только ссылку на память объекта. Если ссылка на объект сохраняется в новую переменную, эта переменная также ссылается на исходный объект. Изменения, внесенные через одну переменную, отражаются и в другой переменной, поскольку обе они ссылаются на одни и те же данные.
Структура (struct) является типом значения. При создании структуры переменная, которой присвоена структура, содержит фактические данные этой структуры. Если структура присваивается новой переменной, все данные копируются. Таким образом, новая переменная и исходная переменная содержат две отдельные копии одинаковых данных. Изменения, внесенные в одну копию, не влияют на другую.
Типы записей могут быть либо ссылочными типами ( record class ), либо типами значений ( record struct ).
Как правило, классы используются для моделирования более сложного поведения. Классы обычно хранят данные, которые должны быть изменены после создания объекта класса. Структуры лучше всего подходят для небольших структур данных. Структуры обычно хранят данные, которые не должны изменяться после создания структуры. Типы записей — это структуры данных с дополнительными членами, синтезированными компилятором. Записи обычно хранят данные, которые не должны изменяться после создания объекта.
Типы значений
Типы значений являются производными от System.ValueType, который является производным от System.Object. Типы, производные от System.ValueType, имеют особое поведение в среде CLR. Переменные типа значения непосредственно содержат их значения. Память для структуры выделяется встроенным образом в любом контексте, объявленном переменной. Для переменных типа значения не предусмотрены раздельное размещение в куче или накладные расходы при сборке мусора. Можно объявить типы record struct , которые являются типами значений, и включить синтезированные члены для записей.
Существует две категории типов значений: struct и enum .
Встроенные числовые типы являются структурами и имеют поля и методы, к которым можно обращаться.
Но объявление и присвоение значений вы выполняете для них так, как если бы они были простыми нестатистическими типами:
Типы значений являются запечатанными. Тип не может быть производным от любого типа значений, например System.Int32. Вы не можете определить структуру для наследования из любого определенного пользователем класса или структуры, так как структура может наследовать только от System.ValueType. Тем не менее структура может реализовывать один или несколько интерфейсов. Можно выполнить приведение типа структуры к любому типу интерфейса, который он реализует. Это приведет к операции упаковки-преобразования, которая создаст программу-оболочку для структуры внутри объекта ссылочного типа в управляемой куче. Операции упаковки-преобразования выполняются при передаче типа значения в метод, принимающий System.Object или любой тип интерфейса в качестве входного параметра. Дополнительные сведения см. в разделе Упаковка-преобразование и распаковка-преобразование.
Используйте ключевое слово struct, чтобы создать собственные пользовательские типы значений. Как правило, структура используется как контейнер для небольшого набора связанных переменных, как показано в следующем примере:
См. сведения в описании типов структур. См. дополнительные сведения о типах значений.
Константа System.IO.FileMode.Create имеет значение 2. Так как имена намного лучше воспринимаются человеком при изучении исходного кода, мы рекомендуем всегда использовать перечисления вместо литеральных числовых констант. Для получения дополнительной информации см. System.IO.FileMode.
Все перечисления наследуют от System.Enum, который наследует от System.ValueType. К перечислениям применимы все те же правила, что к структурам. Дополнительные сведения о перечислениях см. в разделе Типы перечислений.
Ссылочные типы
Тип, который определен как class , record , delegate , массив или interface , является reference type .
Объявляемая переменная с типом reference type будет содержать значение null до тех пор, пока вы не назначите ей экземпляр такого типа или не создадите его с помощью оператора new . Создание и назначение класса демонстрируется в следующем примере:
Вы не можете создать экземпляр interface напрямую с помощью оператора new . Вместо этого создайте и назначьте экземпляр класса, который реализует интерфейс. Рассмотрим следующий пример.
При создании объекта выделяется память в управляемой куче, и переменная хранит только ссылку на расположение объекта. Хранение типов в управляемой куче требует дополнительных действий как при выделении памяти, так и при удалении, которое выполняется функцией автоматического управления памятью в среде CLR, известной как сборка мусора. Сборка мусора является хорошо оптимизированным процессом и в большинстве случаев не ухудшает производительность. Дополнительные сведения о сборке мусора см. в статье Автоматическое управление памятью.
Типы литеральных значений
Так как литералы являются типизированными и все типы в конечном счете являются производными от System.Object, можно написать и скомпилировать следующий код:
Универсальные типы
Использование параметра типа позволяет повторно использовать один же класс для хранения элементов любого типа, не преобразовывая каждый элемент в объект. Универсальные классы коллекций называются строго типизированными коллекциями, так как компилятору известен конкретный тип элементов коллекции и он может выдать ошибку во время компиляции, если, к примеру, вы попытаетесь добавить целое число в объект stringList , созданный в предыдущем примере. Дополнительные сведения см. в статье Универсальные шаблоны.
Неявные типы, анонимные типы и типы, допускающие значение NULL
Вы можете неявно типизировать локальную переменную (но не элементы класса) с помощью ключевого слова var . Такая переменная получает конкретный тип во время компиляции, но этот тип предоставляется компилятором. Дополнительные сведения см. в статье Implicitly Typed Local Variables (Неявно типизированные локальные переменные).
Иногда нет смысла создавать именованный тип для простых наборов связанных значений, которые не будут сохраняться или передаваться за пределами метода. В таких случаях можно применить анонимные типы. Дополнительные сведения см. в статье Анонимные типы.
Обычные типы значений не могут иметь значение null . Но вы можете создать специальные типы, допускающие значения NULL, добавив символ ? после имени типа. Например, тип int? является типом int , который может иметь значение null . Типы, допускающие значение NULL, представляют собой экземпляры универсального типа структуры System.Nullable . Типы, допускающие значение NULL, особенно полезны при передаче данных в базы данных, где могут использоваться числовые значения null , и из таких баз данных. Дополнительные сведения см. в разделе Типы, допускающие значение NULL.
Тип времени компиляции и тип времени выполнения
Переменная может иметь разные типы времени компиляции и времени выполнения. Тип времени компиляции является объявленным или выведенным типом переменной в исходном коде. Тип времени выполнения является типом экземпляра, на который ссылается такая переменная. Часто эти два типа совпадают:
В других случаях тип времени компиляции отличается, как показано в следующих двух примерах:
В обоих предыдущих примерах используется тип времени выполнения string . Тип времени компиляции в первой строке — object , а во второй — IEnumerable .
Если два типа переменной отличаются, важно понимать, когда применяются типы времени компиляции и времени выполнения. Тип времени компиляции определяет все действия, выполняемые компилятором. Такие действия компилятора включают разрешение вызовов методов, разрешение перегрузки, а также доступные неявные и явные приведения. Тип времени выполнения определяет все действия, разрешаемые при выполнении. Такие действия времени выполнения включают отправку вызовов виртуальных методов, оценку выражений is и switch , а также другие API тестирования типов. Чтобы лучше понять, как ваш код взаимодействует с типами, определите, какие действия применяются к каждому типу.
Связанные разделы
Дополнительные сведения см. в следующих статьях:
Читайте также: