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;
}
}
}