Кастинг с «как» - почему это не работает? - PullRequest
1 голос
/ 22 марта 2011

Может быть, слишком рано утром, и я идиот, но меня это немного смущает ...

SqlCommand cmd = new SqlCommand("prc_FooBar", conn));
object obj = cmd.ExecuteScalar();

 // this is fine
decimal? d = (decimal?)(obj as double?);

// this doesn't compile
decimal? d = (obj as double?) as decimal?; 

Почему последняя версия не компилируется?

Ответы [ 3 ]

6 голосов
/ 22 марта 2011

Оператор as отличается от оператора приведения. Этот блог объясняет:

http://blogs.msdn.com/b/csharpfaq/archive/2004/03/12/what-s-the-difference-between-cast-syntax-and-using-the-code-as-code-operator.aspx

Он только «забрасывает» между типами в одной иерархии, в основном следуя идее «есть». decimal? - это не double?, но компилятор может заставить вас думать, что это возможно, когда вы (decimal?)myDouble;, потому что он явно использует его для потери информации. Оператор as не делает этого за вас и, следовательно, завершается ошибкой.

Обновление: вы спрашиваете, почему произошла ошибка компилятора, а не нулевой результат. Это связано с тем, что оператор as никогда не сможет получить double? до decimal?. Попробуйте:

string s = "";
MyClass f = s as MyClass;

Из коробки это не работает, потому что компилятор это знает. Лучше получить ошибку компилятора, потому что он никогда не сможет работать в своем текущем состоянии.

При обычном использовании оператор as может использоваться для перенаправления базовых типов приведения в производные типы, если тип на самом деле является тем типом, о котором вы думаете. Однако тип может быть другим производным типом (компилируется):

MyBase b = new MyDerived1();
MyDerived2 d = b as MyDerived2();

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

Я уверен, что кто-то собирается прийти и сказать мне, как я неправ: -)

3 голосов
/ 22 марта 2011

Из документов :

... оператор as выполняет только эталонные преобразования и преобразования в боксы.

Преобразование из double? в decimal? не подходит ни к одной из этих категорий, так как бокс не идет, а double? не является подтипом или супертипом decimal?.

1 голос
/ 22 марта 2011

var x = v as X эквивалентно:

var v = v is X ? (X)v : null;, но происходит только одна операция проверки типа ((X)v самостоятельно проверяет, является ли v или может быть приведено к X и в противном случае выдает исключение).

Ваш последний случай эквивалентен:

double? tmp = obj is double? ? (double?)obj : null;
decimal? d = tmp is decimal? ? (decimal?)tmp : null;

Во время компиляции известно, что tmp является double? (либо со значением, либо без значения, делающим его эквивалентным null). Поэтому проверка tmp is decimal? всегда ложна, и операция завершается неудачно во время компиляции.

...