C# Reflection — скорость приемлемая или всё-таки медленно?
Добрый день! Продолжаю серию вопросов "не уверен и всегда боялся спросить".
В C# есть Reflection - рефлексия. Иногда переводят "отражение", но мне кажется что термин рефлексия (грубо, взгляд на самого себя) самый что ни на есть верный.
Всегда избегал пользоваться рефлексией, так как считал что это медленно. Соответственно, аттрибутами, идущими из той де рефлексии, пользовался крайне редко и в сценариях, где скорость менее важна.
Сейчас знакомлюсь с проектом, в котором часто используют аттрибуты, причем это действительно удобным решением для хранения данных. И вот тут я подумал - а почему я всегда боялся их применять? Думал медленно? А почему? А где читал? Я не вспомнил.
Поэтому мой вопрос: насколько медленно использовать аттрибуты в частности и Reflection вообще? Если если всё-таки медленно, то скажите: если скорость не так уж и важна в данном конкретном сценарии, вы бы использовали аттрибуты?
Друг, есть одно универсальное правило: работает достаточно шустро - не трогай, работает медленно - бери профайлер.
Заменой рефлексии в некоторых сценариях может быть кодогенерация. В некоторых - избавление от рефлексии путем минимальных архитектурных перестроений. Иногда избавляться от рефлексии не нужно, достаточно провести банальные оптимизации пары-тройки методов (чем тормознутее метод, тем больше абсолютный выигрыш при базовых оптимизациях).
Если скорость не важна - используй решение, которое быстрее всего кодить, либо проще поддерживать.
Использовать в C# Reflection можно и нужно, не спешите с "улучшением" производительности пока в этом нет необходимости. А в случае необходимости изучите результаты Profiler, я думаю упретесь в IO а не в скорость работы Reflection.
Согласен с Сергей, и если все так и нужно будет улучшить производительность, то в некоторых случаях можно заменить Reflection на Expression и получить выигрыш по скорости работы.
var stopwatch1 = new Stopwatch();
stopwatch1.Start();
var toString = typeof(int).GetMethod("ToString", new Type[0]);
for (var i = 0; i < 10000000; i++)
{
toString.Invoke(i, null);
}
stopwatch1.Stop();
stopwatch1.Elapsed.Dump();
var stopwatch2 = new Stopwatch();
stopwatch2.Start();
for (var i = 0; i < 10000000; i++)
{
i.ToString();
}
stopwatch2.Stop();
stopwatch2.Elapsed.Dump();
Коллега сделал тест.
С рефлексией: 00:00:03.3708027
Без рефлексии: 00:00:01.4555174