怪奇物语

怪奇物语

首页 新随笔 联系 管理

LinqExpressionLearn\Linq\ParameterRebinder.cs


using System.Linq.Expressions;

/// <summary>
/// 表达式参数
/// </summary>
public class ParameterRebinder : ExpressionVisitor
{
    /// <summary>
    /// 参数字典
    /// </summary>
    private readonly Dictionary<ParameterExpression, ParameterExpression> map;

    public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
    {
        this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
    }

    /// <summary>
    /// 参数替换
    /// </summary>
    /// <param name="map"></param>
    /// <param name="exp"></param>
    /// <returns></returns>
    public static Expression ReplaceParameters(
        Dictionary<ParameterExpression, ParameterExpression> map,
        Expression exp
    )
    {
        return new ParameterRebinder(map).Visit(exp);
    }

    /// <summary>
    /// 表达式转换
    /// </summary>
    /// <param name="p"></param>
    /// <returns></returns>
    protected override Expression VisitParameter(ParameterExpression p)
    {
        if (map.TryGetValue(p, out ParameterExpression replacement))
        {
            p = replacement;
        }
        return base.VisitParameter(p);
    }
}

LinqExpressionLearn\Linq\PredicateBuilder.cs


using System.Linq.Expressions;

/// <summary>
/// Linq动态拼接
/// </summary>
public static class PredicateBuilder
{
    /// <summary>
    /// True表达式
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static Expression<Func<T, bool>> True<T>()
    {
        return f => true;
    }

    /// <summary>
    /// False表达式
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static Expression<Func<T, bool>> False<T>()
    {
        return f => false;
    }

    /// <summary>
    /// 表达式拼接
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="first"></param>
    /// <param name="second"></param>
    /// <param name="merge"></param>
    /// <returns></returns>
    public static Expression<T> Compose<T>(
        this Expression<T> first,
        Expression<T> second,
        Func<Expression, Expression, Expression> merge
    )
    {
        // 构建参数映射(从第二个参数到第一个参数)
        var map = first
            .Parameters.Select((f, i) => new { f, s = second.Parameters[i] })
            .ToDictionary(p => p.s, p => p.f);

        // 将第二个lambda表达式中的参数替换为第一个lambda中的参数
        var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

        // 将lambda表达式体的组合应用于第一个表达式中的参数
        return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
    }

    /// <summary>
    /// 表达式And拼接
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="first"></param>
    /// <param name="second"></param>
    /// <returns></returns>
    public static Expression<Func<T, bool>> And<T>(
        this Expression<Func<T, bool>> first,
        Expression<Func<T, bool>> second
    )
    {
        return first.Compose(second, Expression.And);
    }

    /// <summary>
    /// 表达式AndAlso拼接
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="first"></param>
    /// <param name="second"></param>
    /// <returns></returns>
    public static Expression<Func<T, bool>> AndAlso<T>(
        this Expression<Func<T, bool>> first,
        Expression<Func<T, bool>> second
    )
    {
        return first.Compose(second, Expression.AndAlso);
    }

    /// <summary>
    /// 表达式Or拼接
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="first"></param>
    /// <param name="second"></param>
    /// <returns></returns>
    public static Expression<Func<T, bool>> Or<T>(
        this Expression<Func<T, bool>> first,
        Expression<Func<T, bool>> second
    )
    {
        return first.Compose(second, Expression.Or);
    }

    /// <summary>
    /// 表达式OrElse拼接
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="first"></param>
    /// <param name="second"></param>
    /// <returns></returns>
    public static Expression<Func<T, bool>> OrElse<T>(
        this Expression<Func<T, bool>> first,
        Expression<Func<T, bool>> second
    )
    {
        return first.Compose(second, Expression.OrElse);
    }
}

LinqExpressionLearn\EleTodo.cs


/// <summary>
/// todo状态
/// </summary>
public enum TodoStatus
{
    /// <summary>
    /// 未做
    /// </summary>
    Pending,

    /// <summary>
    /// 已做
    /// </summary>
    Completed,
}

public class EleTodo
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Remark { get; set; }
    public TodoStatus Status { get; set; }
}

LinqExpressionLearn\global.json


{
  "sdk": {
    "version": "8.0.300"
  }
}

LinqExpressionLearn\ISpecification.cs


using System.Linq.Expressions;

