Является ли кастинг тем же самым, что и преобразование?

StackOverflow https://stackoverflow.com/questions/143997

  •  02-07-2019
  •  | 
  •  

Вопрос

В книге Джесси Либерти "Изучение C #" он говорит: "Объекты одного типа могут быть преобразованы в объекты другого типа.Это называется кастингом ".

Если вы исследуете IL, сгенерированный из приведенного ниже кода, вы можете ясно увидеть, что приведенное присваивание не выполняет то же самое, что преобразованное присваивание.В первом случае вы можете увидеть, как происходит упаковка / распаковка;в последнем вы можете увидеть вызов метода convert.

Я знаю, что в конце концов это может быть просто глупая семантическая разница - но это просто другое слово для преобразования.Я не хочу показаться язвительным, но меня не интересует ничье внутреннее чутье на этот счет - мнения здесь не учитываются!Может ли кто-нибудь указать на окончательную ссылку, которая подтверждает или опровергает, что приведение и преобразование - это одно и то же?

    object x;
    int y;

    x = 4;

    y = ( int )x;

    y = Convert.ToInt32( x );

Спасибо

rp

Примечание добавлено после комментария Мэтта о явном / неявном:

Я не думаю, что неявное / явное - это разница.В коде, который я опубликовал, изменение является явным в обоих случаях.Неявное преобразование - это то, что происходит, когда вы присваиваете short значению int.

Примечание для Sklivvz:

Я хотел получить подтверждение того, что мои подозрения о расплывчатости языка Джесси Либерти (в остальном обычно ясного) были верны.Мне показалось, что Джесси Либерти был немного свободен в выражениях.Я понимаю, что приведение выполняется в иерархии объектов - т. Е. вы не можете привести целое число к строке, но вы могли бы привести пользовательское исключение, полученное из System.Исключение из Системы.Исключение.

Интересно, однако, что когда вы пытаетесь преобразовать значение из int в string , компилятор сообщает вам, что ему не удалось "преобразовать" значение.Может быть, Джесси более прав, чем я думал!

Это было полезно?

Решение

Простой ответ таков:это зависит от обстоятельств.

Для типов значений приведение будет включать в себя подлинное преобразование их в другой тип.Например:

float f = 1.5f;
int i = (int) f; // Conversion

Когда выражение приведения распаковывается, результатом (при условии, что оно работает) является обычно просто копия того, что было в коробке, с тем же шрифтом.Однако есть исключения - вы можете распаковать содержимое из упакованного int в enum (с базовым типом int) и наоборот;аналогично, вы можете распаковать содержимое из упакованного int в обнуляемое<int>.

Когда выражение приведения переводится из одного ссылочного типа в другой и не используется определяемое пользователем преобразование, преобразование самого объекта не выполняется - только тип объекта ссылка "изменяет" - и это действительно только способ, которым рассматривается значение, а не сама ссылка (которая будет состоять из тех же битов, что и раньше).Например:

object o = "hello";
string x = (string) o; // No data is "converted"; x and o refer to the same object

Когда речь заходит о пользовательских преобразованиях, это обычно влечет за собой возврат другого объекта / значения.Например, вы могли бы определить преобразование в string для вашего собственного типа - и это, конечно, были бы не те же данные, что и ваш собственный объект.(Конечно, это может быть уже существующая строка, на которую ссылается ваш объект.) По моему опыту, пользовательские преобразования обычно существуют между типами значений, а не ссылочными типами, так что это редко является проблемой.

Все это считается преобразованиями с точки зрения спецификации, но не все они считаются преобразованием объект в объект другого типа.Я подозреваю, что это случай, когда Джесси Либерти не разбирается в терминологии - я заметил это в "Программировании на C # 3.0", который я только что прочитал.

Это все покрывает?

Другие советы

Ни в коем случае!

