上面我介绍了几种创建对象的方式,现在我开始使用 BenchmarkDotNet 进行基准测试,我也把 new Employee() 直接创建的方式加到测试列表中,并用它作为 "基线",来并比较其他的每种方法,同时我把一些方法的预热操作,放到了构造函数中一次执行,最终的代码如下
using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
namespace ReflectionBenchConsoleApp
{
public class Employee { }
public class ReflectionBenchmarks
{
private readonly ConstructorInfo _ctor;
private readonly IServiceProvider _provider;
private readonly Func<Employee> _expressionActivator;
private readonly Func<Employee> _emitActivator;
private readonly Func<Employee> _natashaActivator;
public ReflectionBenchmarks()
{
_ctor = typeof(Employee).GetConstructor(Type.EmptyTypes);
_provider = new ServiceCollection().AddTransient<Employee>().BuildServiceProvider();
NatashaInitializer.Initialize();
_natashaActivator = Natasha.CSharp.NInstance.Creator<Employee>();
_expressionActivator = Expression.Lambda<Func<Employee>>(Expression.New(typeof(Employee))).Compile();
DynamicMethod dynamic = new("DynamicMethod", typeof(Employee), null, typeof(ReflectionBenchmarks).Module, false);
ILGenerator il = dynamic.GetILGenerator();
il.Emit(OpCodes.Newobj, typeof(Employee).GetConstructor(System.Type.EmptyTypes));
il.Emit(OpCodes.Ret);
_emitActivator = dynamic.CreateDelegate(typeof(Func<Employee>)) as Func<Employee>;
}
[Benchmark(Baseline = true)]
public Employee UseNew() => new Employee();
[Benchmark]
public Employee UseReflection() => _ctor.Invoke(null) as Employee;
[Benchmark]
public Employee UseActivator() => Activator.CreateInstance<Employee>();
[Benchmark]
public Employee UseDependencyInjection() => _provider.GetRequiredService<Employee>();
[Benchmark]
public Employee UseNatasha() => _natashaActivator();
[Benchmark]
public Employee UseExpression() => _expressionActivator();
[Benchmark]
public Employee UseEmit() => _emitActivator();
}
}
接下来,还修改 Program.cs,注意这里需要在 Release 模式下运行测试
using BenchmarkDotNet.Running;
namespace ReflectionBenchConsoleApp
{
public class Program
{
public static void Main(string[] args)
{
var sumary = BenchmarkRunner.Run<ReflectionBenchmarks>();
}
}
}