Это то же самое, что и преобразование? - PullRequest
41 голосов
/ 27 сентября 2008

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

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

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

    object x;
    int y;

    x = 4;

    y = ( int )x;

    y = Convert.ToInt32( x );

Спасибо

гр

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

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

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

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

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

Ответы [ 12 ]

28 голосов
/ 27 сентября 2008

Абсолютно нет!

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

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

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

Попробуйте это

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 [] args) [0x00019] в /home/marco/develop/test/Exceptions.cs:15

17 голосов
/ 27 сентября 2008

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

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

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, которое я только что читал.

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

7 голосов
/ 27 сентября 2008

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

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

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

int i = 5;
double d = i;

Их также называют "расширяющимися конверсиями", и .NET позволяет вам выполнять их без оператора приведения, потому что вы никогда не могли потерять информация, делающая это: возможный диапазон допустимых значений двойного охватывает диапазон допустимых значений для 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

2 голосов
/ 27 сентября 2008

Кастинг включает в себя рекомендации

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 #, которые на самом деле являются преобразованиями .

1 голос
/ 29 октября 2008

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

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.

0 голосов
/ 20 августа 2009

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

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

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

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

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

l = i;

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

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: Преобразование типов и типов

0 голосов
/ 27 сентября 2008

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

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

(тип) оператор приведения - это специфичная для C # * языковая функция , которая преобразует «Между типами, определяющими операторы преобразования

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

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

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

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

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

  • ...

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

0 голосов
/ 27 сентября 2008

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

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

Как пример:

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

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

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

0 голосов
/ 27 сентября 2008

В языковой / каркасной манере речи преобразование из одного типа или класса в другой известно как приведение . Это верно и для .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 таким образом, который подходит для целочисленного класса: затем assign результат до y.

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

0 голосов
/ 27 сентября 2008

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

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

...