Convert пытается получить вам Int32 "любыми возможными способами".Приведение не делает ничего подобного.С помощью приведения вы указываете компилятору обрабатывать объект как Int, без преобразования.

Вы всегда должны использовать приведение, когда вы знаете (по замыслу), что объект является Int32 или другим классом, у которого есть оператор приведения к Int32 (например, float ).

Convert следует использовать со String или с другими классами.

Попробуй это

static void Main(string[] args)
{
    long l = long.MaxValue;

    Console.WriteLine(l);

    byte b = (byte) l;

    Console.WriteLine(b);

    b = Convert.ToByte(l);

    Console.WriteLine(b);

}

Результат:

9223372036854775807

255

Необработанное исключение:

Система.Исключение OverflowException:Значение больше, чем Byte.MaxValue или меньше , чем Byte.Минимальное значение в System.Преобразовать.в байт (значение Int64) [0x00000] в Test.Main (System.Строка [] аргументов) [0x00019] в /home/marco/development/test/Exceptions.cs:15

Лучшее объяснение, которое я видел, можно увидеть ниже, за которым следует ссылка на источник:

"...Правда немного сложнее, чем это..NET предоставляет как бы три способа добраться из пункта А в пункт Б.

Во-первых, существует неявное приведение.Это чугун, который не требуется сделать нечто большее, чем простое назначение:

int i = 5;
double d = i;

Это также называется "расширяющими преобразованиями", и .NET позволяет вам выполнять их без какого-либо оператора приведения, потому что при этом вы никогда не потеряете никакой информации:возможный диапазон допустимых значений double охватывает диапазон допустимых значений для int, а затем некоторых других, поэтому вы никогда не собираетесь выполнять это присвоение, а затем открывать для своего ужас в том, что среда выполнения убрала несколько цифр из вашего значения int.Для ссылочных типов правило, лежащее в основе неявного приведения, заключается в том, что приведение никогда не может вызвать исключение InvalidCastException:компилятору ясно что приведение всегда допустимо.

Вы можете создавать новые операторы неявного приведения для своих собственных типов (что означает, что вы можете выполнять неявные приведения, которые нарушают все правила, если вы глупы в этом).Основное эмпирическое правило заключается в том, что неявное приведение никогда не может включать возможность потери информации при переходе.

Обратите внимание, что лежащее в основе представление сделал изменения в этой преобразования:double представлен совершенно иначе, чем int.

Второй вид преобразования - это явное приведение.Явное приведение требуется везде, где есть вероятность потери информации, или существует вероятность того, что приведение может быть недействительным и, следовательно, выдавать исключение InvalidCastException:

double d = 1.5;
int i = (int)d;

Здесь вы, очевидно, потеряете информацию:я буду 1 после броска, так что 0,5 теряется.Это также известно как "сужение". преобразование, и компилятор требует, чтобы вы включили явное приведение (int), чтобы указать, что да, вы знаете, что информация может быть потеряна, но вам все равно.

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

Третий вид преобразования - это тот, который включает в себя такое радикальное изменение в представлении, что дизайнеры не предусмотрели даже явного приведения:они заставляют вас вызывать метод для выполнения преобразования:

string s = "15";
int i = Convert.ToInt32(s);

Обратите внимание, что здесь нет ничего, что абсолютно требовало бы вызова метода.Неявные и явные приведения также являются вызовами методов (именно так вы создаете свои собственные).Дизайнеры могли бы довольно легко создать четкие оператор приведения, который преобразует строку в int.Требование, чтобы вы вызывали метод, является скорее стилистическим выбором, чем фундаментальным требованием языка.

Стилистические рассуждения звучат примерно так:Преобразование строки в int - это сложное преобразование с множеством возможностей для того, чтобы что-то пошло не так ужасно неправильно:

string s = "The quick brown fox";
int i = Convert.ToInt32(s);

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

