using System.Linq.Expressions; namespace JNPF.Common.Extension { public static class LambdaExpressionExtensions { public static void PropertySetValue(this T instance, string propertyName, string value) { if (!PropertySet.ValueFactories.TryGetValue(propertyName, out Action setAction)) { setAction = PropertySet.CreateSetPropertyValueAction(propertyName); PropertySet.ValueFactories.Add(propertyName, setAction); } setAction(instance, value); } public static void PropertySetValue(this T instance, string propertyName, object value) { if (!PropertySet.ValueFactories2.TryGetValue(propertyName, out Action setAction)) { setAction = PropertySet.CreateSetPropertyValueAction2(propertyName); PropertySet.ValueFactories2.Add(propertyName, setAction); } setAction(instance, value); } public static object GetPropertyValue(this T obj, string propertyName) { if (!ProperyGet.ValueFactories.TryGetValue(propertyName, out var getDateValue)) { getDateValue = ProperyGet.PropertyGetValue(propertyName); ProperyGet.ValueFactories.Add(propertyName, getDateValue); } return getDateValue(obj); } /// /// Lambda表达式拼接 /// /// /// /// /// /// public static Expression> Compose(this Expression> first, Expression> second, Func merge) { // build parameter map (from parameters of second to parameters of first) var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); // replace parameters in the second lambda expression with parameters from the first var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); // apply composition of lambda expression bodies to parameters from the first expression return Expression.Lambda>(merge(first.Body, secondBody), first.Parameters); } /// /// and扩展 /// /// /// /// /// public static Expression> And(this Expression> first, Expression> second) { if (first.IsNull()) { first = second; return first; } return first.Compose(second, Expression.And); } /// /// or扩展 /// /// /// /// /// public static Expression> Or(this Expression> first, Expression> second) { if (first.IsNull()) { first = second; return first; } return first.Compose(second, Expression.Or); } } public class ParameterRebinder : ExpressionVisitor { private readonly Dictionary map; /// /// /// /// public ParameterRebinder(Dictionary map) { this.map = map ?? new Dictionary(); } /// /// /// /// /// /// public static Expression ReplaceParameters(Dictionary map, Expression exp) { return new ParameterRebinder(map).Visit(exp); } /// /// /// /// /// protected override Expression VisitParameter(ParameterExpression p) { ParameterExpression replacement; if (map.TryGetValue(p, out replacement)) { p = replacement; } return base.VisitParameter(p); } } public class PropertySet { public static Dictionary> ValueFactories = new Dictionary>(StringComparer.OrdinalIgnoreCase); public static Dictionary> ValueFactories2 = new Dictionary>(StringComparer.OrdinalIgnoreCase); public static Action CreateSetPropertyValueAction(string propertyName) { var property = typeof(T).GetProperty(propertyName); var target = Expression.Parameter(typeof(object)); var propertyValue = Expression.Parameter(typeof(object)); var castTarget = Expression.Convert(target, typeof(T)); var castPropertyValue = Expression.Convert(propertyValue, property!.PropertyType); var setPropertyValue = Expression.Call(castTarget, property.GetSetMethod()!, castPropertyValue); return Expression.Lambda>(setPropertyValue, target, propertyValue).Compile(); } public static Action CreateSetPropertyValueAction2(string propertyName) { var property = typeof(T).GetProperty(propertyName); var target = Expression.Parameter(typeof(T)); var propExp = Expression.Property(target, propertyName); var propertyValue = Expression.Parameter(typeof(object)); var castPropertyValue = Expression.Convert(propertyValue, property!.PropertyType); var assignExp = Expression.Assign(propExp, castPropertyValue); return Expression.Lambda>(assignExp, new[] { target, propertyValue }).Compile(); } } public class ProperyGet //where T : class, new() { public static Dictionary> ValueFactories = new Dictionary>(StringComparer.OrdinalIgnoreCase); public static Func PropertyGetValue(string name) { var parameterExp = Expression.Parameter(typeof(T), "entity"); var propertyExp = Expression.Property(parameterExp, name); var castExp = Expression.Convert(propertyExp, typeof(object)); var lambda = Expression.Lambda>(castExp, parameterExp); return lambda.Compile(); } } }