В чем разница между кастингом и конверсией?
Эрик Липперт комментирует в этот вопрос, оставил меня в полном недоумении. В чем разница между кастингом и преобразованием в С#?
Ответы
Ответ 1
Я верю, что Эрик пытается сказать:
Кастинг - это термин, описывающий синтаксис (следовательно, синтаксический смысл).
Конверсия - это термин, описывающий, какие действия фактически выполняются за кулисами (и, следовательно, значение семантики).
Литье-выражение используется для преобразования явно выражение для данного тип.
и
Листинговое выражение формы (T) E, где T - тип, а E - унарное выражение, выполняет явное преобразование (§13.2) значения E для ввода T.
Кажется, это подтверждается тем, что оператор трансляции в синтаксисе выполняет явное преобразование.
Ответ 2
Кастинг - это способ сообщить компилятору: "Объект X действительно является типом Y, продолжайте и рассматривайте его как таковой".
Конверсия говорит: "Я знаю, что Object X не является типом Y, но существует способ создания нового объекта из X типа Y, идите вперед и делайте это".
Ответ 3
Мне вспоминается анекдот, который сказал Ричард Фейнман, где он посещает философский класс, и профессор спрашивает его: "Фейнман, ты физик, по-твоему, это электрон и" важный объект "? Поэтому Фейнман задает уточняющий вопрос:" Это кирпич - важный объект? "к классу. У каждого ученика есть другой ответ на этот вопрос. Говорят, что основным абстрактным понятием" кирпичность" является существенный объект. Нет, один конкретный, уникальный кирпич является основным объектом. Нет, части кирпича, которые вы можете эмпирически наблюдать, являются основным объектом. И так далее.
Что, конечно, не отвечать на ваш вопрос.
Я не собираюсь проходить через все эти дюжины ответов и дебатировать с их авторами о том, что я на самом деле имел в виду. Я напишу статью в блоге по этой теме через несколько недель, и мы увидим, что это проливает свет на этот вопрос.
Как насчет аналогии, хотя, а-ля Фейнман. Вы хотите испечь буханку бананового хлеба в субботу утром (как я делаю почти каждое утро в субботу.) Итак, вы проконсультируетесь с The Joy of Cooking, и в нем говорится: "Бла-бла-бла... В другой миске взбейте вместе сухие ингредиенты..."
Очевидно, что есть сильная связь между этой инструкцией и вашими действиями завтра утром, но в равной степени было бы ошибкой скрыть инструкцию с действием. Инструкция состоит из текста. Он имеет местоположение на определенной странице. Он имеет пунктуацию. Если бы вы были на кухне, взбирая муку и пищевую соду, а кто-то спросил, "какова ваша пунктуация прямо сейчас?", Вы, вероятно, подумали бы, что это был странный вопрос. Действие связано с инструкцией, но текстовые свойства команды не являются свойствами действия.
Литье не является конверсией таким же образом, что рецепт не является актом выпечки торта. Рецепт - это текст, который описывает действие, которое вы затем можете выполнить. Оператор литья - это текст, который описывает действие - преобразование, которое может выполнять среда выполнения.
Ответ 4
Из С# Spec 14.6.6:
Литье-выражение используется для преобразования явно выражение для данного типа.
...
Листинговое выражение формы (T) E, где T - тип, а E - унарное выражение, выполняет явное преобразование (§13.2) значения E для ввода T.
Итак, кастинг - это синтаксическая конструкция, используемая для указания компилятору вызывать явные преобразования.
Из С# Spec §13:
Преобразование позволяет выразить один тип, который должен рассматриваться как другой тип. Конверсии могут быть неявными или явно, и это определяет, требуется явное литье. [Пример: Например, преобразование от типа int до типа long неявным, поэтому выражения типа int может неявно рассматриваться как тип длинный. Обратное преобразование из type long to type int, явно, поэтому требуется явное литье.
Итак, конверсии - это то, где выполняется фактическая работа. Вы заметите, что цитата с цитатами говорит о том, что она выполняет явные преобразования, но явные преобразования - это надмножество неявных преобразований, поэтому вы также можете вызывать неявные преобразования (даже если это не обязательно) с помощью выражений-кавычек.
Ответ 5
Просто мое понимание, возможно, слишком просто:
Когда литье основных данных остается неповрежденным (такое же внутреннее представление) - "Я знаю, что это словарь, но вы можете использовать его как ICollection".
При преобразовании вы меняете внутреннее представление на что-то другое - "Я хочу, чтобы этот int был строкой".
Ответ 6
После прочтения комментариев Эрика попытка простого английского:
Кастинг означает, что два типа на одном уровне фактически одинаковы. Они могут реализовать один и тот же интерфейс или наследовать от одного и того же базового класса, или цель может быть "достаточно же" (надмножество?) Для приведения к работе, например, от литья от Int16 до Int32.
Преобразование типов означает, что два объекта могут быть достаточно похожи для преобразования. Возьмем, например, строковое представление числа. Это строка, ее нельзя просто отличить в число, ее нужно разобрать и преобразовать из одного в другой, и процесс может завершиться неудачно. Это может не сработать и для кастинга, но я думаю, что это намного менее дорогостоящий провал.
И это ключевое различие между двумя концепциями, которые я думаю. Преобразование приведет к некоторому разбору или более глубокому анализу и преобразованию исходных данных. Кастинг не анализируется. Он просто пытается совпадение на каком-то полиморфном уровне.
Ответ 7
Кастинг - это создание значения одного типа из другого значения другого типа. Конверсия - это тип кастинга, в котором внутреннее представление значения также должно быть изменено (а не просто его интерпретация).
В С# кастинг и преобразование выполняются с помощью выражения-выражения:
(тип) унарное выражение
Различие важно (и дело сделано в комментарии), потому что только конверсии могут быть созданы с помощью оператора-преобразователя-декларатора. Поэтому в коде могут быть созданы только (неявные или явные) преобразования.
Неявная трансляция без преобразования всегда доступна для подтипов к супертипам, а явное приведение без преобразования всегда доступно для супертипов-подтипов. Никакие другие преобразования без преобразования не допускаются.
Ответ 8
В этом контексте кастинг означает, что вы подвергаете объект определенного типа манипуляции как некоторый другой тип, преобразование означает, что вы фактически изменяете объект данного типа на объект другого типа.
Ответ 9
Эта страница документации MSDN С# предполагает, что бросок - это конкретный экземпляр преобразования: "явное преобразование". То есть преобразование формы x = (int)y
является литой.
Автоматические изменения типа данных (например, myLong = myInt
) являются более общим "преобразованием".
Ответ 10
Листинг - это оператор в классе /struct. Преобразование - это метод/процесс для одного или другого из затронутых классов/структур или может быть в полном разном классе/структуре (т.е. 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
Ссылки Эрика на синтаксическое преобразование по сравнению с символическим преобразованием в основном представляют собой различие между оператором и методологией.
Ответ 11
Листинг является синтаксическим и может включать или не включать преобразование (в зависимости от типа трансляции). Как вы знаете, С++ позволяет указать тип броска, который вы хотите использовать.
Включение/выключение иерархии может считаться или не считаться конверсией, в зависимости от того, кого вы спрашиваете (и на каком языке они говорят!)
Eric (С#) говорит, что приведение к другому типу всегда включает в себя преобразование, хотя это преобразование даже не может изменить внутреннее представление экземпляра.
A С++ - парень не согласится, так как static_cast
может не привести к добавлению какого-либо дополнительного кода (так что "преобразование" на самом деле не реально!)
Ответ 12
Кастинг и преобразование в основном являются одной и той же концепцией в С#, за исключением того, что преобразование может быть выполнено с использованием любого метода, такого как Object.ToString()
. Кастинг выполняется только с оператором литья (T) E
, который описан в других сообщениях, и может использовать преобразования или бокс.
Какой метод преобразования он использует? Компилятор решает на основе классов и библиотек, предоставленных компилятору во время компиляции. Если существует неявное преобразование, вам не требуется использовать оператор литья. Object o = String.Empty
. Если существуют только явные преобразования, вы должны использовать оператор литья. String s = (String) o
.
Вы можете создать explicit
и implicit
операторы преобразования в своих собственных классах. Примечание. Конверсии могут сделать данные похожими или не похожими на оригинальный тип для вас и меня, но все это определяется методами преобразования и делает его законным для компилятора.
Литье всегда относится к использованию оператора литья. Вы можете написать
Object o = float.NaN;
String s = (String) o;
Но если вы заходите на s
, например, в Console.WriteLine
, вы получите время выполнения InvalidCastException
. Таким образом, оператор литья по-прежнему пытается использовать преобразование во время доступа, но соглашается на бокс во время назначения.
Ответ 13
INSERTED EDIT # 2: разве это не смехотворно противоречивая близорукость, поскольку, поскольку я дал этот ответ, вопрос был отмечен как дубликат вопроса, который спрашивает: "Является ли то же самое, что и преобразование?". И ответы "Нет" в подавляющем большинстве сохраняются. Тем не менее, мой ответ здесь указывает на порождающую сущность, почему касты - это не то же самое, что конверсия подавляюще подавлена ( но у меня есть +1 в комментариях). Я полагаю, что у читателей есть трудное время с пониманием того, что приклады применяются на уровне денотационного синтаксиса/семантики, и преобразования применяются на уровне рабочей семантики. Например, приведение ссылки (или указателя на C/С++) - обращение к типу данных в виде коробки - к другому типу данных - не позволяет (на всех языках и сценариях) преобразовывать данные в коробке. Например, в C float a[1]; int* p = (int*)&a;
не гарантирует, что *p
относится к данным int
.
Компилятор компилируется из denotational семантика оперативная семантика. Компиляция не является биективной, т.е. Не гарантируется uncompile (например, Java, LLVM, asm.js или С# bytecode) обратно к любому денотационному синтаксису, который компилируется в этот байт-код (например, Scala, Python, С#, C через Emscripten и т.д.). Таким образом, два слоя не совпадают.
Таким образом, наиболее очевидно, что "бросок" и "преобразование" - это не одно и то же. Мой ответ здесь указывает, что термины применимы к двум различным слоям семантики. Каста применяются к семантике того, что знает денотационный уровень (входной синтаксис компилятора). Конверсии применяются к семантике того, о чем знает уровень работы (среда выполнения или промежуточный байт-код). Я использовал стандартный термин "стертый", чтобы описать, что происходит с денотационной семантикой, которые явно не записаны в слое рабочей семантики.
Например, повторяющиеся дженерики являются примером записи денотационной семантики в слое рабочей семантики, но у них есть недостаток, заключающийся в том, что слой эксплуатационной семантики несовместим с денотационной семантикой более высокого порядка, например. поэтому было больно рассмотреть возможность внедрения Scala generic generic на С# CLR, потому что денотатическая семантика С# для дженериков была жестко закодирована на уровне рабочей семантики.
Приходите, ребята, остановите никого, кто знает намного больше, чем вы. Сделайте домашнее задание первым, прежде чем голосовать.
INSERTED EDIT: Кастинг - это операция, которая происходит на уровне денотационной семантики (где типы выражаются в их полной семантике). Приведение может (например, явное преобразование) или не может (например, повышать) вызвать преобразование в семантическом слое среды выполнения. Сводные ответы на мой ответ (а также прогноз на комментарий Марка Гэвина) показывают мне, что большинство людей не понимают различий между денотационной семантикой и операционным (исполнением) семантика. Вздох.
Я скажу, что Эрик Липперт ответил более просто и более широко для всех языков, , включая С#.
Приведение в синтаксис, поэтому (как и весь синтаксис) удаляется во время компиляции; тогда как преобразование вызывает некоторое действие во время выполнения.
Это истинное утверждение для каждого языка компьютера, о котором я знаю во всей вселенной. Обратите внимание, что в приведенном выше утверждении не сказано, что кастинг и преобразования являются взаимоисключающими.
Приведение может привести к конверсии во время выполнения, но есть случаи, когда это может быть не так.
Причина, по которой у нас есть два разных слова, то есть литье и преобразование, - это способ отдельно описать, что происходит в синтаксисе (оператор трансляции) и время выполнения (преобразование, проверка типа и возможное преобразование).
Важно, чтобы мы поддерживали это разделение понятий, потому что на некоторых языках программирования литье никогда не вызывает преобразования. Также, чтобы понять неявное литье (например, upcasting) происходит только во время компиляции. Причина, по которой я написал этот ответ, состоит в том, что я хочу помочь читателям понять, что они многоязычны с компьютерными языками. А также посмотреть, как это общее определение правильно применяется и в случае с С#.
Также я хотел помочь читателям посмотреть, как я обобщаю концепции в своем уме, что помогает мне в качестве разработчика компьютерных языков. Я пытаюсь передать даром очень редукционистский, абстрактный образ мышления. Но я также пытаюсь объяснить это очень практично. Пожалуйста, не стесняйтесь, дайте мне знать в комментариях, если мне нужно улучшить разъяснение.
Эрик Липперт писал (а):
Литье не является преобразованием таким же образом, что рецепт не является акт выпечки торта. Рецепт - это текст, который описывает действие, которые вы можете выполнить. Оператор литья - это текст, который описывает action - преобразование, которое может выполнять среда выполнения.
Рецепт - это то, что происходит в синтаксисе. Синтаксис всегда стирается и заменяется либо ничем, либо некоторым кодом времени выполнения.
Например, я могу написать подборку на С#, которая ничего не делает и полностью удалена во время компиляции, когда она не вызывает изменения в требования к хранению или upcasting. Мы можем ясно видеть, что приведение - это просто синтаксис, который не меняет код выполнения.
int x = 1;
int y = (int)x;
Giraffe g = new Giraffe();
Animal a = (Animal)g;
Это может использоваться для целей документирования (но все же шумно), но это важно в языках, которые имеют вывод типа, где иногда требуется бросок, чтобы сообщить компилятору, какой тип вы хотите сделать.
Для пример, в Scala a None
имеет тип Option[Nothing]
, где Nothing
- нижний тип, который является подтипом всех возможных типов (не супер-типа). Поэтому иногда, когда вы используете None, тип должен быть добавлен к определенному типу, потому что Scala выполняет только локальный тип вывода, поэтому не всегда может вывести тип, который вы предназначен.
// (None : Option[Int]) casts None to Option[Int]
println(Some(7) <*> ((None : Option[Int]) <*> (Some(9) > add)))
В момент компиляции может быть известно, что он требует преобразования типа, например. int x = (int)1.5
, или может потребовать проверки типа и возможного преобразования типа во время выполнения, например. downcasting. Листинг (т.е. Синтаксис) стирается и заменяется действием времени выполнения.
Таким образом, мы можем ясно видеть, что приравнивание всех выражений с явным преобразованием является ошибкой в документации MSDN. Эта документация намеревается сказать, что для явного преобразования требуется оператор трансляции, но он не должен также предполагать, что все трансляции являются явными преобразованиями. Я уверен, что Эрик Липперт может это понять, когда он пишет блог, который он обещал в своем ответе.
ДОБАВИТЬ. Из комментариев и чата я вижу, что существует некоторая путаница в отношении значения стираемого термина.
Термин "стертый" используется для описания информации, которая была известна во время компиляции, которая не известна во время выполнения. Например, типы могут быть стерты в неориентированных дженериках и называются типа стирания.
Вообще говоря, весь синтаксис стирается, потому что обычно CLI не является биективным (обратимым и взаимно однозначным) с С#. Вы не всегда можете вернуться назад от какого-либо произвольного кода CLI обратно к точному исходному коду С#. Это означает, что информация была удалена.
Те, кто говорят, что они стерты, не являются правильным термином, объединяют реализацию броска с семантикой актера. Бросок - это семантика более высокого уровня (я думаю, что она на самом деле выше синтаксиса, это денотационная семантика, по крайней мере, в случае повышения и понижения), которая говорит на этом уровне семантики, что мы хотим использовать этот тип. Теперь, как это делается во время выполнения, это совершенно другой уровень семантики. На некоторых языках всегда может быть NOOP. Например, в Haskell вся информация для ввода удаляется во время компиляции.