є vs typeof


Відповіді:


167

Це повинно відповісти на це питання, а потім на деякі.

Другий рядок, if (obj.GetType() == typeof(ClassA)) {}швидше, для тих, хто не хоче читати статтю.

(Будьте в курсі, що вони не роблять те саме)


1
+1: В минулому я задавався питанням, чому C # компілятор компілювати typeof(string).TypeHandleв ldtokenінструкції CIL, але схоже , що CLR піклується про нього в JIT. Це все ще потребує декількох додаткових опкодів, але це більш узагальнене застосування оптимізації.
Сем Харвелл

2
Читайте також highlogics.blogspot.ca/2013/09/… - вони протестують для різних фреймворків і x86 vs x64 з різними результатами.
CAD блокується

1
Зверніть увагу, це справедливо лише для типів посилань. А різниця швидкостей не така вже й значна. Враховуючи штрафний показник боксу у випадку значень цінності GetType, isце завжди більш безпечний вибір щодо продуктивності. Звичайно, вони роблять різні речі.
nawfal

Якщо ви поставите це в Resharper, пропонуйте змінити його на "є"!
Роб Седвік

@nawfal, я спочатку вважав, що ваша думка щодо штрафу за бокс має сенс для типів структури, але враховуючи, що ми тестуємо object obj;змінну, чи не є вона вже в коробці, коли це, як правило, тестується? Чи є випадок, коли вам потрібно протестувати тип чогось, і це вже не є об'єктом?
Роб Паркер

193

Чи важливо, що швидше, якщо вони не роблять те саме? Порівнювати виконання тверджень із різним значенням видається поганою ідеєю.

isповідомляє вам, чи об’єкт реалізує ClassAдесь у своїй герархії типу. GetType()розповідає про найбільш похідний тип.

Не те саме.


7
Це має значення, адже в моєму випадку я позитивний, вони повертають той же результат.
ілітіріт

37
@ [ilitirit]: вони повертають той самий результат прямо зараз, але якщо пізніше ви додасте підклас, вони не стануть
Стівен А. Лоу

13
Оптимізація зараз зробить ваш код крихким і складним у обслуговуванні.
ICR

9
Мої заняття запечатані.
ілітірит

26

Вони не роблять те саме. Перший працює, якщо obj має тип ClassA або якогось підкласу ClassA. Друга відповідатиме лише об’єктам типу ClassA. Другий буде швидшим, оскільки не потрібно перевіряти ієрархію класів.

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


1
@amitjha Я трохи стурбований тим, що цей тест проводився під Mono, що він не включає оптимізації JIT, про які йдеться у статті. Оскільки стаття свідчить про протилежне, на мою думку, питання є відкритим. У будь-якому випадку порівняння виконання операцій, які роблять різні речі залежно від типу, видається марною вправою. Використовуйте операцію, яка відповідає потрібній вам поведінці, а не тій, яка "швидша"
tvanfosson

16

Я зробив кілька тестів, де вони роблять те саме - герметичні типи.

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


1
Насправді взагалі не турбуйтеся. Використовуйте те, що має найбільше сенс.
nawfal
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.