LinqExpressionLearn\Linq\ParameterRebinder.cs
| |
| using System.Linq.Expressions; |
| |
| |
| |
| |
| public class ParameterRebinder : ExpressionVisitor |
| { |
| |
| |
| |
| private readonly Dictionary<ParameterExpression, ParameterExpression> map; |
| |
| public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) |
| { |
| this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); |
| } |
| |
| |
| |
| |
| |
| |
| |
| public static Expression ReplaceParameters( |
| Dictionary<ParameterExpression, ParameterExpression> map, |
| Expression exp |
| ) |
| { |
| return new ParameterRebinder(map).Visit(exp); |
| } |
| |
| |
| |
| |
| |
| |
| 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; |
| |
| |
| |
| |
| public static class PredicateBuilder |
| { |
| |
| |
| |
| |
| |
| public static Expression<Func<T, bool>> True<T>() |
| { |
| return f => true; |
| } |
| |
| |
| |
| |
| |
| |
| public static Expression<Func<T, bool>> False<T>() |
| { |
| return f => false; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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); |
| |
| |
| var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); |
| |
| |
| return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| 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); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| 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); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| 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); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| 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
| |
| |
| |
| |
| public enum TodoStatus |
| { |
| |
| |
| |
| Pending, |
| |
| |
| |
| |
| 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; |
| |
| |
| |
| |
| |
| public interface ISpecification<T> |
| { |
| |
| |
| |
| |
| |
| bool IsSatisfiedBy(T obj); |
| |
| |
| |
| |
| |
| 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 } |
| }; |
| |
| |
| 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; |
| |
| |
| |
| |
| |
| |
| public abstract class Specification<T> : ISpecification<T> |
| { |
| |
| |
| |
| |
| |
| public virtual bool IsSatisfiedBy(T obj) |
| { |
| return ToExpression().Compile()(obj); |
| } |
| |
| |
| |
| |
| |
| public abstract Expression<Func<T, bool>> ToExpression(); |
| |
| |
| |
| |
| |
| 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; |
| } |
| } |
| |
| |
| |
| 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; |
| } |
| } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战