using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq.Expressions; using System.Reflection.Emit; using System.Runtime.CompilerServices; using JetBrains.Annotations; namespace IwbZero.ToolCommon.Lambda { // Codes below are taken from https://github.com/scottksmith95/LINQKit project. /// 运算符 public enum PredicateOperator { /// The "Or" Or, /// The "And" And } /// /// See http://www.albahari.com/expressions for information and examples. /// public static class LambdaBuilder { private class RebindParameterVisitor : ExpressionVisitor { private readonly ParameterExpression _oldParameter; private readonly ParameterExpression _newParameter; public RebindParameterVisitor(ParameterExpression oldParameter, ParameterExpression newParameter) { _oldParameter = oldParameter; _newParameter = newParameter; } protected override Expression VisitParameter(ParameterExpression node) { if (node == _oldParameter) { return _newParameter; } return base.VisitParameter(node); } } /// 启动表达式 public static ExpressionStarter New(Expression> expr = null) { return new ExpressionStarter(expr); } /// 使用存根表达式true或false创建表达式,以便在表达式尚未启动时使用。 public static ExpressionStarter New(bool defaultExpression) { return new ExpressionStarter(defaultExpression); } /// Always true [Obsolete("Use PredicateBuilder.New() instead.")] public static Expression> True() { return new ExpressionStarter(true); } /// Always false [Obsolete("Use PredicateBuilder.New() instead.")] public static Expression> False() { return new ExpressionStarter(false); } /// OR public static Expression> Or([NotNull] this Expression> expr1, [NotNull] Expression> expr2) { var expr2Body = new RebindParameterVisitor(expr2.Parameters[0], expr1.Parameters[0]).Visit(expr2.Body); return Expression.Lambda>(Expression.OrElse(expr1.Body, expr2Body), expr1.Parameters); } /// AND public static Expression> And([NotNull] this Expression> expr1, [NotNull] Expression> expr2) { var expr2Body = new RebindParameterVisitor(expr2.Parameters[0], expr1.Parameters[0]).Visit(expr2.Body); return Expression.Lambda>(Expression.AndAlso(expr1.Body, expr2Body), expr1.Parameters); } /// ///用指定的运算符扩展表达式。 /// /// The type /// The source Predicate. /// The second Predicate. /// The Operator (can be "And" or "Or"). /// Expression{Func{T, bool}} public static Expression> Extend([NotNull] this Expression> first, [NotNull] Expression> second, PredicateOperator @operator = PredicateOperator.Or) { return @operator == PredicateOperator.Or ? first.Or(second) : first.And(second); } /// /// 用指定的运算符扩展表达式。 /// /// The type /// The source Predicate. /// The second Predicate. /// The Operator (can be "And" or "Or"). /// Expression{Func{T, bool}} public static Expression> Extend([NotNull] this ExpressionStarter first, [NotNull] Expression> second, PredicateOperator @operator = PredicateOperator.Or) { return @operator == PredicateOperator.Or ? first.Or(second) : first.And(second); } } /// /// ExpressionStarter{T} 它消除了默认的1=0或1=1存根表达式 /// /// The type public class ExpressionStarter { internal ExpressionStarter() : this(false) { } internal ExpressionStarter(bool defaultExpression) { if (defaultExpression) DefaultExpression = f => true; else DefaultExpression = f => false; } internal ExpressionStarter(Expression> exp) : this(false) { _predicate = exp; } /// 实际谓词。只能通过调用Start来设置。 private Expression> Predicate => (IsStarted || !UseDefaultExpression) ? _predicate : DefaultExpression; private Expression> _predicate; /// 确定谓词是否已启动。 public bool IsStarted => _predicate != null; /// 仅当表达式为空时使用的默认表达式 public bool UseDefaultExpression => DefaultExpression != null; /// 默认表达式 public Expression> DefaultExpression { get; set; } /// 设置表达式谓词 /// The first expression public Expression> Start(Expression> exp) { if (IsStarted) throw new Exception("Predicate cannot be started again."); return _predicate = exp; } /// Or public Expression> Or([NotNull] Expression> expr2) { return (IsStarted) ? _predicate = Predicate.Or(expr2) : Start(expr2); } /// And public Expression> And([NotNull] Expression> expr2) { return (IsStarted) ? _predicate = Predicate.And(expr2) : Start(expr2); } /// Show predicate string public override string ToString() { return Predicate?.ToString() ?? throw new InvalidOperationException(); } #region Implicit Operators /// /// Allows this object to be implicitely converted to an Expression{Func{T, bool}}. /// /// public static implicit operator Expression>(ExpressionStarter right) { return right == null ? null : right.Predicate; } /// /// Allows this object to be implicitely converted to an Expression{Func{T, bool}}. /// /// public static implicit operator Func(ExpressionStarter right) { return right == null ? null : (right.IsStarted || right.UseDefaultExpression) ? right.Predicate.Compile() : null; } /// /// Allows this object to be implicitely converted to an Expression{Func{T, bool}}. /// /// public static implicit operator ExpressionStarter(Expression> right) { return right == null ? null : new ExpressionStarter(right); } #endregion Implicit Operators #region Implement Expression methods and properties #if !(NET35) /// public Func Compile() { return Predicate.Compile(); } #endif #if !(NET35 || WINDOWS_APP || NETSTANDARD || PORTABLE || PORTABLE40 || UAP) /// public Func Compile(DebugInfoGenerator debugInfoGenerator) { return Predicate.Compile(debugInfoGenerator); } /// public Expression> Update(Expression body, IEnumerable parameters) { return Predicate.Update(body, parameters); } #endif #endregion Implement Expression methods and properties #region Implement LamdaExpression methods and properties /// public Expression Body => Predicate.Body; /// public ExpressionType NodeType => Predicate.NodeType; /// public ReadOnlyCollection Parameters => Predicate.Parameters; /// public Type Type => Predicate.Type; #if !(NET35) /// public string Name => Predicate.Name; /// public Type ReturnType => Predicate.ReturnType; /// public bool TailCall => Predicate.TailCall; #endif #if !(NET35 || WINDOWS_APP || NETSTANDARD || PORTABLE || PORTABLE40 || UAP) /// public void CompileToMethod(MethodBuilder method) { Predicate.CompileToMethod(method); } /// public void CompileToMethod(MethodBuilder method, DebugInfoGenerator debugInfoGenerator) { Predicate.CompileToMethod(method, debugInfoGenerator); } #endif #endregion Implement LamdaExpression methods and properties #region Implement Expression methods and properties #if !(NET35) /// public virtual bool CanReduce => Predicate.CanReduce; #endif #endregion Implement Expression methods and properties } }