При разработке собственных типов (в частности, собственных типов значений) вы можете решить создать операторы приведения и функции преобразования.Линии , разделяющие "неявное приведение", "явное приведение" и "функцию преобразования" территория немного размыта, поэтому разные люди могут принимать разные решения относительно того, что должно быть чем.Просто постарайтесь иметь в виду потерю информации и возможность возникновения исключений и неверных данных, и это должно помочь вам принять решение ".

  • Брюс Вуд, 16 ноября 2005 года

http://bytes.com/forum/post1068532-4.html

Кастинг включает Ссылки

List<int> myList = new List<int>();
//up-cast
IEnumerable<int> myEnumerable = (IEnumerable<int>) myList;
//down-cast
List<int> myOtherList = (List<int>) myEnumerable;

Обратите внимание, что операции с myList, такие как добавление элемента, отражены в myEnumerable и myOtherList.Это связано с тем, что все они являются ссылками (разных типов) на один и тот же экземпляр.

Заброс вверх безопасен.Преобразование вниз может привести к ошибкам во время выполнения, если программист допустил ошибку в типе.Безопасное отклонение вниз выходит за рамки этого ответа.

Преобразование включает в себя Экземпляры

List<int> myList = new List<int>();
int[] myArray = myList.ToArray();

myList используется для создания myArray.Это неразрушающее преобразование (myList отлично работает после этой операции).Также обратите внимание, что операции с myList, такие как добавление элемента, не отражаются в myArray.Это связано с тем, что они являются полностью отдельными экземплярами.

decimal w = 1.1m;
int x = (int)w;

В C # существуют операции, использующие синтаксис приведения, которые являются фактические преобразования.

Если отбросить семантику, быстрый тест показывает, что они являются НЕ эквивалентно !
Они выполняют задачу по-разному (или, возможно, они выполняют разные задачи).

x=-2.5 (int)x=-2 Convert.ToInt32(x)=-2
x=-1.5 (int)x=-1 Convert.ToInt32(x)=-2
x=-0.5 (int)x= 0 Convert.ToInt32(x)= 0
x= 0.5 (int)x= 0 Convert.ToInt32(x)= 0
x= 1.5 (int)x= 1 Convert.ToInt32(x)= 2
x= 2.5 (int)x= 2 Convert.ToInt32(x)= 2

Обратите внимание на x=-1.5 и x=1.5 случаи.

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

Приведение всегда означает изменение типа данных объекта.Это может быть сделано, например, путем преобразования значения с плавающей запятой в целое значение или путем переосмысления битов.Обычно это поддерживаемый язык (читать:поддерживаемая компилятором) операция.

Термин "преобразование" иногда используется для приведения, но обычно это выполняется какой-либо библиотекой или вашим собственным кодом и не обязательно приводит к тому же, что и приведение.Например, если у вас есть значение imperial weight и вы преобразуете его в metric weight, оно может сохранить тот же тип данных (скажем, float), но стать другим числом.Другим типичным примером является преобразование из градусов в радианы.

Говоря языком, не зависящим от фреймворка, преобразование из одного типа или класса в другой известно как Кастинг.Это верно и для .NET, как показывают ваши первые четыре строки:

object x;
int y;

x = 4;

y = ( int )x;

