Страницы

Поиск по вопросам

четверг, 25 октября 2018 г.

Существует ли возможность создавать объект определенного типа, без использования класса Activator? [дубликат]

На данный вопрос уже ответили: Способы создания объектов в C# 2 ответа Для приведения типов наследуемого объекта написана функция. Есть-ли какая-либо возможность создать объект нужного типа без использования класса Activator?
public T ToObject() { var o = Activator.CreateInstance(typeof(T)); ... return (T)o }


Ответ

Я написал простой тест для 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)(); }

Комментариев нет:

Отправить комментарий