寻找性能更优秀的动态 Getter 和 Setter 方案

public static class ValueGetter
{
    public static object Get(Type objType, Type valueType, PropertyInfo info)
    {
        var bodyExp = Expression.Call(
            typeof(ValueGetter<,,>).MakeGenericType(objType, info.PropertyType, valueType),
            nameof(ValueGetter<object, object, object>.GetGetter),
            Array.Empty<Type>(),
            Expression.Constant(info));
        var finalExp = Expression.Lambda<Func<object>>(bodyExp);
        var func = finalExp.Compile();
        var re = func.Invoke();
        return re;
    }

    public static object Get(Type objType, PropertyInfo info)
    {
        var bodyExp = Expression.Call(typeof(ValueGetter<>).MakeGenericType(objType),
            nameof(ValueGetter<object>.GetGetter),
            Array.Empty<Type>(),
            Expression.Constant(info));
        var finalExp = Expression.Lambda<Func<object>>(bodyExp);
        var func = finalExp.Compile();
        var re = func.Invoke();
        return re;
    }

    internal static SwitchCase CreateGetterCase<TTargetObject, TTargetValue>(PropertyInfo propertyInfo)
    {
        var sourceObjExp = Expression.Parameter(typeof(TTargetObject), "sourceObj");
        var finalExp =
            Expression.Lambda<Func<TTargetObject, TTargetValue>>(
                Expression.Convert(Expression.Property(sourceObjExp, propertyInfo), typeof(TTargetValue)),
                sourceObjExp);
        var getter = finalExp.Compile();
        var caseExp = Expression.Constant(propertyInfo);
        return Expression.SwitchCase(Expression.Constant(getter), caseExp);
    }

    internal static Func<PropertyInfo, Func<TTargetObject, TTargetValue>> CreateGetter<TTargetObject, TTargetValue>(
        IEnumerable<PropertyInfo> propertyInfos,
        Func<PropertyInfo, SwitchCase> caseFactory)
    {
        var pExp = Expression.Parameter(typeof(PropertyInfo), "info");
        var cases = propertyInfos.Select(caseFactory);

        var switchExp =
            Expression.Switch(pExp,
                Expression.Constant(null,
                    typeof(Func<TTargetObject, TTargetValue>)),
                null,
                cases);
        var funcExp = Expression.Lambda<Func<PropertyInfo, Func<TTargetObject, TTargetValue>>>(switchExp, pExp);
        var re = funcExp.Compile();
        return re;
    }
}

public static class ValueGetter<TTargetObject, TPropertyValue, TTargetValue>
{
    private static readonly Func<PropertyInfo, Func<TTargetObject, TTargetValue>> Finder;

    static ValueGetter()
    {
        var propertyInfos = typeof(TTargetObject).GetRuntimeProperties()
            .Where(x => x.CanRead)
            .Where(x => x.PropertyType == typeof(TPropertyValue));

        Finder = ValueGetter.CreateGetter<TTargetObject, TTargetValue>(propertyInfos,
            ValueGetter.CreateGetterCase<TTargetObject, TTargetValue>);
    }

    public static Func<TTargetObject, TTargetValue> GetGetter(PropertyInfo info)
    {
        return Finder.Invoke(info);
    }
}

public static class ValueGetter<TTargetObject>
{
    private static readonly Func<PropertyInfo, Func<TTargetObject, object>> Finder;

    static ValueGetter()
    {
        var propertyInfos = typeof(TTargetObject).GetRuntimeProperties()
            .Where(x => x.CanRead);

        Finder = ValueGetter.CreateGetter<TTargetObject, object>(propertyInfos,
            ValueGetter.CreateGetterCase<TTargetObject, object>);
    }

    public static Func<TTargetObject, object> GetGetter(PropertyInfo info)
    {
        return Finder.Invoke(info);
    }
}
public static class ValueSetter
{
    public static object Get(Type objType, Type valueType, PropertyInfo info)
    {
        var bodyExp = Expression.Call(
            typeof(ValueSetter<,,>).MakeGenericType(objType, info.PropertyType, valueType),
            nameof(ValueSetter<object, object, object>.GetSetter),
            Array.Empty<Type>(),
            Expression.Constant(info));
        var finalExp = Expression.Lambda<Func<object>>(bodyExp);
        var func = finalExp.Compile();
        var re = func.Invoke();
        return re;
    }

    public static object Get(Type objType, PropertyInfo info)
    {
        var bodyExp = Expression.Call(typeof(ValueSetter<>).MakeGenericType(objType),
            nameof(ValueSetter<object, object, object>.GetSetter),
            Array.Empty<Type>(),
            Expression.Constant(info));
        var finalExp = Expression.Lambda<Func<object>>(bodyExp);
        var func = finalExp.Compile();
        var re = func.Invoke();
        return re;
    }