C и C-подобные языки (такие как C #) используют (newtype)somevar синтаксис для приведения.В VB.NET, например, для этого есть явно встроенные функции.Последняя строка будет записана следующим образом:

y = CInt(x)

Или, для более сложных типов:

y = CType(x, newtype)

Где "C", очевидно, является сокращением от "cast".

.NET также имеет Convert() функция, однако.Это не встроенная языковая функция (в отличие от двух вышеупомянутых), а скорее одна из фреймворка.Это становится понятнее, когда вы используете язык, который не обязательно используется вместе с .NET:скорее всего, у них все еще есть свои собственные средства кастинга, но именно .NET добавляет Convert().

Как говорит Мэтт, разница в поведении заключается в том, что Convert() является более явным.Вместо того, чтобы просто указывать компилятору обрабатывать y как целочисленный эквивалент x, вы специально говорите ему изменить x таким образом, который подходит для класса integer, тогда присвоите результат y.

В вашем конкретном случае приведение выполняет то, что называется "распаковкой", тогда как Convert() фактически получит целочисленное значение.Результат будет выглядеть тем же самым, но есть небольшие различия. объяснено Китом.

В соответствии с таблицей 1-7, озаглавленной "Методы явного преобразования" на странице 55 главы 1, урок 4 из Набор для самостоятельного обучения MCTS (экзамен 70-536):Microsoft® .NET Framework 2.0—Фонд разработки приложений, Безусловно, между ними есть разница.

Система.Преобразовать не зависит от языка и преобразует "Между типами, которые реализуют Система.Конвертируемый в иконку интерфейс."

оператор приведения (типа) является Специфичный для C # языковая функция, которая преобразует "Между типами, определяющими операторы преобразования."

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

В соответствии с разделом , озаглавленным Как реализовать преобразование в пользовательских типах на стр.56-57 в приведенном выше уроке, операторы преобразования (casting) предназначены для упрощения преобразований между числовыми типами, в то время как Convert() позволяет выполнять преобразования в зависимости от языка.

Какой метод вы выберете, зависит от типа преобразования, которое вы хотите выполнить:

  • Определить операторы преобразования для упрощения сужения и расширения преобразования между числовыми типами.

  • Реализовать Система.Конвертируемый значок чтобы включить преобразование с помощью Система.Обращать.Используйте этот метод для обеспечения конверсий в зависимости от конкретной культуры.

  • ...

Теперь должно быть яснее, что, поскольку оператор преобразования cast реализован отдельно от интерфейса IConvertible, Convert() не обязательно является просто другим именем для приведения.(Но я могу представить, где одна реализация может ссылаться на другую для обеспечения согласованности).

Не забывайте о других методах приведения и преобразования переменных:as, Parse, TryParse а также неявное преобразование между совместимыми типами данных.

На этом сайте есть хороший пример того, какие результаты дает большинство методов:Упаковка и распаковка C #

Итак, учитывая эти примерные переменные:

int i = 3, x;
long l;
string s = "5";

В принципе, вы можете использовать неявное приведение между двумя совместимыми типами:

l = i;

Явное приведение с использованием распаковки или как ключевое слово:

s = (string)i;
//or
s = i as string;

Явные преобразования с использованием методов из системы.Преобразование:

i = System.Convert.ToInt32(s);

Явные преобразования с использованием методов из определенного типа данных:

i = int.Parse(s);
i = int.TryParse(s, x);

Явные преобразования с использованием методов из экземпляра переменной:

s = i.ToString();

Я думаю , что Кастинг это просто способ выполнения назначений между двумя совместимыми типами.

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

Немного полезной информации также о MSDN: Приведение и преобразования типов

Приведение, по сути, просто указывает среде выполнения "притвориться", что объект является новым типом.На самом деле это никоим образом не преобразует и не изменяет объект.

Convert, однако, будет выполнять операции по преобразованию одного типа в другой.

В качестве примера:

char caster = '5';
Console.WriteLine((int)caster);

Результат этих операторов будет равен 53, потому что все, что сделала среда выполнения, - это посмотрела на битовый шаблон и обработала его как int.В итоге вы получаете ascii-значение символа 5, а не число 5.

Однако, если вы используете Convert .ToInt32 (заклинатель), вы получите 5, потому что он фактически считывает строку и изменяет ее правильно.(По сути, он знает, что значение ASCII 53 на самом деле является целочисленным значением 5.)

Разница здесь заключается в том, является ли преобразование неявным или явным.Первый из них - это приведение, второй - это более явный вызов функции, которая преобразует.Вероятно, они делают одно и то же по-разному.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top