Что более эффективно: myType.GetType() или typeof(MyType)?

Предположим, у меня есть класс MyType:

sealed class MyType
{
    static Type typeReference = typeof(MyType);
    //...
}

Учитывая следующий код:

var instance = new MyType();
var type1 = instance.GetType();
var type2 = typeof(MyType);
var type3 = typeReference;

Какое из этих назначений переменных было бы наиболее эффективным?

Является ли производительность GetType() или typeof() достаточной, чтобы было выгодно сохранить тип в статическом поле?


person Dan    schedule 24.05.2013    source источник
comment
Вы получаете экземпляр во время выполнения (динамический, дженерики?) или он указывается во время компиляции?   -  person It'sNotALie.    schedule 24.05.2013
comment
@newStackExchangeInstance Я просто спрашиваю в контексте точного кода, который я предоставил.   -  person Dan    schedule 24.05.2013


Ответы (5)


typeof(SomeType) — это простой поиск токена метаданных

GetType() — виртуальный вызов; с положительной стороны вы получите производный тип, если это подкласс, но с отрицательной стороны вы получите производный класс, если это подкласс. Если вы понимаете, что я имею в виду. Кроме того, GetType() требует упаковки для структур и плохо работает для структур, допускающих значение NULL.

Если вы знаете тип во время компиляции, используйте typeof().

person Marc Gravell    schedule 24.05.2013
comment
Как GetType требует упаковки для структур? - person Dan; 24.05.2013
comment
@Dan, потому что это виртуальный вызов, который нельзя переопределить. Все остальные методы структуры (Equals, ToString, GetHashCode и т. д.) могут быть переопределены, что позволяет вызывать их без упаковки с помощью вызова или ограниченного вызова. Но для вызова непереопределенного метода в структуре требуется упаковка, а затем вызов виртуального метода для объекта. - person Marc Gravell; 24.05.2013
comment
Понятно. Я никогда не думал об этом. Спасибо! - person Dan; 24.05.2013
comment
@Dan, однако, одно интересное наблюдение заключается в том, что во всех неуниверсальных случаях, связанных со структурами, компилятор может фактически (но не) заменить GetType() на typeof. Хотя правильное поведение в случае nullable-T вызывает сомнения. - person Marc Gravell; 24.05.2013

Я бы выбрал type2. Для получения типа не требуется создание экземпляра. И это наиболее удобочитаемо для человека.

person mason    schedule 24.05.2013
comment
Это хорошие моменты, но я беспокоюсь об эффективности больше, чем о читабельности. - person Dan; 24.05.2013

Единственный способ узнать это измерить.

Вариант "type1" никоим образом не надежен и не рекомендуется, так как не все типы могут быть построены. Хуже того, он выделяет память, которая должна быть сборщиком мусора, и вызывает конструкторы объектов.

Что касается оставшихся двух вариантов, на моей машине «тип 3» примерно в два раза быстрее, чем «тип 1», как в режиме отладки, так и в режиме выпуска. Помните, что это верно только для моего теста — результаты могут быть неверны для других типов процессоров, типов машин, компиляторов или версий .NET.

        var sw = System.Diagnostics.Stopwatch.StartNew();
        for (int i = 0; i < 10000000; i++)
        {
            var y = typeof(Program).ToString();
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        for (int i = 0; i < 10000000; i++)
        {
            var y = typeReference.ToString();
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);

Тем не менее, немного тревожно, что этот вопрос задается без четкого требования. Если вы заметили проблему с производительностью, вы, вероятно, уже профилировали ее и знали, какой вариант был лучше. Это говорит мне о том, что это, скорее всего, преждевременная оптимизация — вы знаете поговорку: «преждевременная оптимизация — корень всех зол».

Программный код измеряется не только производительностью. Это также измеряется правильностью, производительностью разработчика и ремонтопригодностью. Увеличение сложности вашего кода без сильной причины просто переносит эти затраты куда-то еще. То, что могло бы не быть проблемой, теперь превратилось в серьезную потерю производительности, как сейчас, так и для будущих сопровождающих приложения.

Я бы рекомендовал всегда использовать вариант "type1". Код измерения, который я перечислил, не является реальным сценарием. Кэширование typeof в ссылочной переменной, вероятно, имеет массу побочных эффектов, особенно в отношении того, как .NET загружает сборки. Вместо того, чтобы загружать их только при необходимости, это может привести к тому, что они будут загружаться все при каждом использовании приложения, превращая теоретическую оптимизацию производительности в очень реальную проблему производительности.

person ShadowChaser    schedule 27.05.2013
comment
Извиняюсь, если ответ был немного проповедническим, я просто представляю, как Google подхватывает это и тысячи начинающих разработчиков внезапно отбрасывают оператор typeof()! - person ShadowChaser; 28.05.2013

Они довольно разные.

typeof(MyType) получает объект Type, описывающий тип MyType, разрешенный в типе компиляции с помощью инструкции ldtoken.

myInstance.GetType() получает объект Type, описывающий тип времени выполнения переменной myInstance.

Оба предназначены для разных сценариев.

Вы не можете использовать typeof(MyType), если вы не знаете тип во время компиляции и не имеете к нему доступа.

Вы не можете использовать myInstance.GetType(), если у вас нет экземпляра типа.

typeof(MyType) всегда более эффективен, но вы не можете использовать его, если не видите тип во время компиляции. Вы не можете использовать typeof(MyType), чтобы узнать реальный тип некоторой переменной во время выполнения, потому что вы не знаете тип.

person Ark-kun    schedule 31.05.2013
comment
Я понимаю их различия в том, что касается использования. Для примера, который я опубликовал, результаты будут объектами одного типа. У меня вопрос, что эффективнее и почему? - person Dan; 31.05.2013

Оба в основном одинаковы. Хотя typeof можно использовать в классе, не являющемся экземпляром, например

typeof(MyClass);

Но

MyClass.GetType();

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

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

person ncourcy84    schedule 24.05.2013
comment
Я понимаю, что все 3 предоставленных мной назначения переменных функционально эквивалентны, но мне интересно, что более эффективно. - person Dan; 24.05.2013
comment
С технической точки зрения typeof будет быстрее. - person ncourcy84; 24.05.2013
comment
Я всегда говорю только технически. Я не знаю, как не. Что заставляет вас говорить, что это более эффективно? - person Dan; 24.05.2013
comment
Я пересмотрел свою позицию. Поскольку typeof(Class) возвращает объект System.Type, обе формы синтаксиса будут использовать один и тот же механизм. Как было сказано ранее, единственное отличие состоит в том, что typeof можно использовать только в классе, не являющемся экземпляром, а Object.GetType() требует, чтобы экземпляр объекта был создан. - person ncourcy84; 24.05.2013
comment
Что вообще означает класс, не являющийся экземпляром? - person Ark-kun; 31.05.2013
comment
Класс, который не является экземпляром, например: int. Не объект, объявленный с типом int. - person ncourcy84; 31.05.2013
comment
Классы/типы не являются экземплярами/объектами. Объекты не объявляются с типом, переменные есть. Объекты/экземпляры могут быть созданы/построены из типа/класса. - person Ark-kun; 31.05.2013
comment
С введением объектно-ориентированного программирования одно и то же слово «объект» относится к конкретному экземпляру класса. Выдержка из Википедии. Может быть, я плохо выразился, но это то, что я имел в виду. Неэкземплярный класс — это тип, экземплярный класс — это объект. - person ncourcy84; 31.05.2013