Это то же самое, что и преобразование?

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

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

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

    object x;
    int y;

    x = 4;

    y = ( int )x;

    y = Convert.ToInt32( x );

Спасибо

Р.П.

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

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

Примечание для Скливвз:

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

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

12 ответов

Решение

Простой ответ: это зависит.

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

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

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

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

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

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

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

Это охватывает все?

Точно нет!

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

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

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

Попробуй это

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

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

System.OverflowException: значение больше, чем Byte.MaxValue или меньше, чем Byte.MinValue в System.Convert.ToByte (значение Int64) [0x00000] в Test.Main (аргументы System.String[]) [0x00019] в /home/marco/develop/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. Требование, чтобы вы вызывали метод, является стилистическим выбором, а не фундаментальным требованием языка.

Стилистические рассуждения выглядят примерно так: String-to-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 случаев.

В языковой / не зависящей от фреймворка манере преобразование из одного типа или класса в другой называется кастингом. Это верно и для.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", очевидно, означает "бросок".

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

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

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

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

System.Convert не зависит от языка и выполняет преобразование "между типами, которые реализуют интерфейс System.IConvertible ".

(тип) оператор приведения - это особая языковая особенность C#, которая преобразует "между типами, определяющими операторы преобразования ".

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

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

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

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

  • Реализуйте System.IConvertible, чтобы включить преобразование через System.Convert. Используйте эту технику, чтобы включить специфичные для культуры преобразования.

  • ...

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

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

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

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

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

На этом сайте есть хороший пример того, что выводит большинство методов: C# Boxing и Unboxing

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

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

По сути, вы можете иметь неявное приведение между двумя совместимыми типами:

l = i;

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

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

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

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(caster), вы получите 5, потому что он на самом деле читает строку и корректно ее изменяет. (По сути, он знает, что значение ASCII 53 на самом деле является целочисленным значением 5.)

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

Другие вопросы по тегам