-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExpressionExtension.cs
138 lines (102 loc) · 4.18 KB
/
ExpressionExtension.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System.Linq.Expressions;
using System.Reflection;
namespace Netcorext.Extensions.Linq;
public static class ExpressionExtension
{
public static Expression<Func<TSource, bool>> And<TSource>(this Expression<Func<TSource, bool>> expr1, Expression<Func<TSource, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<TSource, bool>>(Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<TSource, bool>> Or<TSource>(this Expression<Func<TSource, bool>> expr1, Expression<Func<TSource, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<TSource, bool>>(Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<TDestination, bool>> Convert<TDestination>(this Expression source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
var param = Expression.Parameter(typeof(TDestination), "z");
var result = source switch
{
LambdaExpression exp => new ConvertExpressionVisitor<TDestination>(param).Visit(exp.Body),
_ => new ConvertExpressionVisitor<TDestination>(param).Visit(source)
};
if (result == null)
throw new ArgumentNullException(nameof(result));
var lambda = Expression.Lambda<Func<TDestination, bool>>(result, new[] { param });
return lambda;
}
private static Expression Replace(this Expression expression, Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
}
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression _from, _to;
public ReplaceVisitor(Expression from, Expression to)
{
_from = from;
_to = to;
}
public override Expression Visit(Expression node)
{
return node == _from ? _to : base.Visit(node);
}
}
internal class ConvertExpressionVisitor<T> : ExpressionVisitor
{
private readonly ParameterExpression _param;
public ConvertExpressionVisitor(ParameterExpression param)
{
_param = param;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return _param;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType != MemberTypes.Property) return base.VisitMember(node);
MemberExpression memberExpression = null;
var memberName = node.Member.Name;
var otherMember = typeof(T).GetProperty(memberName);
if (otherMember == null) return Expression.Constant(true);
var exp = Visit(node.Expression);
memberExpression = Expression.Property(exp, otherMember);
return memberExpression;
}
protected override Expression VisitBinary(BinaryExpression node)
{
if (node.NodeType != ExpressionType.Equal)
{
var expression = base.VisitBinary(node);
if (!(expression is BinaryExpression exp))
{
return expression;
}
if (exp.Left.NodeType == ExpressionType.Constant && exp.Right.NodeType == ExpressionType.Constant)
return expression;
return exp.Left.NodeType == ExpressionType.Constant ? exp.Right : exp.Left;
}
var type = typeof(T);
foreach (var child in new[] { node.Left, node.Right })
{
switch (child)
{
case MemberExpression exp:
if (!type.GetMember(exp.Member.Name).Any())
return Expression.Constant(true);
break;
case UnaryExpression exp:
var memExp = exp.Operand as MemberExpression;
if (memExp == null || !type.GetMember(memExp.Member.Name).Any())
return Expression.Constant(true);
break;
}
}
return base.VisitBinary(node);
}
}