У меня есть программа, требующая быстрой работы. В одном из его внутренних циклов мне нужно проверить тип объекта, чтобы увидеть, наследуется ли он от определенного интерфейса.
Один из способов сделать это - использовать встроенную в CLR функцию проверки типов. Самый элегантный метод, вероятно, это ключевое слово is:
if (obj is ISpecialType)
Другой подход - предоставить базовому классу мою собственную виртуальную функцию GetType (), которая возвращает предопределенное значение перечисления (в моем случае на самом деле мне нужен только bool). Этот метод будет быстрым, но менее элегантным.
Я слышал, что есть инструкция IL специально для ключевого слова is, но это не значит, что она выполняется быстро при переводе в собственную сборку. Может ли кто-нибудь поделиться некоторыми взглядами на эффективность «есть» по сравнению с другим методом?
ОБНОВЛЕНИЕ: Спасибо за все осознанные ответы! Кажется, в ответах разбросано несколько полезных моментов: точка зрения Эндрю об автоматическом выполнении преобразования важна, но данные о производительности, собранные Binary Worrier и Яном, также чрезвычайно полезны. Было бы здорово, если бы один из ответов был отредактирован, чтобы включить всю эту информацию.
источник
Ответы:
Использование
is
может снизить производительность, если после проверки типа вы приведете к этому типу.is
фактически приводит объект к типу, который вы проверяете, поэтому любое последующее приведение является избыточным.Если вы все равно собираетесь кастовать, вот лучший подход:
источник
as
основном выполняется та же операция, что иis
(а именно, проверка типа). Единственная разница в том, что он возвращаетсяnull
вместоfalse
.Я с Яном , ты, наверное, не хочешь этого делать.
Однако, чтобы вы знали, между ними очень мало различий, более 10 000 000 итераций.
Я лично не стал бы исправлять эту проблему таким образом, но если бы мне пришлось выбрать один метод, это была бы встроенная проверка IS, разница в производительности не стоит того, чтобы учитывать накладные расходы на кодирование.
Мои базовые и производные классы
JubJub: По запросу больше информации о тестах.
Я запустил оба теста из консольного приложения (отладочная сборка), каждый тест выглядит следующим образом
В выпуске я получаю разницу в 60 - 70 мс, как Ян.
Дальнейшее обновление - 25 октября 2012 г.
Спустя пару лет я кое-что заметил в этом: компилятор может выбрать опускание
bool b = a is MyClassB
в выпуске, потому что b нигде не используется.Этот код. . .
. . . последовательно показывает, что
is
проверка проходит примерно через 57 миллисекунд, а сравнение enum происходит через 29 миллисекунд.NB, я бы предпочел
is
чек, разница слишком мала, чтобы о ней заботитьсяисточник
is
которое вызывает вам оператор, и что чрезмерное количество слухов о проектировании и кодировании дляis
оператора будет стоить целое состояние качество кода и, в конечном итоге, самоубийство с точки зрения производительности. В данном случае я поддерживаю свое заявление. «Есть» оператор не никогда не будет проблема с производительностью выполнения.Хорошо, я поговорил об этом с кем-то и решил проверить это еще раз. Насколько я могу судить, производительность
as
иis
оба очень хороши по сравнению с тестированием вашего собственного члена или функции для хранения информации о типе.Я использовал
Stopwatch
, который, как я только что узнал, может быть не самым надежным подходом, поэтому я тоже попробовалUtcNow
. Позже я также попробовал подход с использованием времени процессора, который, похоже, похож наUtcNow
включение непредсказуемого времени создания. Я также попытался сделать базовый класс неабстрактным без виртуальных объектов, но, похоже, это не имело значительного эффекта.Я запускал это на Quad Q6600 с 16 ГБ ОЗУ. Даже с итерациями в 50 мил, числа все еще колеблются в районе +/- 50 или около того миллисекунд, поэтому я не стал бы вдаваться в подробности о незначительных различиях.
Было интересно увидеть, что x64 создается быстрее, но выполняется как / медленнее, чем x86.
Режим выпуска x64:
Секундомер:
As: 561 мс
Is: 597 мс
Базовое свойство: 539 мс
Базовое поле: 555 мс
Базовое поле RO: 552 мс
Виртуальный тест GetEnumType (): 556
мс Тест виртуального IsB (): 588 мс
Время создания: 10416 мс
UtcNow:
As: 499 мс
Is: 532 мс
Базовое свойство: 479 мс
Базовое поле: 502 мс
Базовое поле RO: 491 мс
Virtual GetEnumType (): 502 мс
Virtual bool IsB (): 522 мс
Время создания: 285 мс (Это число кажется ненадежным с UtcNow. Я также получаю 109 мс и 806мс.)
Режим выпуска x86:
Секундомер:
As: 391 мс
Is: 423 мс
Базовое свойство: 369 мс
Базовое поле: 321 мс
Базовое поле RO: 339 мс
Виртуальный тест GetEnumType (): 361
мс Тест виртуального IsB (): 365 мс
Время создания: 14106 мс
UtcNow:
As: 348 мс
Is: 375 мс
Базовое свойство: 329 мс
Базовое поле: 286 мс
Базовое поле RO: 309 мс
Виртуальный GetEnumType (): 321 мс
Virtual bool IsB (): 332 мс
Время создания: 544 мс (Это число кажется ненадежным с UtcNow.)
Вот большая часть кода:
источник
Андрей прав. Фактически, при анализе кода Visual Studio сообщает об этом как о ненужном приведении.
Одна идея (не зная, что вы делаете, - это своего рода выстрел в темноте), но мне всегда советовали избегать такой проверки и вместо этого иметь другой класс. Поэтому вместо того, чтобы выполнять некоторые проверки и выполнять разные действия в зависимости от типа, пусть класс знает, как обрабатывать себя ...
например, Obj может иметь значение ISpecialType или IType;
оба имеют определенный метод DoStuff (). Для IType он может просто возвращать или выполнять пользовательские действия, тогда как ISpecialType может делать другие вещи.
Затем это полностью удаляет любое преобразование, делает код более чистым и легким в обслуживании, а класс знает, как выполнять свои собственные задачи.
источник
Я провел сравнение производительности двух вариантов сравнения типов
Результат: Использование "is" примерно в 10 раз быстрее !!!
Вывод:
Время для сравнения типов: 00: 00: 00.456
Время для сравнения: 00: 00: 00.042
Мой код:
источник
Эндрю Хейр сказал о потере производительности, когда вы выполняете
is
проверку, а затем приведение было допустимым, но в C # 7.0 мы можем проверить соответствие шаблону ведьмы, чтобы избежать дополнительного приведения в дальнейшем:Более того, если вам нужно проверить между несколькими типами, конструкции сопоставления с образцом в C # 7.0 теперь позволяют выполнять операции
switch
с типами:Вы можете узнать больше о сопоставлении с образцом в C # в документации здесь .
источник
OneOf<T...>
но у них есть серьезные недостатки) .Если кому-то интересно, я провел тесты в движке Unity 2017.1 с версией среды выполнения сценариев .NET4.6 (Experimantal) на ноутбуке с процессором i5-4200U. Полученные результаты:
Average Relative To Local Call LocalCall 117.33 1.00 is 241.67 2.06 Enum 139.33 1.19 VCall 294.33 2.51 GetType 276.00 2.35
Полная статья: http://www.ennoble-studios.com/tuts/unity-c-performance-comparison-is-vs-enum-vs-virtual-call.html
источник
Мне всегда советовали избегать такой проверки и вместо этого иметь другой класс. Поэтому вместо того, чтобы выполнять некоторые проверки и выполнять разные действия в зависимости от типа, пусть класс знает, как обрабатывать себя ...
например, Obj может иметь значение ISpecialType или IType;
оба имеют определенный метод DoStuff (). Для IType он может просто возвращать или выполнять пользовательские действия, тогда как ISpecialType может делать другие вещи.
Затем это полностью удаляет любое преобразование, делает код более чистым и легким в обслуживании, а класс знает, как выполнять свои собственные задачи.
источник