Этот вопрос уже имеет ответ здесь:
Комментарии Eric Lippert в этом вопросе оставили меня полностью смущенным. Каково различие между кастингом и преобразованием в C#?
Я считаю, что Эрик пытается сказать следующее:
Приведение - это термин, описывающий синтаксис (отсюда синтаксическое значение).
Преобразование - это термин, описывающий, какие действия фактически выполняются за кулисами (и, следовательно, семантическое значение).
Выражение приведения используется для преобразования явно выражение для данного тип.
И
Приведение-выражение формы (T) E, где T - тип, а E - унарное выражение, выполняет явное преобразование (§13.2) значения E для ввода T.
Похоже, это подтверждается заявлением о том, что оператор приведения в синтаксисе выполняет явное преобразование.
Приведение и преобразование - это в основном та же концепция в C #, за исключением того, что преобразование может быть выполнено с использованием любого метода, такого как Object.ToString ()
. Приведение выполняется только с помощью оператора приведения (T) E
, который описан в других сообщениях, и может использовать преобразования или бокс.
Какой метод преобразования он использует? Компилятор принимает решение на основе классов и библиотек, предоставленных компилятору во время компиляции. Если существует неявное преобразование, вам не требуется использовать оператор приведения. Объект o = String.Empty
. Если существуют только явные преобразования, вы должны использовать оператор приведения. Строка s = (Строка) или
.
Вы можете создавать явные
и неявные
операторы преобразования в своих собственных классах. Примечание: преобразования могут сделать данные очень похожими или совсем не похожими на исходный тип для вас и меня, но все это определяется методами преобразования и делает его допустимым для компилятора.
Приведение всегда относится к использованию оператора приведения. Вы можете написать
Object o = float.NaN;
String s = (String) o;
, но если вы получите доступ к s
, например, в Console.WriteLine
, вы получите время выполнения InvalidCastException
. Таким образом, оператор приведения все еще пытается использовать преобразование во время доступа, но соглашается на бокс во время присваивания.
Приведение - это способ сказать компилятору: «Объект X действительно является Типом Y, продолжайте и относитесь к нему как к таковому».
Преобразование говорит: «Я знаю, что объект X не является типом Y, но существует способ создать новый объект из X типа Y, продолжайте и сделайте это».
Мне вспоминается анекдот, рассказанный Ричардом Фейнманом, когда он посещает класс философии, и профессор спрашивает его: «Фейнман, ты физик, по твоему мнению, электрон "существенный объект"? " Итак, Фейнман задает уточняющий вопрос: «Является ли кирпич важным объектом?» к классу. У каждого ученика свой ответ на этот вопрос. Они говорят, что существенным объектом является фундаментальное абстрактное понятие «кирпичность». Нет, один конкретный, уникальный кирпич - это предмет первой необходимости. Нет, части кирпича, которые вы можете наблюдать эмпирически, являются существенным объектом. И так далее.
Что, конечно, не для ответа на ваш вопрос.
Я не собираюсь перебирать все эти дюжины ответов и спорить с их авторами о том, что я на самом деле имел в виду. Я напишу статью в блоге на эту тему через несколько недель, и мы посмотрим, прольет ли это какой-нибудь свет на этот вопрос.
А как насчет аналогии а-ля Фейнман? Вы хотите испечь буханку бананового хлеба в субботу утром (как я делаю почти каждое субботнее утро). Итак, вы обратитесь к The Joy of Cooking, и там написано: «бла-бла-бла… В другой миске смешайте сухие ингредиенты. .."
Очевидно, что существует тесная связь между этой инструкцией и вашими действиями завтра утром, но столь же ясно, что было бы ошибкой объединять инструкцию с действием . Инструкция состоит из текста. Это место на определенной странице. В нем есть знаки препинания. Если бы вы были на кухне, взбивая муку и пищевую соду, и кто-то спросил бы: «Какая у вас сейчас пунктуация?», вы бы, вероятно, подумали, что это было. странный вопрос. Действие связано с инструкцией, но текстовые свойства инструкции не являются свойствами действия.
Приведение не является преобразованием в том же смысле, как рецепт не является действием выпечки торта . Рецепт - это текст, описывающий действие, которое вы затем можете выполнить. Оператор приведения - это текст, который описывает действие - преобразование, - которое среда выполнения может затем выполнить.
После прочтения комментариев Эрика, попытка на простом английском:
Casting означает, что два типа фактически одинаковы на каком-то уровне. Они могут реализовывать один и тот же интерфейс или наследоваться от одного базового класса, или объект может быть достаточно "одинаковым" (супермножество?), чтобы приведение сработало, например, приведение из Int16 в Int32.
Преобразование типов означает, что два объекта могут быть достаточно похожи, чтобы их можно было преобразовать. Возьмем, к примеру, строковое представление числа. Это строка, ее нельзя просто привести к числу, ее нужно разобрать и преобразовать из одного в другое, и этот процесс может закончиться неудачей. Может произойти сбой и при приведении, но я представляю, что это гораздо менее затратный сбой.
И это ключевое различие между двумя концепциями, как мне кажется. Преобразование влечет за собой некий разбор или более глубокий анализ и преобразование исходных данных. Кастинг не разбирает. Он просто пытается найти соответствие на некотором полиморфном уровне.
В этом контексте приведение означает, что вы открываете объект данного типа для манипуляции как некоторый другой тип, преобразование означает, что вы фактически меняете объект данного типа на объект другого типа.
Эта страница документации MSDN C# говорит о том, что приведение - это особый случай преобразования: "явное преобразование". То есть, преобразование вида x = (int)y
- это приведение.
Автоматическое изменение типа данных (например, myLong = myInt
) - это более общее "преобразование"
Просто мое понимание, возможно, слишком простое:
При преобразовании основные данные остаются нетронутыми (такое же внутреннее представление) - «Я знаю, что это словарь, но вы можете использовать его как ICollection».
При преобразовании вы меняете внутреннее представление на другое - «Я хочу, чтобы этот int был строкой».
Приведение - это оператор класса / структуры. Преобразование - это метод / процесс одного или другого затронутого класса / структуры или может быть в совершенно другом классе / структуре (например, Converter.ToInt32 ()
Операторы приведения бывают двух видов: неявные и явные
Неявные операторы приведения указывают, что данные одного типа (скажем, Int32) могут всегда быть представлены как другой тип (десятичный) без потери данных / точности .
int i = 25;
decimal d = i;
] Явные операторы приведения указывают, что данные одного типа (десятичные) могут всегда быть точно представлены как другой тип (int), но могут быть потери данных / точности.Поэтому компилятор требует, чтобы вы явно заявили, что вы знаете об этом и хотите сделать это в любом случае, с помощью явного синтаксиса приведения:
decimal d = 25.0001;
int i = (int)d;
Преобразование принимает два типа, которые не обязательно связаны каким-либо образом , и пытается преобразовать одно в другое с помощью некоторого процесса, например синтаксического анализа. Если все известные алгоритмы преобразования терпят неудачу, процесс может либо выбросить исключение, либо вернуть значение по умолчанию:
string s = "200";
int i = Converter.ToInt32(s); // set i to 200 by parsing s
string s = "two hundred";
int i = Converter.ToInt32(s); // sets i to 0 because the parse fails
Ссылки Эрика на синтаксическое преобразование и симантическое преобразование - это, по сути, различие между оператором и методологией.
Приведение является синтаксическим и может включать или не включать преобразование (в зависимости от типа приведения). Как вы знаете, C ++ позволяет указать тип приведения , который вы хотите использовать.
Приведение вверх / вниз по иерархии может рассматриваться или не рассматриваться как преобразование, в зависимости от того, кого вы спрашиваете (и на каком языке они говорят!)
Эрик (C #) говорит, что приведение к другому Тип всегда включает преобразование, хотя это преобразование может даже не изменить внутреннее представление экземпляра.
Специалист по C ++ не согласится, поскольку static_cast
может не привести к дополнительному коду (так что «преобразование» на самом деле нереально!)
Из спецификации C # 14.6.6:
Выражение приведения используется для преобразования явно выражение для данного тип.
...
Приведение-выражение вида (T) E, где T - тип, а E - унарное выражение, выполняет явное преобразование (§13.2) значения E для типа T.
Таким образом, приведение типов - это синтаксическая конструкция, используемая для указания компилятору вызывать явные преобразования.
Из C # Spec §13:
Преобразование позволяет выражение один тип должен рассматриваться как другой тип. Преобразования могут быть неявными или явный, и это определяет, требуется явное приведение. [Пример: например, преобразование от типа int к типу long неявный, поэтому выражения типа int может неявно рассматриваться как тип длинный. Противоположное преобразование, от type long для типа int, является явным, поэтому требуется явное приведение.
Таким образом, преобразование - это то, где и выполняется фактическая работа.Вы заметите, что цитата выражения приведения говорит о том, что он выполняет явные преобразования, но явные преобразования являются надмножеством неявных преобразований, поэтому вы также можете вызывать неявные преобразования (даже если вам это не нужно) через выражения приведения.
Casting - это создание значения одного типа из другого значения другого типа. Конвертация - это тип приведения, при котором внутреннее представление значения также должно быть изменено (а не только его интерпретация).
В C# приведение и преобразование выполняются с помощью cast-выражения:
( type ) unary-expression
Различие важно (и об этом говорится в комментарии), потому что только преобразования могут быть созданы conversion-operator-declarator. Поэтому в коде могут быть созданы только (неявные или явные) преобразования.
Неявное приведение без преобразования всегда доступно для приведения подтипа к супертипу, а явное приведение без преобразования всегда доступно для приведения супертипа к подтипу. Никакие другие неконверсионные приведения не допускаются.