С# "как" литой против классического литья

Возможный дубликат:
Кастинг против использования ключевого слова 'as в CLR

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

SomeClass someObject = (SomeClass) obj;

можно использовать этот синтаксис:

SomeClass someObject = obj as SomeClass;

который, кажется, возвращает null, если obj не является SomeClass, а не бросает исключение класса.

Я вижу, что это может привести к исключению NullReferenceException, если сбой броска и я пытаюсь получить доступ к переменной someObject. Поэтому мне интересно, какое обоснование этого метода? Зачем использовать этот способ кастинга, а не (старый) - кажется, что он только что переместил проблему неудачного нажатия "глубже" в код.

Ответ 1

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

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

Примечание:

Метод as может использоваться только для типов, которым может быть присвоено значение null. Это использование только для ссылочных типов, но когда .NET 2.0 вышел, в нем была введена концепция типа значения NULL. Поскольку этим типам может быть присвоено значение null, они действительны для использования с оператором as.

Ответ 2

Нулевое сравнение MUCH быстрее, чем бросание и исключение. Исключения имеют значительные накладные расходы - трассировка стека должна быть собрана и т.д.

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

Ответ 3

В некоторых случаях легко справиться с null, чем исключение. В частности, оператор коалесцирования удобен:

SomeClass someObject = (obj as SomeClass) ?? new SomeClass();

Он также упрощает код, в котором вы находитесь (не использующий полиморфизм и) ветвление на основе типа объекта:

ClassA a;
ClassB b;
if ((a = obj as ClassA) != null)
{
    // use a
}
else if ((b = obj as ClassB) != null)
{
    // use b
}

Как указано на странице

Ответ 4

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

  • Когда вам нужно только знать, что объект имеет определенный тип, но не нужно специально действовать на членов этого типа.
  • Если вы хотите избежать исключений и вместо этого явно имеете дело с null
  • Вы хотите знать, есть ли CLR-преобразование между объектами, а не только какое-то определенное пользователем преобразование.

Третий пункт является тонким, но важным. Не существует сопоставления 1-1 между тем, какие отливки будут успешными с оператором литья и тем, что будет успешным с оператором as. Оператор as строго ограничивается конверсиями CLR и не будет учитывать пользовательские преобразования (оператор трансляции будет).

В частности оператор as допускает только следующее (из раздела 7.9.11 спецификации С# lang)

  • Точность (§6.1.1), неявная ссылка (§6.1.6), бокс (§6.1.7), явная ссылка (§6.2.4) или разблокировка (§6.2.5), существует из тип E в T.
  • Тип E или T - открытый тип.
  • E - нулевой литерал.

Ответ 5

Ключевое слово as полезно, если вы действительно не знаете, какой тип переменной может быть. Если у вас есть одна функция, которая будет следовать различным путям кода в зависимости от фактического типа параметра, у вас есть два варианта:

Во-первых, используя обычный литье:

if(myObj is string)
{
    string value = (string)myObj;

    ... do something
}
else if(myObj is MyClass)
{
    MyClass = (MyClass)myObj;
}

Для этого требуется, чтобы вы проверяли тип объекта с помощью is, чтобы вы не пытались применить его к чему-то, что не получится. Это также немного избыточно, поскольку проверка is -type выполняется снова в броске (так что при необходимости может генерировать исключение).

Альтернативой является использование as.

string myString = myObj as string;
MyClass myClass = myObj as MyClass;

if(myString != null)
{

}
else if(myClass != null)
{

}

Это делает код несколько короче, а также исключает проверку избыточного типа.

Ответ 6

используя как будет возвращать значение null, если не действительное действие, которое позволяет вам делать другие вещи, кроме того, чтобы обернуть листинг в try/catch. Я ненавижу классический актерский состав. Я всегда использую роль, если я не уверен. Плюс, исключения дороги. Нулевые проверки не являются.

Ответ 7

Я думаю, что лучшим "правилом" было бы использовать ключевое слово "как", когда он ожидал, что ваш объект не будет объектом, на который вы производите:

var x = GiveMeSomething();

var subject = x as String;

if(subject != null)
{
  // do what you want with a string
}
else
{
  // do what you want with NOT a string
}

Однако, когда ваш объект ДОЛЖЕН быть того типа, который вы используете, используйте "классический отбор", как вы его называете. Потому что, если это не тот тип, который вы ожидаете, вы получите исключение, которое соответствует исключительной ситуации.

Ответ 8

Здесь нет ничего глубокого. В принципе, удобно тестировать что-то, чтобы увидеть, имеет ли он определенный тип (т.е. использовать "как" ). Вы хотите проверить результат вызова "как", чтобы увидеть, является ли результат нулевым.

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

Ответ 9

Вы используете оператор "как", чтобы избежать возможности исключения, например. вы можете с легкостью справиться с отказом литья по логике. Используйте только актеры, если вы уверены, что объект имеет нужный тип. Я почти всегда использую "как", а затем проверяю значение null.

Ответ 10

Я полагаю, что полезно, если результат трансляции будет передан методу, который, как вы знаете, будет обрабатывать нулевые ссылки без металирования и ArgumentNullException или тому подобное.

Я очень мало использую для as, так как:

obj as T

медленнее, чем:

if (obj is T)
    ...(T)obj...

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