#c_sharp
This question already has answers here: Способы создания объектов в C# (2 ответа) Closed 1 год назад. Для приведения типов наследуемого объекта написана функция. Есть-ли какая-либо возможность создать объект нужного типа без использования класса Activator? public T ToObject() { var o = Activator.CreateInstance(typeof(T)); ... return (T)o }
Ответы
Ответ 1
Я написал простой тест для BenchmarkDotNet: [MemoryDiagnoser] public class Creator { public class A { } [Benchmark] public A ExplicitCtor() { return new A(); } [Benchmark] public A WithActivator() { return Activator.CreateInstance(); } [Benchmark] public A WithReflection() { return (A)typeof(A).GetConstructor(new Type[0]).Invoke(new object[0]); } ConstructorInfo ctor; [Benchmark] public A WithReflectionCached() { if (ctor == null) ctor = typeof(A).GetConstructor(new Type[0]); return (A)ctor.Invoke(new object[0]); } Func lambda; [Benchmark] public A WithLambla() { if (lambda == null) lambda = Expression.Lambda>(Expression.New(typeof(A)), Array.Empty ()).Compile(); return lambda(); } [Benchmark] public A WithCustomActivator() { return CustomActivator.CreateInstance(); } } (CustomActivator by Sergey Teplyakov можно взять здесь) Результаты получились следующие: | Method | Mean | Error | StdDev | Median | Gen 0 | Allocated | |--------------------- |-----------:|----------:|----------:|-----------:|-------:|----------:| | ExplicitCtor | 2.591 ns | 0.0523 ns | 0.0489 ns | 2.582 ns | 0.0076 | 12 B | | WithActivator | 113.661 ns | 0.4652 ns | 0.3885 ns | 113.583 ns | 0.0074 | 12 B | | WithReflection | 369.719 ns | 6.9477 ns | 5.4243 ns | 367.856 ns | 0.0229 | 36 B | | WithReflectionCached | 281.290 ns | 0.9358 ns | 0.7814 ns | 281.415 ns | 0.0148 | 24 B | | WithLambla | 17.391 ns | 0.0700 ns | 0.0621 ns | 17.373 ns | 0.0076 | 12 B | | WithCustomActivator | 27.644 ns | 0.6665 ns | 1.3155 ns | 27.039 ns | 0.0076 | 12 B | Т.е. что мы видим: рефлексия очень медленная и даже кеширование конструктора не сильно помогает, создание объекта с помощью Activator быстрее явной рефлексии в 2,5-3 раза, но всё еще сильно медленнее явного вызова конструктора (в 40 раз!), наиболее эффективный метод, как и ожидалось — создание и кеширование делегата, создающего объекты, он всего в ~6 раз медленнее явного вызова конструктора (тут, подозреваю, медленное именно создание делегата, а сам его вызов не должен уступать явному вызову конструктора, т.е. чем больше объектов мы будем создавать, тем ближе будет средняя скорость к идеальной). Таким образом, имеет смысл переписать ваш метод во что-то вроде такого: Dictionary cache = new Dictionary (); public T Create () { if (!cache.TryGetValue(typeof(T), out var d)) d = cache[typeof(T)] = Expression.Lambda >( Expression.New(typeof(T)), Array.Empty ()) .Compile(); return ((Func )d)(); }
Комментариев нет:
Отправить комментарий