    internal static SwitchCase CreateSetterCase<TTargetObject, TTargetValue>(PropertyInfo propertyInfo)
    {
        var sourceObjExp = Expression.Parameter(typeof(TTargetObject), "sourceObj");
        var valueExp = Expression.Parameter(typeof(TTargetValue), "value");
        var newValueExp = Expression.Convert(valueExp, propertyInfo.PropertyType);
        var bodyExp = Expression.Assign(Expression.Property(sourceObjExp, propertyInfo), newValueExp);
        var finalExp =
            Expression.Lambda<Action<TTargetObject, TTargetValue>>(bodyExp, sourceObjExp, valueExp);
        var getter = finalExp.Compile();
        var caseExp = Expression.Constant(propertyInfo);
        return Expression.SwitchCase(Expression.Constant(getter), caseExp);
    }

    internal static Func<PropertyInfo, Action<TTargetObject, TTargetValue>> CreateSetter<TTargetObject,
        TTargetValue>(
        IEnumerable<PropertyInfo> propertyInfos,
        Func<PropertyInfo, SwitchCase> caseFactory)
    {
        var pExp = Expression.Parameter(typeof(PropertyInfo), "info");
        var cases = propertyInfos.Select(caseFactory);
        var switchExp =
            Expression.Switch(pExp,
                Expression.Constant(null,
                    typeof(Action<TTargetObject, TTargetValue>)),
                null,
                cases);
        var funcExp = Expression.Lambda<Func<PropertyInfo, Action<TTargetObject, TTargetValue>>>(switchExp, pExp);
        var re = funcExp.Compile();
        return re;
    }
}

public static class ValueSetter<TTargetObject, TPropertyValue, TTargetValue>
{
    private static readonly Func<PropertyInfo, Action<TTargetObject, TTargetValue>> Finder;

    static ValueSetter()
    {
        var propertyInfos = typeof(TTargetObject).GetRuntimeProperties()
            .Where(x => x.CanWrite)
            .Where(x => x.PropertyType == typeof(TPropertyValue));

        Finder = ValueSetter.CreateSetter<TTargetObject, TTargetValue>(propertyInfos,
            ValueSetter.CreateSetterCase<TTargetObject, TTargetValue>);
    }

    public static Action<TTargetObject, TTargetValue> GetSetter(PropertyInfo info)
    {
        return Finder.Invoke(info);
    }
}

public static class ValueSetter<TTargetObject>
{
    private static readonly Func<PropertyInfo, Action<TTargetObject, object>> Finder;

    static ValueSetter()
    {
        var propertyInfos = typeof(TTargetObject).GetRuntimeProperties()
            .Where(x => x.CanWrite);

        Finder = ValueSetter.CreateSetter<TTargetObject, object>(propertyInfos,
            ValueSetter.CreateSetterCase<TTargetObject, object>);
    }

    public static Action<TTargetObject, object> GetSetter(PropertyInfo info)
    {
        return Finder.Invoke(info);
    }
}
public class Cl
{
    public string Name { get; set; }
    public string Test1 { get; set; }
    public DateTime Now { get; set; }
    public int Age { get; set; } 
    public bool Sex { get; set; }
    public double Animo { get; set; }

}

static void Main(string[] args)
{
    //ConstantExpression _constExp = Expression.Constant("aaa", typeof(string));//一个常量
    //MethodCallExpression _methodCallexp = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), _constExp);
    //Expression<Action> consoleLambdaExp = Expression.Lambda<Action>(_methodCallexp);
    //consoleLambdaExp.Compile()();

    var cl = new Cl();
    var _nameProperty = typeof(Cl).GetProperty(nameof(Cl.Name))!;
    var _ageProperty = typeof(Cl).GetProperty(nameof(Cl.Age))!;
    var _nameFunc = ValueSetter<Cl, string, string>.GetSetter(_nameProperty);
    ValueSetter<Cl, int, int>.GetSetter(_ageProperty).Invoke(cl, 16);
    ValueSetter<Cl>.GetSetter(_nameProperty).Invoke(cl, "dalao");

    cl.Name = "dalao";
    cl.Age = 16;
    _nameProperty.SetValue(cl, "dalao1");
    _ageProperty.SetValue(cl, 17);
    ValueSetter<Cl, string, string>.GetSetter(_nameProperty).Invoke(cl, "dalao2");
    ValueSetter<Cl, int, int>.GetSetter(_ageProperty).Invoke(cl, 18);
    ValueSetter<Cl>.GetSetter(_nameProperty).Invoke(cl, "dalao3");
    _nameFunc.Invoke(cl, "dalao4");

    var t1 = ValueGetter<Cl, int, int>.GetGetter(_ageProperty).Invoke(cl);
    var t2 = ValueGetter<Cl, string, string>.GetGetter(_nameProperty).Invoke(cl);
    var name = (string)_nameProperty.GetValue(cl);
    var age = (int)_ageProperty.GetValue(cl);
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值