Net Core 一个简单的封装,缓存表达式树去生成反射的调用

namespace LuciusLiang.Common
{
    /// <summary>
    /// 自定义表达式构建
    /// </summary>
    public class CustomExpressionBuilder
    {
        /// <summary>
        /// 内置缓存
        /// </summary>
        private static IMemoryCache _memoryCache = new MemoryCache(new MemoryCacheOptions());

        /// <summary>
        /// 构建获取 TAttributeType 特性委托
        /// </summary>
        /// <typeparam name="TAttributeType">需要获取的 Attribute 类型</typeparam>
        /// <returns></returns>
        public static Func<MemberInfo, TAttributeType> BuildGetAttribute<TAttributeType>() where TAttributeType : Attribute
        {
            var cacheName = "GetAttribute_" + typeof(TAttributeType).Name;

            if (_memoryCache.TryGetValue(cacheName, out Func<MemberInfo, TAttributeType> funcCallMethod)) 
            {
                return funcCallMethod;
            }

            var methodInfo = typeof(CustomAttributeExtensions).GetMethod(nameof(CustomAttributeExtensions.GetCustomAttribute), new[] { typeof(MemberInfo) });

            funcCallMethod = BuildCallStaticMethod<Func<MemberInfo, TAttributeType>>(methodInfo, new Type[] { typeof(TAttributeType) });

            _memoryCache.Set(cacheName, funcCallMethod);

            return funcCallMethod;
        }

        /// <summary>
        /// 构建调用泛型函数委托
        /// </summary>
        /// <typeparam name="TCallMethodDelegateType">构建的委托类型</typeparam>
        /// <param name="methodInfo">调用的方法 MethodInfo</param>
        /// <param name="genericMethodArgments">泛型函数参数</param>
        /// <returns></returns>
        public static TCallMethodDelegateType BuildCallStaticMethod<TCallMethodDelegateType>(MethodInfo methodInfo, Type[] genericMethodArgments = null) where TCallMethodDelegateType : Delegate
        {
            var cacheName = $"{ methodInfo.DeclaringType.Name }_StaticMethod_{ methodInfo.Name }";

            if (_memoryCache.TryGetValue(cacheName, out TCallMethodDelegateType funcCallMethod)) 
            {
                return funcCallMethod;
            }

            if (methodInfo.IsGenericMethod) 
            {
                methodInfo = methodInfo.MakeGenericMethod(genericMethodArgments);
            }

            var methodParamsExpression = methodInfo.GetParameters().Select(t => { return Expression.Parameter(t.ParameterType, t.Name); }).ToList();

            var methodCallExpression = Expression.Call(methodInfo, methodParamsExpression);

            funcCallMethod = Expression.Lambda<TCallMethodDelegateType>(methodCallExpression, methodParamsExpression).Compile();

            _memoryCache.Set(cacheName, funcCallMethod);

            return funcCallMethod;
        }

        /// <summary>
        /// 构建目标类型的函数调用委托
        /// 委托参数顺序:
        /// <para>第一个(必须): TSource 类型 </para>
        /// <para>第二个(可选,可多个,如果函数没有参数就没有):调用函数型数类型 </para>
        /// <para>最后一个是返回参数类型:(可选,如果返回为Void)</para>
        /// </summary>
        /// <typeparam name="TSource">调用函数的所属类类型</typeparam>
        /// <typeparam name="TCallMethodDelegateType">生成的委托类型</typeparam>
        /// <param name="methodInfo">调用的函数 MethodInfo 信息</param>
        /// <returns></returns>
        public static TCallMethodDelegateType BuildTypeCallMethod<TSource, TCallMethodDelegateType>(MethodInfo methodInfo) 
            where TCallMethodDelegateType : Delegate
            where TSource : class
        {
            var cacheName = $"{typeof(TSource).Name}_Method_{methodInfo.Name}";

            if (_memoryCache.TryGetValue(cacheName, out TCallMethodDelegateType funcCallMethod)) 
            {
                return funcCallMethod;
            }

            var sourceTypeExpression = Expression.Parameter(typeof(TSource), typeof(TSource).Name);

            var methodParamsExpression = methodInfo.GetParameters().Select(t => { return Expression.Parameter(t.ParameterType, t.Name); }).ToList();

            var methodCallExpression = Expression.Call(sourceTypeExpression, methodInfo, methodParamsExpression);

            // 将实例类型插入到第一个位置
            methodParamsExpression.Insert(0, sourceTypeExpression);

            funcCallMethod = Expression.Lambda<TCallMethodDelegateType>(methodCallExpression, methodParamsExpression).Compile();

            _memoryCache.Set(cacheName, funcCallMethod);

            return funcCallMethod;
        }

        /// <summary>
        /// 构建 GetProperty 的委托
        /// </summary>
        /// <typeparam name="TSource">属性所属类类型</typeparam>
        /// <typeparam name="TPropertyType">属性类型</typeparam>
        /// <param name="propertyName">属性名称</param>
        /// <returns></returns>
        public static Func<TSource, TPropertyType> BuildGetProperty<TSource, TPropertyType>(string propertyName) where TSource : class
        {
            var cacheName = $"{typeof(TSource).Name}_GetProperty_{propertyName}";

            if (_memoryCache.TryGetValue(cacheName, out Func<TSource, TPropertyType> funcGetProperty)) 
            {
                return funcGetProperty;
            }

            var sourceTypeExpression = Expression.Parameter(typeof(TSource));

            var getPropertyExpression = Expression.Property(sourceTypeExpression, propertyName);

            funcGetProperty = Expression.Lambda<Func<TSource, TPropertyType>>(getPropertyExpression, sourceTypeExpression).Compile();

            _memoryCache.Set(cacheName, funcGetProperty);

            return funcGetProperty;
        }

        /// <summary>
        /// 构建 SetProperty 的委托
        /// </summary>
        /// <typeparam name="TSource">属性所属类类型</typeparam>
        /// <typeparam name="TPropertyType">属性类型</typeparam>
        /// <param name="propertyName">属性名称</param>
        /// <returns></returns>
        public static Action<TSource, TPropertyType> BuildSetProperty<TSource, TPropertyType>(string propertyName) where TSource : class
        {
            var cacheName = $"{typeof(TSource).Name}_SetProperty_{propertyName}";

            if (_memoryCache.TryGetValue(cacheName, out Action<TSource, TPropertyType> actionSetMethod))
            {
                return actionSetMethod;
            }

            var methodInfo = typeof(TSource).GetProperty(propertyName).SetMethod;

            actionSetMethod = BuildTypeCallMethod<TSource, Action<TSource, TPropertyType>>(methodInfo);

            _memoryCache.Set(cacheName, actionSetMethod);

            return actionSetMethod;
        }

    }
}

 

posted @ 2021-02-02 22:46  一直踩坑的码农  阅读(171)  评论(0编辑  收藏  举报