Я знаю 1 способ создать объекта в C#:
public static class ObjectCreator
{
public static T GetObject<T>() where T : class
{
return (T)Activator.CreateInstance(typeof(T));
}
}
Есть ли более производительные?
Update класс с известными способами:
public class ObjectCreator<T> where T: new()
{
protected Func<T> V4Lambda;
protected Func<T> V5Lambda;
public ObjectCreator()
{
Type sType = typeof(T);
//V4
V4Lambda = Expression.Lambda<Func<T>>(Expression.New(sType)).Compile();
//V5
V5Lambda = DynamicModuleLambdaCompiler.GenerateFactory<T>();
}
public T V1()
{
return (T)Activator.CreateInstance(typeof(T));
}
public T V2()
{
return new T();
}
public T V3()
{
return CustomActivator.CreateInstance<T>();
}
public T V4()
{
return V4Lambda();
}
public T V5()
{
return V5Lambda();
}
}
public static class CustomActivator
{
public static T CreateInstance<T>() where T : new()
{
return ActivatorImpl<T>.Factory();
}
private class ActivatorImpl<T> where T : new()
{
private static readonly Expression<Func<T>> _expr = () => new T();
public static readonly Func<T> Factory = _expr.Compile();
}
}
public static class DynamicModuleLambdaCompiler
{
public static Func<T> GenerateFactory<T>() where T : new()
{
Expression<Func<T>> 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<T>)method.CreateDelegate(typeof(Func<T>));
}
}
Результаты моего тестирования:
В следующих статьях Сергея Теплякова
делается вывод, что самый быстрый способ создания объекта - это распарсить лямбду в выражение и скомпилировать его:
public static class DynamicModuleLambdaCompiler
{
public static Func<T> GenerateFactory<T>() where T:new()
{
Expression<Func<T>> 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<T>)method.CreateDelegate(typeof(Func<T>));
}
}
public static class FastActivator<T> where T : new()
{
/// <summary>
/// Extremely fast generic factory method that returns an instance
/// of the type <typeparam name="T"/>.
/// </summary>
public static readonly Func<T> Create =
DynamicModuleLambdaCompiler.GenerateFactory<T>();
}
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 |
Вы не должны заниматься низкоуровневыми микрооптимизациями практически никогда. (Потому что компилятор рано или поздно сумеет оптимизировать лучше.)
Но если в каком-то месте вам реально нужна оптимизация, то достаточно просто передать создающую функцию Func<T>
куда нужно, и всё:
public class ObjectCreator<Т>
{
Func<T> create;
public ObjectCreator(Func<T> 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 |
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Здравствуйте, есть ответ полученный для httpClientОтвет считываю не в строку, а в поток (т
Добрый день, стоит такая цель : синхронизироваться с почтой и иметь возможность загружать/скачивать письмаЕсть ли такая возможность ? желательно...
Пожалуйста, приведите пример как создать новый тип (класс) age, наследовать его от int, ограничить от 0 до 100Спасибо