Прямое кастинг против "как" оператора?

Рассмотрим следующий код:

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
}

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

+645
25 сент. '08 в 10:09
источник поделиться
17 ответов
string s = (string)o; // 1

Выбрасывает InvalidCastException, если o не является string. В противном случае присваивается o <<24 > , даже если 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 не является литой и является просто вызовом метода. Используйте его, когда вам нужно строковое представление нестрокового объекта.

+770
25 сент. '08 в 10:16
источник

Связанные вопросы


Похожие вопросы

  1. string s = (string)o; Используйте, когда что-то определенно должно быть другим.
  2. string s = o as string; Используйте, когда что-то может быть другим.
  3. string s = o.ToString(); Используйте, когда вам все равно, что это такое, но вы просто хотите использовать доступное строковое представление.
+321
25 сент. '08 в 10:31
источник

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

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

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

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

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

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

+26
25 сент. '08 в 10:16
источник

Если вы уже знаете, к какому типу он может быть применен, используйте 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(), чтобы получить удобочитаемое строковое представление любого объекта, даже если оно не может быть передано в строку.

+9
25 сент. '08 в 10:41
источник

Ключевое слово 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;
}

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

+7
25 сент. '08 в 11:17
источник

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

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

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

string s = o as string;

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

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

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

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

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

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

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

+6
25 сент. '08 в 10:15
источник

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

Предположим, что a является Animal:

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

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

получит a с минимальным количеством бросков.

+5
25 сент. '08 в 10:31
источник

В соответствии с экспериментами, запущенными на этой странице: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

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

Вывод: оператор "как" обычно быстрее, чем приведение. Иногда во много раз быстрее, иногда просто быстрее.

Я воспринимаю нечто более "понятное".

Итак, поскольку он работает быстрее и "безопаснее" (wont throw exception), и, возможно, его легче читать, я рекомендую использовать "как" все время.

+4
15 авг. '10 в 18:36
источник

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

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

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

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

+4
25 сент. '08 в 10:17
источник
string s = o as string; // 2

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

+3
25 сент. '08 в 11:05
источник

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

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

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

((string)o).ToLower();

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

(o as string).ToLower();

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

+3
03 апр. '14 в 14:28
источник

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

Прямое литье

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

  • Пользовательское неявное/явное кастинг: Обычно создается новый объект.
  • Тип значения Неявный: Копирование без потери информации.
  • Тип значения Явный: Копирование и информация могут быть потеряны.
  • Отношение 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
    }
+3
25 сент. '16 в 4:47
источник

Я хотел бы обратить внимание на следующие особенности оператора as:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as

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

+1
17 окт. '18 в 12:11
источник

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

String s = String.Concat(o);
0
23 июн. '12 в 1:31
источник

Так как никто не упомянул об этом, ближайший к instanceOf к Java по ключевым словам:

obj.GetType().IsInstanceOfType(otherObj)
0
13 окт. '15 в 20:21
источник

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

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

В С# 7.0 появилась новая крутая функция для упрощения приведения и проверки Соответствие шаблону:

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;
 }
0
03 авг. '17 в 7:34
источник

В С# поддерживаются следующие две формы преобразования типов (литье):

|

(Резюме

• Преобразование статического типа v в c в данном выражении

• возможно только в том случае, если динамический тип v является c или подтипом c

• Если нет, исключается InvalidCastException

|

v как C

• Нефатальный вариант (c) v

• Таким образом, преобразуйте статический тип v в c в данном выражении

• Возвращает значение null, если динамический тип v не является c, или подтип c

0
27 мая '18 в 13:17
источник

Посмотрите другие вопросы по меткам или Задайте вопрос