/// <summary>
/// 规约接口
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ISpecification<T>
{
    /// <summary>
    /// 用来验证模型是否满足规约要求
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    bool IsSatisfiedBy(T obj);

    /// <summary>
    /// 获取表示当前规约的LINQ表达式。
    /// </summary>
    /// <returns></returns>
    Expression<Func<T, bool>> ToExpression();
}

LinqExpressionLearn\LinqExpressionLearn.csproj


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

LinqExpressionLearn\LinqExpressionLearn.sln

LinqExpressionLearn\Program.cs


class Program
{
    static void Main(string[] args)
    {
        // 创建一些示例待办事项
        var todos = new List<EleTodo>
        {
            new EleTodo { Id = Guid.NewGuid(), Name = "买牛奶", Remark = "超市", Status = TodoStatus.Pending },
            new EleTodo { Id = Guid.NewGuid(), Name = "买面包", Remark = "便利店", Status = TodoStatus.Completed },
            new EleTodo { Id = Guid.NewGuid(), Name = "买鸡蛋", Remark = "超市", Status = TodoStatus.Pending },
            new EleTodo { Id = Guid.NewGuid(), Name = "买面包", Remark = "超市", Status = TodoStatus.Pending }
        };

        // 创建 TodoAppService 实例
        var todoAppService = new TodoAppService(todos.AsEnumerable());

        // 使用规约来过滤待办事项
        var filteredTodos = todoAppService.FilterTodos("买面包");

        // 输出过滤后的待办事项
        foreach (var todo in filteredTodos)
        {
            Console.WriteLine($"ID: {todo.Id}, Name: {todo.Name}, Remark: {todo.Remark}, Status: {todo.Status}");
        }
    }
}





LinqExpressionLearn\Specification.cs


using System.Linq.Expressions;


/// <summary>
/// 规约
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class Specification<T> : ISpecification<T>
{
    /// <summary>
    /// 用来验证模型是否满足规约要求
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public virtual bool IsSatisfiedBy(T obj)
    {
        return ToExpression().Compile()(obj);
    }

    /// <summary>
    /// 获取表示当前规范的LINQ表达式
    /// </summary>
    /// <returns></returns>
    public abstract Expression<Func<T, bool>> ToExpression();

    /// <summary>
    /// 将规范隐式转换为表达式。
    /// </summary>
    /// <param name="specification"></param>
    public static implicit operator Expression<Func<T, bool>>(Specification<T> specification)
    {
        return specification.ToExpression();
    }
}

LinqExpressionLearn\TodoAppService.cs



public class TodoAppService
{
    private readonly IEnumerable<EleTodo> _todos;

    public TodoAppService(IEnumerable<EleTodo> todos)
    {
        _todos = todos;
    }

    public IEnumerable<EleTodo> FilterTodos(string? name, string? remark = null, TodoStatus? status =null)
    {
        var specification = new TodoNameRemarkStatusFiltereSpecification(name, remark, status);
        var filteredTodos = _todos.Where(specification.ToExpression().Compile()).ToList();
        return filteredTodos;
    }
}


LinqExpressionLearn\TodoNameRemarkStatusFiltereSpecification.cs


using System.Linq.Expressions;



public class TodoNameRemarkStatusFiltereSpecification : Specification<EleTodo>
{
    private string? _name;
    private string? _remark;
    private TodoStatus? _status;

    public TodoNameRemarkStatusFiltereSpecification(string? name, string? remark, TodoStatus? status)
    {
        _name = name;
        _remark = remark;
        _status = status;
    }

    public override Expression<Func<EleTodo, bool>> ToExpression()
    {
        Expression<Func<EleTodo, bool>> filter = PredicateBuilder.True<EleTodo>();

        if (!string.IsNullOrEmpty(_name))
        {
            filter = filter.Compose(x => x.Name.Contains(_name), Expression.AndAlso);
        }

        if (!string.IsNullOrEmpty(_name) && !string.IsNullOrEmpty(_remark))
        {
            filter = filter.Compose(x => x.Name.Contains(_name) && (x.Remark == null ? false : x.Remark.Contains(_remark)), Expression.AndAlso);
        }

        if (!string.IsNullOrEmpty(_name) && !string.IsNullOrEmpty(_remark) && _status != null)
        {
            filter = filter.Compose(
                x => x.Name.Contains(_name) && (x.Remark == null ? false : x.Remark.Contains(_remark)) && x.Status == _status,
                Expression.AndAlso
            );
        }

        return filter;
    }
}
posted on 2024-08-18 17:12  超级无敌美少男战士  阅读(15)  评论(0)    收藏  举报