Как всегда, единственный правильный способ ответить на вопрос о производительности - это фактически измерить код.
Вот пример LINQPad программы, которая тестирует:
- Activator.CreateInstance
- новый T ()
- вызов делегата, который вызывает new T ()
Как всегда, возьмите программу производительности с небольшим количеством соли, здесь могут быть ошибки, которые искажают результаты.
Вывод (временные значения в миллисекундах):
Test1 - Activator.CreateInstance<T>()
12342
Test2 - new T()
1119
Test3 - Delegate
1530
Baseline
578
Обратите внимание, что вышеприведенные сроки относятся к 100.000.000 (100 миллионам) конструкций объекта. Перегрузка может не быть реальной проблемой для вашей программы.
Предупреждающим выводом будет то, что Activator.CreateInstance<T>
занимает примерно в 11 раз больше времени, чтобы выполнить ту же работу, что и new T()
, а делегату - примерно в 1,5 раза больше. Обратите внимание, что конструктор здесь ничего не делает, поэтому я попытался измерить только издержки различных методов.
Редактировать: Я добавил базовый вызов, который не создает объект, но выполняет все остальное, и рассчитал это тоже. Исходя из этого, похоже, что делегат занимает на 75% больше времени, чем простой new (), а Activator.CreateInstance - примерно на 1100%.
Однако это микрооптимизация. Если вам действительно нужно это сделать и извлечь последнюю унцию производительности какого-то критичного по времени кода, я бы либо вручную написал делегат для использования, либо, если это невозможно, т.е. вам нужно предоставить тип во время выполнения, я бы использовал Reflection.Emit для динамического создания этого делегата.
В любом случае, и вот мой реальный ответ:
Если у вас проблемы с производительностью, сначала определите, где находится ваше узкое место. Да, приведенные выше временные параметры могут указывать на то, что Activator.CreateInstance имеет больше служебных данных, чем динамически создаваемый делегат, но в вашей кодовой базе может быть гораздо больше рыбы, которую нужно жарить, прежде чем вы достигнете (или даже должны будете) достичь этого уровня оптимизации. *
И просто чтобы убедиться, что я действительно отвечу на ваш конкретный вопрос: нет, я бы не стал препятствовать использованию Activator.CreateInstance. Вы должны знать, что он использует рефлексию, так что вы знаете, что если это превысит ваши списки узких мест профилирования, то вы могли бы что-то с этим сделать, но тот факт, что он использует рефлексию, не означает, что равно узкое место.
Программа:
void Main()
{
const int IterationCount = 100000000;
// warmup
Test1();
Test2();
Test3();
Test4();
// profile Activator.CreateInstance<T>()
Stopwatch sw = Stopwatch.StartNew();
for (int index = 0; index < IterationCount; index++)
Test1();
sw.Stop();
sw.ElapsedMilliseconds.Dump("Test1 - Activator.CreateInstance<T>()");
// profile new T()
sw.Restart();
for (int index = 0; index < IterationCount; index++)
Test2();
sw.Stop();
sw.ElapsedMilliseconds.Dump("Test2 - new T()");
// profile Delegate
sw.Restart();
for (int index = 0; index < IterationCount; index++)
Test3();
sw.Stop();
sw.ElapsedMilliseconds.Dump("Test3 - Delegate");
// profile Baseline
sw.Restart();
for (int index = 0; index < IterationCount; index++)
Test4();
sw.Stop();
sw.ElapsedMilliseconds.Dump("Baseline");
}
public void Test1()
{
var obj = Activator.CreateInstance<TestClass>();
GC.KeepAlive(obj);
}
public void Test2()
{
var obj = new TestClass();
GC.KeepAlive(obj);
}
static Func<TestClass> Create = delegate
{
return new TestClass();
};
public void Test3()
{
var obj = Create();
GC.KeepAlive(obj);
}
TestClass x = new TestClass();
public void Test4()
{
GC.KeepAlive(x);
}
public class TestClass
{
}