Должен ли я использовать (ObjectType) или «as ObjectType» при приведении в c #?

Возможный дубликат:
Приведение: (NewType) vs. Объект как NewType

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

MyObjectType senderAsMyType = (MyObjectType) sender;

Недавно я понял, что это тоже можно сделать так:

MyObjectType senderAsMyType = sender as MyObjectType;

Какой способ наиболее эффективен? Так что я могу сделать свой код последовательным и использовать один из способов повсюду. Или у них обоих есть свои плюсы и минусы? Если да, то не могли бы кто-нибудь проинформировать меня о них.

Еще раз спасибо,


person Lloyd Powell    schedule 28.07.2009    source источник
comment
Важным моментом, о котором никто не упомянул, является то, что приведение типов и as не делают одно и то же. Например, если у вас есть заданное пользователем явное преобразование из Foo в Bar, тогда (Bar) foo вызывает метод преобразования, а foo как Bar - нет. Убедитесь, что вы выбрали тот вариант, который действительно делает то, что вы хотите. Сделайте это правильно, затем проясните, и только потом подумайте о том, чтобы сделать это быстрее.   -  person Eric Lippert    schedule 28.07.2009


Ответы (9)


Если вы хотите избежать InvalidCastExceptions использования

MyObjectType senderAsMyType = sender as MyObjectType;

в противном случае используйте

MyObjectType senderAsMyType = (MyObjectType)sender;

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

Что касается производительности, я бы сказал, что вы не найдете заметной разницы между двумя разными видами литья. Мне было интересно, поэтому я использовал BenchmarkHelper Джона Скита и получил результаты, которые подтвердили мои подозрения:

Тест:

using System;
using BenchmarkHelper;

class Program
{
    static void Main()
    {
        Object input = "test";
        String output = "test";

        var results = TestSuite.Create("Casting", input, output)
            .Add(cast)
            .Add(asCast)
            .RunTests()
            .ScaleByBest(ScalingMode.VaryDuration);
        results.Display(ResultColumns.NameAndDuration | ResultColumns.Score,
                results.FindBest());
    }

    static String cast(Object o)
    {
        return (String)o;
    }

    static String asCast(Object o)
    {
        return o as String;
    }

}

Вывод:

============ Casting ============
cast   30.021 1.00
asCast 30.153 1.00
person Andrew Hare    schedule 28.07.2009

Думаю, этот ответ поможет ...

Приведение: (NewType) против объекта как NewType

person Simon Keep    schedule 28.07.2009
comment
Ааа, извини, я не смог найти ответ, когда искал. Спасибо - person Lloyd Powell; 28.07.2009

Основное отличие: если sender не является экземпляром MyObjectType или одного из его подклассов, первый пример (прямое приведение) вызывает исключение; второй (как оператор) возвращает null.

Ни один из них явно не лучше или хуже; вы должны использовать тот или иной вариант в зависимости от ситуации, с которой вы сталкиваетесь в данный момент. Если sender не MyObjectType, что вы хотите сделать? вероятно, в этом случае, поскольку это обработчик событий, выдача исключения совершенно нормально ...

person Paolo Tedesco    schedule 28.07.2009

Вы должны использовать (MyObjectType), когда это возможно, потому что вы сразу получите исключение, если приведение не удастся. С as вы можете получить исключение NullRef где-нибудь позже.
Используйте as только тогда, когда вы сразу обрабатываете неудачное приведение.

person tanascius    schedule 28.07.2009

Они делают немного разные вещи. Все зависит от того, чего вы хотите.

// Will throw an exception if the cast cannot be made
MyObjectType foo = (MyObjectType)bar; 

or

// Will return null if the cast cannot be made
MyObjectType foo = bar as MyObjectType;

Что вы используете, зависит от вас? Если вы ожидаете, что приведение будет часто терпеть неудачу (и вас это устраивает), выберите as и затем проверьте значение null, если вы ожидаете, что он никогда не откажет, выберите (type).

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

person Colin Mackay    schedule 28.07.2009

MyObjectType senderAsMyType = (MyObjectType) sender;

Это вызовет InvalidCastException, если отправитель не может быть переведен в MyObjectType.

MyObjectType senderAsMyType = sender as MyObjectType;

senderAsMyType будет null, если отправитель не может быть переведен на MyObject. Этот метод нельзя использовать с типами значений.

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

person Garry Shutler    schedule 28.07.2009
comment
Я думаю, что скорость очень субъективна и будет зависеть от ожидаемого процента отказов отливок. - person Simon P Stevens; 28.07.2009

Это зависит от ваших ожиданий от ваших объектов. Если объект должен быть этого типа, и вам необходимо получить доступ к членам этого объекта, используйте:

MyObjectType senderAsMyType = (MyObjectType) sender;

Как указывалось ранее, это вызывает исключение InvalidCastException, если оно недопустимо.

Если он может относиться к этому типу, и вы хотите предпринять действие только в том случае, если это так, используйте 'as' и проверьте наличие null

MyObjectType senderAsMyType = sender as MyObjectType;

if(senderAsMyType != null)
{
    senderAsMyType.MyMethod()
}

Однако, если вы проверяете только тип, но объект не нужен, используйте оператор 'is', так как это будет самым дешевым с точки зрения ресурсов.

if(sender is MyObjectType)
    //do something
person MattH    schedule 28.07.2009

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

Прямое приведение типа «(ObjectType)» может завершиться ошибкой и вызовет исключение InvalidCastException.

"as" не приведет к ошибке с исключением, но вместо этого вернет нулевой объект, если приведение не работает.

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

Если вы не уверены в типе объекта, может быть полезно использовать «as» и просто проверить наличие null.

person Simon P Stevens    schedule 28.07.2009

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

public void MyFunction(MyObject obj)
{
  obj.DoSomething();
  SpecializedObject specialized = obj as SpecializedObject;
  if(specialized!=null)
  {
    specialized.DoSthSpecial();
  }
}

И используйте обычное приведение, если вы уверены, что тип будет именно таким, как вы ожидаете, вам просто нужно выполнить приведение по техническим причинам:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
MyObject obj = (MyObject)xmlSerializer.Deserialize(xml);

так не только быстрее, но и не скрывает ошибок.

person Grzenio    schedule 28.07.2009