В чем разница между dynamic, var и object в C#?

Ответ

Ключевое различие между dynamic, var и object заключается в времени проверки типов и необходимости приведения.

  • var — вывод типа на этапе компиляции (compile-time). Это не тип, а указание компилятору самому определить и подставить статический тип на основе выражения инициализации. После определения тип фиксируется.

    var number = 10;        // Компилятор определяет тип как `int`
    // number = "text";    // ОШИБКА КОМПИЛЯЦИИ: нельзя присвоить string переменной типа int
  • dynamic — обход проверки типов на этапе компиляции. Тип и операции проверяются только во время выполнения (runtime). Это может привести к исключениям RuntimeBinderException, если операция недопустима.

    dynamic value = 10;
    value = "text";        // OK, тип меняется
    int length = value.Length; // OK на этапе компиляции, но упадет в runtime, т.к. у int нет свойства Length
  • object — корневой тип системы. Все типы наследуются от object. Для работы с конкретным типом требуется явное приведение (упаковка/распаковка для значимых типов).

    object obj = 10;        // Упаковка (boxing): int -> object
    int num = (int)obj;     // Распаковка (unboxing): object -> int (требуется явное приведение)
    // string str = (string)obj; // InvalidCastException в runtime
Сводная таблица: Ключевое слово Проверка типа Безопасность Приведение Основное назначение
var Компиляция (статическая) Высокая Не требуется Упрощение синтаксиса, LINQ-запросы
dynamic Выполнение (динамическая) Низкая Не требуется Работа с COM, динамическими языками (Python), отражение
object Компиляция (к object) Средняя Требуется явное Общие контейнеры, полиморфные коллекции

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

Ответ 18+ 🔞

А, ну это классика, блядь! Три штуки, которые новичков в C# вводят в ступор, как будто им в жопу кирпич засунули. Сейчас разжую, как бабушка котлету.

Смотри, вся разница — когда компилятор тебе мозги выносит за неправильные типы. Вот и вся магия.

  • var — это просто лень писать длинные типы, а компилятор — не дурак. Ты ему говоришь: «Сам догадайся, что тут». Он смотрит на правую часть, определяет тип раз и навсегда при компиляции и подставляет его, будто ты его сам написал. Всё. Тип статический, менять его потом — хуй тебе, а не смена типа.

    var digit = 42; // Компилятор видит 42 и думает: «А, ну это int, епта».
    // digit = "сорок два"; // А тут он тебе сразу в редакторе подсветит красным: «Иди нахуй, тут int, а ты string суёшь!» — ошибка компиляции.
  • dynamic — это полная анархия и «поверю на слово». Ты компилятору говоришь: «Отстань от меня, я сам разберусь в момент выполнения». Он такой: «Окей, похуй». И проверяет хуйню твою только когда программа уже бежит. Это как ходить по минному полю в темноте — шагнул не туда, и тебе в ебальник RuntimeBinderException прилетает.

    dynamic stuff = 100500;
    stuff = "сто тысяч"; // Да похуй, меняй. Компилятор молчит.
    int len = stuff.Length; // На компиляции — тишина. А в рантайме — БАБАХ! — исключение, потому что у числа 100500 свойства Length нет, дурачок.
  • object — это дед всех типов, универсальный холодильник. В него можно засунуть что угодно: пирожок (int), селёдку (string), бутылку пива (любой класс). Но чтобы это потом достать и съесть, надо точно помнить, что ты туда положил, и явно привести обратно. Иначе — либо ошибка компиляции, либо тебя в рантайме InvalidCastException трахнет.

    object box = 777; // Упаковал int в object (boxing).
    int num = (int)box; // Распаковал обратно (unboxing) — ок.
    // string text = (string)box; // Компилятор пропустит, но при запуске — словишь каст эксепшн, потому что в коробке не строка, а число.

Короче, таблица, чтобы вообще не ебеть мозг:

Штука Когда проверяет типы Надёжность Нужно ли приводить? Зачем вообще нужно?
var При компиляции Высокая, статическая Не нужно Не париться писать длинные типы в LINQ или когда Dictionary<string, List<MySuperPuperClass>> лень выводить.
dynamic При выполнении (runtime) Низкая, можно выстрелить в ногу Не нужно Когда работаешь с какой-то ебейшей динамической хуйнёй: COM-объектами, питоном, рефлексией.
object При компиляции (к object) Средняя, можно налажать с кастом Требуется явное Когда нужен общий ящик для всего подряд, например, в старой необобщённой коллекции ArrayList.

Простое правило жизни:
Используй var везде, где справа и так понятно, что за тип. Это просто удобно.
dynamic — только если реально приперло и без динамики никуда, и ты готов ловить исключения.
object — когда пишешь какую-то архаичную хуйню или нужен максимально общий контейнер, и ты не боишься кастов.

Вот и вся философия, блядь. Не усложняй.