это vs typeof

Какой из этих фрагментов кода быстрее?

if (obj is ClassA) {}

if (obj.GetType() == typeof(ClassA)) {}

Изменить: я знаю, что они не делают то же самое.


person ilitirit    schedule 08.10.2008    source источник
comment
Ответил на аналогичный вопрос здесь: stackoverflow.com/questions/57701/   -  person swilliams    schedule 09.10.2008


Ответы (4)


Это должно ответить на то, что вопрос, а потом еще несколько.

Вторая строка, if (obj.GetType() == typeof(ClassA)) {}, быстрее для тех, кто не хочет читать статью.

(Имейте в виду, что они не делают то же самое)

person MagicKat    schedule 08.10.2008
comment
+1: Раньше я задавался вопросом, почему компилятор C # не компилирует typeof(string).TypeHandle в ldtoken инструкцию CIL, но похоже, что CLR позаботится об этом в JIT. По-прежнему требуется несколько дополнительных кодов операций, но это более обобщенное применение оптимизации. - person Sam Harwell; 22.02.2010
comment
Прочтите upperlogics.blogspot.ca/2013/09 / тоже - они повторно тестируют для разных фреймворков и x86 против x64 с очень разными результатами. - person CAD bloke; 29.07.2014
comment
Обратите внимание, это верно только для ссылочных типов. Да и разница в скорости не такая уж и значительная. Учитывая штраф за упаковку в случае типов значений для GetType, is всегда является более безопасным выбором с точки зрения производительности. Конечно, они делают разные вещи. - person nawfal; 04.08.2014
comment
Если вы поместите это в Resharper, предложите изменить его на is! - person Rob Sedgwick; 13.01.2015
comment
@nawfal, я изначально думал, что ваша точка зрения о штрафных санкциях имеет смысл для типов структур, но, учитывая, что мы тестируем переменную object obj;, разве она уже не упакована, когда это, как правило, проверяется? Есть ли случай, когда вам нужно проверить тип чего-то, а он еще не упакован как объект? - person Rob Parker; 02.11.2016
comment
@RobSedgwick, мне интересно, изменилась ли ситуация с .NET 2.0, когда специально оптимизированный GetType() == typeof подход был самым быстрым (наименее расточительным) и FxCop предупреждал не использовать is (as лучше, но невозможно для типов структур; FxCop может не предупредили для is с типом структуры). Возможно, is более оптимизирован в .NET 4.x, чем раньше в .NET 2.0? - person Rob Parker; 02.11.2016
comment
@RobParker, если тип значения уже упакован как переменная object, тогда вы правы, вызов GetType не имеет значения. Но я не уверен, что это так в данной ссылке. - person nawfal; 03.11.2016
comment
@nawfal, какой еще объявленный тип может быть рассматриваемой переменной, которая может содержать тип структуры? Может ли структура наследовать или реализовать интерфейс (я думаю, что нет, но, возможно, последнее разрешено)? - person Rob Parker; 22.11.2016
comment
@RobParker Structs может реализовывать интерфейсы, но если вы объявите их как их тип интерфейса, то да, они будут помещены в коробку. Например, IInterfaceForMyStruct myStruct = new MyStruct(); ведет к переменной в рамке. Конечно, все структуры и перечисления наследуются от общего базового класса ValueType (который, в свою очередь, наследуется от object, что приводит к унифицированной системе типов), но определяемые пользователем типы значений не могут наследовать что-либо, только реализуют . - person nawfal; 22.11.2016
comment
@nawfal, хорошо, хорошее разъяснение. Но как же тогда у вас могла быть эта проблема, если у вас еще не было переменной в штучной упаковке? Если бы это был объявленный конкретный тип значения, не было бы необходимости проверять его тип (особенно при невозможности наследования). Можете ли вы объявить переменную ValueType, которая может содержать любой тип значения, и не нужно ли ее уже помещать в коробку? Я думаю, что поддержка полиморфизма потребует, чтобы он был помещен в коробку и в этом случае. - person Rob Parker; 28.11.2016
comment
@RobParker, ты прав. Если вы объявляете свой тип значения как ValueType, переменная должна быть помещена в рамку. Если переменная объявлена ​​как конкретный тип значения, вы всегда можете полагаться на mystruct is MyStruct, а не на mystruct.GetType(), что вызовет бокс. Возможно, полезно в общем контексте. - person nawfal; 28.11.2016
comment
Ссылка ведет в какое-то меню. - person Necronomicron; 25.02.2020
comment
Мертвая ссылка. У кого-нибудь есть хотя бы ссылка на статью? - person paradise; 27.03.2020

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

