You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
crop/SlnMesnac.Common/ExpressionExtensions.cs

174 lines
6.8 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Linq;
using System.Text;
#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
* 版权所有 (c) 2024 WenJY 保留所有权利。
* CLR版本4.0.30319.42000
* 机器名称LAPTOP-E0N2L34V
* 命名空间SlnMesnac.Common
* 唯一标识496f8d2b-70e3-4a05-ae18-a9b0fcd06b82
*
* 创建者WenJY
* 电子邮箱wenjy@mesnac.com
* 创建时间2024-03-27 21:58:35
* 版本V1.0.0
* 描述:
*
*--------------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本V1.0.0
*--------------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
namespace SlnMesnac.Common
{
/// <summary>
/// 谓词表达式构建器
/// </summary>
public static class ExpressionExtensions
{
/// <summary>
/// 创建一个值恒为 <c>true</c> 的表达式。
/// </summary>
/// <typeparam name="T">表达式方法类型</typeparam>
/// <returns>一个值恒为 <c>true</c> 的表达式。</returns>
public static Expression<Func<T, bool>> True<T>() { return p => true; }
/// <summary>
/// 创建一个值恒为 <c>false</c> 的表达式。
/// </summary>
/// <typeparam name="T">表达式方法类型</typeparam>
/// <returns>一个值恒为 <c>false</c> 的表达式。</returns>
public static Expression<Func<T, bool>> False<T>() { return f => false; }
/// <summary>
/// 使用 Expression.OrElse 的方式拼接两个 System.Linq.Expression。
/// </summary>
/// <typeparam name="T">表达式方法类型</typeparam>
/// <param name="left">左边的 System.Linq.Expression 。</param>
/// <param name="right">右边的 System.Linq.Expression。</param>
/// <returns>拼接完成的 System.Linq.Expression。</returns>
public static Expression<T> Or<T>(this Expression<T> left, Expression<T> right)
{
return MakeBinary(left, right, Expression.OrElse);
}
/// <summary>
/// 使用 Expression.AndAlso 的方式拼接两个 System.Linq.Expression。
/// </summary>
/// <typeparam name="T">表达式方法类型</typeparam>
/// <param name="left">左边的 System.Linq.Expression 。</param>
/// <param name="right">右边的 System.Linq.Expression。</param>
/// <returns>拼接完成的 System.Linq.Expression。</returns>
public static Expression<T> And<T>(this Expression<T> left, Expression<T> right)
{
return MakeBinary(left, right, Expression.AndAlso);
}
/// <summary>
/// 使用自定义的方式拼接两个 System.Linq.Expression。
/// </summary>
/// <typeparam name="T">表达式方法类型</typeparam>
/// <param name="left">左边的 System.Linq.Expression 。</param>
/// <param name="right">右边的 System.Linq.Expression。</param>
/// <param name="func"> </param>
/// <returns>拼接完成的 System.Linq.Expression。</returns>
private static Expression<T> MakeBinary<T>(this Expression<T> left, Expression<T> right, Func<Expression, Expression, Expression> func)
{
return MakeBinary((LambdaExpression)left, right, func) as Expression<T>;
}
/// <summary>
/// 拼接两个 <paramref>
/// <name>System.Linq.Expression</name>
/// </paramref> ,两个 <paramref>
/// <name>System.Linq.Expression</name>
/// </paramref> 的参数必须完全相同。
/// </summary>
/// <param name="left">左边的 <paramref>
/// <name>System.Linq.Expression</name>
/// </paramref> </param>
/// <param name="right">右边的 <paramref>
/// <name>System.Linq.Expression</name>
/// </paramref> </param>
/// <param name="func">表达式拼接的具体逻辑</param>
/// <returns>拼接完成的 <paramref>
/// <name>System.Linq.Expression</name>
/// </paramref> </returns>
private static LambdaExpression MakeBinary(this LambdaExpression left, LambdaExpression right, Func<Expression, Expression, Expression> func)
{
var data = Combinate(right.Parameters, left.Parameters).ToArray();
right = ParameterReplace.Replace(right, data) as LambdaExpression;
return Expression.Lambda(func(left.Body, right.Body), left.Parameters.ToArray());
}
/// <summary>
/// 合并参数
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
private static IEnumerable<KeyValuePair<T, T>> Combinate<T>(IEnumerable<T> left, IEnumerable<T> right)
{
var a = left.GetEnumerator();
var b = right.GetEnumerator();
while (a.MoveNext() && b.MoveNext())
yield return new KeyValuePair<T, T>(a.Current, b.Current);
}
}
internal sealed class ParameterReplace : ExpressionVisitor
{
public static Expression Replace(Expression e, IEnumerable<KeyValuePair<ParameterExpression, ParameterExpression>> paramList)
{
var item = new ParameterReplace(paramList);
return item.Visit(e);
}
private readonly Dictionary<ParameterExpression, ParameterExpression> _parameters;
public ParameterReplace(IEnumerable<KeyValuePair<ParameterExpression, ParameterExpression>> paramList)
{
_parameters = paramList.ToDictionary(p => p.Key, p => p.Value, new ParameterEquality());
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression result;
if (_parameters.TryGetValue(p, out result))
return result;
return base.VisitParameter(p);
}
#region class: ParameterEquality
private class ParameterEquality : IEqualityComparer<ParameterExpression>
{
public bool Equals(ParameterExpression x, ParameterExpression y)
{
if (x == null || y == null)
return false;
return x.Type == y.Type;
}
public int GetHashCode(ParameterExpression obj)
{
if (obj == null)
return 0;
return obj.Type.GetHashCode();
}
}
#endregion
}
}