Бөлісу құралы:


Система типов C#

Подсказка

Вы новичок в разработке программного обеспечения? Сначала начните с учебников для начинающих. Они ведут вас шаг за шагом по процессу написания программ и по ходу дела объясняют типы.

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

C# — это строго типизированный язык. Каждая переменная, константа и выражение имеют тип. Компилятор применяет безопасность типов , проверяя, является ли каждая операция в коде допустимой для используемых типов. Например, можно добавить два int значения, но нельзя добавить и 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 использует для дополнительных проверок безопасности во время выполнения.

Объявление переменных с типами

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

// Explicit type:
int count = 10;
double temperature = 36.6;

// Compiler-inferred type:
var name = "C#";
var items = new List<string> { "one", "two", "three" };

Параметры метода и возвращаемые значения также имеют типы. Следующий метод принимает string и intвозвращает string:

static string GetGreeting(string name, int visitCount)
{
    return visitCount switch
    {
        1 => $"Welcome, {name}!",
        _ => $"Welcome back, {name}! Visit #{visitCount}."
    };
}

После объявления переменной нельзя изменить его тип или назначить значение, несовместимое с объявленным типом. Значения можно преобразовать в другие типы. Компилятор выполняет неявные преобразования , которые не теряют данные автоматически. Явные преобразования (приведения) требуют указания преобразования в коде. Для получения дополнительной информации см. Приведение и преобразование типов.

Встроенные типы и настраиваемые типы

C# предоставляет встроенные типы для общих данных: целых чисел, чисел с плавающей запятой, boolcharи string. Каждая программа C# может использовать эти встроенные типы без дополнительных ссылок.

Помимо встроенных типов, можно создать собственные типы с помощью нескольких конструкций:

  • Классы — ссылочные типы для поведения моделирования и сложных объектов. Поддержка наследования и полиморфизма.
  • Структуры — типы значений для небольших, упрощенных данных. Каждая переменная содержит собственную копию.
  • Записи — классы или структуры с равенством, созданным компилятором, ToStringи недеструктивная мутация с помощью with выражений.
  • Интерфейсы — контракты, которые определяют элементы, которые могут быть реализованы любым классом или структурой.
  • Перечисления — именованные наборы целочисленных констант, такие как дни недели или режимы доступа к файлам.
  • Кортежи — упрощенные структурные типы, которые группирует связанные значения без определения именованного типа.
  • Универсальные шаблоны — типо-параметризованные конструкции, такие как List<T> и Dictionary<TKey, TValue> обеспечивающие безопасность типов при повторном использовании одной логики для разных типов.

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

Каждый тип в C# — это тип значения или ссылочный тип. Это различие определяет, как переменные хранят данные и как работает назначение.

Типы значений хранят данные напрямую. При назначении типа значения новой переменной среда выполнения копирует данные. Изменения в одной переменной не влияют на другую. Структуры, перечисления и встроенные числовые типы являются всеми типами значений.

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

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

public readonly record struct Coords(int X, int Y);
// Value type: each variable holds its own copy
var point1 = new Coords(3, 4);
var point2 = point1;
Console.WriteLine($"point1: ({point1.X}, {point1.Y})");
Console.WriteLine($"point2: ({point2.X}, {point2.Y})");
// point1 and point2 are independent copies

// Reference type: both variables refer to the same object
var list1 = new List<int> { 1, 2, 3 };
var list2 = list1;
list2.Add(4);
Console.WriteLine($"list1 count: {list1.Count}"); // 4 — same object

Все типы в конечном счете являются производными от System.Object. Типы значений происходят от System.ValueType, который, в свою очередь, происходит от object. Эта унифицированная иерархия называется common Type System (CTS). Дополнительные сведения о наследовании см. в разделе "Наследование".

Выберите тип типа

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

  • Кортеж — временное группирование значений, которое не требует именованного типа или поведения.
  • struct или record struct — небольшие данные (примерно 64 байта или меньше), семантика значений или неизменяемость. Структуры записи добавляют поддержку равенства на основе значений и with выражений.
  • record class — в первую очередь данные с равенством на основе значений, ToStringа также недеструктивной мутацией. Поддерживает наследование.
  • class — сложное поведение, полиморфизм или изменяемое состояние. Большинство пользовательских типов — это классы.
  • interface — контракт, который могут реализовать несвязанные типы. Определяет возможности, а не личность.
  • enum — фиксированный набор именованных констант, например коды состояния или параметры.

Более одного варианта часто является разумным.

Тип времени компиляции и тип времени выполнения

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

// Compile-time and run-time types match:
string message = "Hello, world!";

// Compile-time type differs from run-time type:
object boxed = "This is a string at run time";
IEnumerable<char> characters = "abcdefghijklmnopqrstuvwxyz";

В предыдущем примере boxed имеет тип object времени компиляции, но тип stringвремени выполнения. Задание работает, так как string является производным от object. Аналогичным образом characters имеет тип времени компиляции IEnumerable<char>, и присваивание выполняется, поскольку string реализует этот интерфейс. Тип времени компиляции управляет разрешением перегрузки и доступными преобразованиями. Тип времени выполнения управляет отправкой виртуальных методов, is выражениями и switch выражениями.

См. также

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

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