2008-09-25 1 views
545

Рассмотрим следующий код:Прямое кастинг против «как» оператора?

void Handler(object o, EventArgs e) 
{ 
    // I swear o is a string 
    string s = (string)o; // 1 
    //-OR- 
    string s = o as string; // 2 
    // -OR- 
    string s = o.ToString(); // 3 
} 

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

+1

Не совсем дубликат, но есть также некоторые дискуссии о производительности в [предыдущий вопрос] (HTTP: // stackoverflow.com/questions/2483/casting-newtype-vs-object-as-newtype). – Unsliced 2008-09-25 10:23:31

+4

4th: `string s = Convert.ToString (o)`; 5th: `string s = $" {o} "` (или эквивалентно форма `string.Format` для более раннего C#) – 2016-02-07 21:48:56

ответ

639
string s = (string)o; // 1 

Броски InvalidCastException если o не string. В противном случае присваивает os, даже если o - null.

string s = o as string; // 2 

Назначает null к s если o не string или если o является null. По этой причине вы не можете использовать его со значениями типов (оператор в таком случае никогда не сможет вернуть null). В противном случае присваивается o - s.

string s = o.ToString(); // 3 

Вызывает NullReferenceException если o является null. Назначает любые o.ToString() возвращается к s, независимо от того, какой тип o есть.


Используйте 1 для большинства конверсий - это просто и понятно. Я почти никогда не использую 2, поскольку, если что-то не соответствует типу, я обычно ожидаю, что произойдет исключение. Я только видел необходимость в этом возврате-нулевом типе функций с плохо разработанными библиотеками, использующими коды ошибок (например, return null = error, вместо использования исключений).

3 не является литой и является всего лишь методом вызова. Используйте его, когда вам нужно строковое представление нестрокового объекта.

+2

Вы можете назначить «null» значениям типов, если они явно определены, например: int? я; строка s = "5"; i = s как int; // i теперь 5 s = null; i = s как int; // i теперь null – Anheledir 2008-09-25 10:41:25

+3

RE: Anheledir На самом деле я был бы пустым после первого вызова. Вы должны использовать явную функцию преобразования, чтобы получить значение строки. – Guvante 2008-09-25 10:47:18

+37

RE: Sander На самом деле есть еще одна очень веская причина для использования, поскольку он упрощает ваш проверочный код (проверяйте значение null, а затем проверяйте нулевой и правильный тип). Это полезно, поскольку много времени вы предпочитаете бросать обычное одно исключение , Но это правда, что слепые, как звонки, плохи. – Guvante 2008-09-25 10:48:50

6

«as» основан на «is», который является ключевым словом, который проверяет во время выполнения, если объект является полиморфно совместимым (в основном, если выполняется бросок) и возвращает null, если проверка завершилась с ошибкой.

Эти два эквивалентны:

Использование 'как':

string s = o as string; 

Использование 'является':

if(o is string) 
    s = o; 
else 
    s = null; 

Наоборот, бросок с стиле выполнен также в runtime, но генерирует исключение, если бросок не может быть выполнен.

Просто добавить важный факт:

«как» ключевое слово работает только со ссылочными типами. Вы не можете:

// I swear i is an int 
int number = i as int; 

В этих случаях вы должны использовать литье.

+0

'is' работает на любом типе – leppie 2008-09-25 10:18:28

+0

Спасибо, что указали мою ошибку, вы правы. Я отредактировал ответ. ой, извини. – 2008-09-25 10:22:03

26

Это действительно зависит от того, знаете ли вы, что o - это строка и то, что вы хотите с ней сделать.Если ваш комментарий означает, что o действительно действительно представляет собой строку, я бы предпочел прямолинейный (string)o - он вряд ли потерпит неудачу.

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

С оператором as, если o не является строкой, s устанавливается в null, что очень удобно, если вы не уверены и хотите проверить s:

string s = o as string; 
if (s == null) 
{ 
    // well that's not good! 
    gotoPlanB(); 
} 

Однако, если вы не» т выполнить этот тест, вы будете использовать s позже и получите бросок NullReferenceException. Они, как правило, более распространены, и лот сложнее отследить, как только они происходят в дикой природе, так как почти каждая строка разыгрывает переменную и может ее выбросить. С другой стороны, если вы пытаетесь применить к типу значения (любой примитив или структуры, такие как DateTime), вы должны использовать прямой литой - as не будет работать.

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

4

"(string) o" приведет к InvalidCastException, поскольку нет прямого трансляции.

«o as string» приведет к тому, что s является нулевой ссылкой, а не генерируется исключение.

«o.ToString()» не является листингом какого-либо рода per se, это метод, реализованный объектом и, таким образом, так или иначе, каждым классом в .net, который «что-то делает», с экземпляром класса, на который он вызван, и возвращает строку.

Не забывайте, что для преобразования в строку существует также Convert.ToString (someType instanceOfThatType), где someType является одним из множества типов, по существу базовых типов фреймворков.

260
  1. Используется, когда что-то должно определенно быть другая вещь.
  2. использование когда чтото бывает прочее предмет.
  3. Используйте, когда вам все равно, что это только вы просто хотите использовать доступное представление строки.
5

2 полезен для литья производного типа.

Пусть животное:

b = a as Badger; 
c = a as Cow; 

if (b != null) 
    b.EatSnails(); 
else if (c != null) 
    c.EatGrass(); 

получит в подается с минимальным слепков.

8

Если вы уже знаете, какой тип он может использовать, чтобы использовать бросок C-стиль:

var o = (string) iKnowThisIsAString; 

Обратите внимание, что только с C-стиле гипсе Вы можете выполнить явное типа принуждением.

Если вы не знаете, является ли это желаемый тип и вы собираетесь использовать его, если он используется в качестве ключевое слово:

var s = o as string; 
if (s != null) return s.Replace("_","-"); 

//or for early return: 
if (s==null) return; 

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

Используйте ToString(), чтобы получить удобочитаемое строковое представление любого объекта, даже если оно не может быть передано в строку.

3
string s = o as string; // 2 

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

7

Ключевое слово as является хорошим в asp.net при использовании метода FindControl.

Hyperlink link = this.FindControl("linkid") as Hyperlink; 
if (link != null) 
{ 
    ... 
} 

Это означает, что вы можете работать на набранный переменную, а затем того, чтобы затем бросить его из object, как вы бы с прямым броском:

object linkObj = this.FindControl("linkid"); 
if (link != null) 
{ 
    Hyperlink link = (Hyperlink)linkObj; 
} 

Это не огромная вещь, но она сохраняет линии кода и присваивания значения переменной, плюс это более читаемым

3

Согласно экспериментам выполняются на этой странице: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

(т на его странице иногда появляются ошибки «незаконного реферера», поэтому просто обновляйте, если это так)

Заключение: оператор «как», как правило, быстрее, чем приведение. Иногда во много раз быстрее, иногда просто быстрее.

I peronsonally вещь «как» также более читаема.

Так как он работает быстрее и «безопаснее» (обычно исключает исключение), и, возможно, его легче читать, я рекомендую использовать «как» все время.

0

При попытке получить строковое представление чего-либо (любого типа), которое потенциально может быть нулевым, я предпочитаю следующую строку кода. Он компактный, он вызывает ToString(), и он корректно обрабатывает нули. Если o равно null, s будет содержать String.Empty.

String s = String.Concat(o); 
3

Все данные ответы хороши, если я мог бы добавить что-то: Чтобы непосредственно использовать методы и свойства струны (например,ToLower) вы не можете писать:

(string)o.ToLower(); // won't compile 

вы можете только написать:

((string)o).ToLower(); 

, но вы можете написать вместо этого:

(o as string).ToLower(); 

Опция as является более удобным для чтения (по крайней мере, мое мнение).

0

Поскольку никто не упомянул об этом, ближе всего к InstanceOf на Java с помощью ключевого слова это:

obj.GetType().IsInstanceOfType(otherObj) 
2

Кажется, два из них концептуально отличаются.

Прямая Casting

типы не должны быть строго связаны. Он поставляется во всех видах ароматов.

  • Пользовательские неявное/явное приведение: Обычно создается новый объект.
  • Тип значения Неявный: Копирование без потери информации.
  • Тип значения Явный: Копирование и информация могут быть утеряны.
  • Отношение IS-A: Измените ссылочный тип, в противном случае вы получите исключение.
  • Тот же тип: «Кастинг избыточен».

Похоже, что объект будет преобразован во что-то другое.

AS оператор

Типы имеют прямое отношение. Как и в:

  • Ссылочные типы: IS-A отношения Объекты всегда одинаковы, только ссылки на изменения.
  • Типы значений: Копия Тип бокса и типа с нулевым значением.

Похоже, что вы собираетесь обрабатывать объект по-другому.

Образцы и IL

class TypeA 
    { 
     public int value; 
    } 

    class TypeB 
    { 
     public int number; 

     public static explicit operator TypeB(TypeA v) 
     { 
      return new TypeB() { number = v.value }; 
     } 
    } 

    class TypeC : TypeB { } 
    interface IFoo { } 
    class TypeD : TypeA, IFoo { } 

    void Run() 
    { 
     TypeA customTypeA = new TypeD() { value = 10 }; 
     long longValue = long.MaxValue; 
     int intValue = int.MaxValue; 

     // Casting 
     TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL: call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA) 
     IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass ConsoleApp1.Program/IFoo 

     int loseValue = (int)longValue; // explicit -- IL: conv.i4 
     long dontLose = intValue; // implict -- IL: conv.i8 

     // AS 
     int? wraps = intValue as int?; // nullable wrapper -- IL: call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0) 
     object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32 
     TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD 
     IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo 

     //TypeC d = customTypeA as TypeC; // wouldn't compile 
    } 
0

Использование прямого литья string s = (string) o; если в логическом контексте вашего приложения string является единственным допустимым типом. При таком подходе вы получите InvalidCastException и реализуете принцип Fail-fast. Ваша логика будет защищена от дальнейшей передачи недопустимого типа или получения исключения NullReferenceException при использовании оператора as.

Если логика ожидает несколько разных типов, наберите string s = o as string; и проверьте ее на null или используйте оператор is.

Новая интересная особенность появились в C# 7.0, чтобы упростить бросание и чек является Pattern matching:

if(o is string s) 
{ 
    // Use string variable s 
} 

or 

switch (o) 
{ 
    case int i: 
    // Use int variable i 
    break; 
    case string s: 
    // Use string variable s 
    break; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^