Я изучаю C# 7.0 в двух словах, 7-е издание. Есть часть текста, которую я не мог понять (страницы 24 и 25)
"Implicit conversions are allowed when both of the following are true:
1) The compiler can guarantee they will always succeed.
2) No information is lost in conversion. (A minor caveat is that very large long values lose some precision when converted to double)
Conversely, explicit conversions are required when one of the following is true:
1)The compiler cannot guarantee they will always succeed.
2)Information may be lost during conversion."
If the compiler can determine that a >conversion will always fail, both kinds of conversion are prohibited"
Вы можете привести примеры, когда компилятор не может гарантировать преобразование?
см. softwareengineering.stackexchange.com/questions/284359/…
лучший способ научиться этому - создать консольное приложение и поиграть, много веселья там
Например, приведение ссылки интерфейса IFoo к объекту Foo. Компилятор не может быть уверен, что это действительно может быть объект класса Bar, который также реализует IFoo. Если это так, вы получите исключение InvalidCastException во время выполнения. В общем, любое преобразование, которое является восходящим, переходя от менее специализированного типа к более специализированному типу. В целом плохая идея, но иногда неизбежная. Примеры с плавающей запятой не очень хороши, они действительно успешны во время выполнения, и вы получите число, которое может вас удивить.
Неявные преобразования существуют для преобразования типа данных, например short
в int
или int
в long
. Другой пример - это int
в float
или double
. Такие типы данных всегда можно привести к их более крупным аналогам.
Обратное неверно: double
(всегда) не может быть преобразован в int
. long
не всегда подходит к int
или short
.
для добавления контекста примером явного преобразования будет строка в целое число, потому что вы никогда не узнаете, является ли содержимое строки числом, буквенно-цифровым или просто текстовым значением
double
- int
также имеет явный оператор. @MrVoid
да, вы на 100% правы, я просто подумал, что просто числовые значения могут иногда немного сбивать с толку.
Спасибо за ваш ответ. Так компилятор определяет, гарантировать ли преобразование только размер данных?
Нет. Как сказал MrVoid, это зависит от обоих типов данных. Например, все с string
- плохой выбор. @Coder
Извините только что прочитал его комментарий. Да, это интересный пример. Где я могу узнать об этом подробнее? Я пытаюсь думать, как компилятор, чтобы учесть возможные случаи.
"Что-нибудь со строкой - плохой выбор, например.", Можете ли вы пояснить @PatrickHofman? Благодарность
@Coder docs.microsoft.com/en-us/dotnet/csharp/programming-guide/typ es /… и docs.microsoft.com/en-us/dotnet/csharp/language-reference/….
@MrVoid Ну, было бы сложно неявно преобразовать любой тип данных из и в строку.
да, видно, это не очень хороший пример для всей картины.
double
в int
и long
в int
или short
не являются примерами случая 1, а случая 2. Они могут потерять информацию, но никогда не выходят из строя. Примером преобразования, которое может привести к сбою, может быть преобразование объекта класса в подкласс.
@ sepp2k Мой первый абзац наоборот, и там можно без потерь конвертировать.
Потому что именно так работает Stack Overflow @Coder. Просто выберите тот, который вам больше всего помог.
@PatrickHofman Конечно, я говорил о втором абзаце. В книге перечислены две причины, по которым преобразование не может быть неявным: 1) оно может потерпеть неудачу или 2) оно может привести к потере информации. OP попросил привести примеры, в которых преобразование может завершиться неудачно (например, случай 1). Я говорю, что вы привели примеры случая 2 во втором абзаце, но вы не привели никаких примеров случая 1.
Или, другими словами: double
может всегда конвертируется в int
(нет ситуации, когда (int)myDouble
когда-либо вызовет исключение - в отличие, скажем, от (MySubclass)myObject
), он просто не всегда может быть преобразован без потери информации.
Примером того, когда компилятор не может гарантировать преобразование, может быть предположение о типах во время выполнения. Очень простой пример может быть это
public int Add(object a, object b)
{
return ((int)a) + ((int)b);
}
Здесь вы работаете с предположением, что вам будет передано int во время выполнения, по какой-либо причине вы потеряли безопасность типа и работаете с объектом. Компилятор не знает и не может знать этого во время компиляции, поэтому вам нужно явное приведение.
Это крайний пример, но, надеюсь, он немного проясняет его.
Пока что ответы сосредоточены на типах значений.
Для ссылочных типов существуют преобразования базового класса, производного класса и интерфейса.
class A { } // base class
class B : A { } // B is-an A
class C : A { } // C is-an A
B b = new B(); // instance of B
A a = b; // ok, conversion to base class can't fail because B is an A
C c = (C) a; // but conversion to derived could fail, a could be a B
double
вint
?