解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
7.02 KiB
X
using System.Linq.Expressions;
using System.Reflection;
using BenchmarkDotNet.Attributes;
using NewLife.Reflection;

namespace Benchmark.ReflectBenchmarks;

/// <summary>测试用模型类</summary>
internal class SampleModel
{
    public String Name { get; set; } = "";
    public Int32 Age { get; set; }
    public DateTime CreateTime { get; set; }

    public String GetDisplayName() => $"{Name}({Age})";
    public Int32 Add(Int32 a, Int32 b) => a + b;
}

/// <summary>Reflect 扩展与原始 .NET 反射性能对比基准测试</summary>
[MemoryDiagnoser]
[SimpleJob(iterationCount: 20)]
public class ReflectBenchmark
{
    private PropertyInfo _pi = null!;
    private MethodInfo _miNoParam = null!;
    private MethodInfo _miWithParam = null!;
    private Type _type = null!;
    private SampleModel _model = null!;

    // 预编译委托(用于 Baseline 对比)
    private Func<Object?, Object?> _directGetter = null!;
    private Action<Object?, Object?> _directSetter = null!;
    private Func<Object> _directCtor = null!;
    private Func<Object?, Object?> _directInvokeNoParam = null!;
    private Func<Object?, Object?[]?, Object?> _directInvokeWithParam = null!;

    private static readonly Object[] _invokeArgs = [3, 4];

