Приведение: (NewType) vs. Object как NewType

В чем собственно разница между этими двумя слепками?

SomeClass sc = (SomeClass)SomeObject;
SomeClass sc2 = SomeObject as SomeClass;

Обычно, разве они оба не должны быть явным приведением к указанному типу?

Ответов (12)

Решение

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

[Редактировать]

Мой первоначальный ответ, безусловно, является наиболее заметным различием, но, как указывает Эрик Липперт , это не единственное различие . Другие отличия включают:

  • Вы не можете использовать оператор as для приведения к типу, который не принимает значение null в качестве значения.
  • Вы не можете использовать as для преобразования таких вещей, как числа, в другое представление (например, float в int).

И, наконец, используя «as» вместо оператора приведения, вы также говорите: «Я не уверен, что это удастся».

Чтобы расширить комментарий Ритмиса , вы не можете использовать ключевое слово as для структур (типов значений), поскольку они не имеют нулевого значения.

Приведение в скобках вызывает исключение, если попытка приведения не удалась. Приведение "as" возвращает null, если попытка приведения не удалась.

Также обратите внимание, что вы можете использовать ключевое слово as только со ссылочным типом или типом, допускающим значение NULL.

то есть:

double d = 5.34;
int i = d as int;

не будет компилироваться

double d = 5.34;
int i = (int)d;

будет компилировать.

Они выбрасывают разные исключения.

(): Исключение NullReferenceException
как: InvalidCastException

Что может помочь при отладке.

Ключевое слово as пытается преобразовать объект, и если преобразование завершается неудачно, возвращается null. Оператор приведения () немедленно вызовет исключение в случае сбоя приведения.

Используйте ключевое слово C# as только в том случае, если вы ожидаете, что приведение типов завершится неудачно в неисключительном случае. Если вы рассчитываете на успешное приведение типов и не готовы к получению какого-либо объекта, который завершится ошибкой, вам следует использовать оператор приведения (), чтобы возникло соответствующее и полезное исключение.

Примеры кода и дополнительные пояснения: http://blog.nerdbank.net/2008/06/when-not-to-use-c-keyword.html

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

DateTime i = (DateTime)value;
// is like doing
DateTime i = value is DateTime ? value as DateTime : throw new Exception(...);

и следующий должен легко догадаться, что он делает

DateTime i = value as DateTime;

в первом случае, если значение не может быть приведено, возникает исключение, во втором случае, если значение не может быть приведено, i устанавливается в значение null.

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

Это похоже на разницу между Parse и TryParse. Вы используете TryParse, когда ожидаете, что он может потерпеть неудачу, но если у вас есть надежная уверенность, что он не подведет, вы используете Parse.

Приведение типов с использованием «as», конечно, намного быстрее, когда приведение не выполняется, так как это позволяет избежать затрат на создание исключения.

Но когда бросок успешен, это не быстрее. График на http://www.codeproject.com/KB/cs/csharpcasts.aspx вводит в заблуждение, потому что не объясняет, что он измеряет.

Итог:

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

  • Если вы не знаете, удастся ли это, используйте оператор «as» и проверьте результат на нуль.

Для тех из вас, у кого есть опыт работы с VB.NET, (тип) такой же, как DirectCast, а «as type» - это то же самое, что и TryCast.

Все это относится к ссылочным типам, типы значений не могут использовать as ключевое слово, поскольку они не могут быть нулевыми.

//if I know that SomeObject is an instance of SomeClass
SomeClass sc = (SomeClass) someObject;


//if SomeObject *might* be SomeClass
SomeClass sc2 = someObject as SomeClass;

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

Лучше всего использовать, as если вы не знаете тип:

//we need to know what someObject is
SomeClass sc;
SomeOtherClass soc;

//use as to find the right type
if( ( sc = someObject as SomeClass ) != null ) 
{
    //do something with sc
}
else if ( ( soc = someObject as SomeOtherClass ) != null ) 
{
    //do something with soc
}

Однако, если вы абсолютно уверены, что someObject это экземпляр, SomeClass используйте cast.

В .Net 2 или выше универсальные шаблоны означают, что вам очень редко нужно иметь нетипизированный экземпляр ссылочного класса, поэтому последний используется реже.

Разница между этими двумя подходами заключается в том, что первый объект ((SomeClass) obj) может вызвать вызов преобразователя типов .

Что ж, оператор 'as' «помогает» вам похоронить вашу проблему на более низком уровне, потому что, когда ему предоставляется несовместимый экземпляр, он вернет null, возможно, вы передадите это методу, который передаст его другому, и так далее, и, наконец, вы я получу исключение NullReferenceException, которое затруднит отладку.

Не злоупотребляйте этим. Оператор прямого приведения лучше в 99% случаев.