is сообщает вам, реализует ли объект ClassA где-нибудь в своей иерархии типов. GetType() расскажет вам о наиболее производном типе.

Не то же самое.

person Jay Bazuzi    schedule 08.10.2008
comment
Это имеет значение, потому что в моем случае я уверен, что они возвращают тот же результат. - person ilitirit; 09.10.2008
comment
@ [ilitirit]: они возвращают тот же результат прямо сейчас, но если вы добавите подкласс позже, они не будут - person Steven A. Lowe; 09.10.2008
comment
Оптимизация сейчас сделает ваш код хрупким и трудным в обслуживании. - person ICR; 09.10.2008

Они не делают то же самое. Первый работает, если obj имеет тип ClassA или некоторый подкласс ClassA. Второй будет соответствовать только объектам типа ClassA. Второй будет быстрее, так как ему не нужно проверять иерархию классов.

Для тех, кто хочет знать причину, но не хочет читать статью, указанную в is vs typeof.

person tvanfosson    schedule 08.10.2008
comment
@amitjha Меня немного беспокоит, что, поскольку этот тест был запущен под Mono, он не включает оптимизацию JIT, упомянутую в статье. Поскольку в статье показано обратное, на мой взгляд, вопрос открытый. В любом случае сравнение производительности операций, выполняющих разные действия в зависимости от типа, кажется бесполезным занятием. Используйте операцию, которая соответствует нужному вам поведению, а не более быструю. - person tvanfosson; 04.04.2016

Я провел несколько тестов, где они делают то же самое - закрытые типы.

var c1 = "";
var c2 = typeof(string);
object oc1 = c1;
object oc2 = c2;

var s1 = 0;
var s2 = '.';
object os1 = s1;
object os2 = s2;

bool b = false;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
    b = c1.GetType() == typeof(string); // ~60ms
    b = c1 is string; // ~60ms

    b = c2.GetType() == typeof(string); // ~60ms
    b = c2 is string; // ~50ms

    b = oc1.GetType() == typeof(string); // ~60ms
    b = oc1 is string; // ~68ms

    b = oc2.GetType() == typeof(string); // ~60ms
    b = oc2 is string; // ~64ms


    b = s1.GetType() == typeof(int); // ~130ms
    b = s1 is int; // ~50ms

    b = s2.GetType() == typeof(int); // ~140ms
    b = s2 is int; // ~50ms

    b = os1.GetType() == typeof(int); // ~60ms
    b = os1 is int; // ~74ms

    b = os2.GetType() == typeof(int); // ~60ms
    b = os2 is int; // ~68ms


    b = GetType1<string, string>(c1); // ~178ms
    b = GetType2<string, string>(c1); // ~94ms
    b = Is<string, string>(c1); // ~70ms

    b = GetType1<string, Type>(c2); // ~178ms
    b = GetType2<string, Type>(c2); // ~96ms
    b = Is<string, Type>(c2); // ~65ms

    b = GetType1<string, object>(oc1); // ~190ms
    b = Is<string, object>(oc1); // ~69ms

    b = GetType1<string, object>(oc2); // ~180ms
    b = Is<string, object>(oc2); // ~64ms


    b = GetType1<int, int>(s1); // ~230ms
    b = GetType2<int, int>(s1); // ~75ms
    b = Is<int, int>(s1); // ~136ms

    b = GetType1<int, char>(s2); // ~238ms
    b = GetType2<int, char>(s2); // ~69ms
    b = Is<int, char>(s2); // ~142ms

    b = GetType1<int, object>(os1); // ~178ms
    b = Is<int, object>(os1); // ~69ms

    b = GetType1<int, object>(os2); // ~178ms
    b = Is<int, object>(os2); // ~69ms
}

sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());

Универсальные функции для проверки универсальных типов:

static bool GetType1<S, T>(T t)
{
    return t.GetType() == typeof(S);
}
static bool GetType2<S, T>(T t)
{
    return typeof(T) == typeof(S);
}
static bool Is<S, T>(T t)
{
    return t is S;
}

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

var c1 = new Class1();
var c2 = new Class2();
object oc1 = c1;
object oc2 = c2;

var s1 = new Struct1();
var s2 = new Struct2();
object os1 = s1;
object os2 = s2;

bool b = false;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
    b = c1.GetType() == typeof(Class1); // ~60ms
    b = c1 is Class1; // ~60ms

    b = c2.GetType() == typeof(Class1); // ~60ms
    b = c2 is Class1; // ~55ms

    b = oc1.GetType() == typeof(Class1); // ~60ms
    b = oc1 is Class1; // ~68ms

    b = oc2.GetType() == typeof(Class1); // ~60ms
    b = oc2 is Class1; // ~68ms


    b = s1.GetType() == typeof(Struct1); // ~150ms
    b = s1 is Struct1; // ~50ms

    b = s2.GetType() == typeof(Struct1); // ~150ms
    b = s2 is Struct1; // ~50ms

    b = os1.GetType() == typeof(Struct1); // ~60ms
    b = os1 is Struct1; // ~64ms

    b = os2.GetType() == typeof(Struct1); // ~60ms
    b = os2 is Struct1; // ~64ms


    b = GetType1<Class1, Class1>(c1); // ~178ms
    b = GetType2<Class1, Class1>(c1); // ~98ms
    b = Is<Class1, Class1>(c1); // ~78ms

    b = GetType1<Class1, Class2>(c2); // ~178ms
    b = GetType2<Class1, Class2>(c2); // ~96ms
    b = Is<Class1, Class2>(c2); // ~69ms

    b = GetType1<Class1, object>(oc1); // ~178ms
    b = Is<Class1, object>(oc1); // ~69ms

    b = GetType1<Class1, object>(oc2); // ~178ms
    b = Is<Class1, object>(oc2); // ~69ms


    b = GetType1<Struct1, Struct1>(s1); // ~272ms
    b = GetType2<Struct1, Struct1>(s1); // ~140ms
    b = Is<Struct1, Struct1>(s1); // ~163ms

    b = GetType1<Struct1, Struct2>(s2); // ~272ms
    b = GetType2<Struct1, Struct2>(s2); // ~140ms
    b = Is<Struct1, Struct2>(s2); // ~163ms

    b = GetType1<Struct1, object>(os1); // ~178ms
    b = Is<Struct1, object>(os1); // ~64ms

    b = GetType1<Struct1, object>(os2); // ~178ms
    b = Is<Struct1, object>(os2); // ~64ms
}

sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());

И виды:

sealed class Class1 { }
sealed class Class2 { }
struct Struct1 { }
struct Struct2 { }

Вывод:

  1. Вызов GetType на structs выполняется медленнее. GetType определен в object классе, который не может быть переопределен в подтипах, и поэтому structs необходимо поместить в коробку для вызова GetType.

  2. В экземпляре объекта GetType быстрее, но очень незначительно.

  3. Для общего типа, если T равно class, is выполняется намного быстрее. Если T равно struct, то is намного быстрее, чем GetType, но typeof(T) намного быстрее, чем оба. В случаях, когда T является class, typeof(T) ненадежен, поскольку он отличается от фактического базового типа t.GetType.

Короче говоря, если у вас есть экземпляр object, используйте GetType. Если у вас общий тип class, используйте is. Если у вас общий тип struct, используйте typeof(T). Если вы не уверены, является ли универсальный тип ссылочным типом или типом значения, используйте is. Если вы хотите всегда соответствовать одному стилю (для запечатанных типов), используйте is ..

person nawfal    schedule 12.02.2013
comment
На самом деле, мне все равно. Используйте то, что имеет наибольший смысл. - person nawfal; 29.01.2015