Я знаю, что уже есть несколько сообщений о различии между приведениями и оператором as
. Все они в основном повторяют те же факты:
- Оператор
as
не будет бросать, но возвращаетnull
, если сбрасывает - Следовательно, оператор
as
работает только с ссылочными типами - Оператор
as
не будет использовать пользовательские операторы преобразования
Ответы, как правило, бесконечно обсуждают, как использовать или не использовать ту или иную, а также плюсы и минусы каждого, даже их производительность (которая меня совсем не интересует).
Но здесь есть что-то еще. Рассмотрим:
static void MyGenericMethod<T>(T foo)
{
var myBar1 = foo as Bar; // compiles
var myBar2 = (Bar)foo; // does not compile ('Cannot cast expression of
// type 'T' to type 'Bar')
}
Пожалуйста, не обращайте внимания на то, является ли этот явно несостоятельный пример хорошей практикой или нет. Меня беспокоит очень интересное несоответствие между ними тем, что литье не будет компилироваться, тогда как as
. Я действительно хотел бы знать, может ли кто-нибудь пролить свет на это.
Как часто отмечается, оператор as
игнорирует пользовательские преобразования, но в приведенном выше примере он явно более эффективен для двух. Обратите внимание, что as
в отличие от компилятора не существует известного соединения между типом T и Bar (неизвестным во время компиляции). Бросок полностью "run-time". Должны ли мы подозревать, что литье разрешено, полностью или частично, во время компиляции и оператор as
не?
Кстати, добавление ограничения типа неудивительно исправляет литье, таким образом:
static void MyGenericMethod<T>(T foo) where T : Bar
{
var myBar1 = foo as Bar; // compiles
var myBar2 = (Bar)foo; // now also compiles
}
Почему оператор as
компилируется, а литой нет?