    [GlobalSetup]
    public void Setup()
    {
        _type = typeof(SampleModel);
        _pi = _type.GetProperty(nameof(SampleModel.Name))!;
        _miNoParam = _type.GetMethod(nameof(SampleModel.GetDisplayName))!;
        _miWithParam = _type.GetMethod(nameof(SampleModel.Add))!;
        _model = new SampleModel { Name = "Hello", Age = 42, CreateTime = DateTime.Now };

        // 预先编译直接委托(基准对比用,排除首次编译开销)
        var obj = Expression.Parameter(typeof(Object), "obj");
        var cast = Expression.Convert(obj, _type);
        _directGetter = Expression.Lambda<Func<Object?, Object?>>(
            Expression.Convert(Expression.Property(cast, _pi), typeof(Object)), obj).Compile();

        var val = Expression.Parameter(typeof(Object), "val");
        _directSetter = Expression.Lambda<Action<Object?, Object?>>(
            Expression.Assign(Expression.Property(Expression.Convert(obj, _type), _pi),
                Expression.Convert(val, _pi.PropertyType)), obj, val).Compile();

        var ctor = _type.GetConstructor(Type.EmptyTypes)!;
        _directCtor = Expression.Lambda<Func<Object>>(Expression.New(ctor)).Compile();

        // 0-param 直接 Func<Object?,Object?> 委托(不含 Object[] 数组开销)
        _directInvokeNoParam = Expression.Lambda<Func<Object?, Object?>>(
            Expression.Convert(Expression.Call(Expression.Convert(obj, _type), _miNoParam), typeof(Object)),
            obj).Compile();

        var argsParam = Expression.Parameter(typeof(Object?[]), "args");
        _directInvokeWithParam = Expression.Lambda<Func<Object?, Object?[]?, Object?>>(
            Expression.Convert(
                Expression.Call(Expression.Convert(obj, _type), _miWithParam,
                    Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(0)), typeof(Int32)),
                    Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(1)), typeof(Int32))),
                typeof(Object)),
            obj, argsParam).Compile();

        // 预热 NewLife 缓存(排除首次编译开销)
        _ = _model.GetValue((MemberInfo)_pi);
        _model.SetValue((MemberInfo)_pi, "Warmup");
        _ = _type.CreateInstance();
        _ = _type.GetProperties(true);
        _ = _model.Invoke(_miNoParam, (Object?[]?)null);
        _ = _model.Invoke(_miWithParam, _invokeArgs);
        // 同时预热 Provider 直调路径
        _ = Reflect.Provider.GetValue(_model, _pi);
        Reflect.Provider.SetValue(_model, _pi, "Warmup");
        _ = Reflect.Provider.Invoke(_model, _miNoParam, null);
        _ = Reflect.Provider.Invoke(_model, _miWithParam, _invokeArgs);
    }

    #region 属性 Get
    [Benchmark(Description = "属性Get-原始反射")]
    public Object? RawPropertyGet() => _pi.GetValue(_model, null);

    [Benchmark(Description = "属性Get-直接Lambda")]
    public Object? DirectLambdaGet() => _directGetter(_model);

    [Benchmark(Description = "属性Get-Provider直调")]
    public Object? ProviderPropertyGet() => Reflect.Provider.GetValue(_model, _pi);

    [Benchmark(Description = "属性Get-扩展方法")]
    public Object? ExtMethodPropertyGet() => _model.GetValue((MemberInfo)_pi);
    #endregion

    #region 属性 Set
    [Benchmark(Description = "属性Set-原始反射")]
    public void RawPropertySet() => _pi.SetValue(_model, "World", null);

    [Benchmark(Description = "属性Set-直接Lambda")]
    public void DirectLambdaSet() => _directSetter(_model, "World");

    [Benchmark(Description = "属性Set-Provider直调")]
    public void ProviderPropertySet() => Reflect.Provider.SetValue(_model, _pi, "World");

    [Benchmark(Description = "属性Set-扩展方法")]
    public void ExtMethodPropertySet() => _model.SetValue((MemberInfo)_pi, "World");
    #endregion

    #region CreateInstance
    [Benchmark(Description = "CreateInstance-Activator")]
    public Object ActivatorCreate() => Activator.CreateInstance(_type)!;

    [Benchmark(Description = "CreateInstance-直接Lambda")]
    public Object DirectLambdaCreate() => _directCtor();

    [Benchmark(Description = "CreateInstance-扩展方法")]
    public Object? NewLifeCreate() => _type.CreateInstance();
    #endregion

    #region Invoke(无参数)
    [Benchmark(Description = "Invoke无参-原始反射")]
    public Object? RawInvokeNoParam() => _miNoParam.Invoke(_model, null);

    [Benchmark(Description = "Invoke无参-直接Lambda")]
    public Object? DirectLambdaInvokeNoParam() => _directInvokeNoParam(_model);

    [Benchmark(Description = "Invoke无参-Provider直调")]
    public Object? ProviderInvokeNoParam() => Reflect.Provider.Invoke(_model, _miNoParam, null);

    [Benchmark(Description = "Invoke无参-扩展方法")]
    public Object? ExtMethodInvokeNoParam() => _model.Invoke(_miNoParam, (Object?[]?)null);
    #endregion

    #region Invoke(带参数)
    [Benchmark(Description = "Invoke带参-原始反射")]
    public Object? RawInvokeWithParam() => _miWithParam.Invoke(_model, _invokeArgs);

    [Benchmark(Description = "Invoke带参-直接Lambda")]
    public Object? DirectLambdaInvokeWithParam() => _directInvokeWithParam(_model, _invokeArgs);

    [Benchmark(Description = "Invoke带参-Provider直调")]
    public Object? ProviderInvokeWithParam() => Reflect.Provider.Invoke(_model, _miWithParam, _invokeArgs);

    [Benchmark(Description = "Invoke带参-扩展方法")]
    public Object? ExtMethodInvokeWithParam() => _model.Invoke(_miWithParam, _invokeArgs);
    #endregion

    #region GetProperties
    [Benchmark(Description = "GetProperties-原始反射")]
    public PropertyInfo[] RawGetProperties() => _type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

    [Benchmark(Description = "GetProperties-扩展方法缓存")]
    public IList<PropertyInfo> CachedGetProperties() => _type.GetProperties(true);
    #endregion
}