#c_sharp #net #рефлексия
Я знаю 1 способ создать объекта в C#: public static class ObjectCreator { public static T GetObject() where T : class { return (T)Activator.CreateInstance(typeof(T)); } } Есть ли более производительные? Update класс с известными способами: public class ObjectCreator where T: new() { protected Func V4Lambda; protected Func V5Lambda; public ObjectCreator() { Type sType = typeof(T); //V4 V4Lambda = Expression.Lambda >(Expression.New(sType)).Compile(); //V5 V5Lambda = DynamicModuleLambdaCompiler.GenerateFactory (); } public T V1() { return (T)Activator.CreateInstance(typeof(T)); } public T V2() { return new T(); } public T V3() { return CustomActivator.CreateInstance (); } public T V4() { return V4Lambda(); } public T V5() { return V5Lambda(); } } public static class CustomActivator { public static T CreateInstance () where T : new() { return ActivatorImpl .Factory(); } private class ActivatorImpl where T : new() { private static readonly Expression > _expr = () => new T(); public static readonly Func Factory = _expr.Compile(); } } public static class DynamicModuleLambdaCompiler { public static Func GenerateFactory () where T : new() { Expression > expr = () => new T(); NewExpression newExpr = (NewExpression)expr.Body; var method = new DynamicMethod( name: "lambda", returnType: newExpr.Type, parameterTypes: new Type[0], m: typeof(DynamicModuleLambdaCompiler).Module, skipVisibility: true); ILGenerator ilGen = method.GetILGenerator(); // Constructor for value types could be null if (newExpr.Constructor != null) { ilGen.Emit(OpCodes.Newobj, newExpr.Constructor); } else { LocalBuilder temp = ilGen.DeclareLocal(newExpr.Type); ilGen.Emit(OpCodes.Ldloca, temp); ilGen.Emit(OpCodes.Initobj, newExpr.Type); ilGen.Emit(OpCodes.Ldloc, temp); } ilGen.Emit(OpCodes.Ret); return (Func )method.CreateDelegate(typeof(Func )); } } Результаты моего тестирования:
Ответы
Ответ 1
В следующих статьях Сергея Теплякова Исследуем new() ограничение в C# Dissecting the new() constraint in C#: a perfect example of a leaky abstraction делается вывод, что самый быстрый способ создания объекта - это распарсить лямбду в выражение и скомпилировать его: public static class DynamicModuleLambdaCompiler { public static FuncGenerateFactory () where T:new() { Expression > expr = () => new T(); NewExpression newExpr = (NewExpression)expr.Body; var method = new DynamicMethod( name: "lambda", returnType: newExpr.Type, parameterTypes: new Type[0], m: typeof(DynamicModuleLambdaCompiler).Module, skipVisibility: true); ILGenerator ilGen = method.GetILGenerator(); // Constructor for value types could be null if (newExpr.Constructor != null) { ilGen.Emit(OpCodes.Newobj, newExpr.Constructor); } else { LocalBuilder temp = ilGen.DeclareLocal(newExpr.Type); ilGen.Emit(OpCodes.Ldloca, temp); ilGen.Emit(OpCodes.Initobj, newExpr.Type); ilGen.Emit(OpCodes.Ldloc, temp); } ilGen.Emit(OpCodes.Ret); return (Func )method.CreateDelegate(typeof(Func )); } } public static class FastActivator where T : new() { /// /// Extremely fast generic factory method that returns an instance /// of the type public static readonly Func. /// Create = DynamicModuleLambdaCompiler.GenerateFactory (); } Method | Mean | StdDev | Gen 0 | ------------------------ |----------- |---------- |------- | ActivatorCreateInstance | 95.0161 ns | 1.0861 ns | 0.0005 | FuncBasedFactory | 6.5741 ns | 0.0608 ns | 0.0034 | FastActivator_T_Create | 5.1715 ns | 0.0466 ns | 0.0034 | Ответ 2
Вы не должны заниматься низкоуровневыми микрооптимизациями практически никогда. (Потому что компилятор рано или поздно сумеет оптимизировать лучше.) Но если в каком-то месте вам реально нужна оптимизация, то достаточно просто передать создающую функцию Funcкуда нужно, и всё: public class ObjectCreator<Т> { Func create; public ObjectCreator(Func create) => this.create = create; public T GetObject() => create(); } Вы потеряете немного абстракцию, но вам же ехать, а не шашечки? Это самый быстрый путь. Ещё быстрее будет просто в нужном месте вызвать нужный конструктор. Потому что вызов делегата небесплатен. С другой стороны, если вам нужны нанооптимизации, вы выбрали себе не ту платформу. Бенчмарки: BenchmarkDotNet=v0.10.9, OS=Windows 7 SP1 (6.1.7601) Processor=Intel Core i7-2600K CPU 3.40GHz (Sandy Bridge), ProcessorCount=8 Frequency=3320429 Hz, Resolution=301.1659 ns, Timer=TSC [Host] : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2053.0 DefaultJob : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2053.0 Method | Mean | Error | StdDev | ----------------------------------------------- |----------:|----------:|----------:| V1_Activator_CreateInstance | 70.639 ns | 0.3354 ns | 0.3138 ns | V2_NewGenericConstraint | 77.813 ns | 0.2788 ns | 0.2608 ns | V3_CustomActivator_CreateInstance | 20.237 ns | 0.0562 ns | 0.0498 ns | V4_Expression_Compile | 11.175 ns | 0.1693 ns | 0.1584 ns | V5_DynamicModuleLambdaCompiler_GenerateFactory | 4.822 ns | 0.0322 ns | 0.0301 ns | V6_Factory_Func | 3.967 ns | 0.0247 ns | 0.0231 ns | V7_Direct_Constructor_Call | 3.047 ns | 0.0207 ns | 0.0194 ns |
Комментариев нет:
Отправить комментарий