это против typeof - PullRequest
       12

это против typeof

138 голосов
/ 09 октября 2008

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

if (obj is ClassA) {}

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

Edit: Я знаю, что они не делают то же самое.

Ответы [ 4 ]

183 голосов
/ 09 октября 2008

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

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

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

160 голосов
/ 09 октября 2008

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

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

25 голосов
/ 09 октября 2008

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

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

16 голосов
/ 12 февраля 2013

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

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 на struct с выполняется медленнее. GetType определен для класса object, который не может быть переопределен в подтипах и, следовательно, struct с быть в штучной упаковке, чтобы называться 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 ..

...