Dynamic If Statement - Complex Filtering - c#

I have a C# project that allows users to create filters on data using Regular Expressions. They can add as many filters as they want. Each filter consists of a Field and a regular expression that the user types in.
Right now it works with all AND logic. I loop through each filter and if it doesn't match I set skip = true and break out of the loop. Then if skip == true I skip that record and don't include it. So each and every filter must match in order for the field to be included.
However, now they want the ability to add more complex logic rules. So for example if they have created 4 filter rules. They want to be able to specify:
1 AND 2 AND (3 OR 4)
or they may want to specify
1 OR 2 OR 3 OR 4
or they may want to specify
(1 AND 2 AND 3) OR 4
and so on...I think you get the point.
I have added a textbox where they can type in the logic that they want.
I have been racking my brain and I am stumped on how to make this work. My only conclusion is to somehow be able to create a dynamic IF statement that is based on the text they type into the textbox but I don't know if that is even possible.
It seems like there should be an easy way to do this but I can't figure it out. If anyone could help me, I would really appreciate it.
Thanks!

Here's a full test that works as you want it with regular expressions and AND, OR and brackets. Note that this only supports the operators AND and OR and parentheses ( and ) and expects the input to be somewhat well formed (regular expressions must not have spaces). The parsing can be improved, the idea remains the same.
Here is the overall test:
var input = ".* AND [0-9]+ AND abc OR (abc AND def)";
var rpn = ParseRPN(input);
var test = GetExpression(new Queue<string>(rpn.Reverse())).Compile();
test("abc"); // false
test("abc0"); // true
test("abcdef"); // true
Here is the parsing to reverse polish notation:
public Queue<string> ParseRPN(string input)
{
// improve the parsing into tokens here
var output = new Queue<string>();
var ops = new Stack<string>();
input = input.Replace("(","( ").Replace(")"," )");
var split = input.Split(' ');
foreach (var token in split)
{
if (token == "AND" || token == "OR")
{
while (ops.Count > 0 && (ops.Peek() == "AND" || ops.Peek() == "OR"))
{
output.Enqueue(ops.Pop());
}
ops.Push(token);
}
else if (token == "(") ops.Push(token);
else if (token == ")")
{
while (ops.Count > 0 && ops.Peek() != "(")
{
output.Enqueue(ops.Pop());
}
ops.Pop();
}
else output.Enqueue(token); // it's a number
}
while (ops.Count > 0)
{
output.Enqueue(ops.Pop());
}
return output;
}
And the magic GetExpression:
public Expression<Func<string,bool>> GetExpression(Queue<string> input)
{
var exp = input.Dequeue();
if (exp == "AND") return GetExpression(input).And(GetExpression(input));
else if (exp == "OR") return GetExpression(input).Or(GetExpression(input));
else return (test => Regex.IsMatch(test, exp));
}
Note this does rely on PredicateBuilder, but the extension functions used are here in there completeness:
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<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
}

Something like following - define operation classes to represent binary operation and build your tree:
interface IFilter
{
bool Filter(Record r);
}
class SimpleFilter : IFilter
{
bool Filter(Record r)
{
return RegExpMatch(r);
}
}
class AndFilter : IFilter
{
public AndFilter(IFilter left, IFilter right) {}
bool Filter(Record r)
{
return left.Filter(r) && right.Filter(r);
}
}
class OrFilter : IFilter
{
public OrFilter(IFilter left, IFilter right) {}
bool Filter(Record r)
{
return left.Filter(r) || right.Filter(r);
}
}

First step is to parse your expression into an abstract syntax tree. To do that, you can use the shunting-yard algorithm.
After you have done that, you can recursively evaluate the tree, using virtual methods or an interface. For example, you can have a SimpleNode class, that represents a simple expression (like 1 in your example) and can evaluate it. Then you have AndNode that represents AND operation and has two child nodes. It evaluates the child nodes and returns whether both succeeded.

This explanation of the Specification pattern (with example code) should help.
http://en.wikipedia.org/wiki/Specification_pattern#C.23

There may be libraries to do this sort of thing for you, but in the past, I've hand-rolled something along these lines, based around using Predicate;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
public enum CombineOptions
{
And,
Or,
}
public class FilterExpression
{
public string Filter { get; set; }
public CombineOptions Options { get; private set; }
public FilterExpression(string filter, CombineOptions options)
{
this.Filter = filter;
this.Options = options;
}
}
public static class PredicateExtensions
{
public static Predicate<T> And<T>
(this Predicate<T> original, Predicate<T> newPredicate)
{
return t => original(t) && newPredicate(t);
}
public static Predicate<T> Or<T>
(this Predicate<T> original, Predicate<T> newPredicate)
{
return t => original(t) || newPredicate(t);
}
}
public static class ExpressionBuilder
{
public static Predicate<string> BuildExpression(IEnumerable<FilterExpression> filterExpressions)
{
Predicate<string> predicate = (delegate
{
return true;
});
foreach (FilterExpression expression in filterExpressions)
{
string nextFilter = expression.Filter;
Predicate<string> nextPredicate = (o => Regex.Match(o, nextFilter).Success);
switch (expression.Options)
{
case CombineOptions.And:
predicate = predicate.And(nextPredicate);
break;
case CombineOptions.Or:
predicate = predicate.Or(nextPredicate);
break;
}
}
return predicate;
}
}
class Program
{
static void Main(string[] args)
{
FilterExpression f1 = new FilterExpression(#"data([A-Za-z0-9\-]+)$", CombineOptions.And);
FilterExpression f2 = new FilterExpression(#"otherdata([A-Za-z0-9\-]+)$", CombineOptions.And);
FilterExpression f3 = new FilterExpression(#"otherdata([A-Za-z0-9\-]+)$", CombineOptions.Or);
// result will be false as "data1" does not match both filters
Predicate<string> pred2 = ExpressionBuilder.BuildExpression(new[] { f1, f2 });
bool result = pred2.Invoke("data1");
// result will be true as "data1" matches 1 of the 2 Or'd filters
Predicate<string> pred3 = ExpressionBuilder.BuildExpression(new[] { f1, f3 });
result = pred3.Invoke("data1");
}
}
}
All you'll need to do now is parse the 'brackets' to determine the order in which your FilterExpressions should be sent to the BuildExpression method. You might need to tweak it for more complex expressions, but hopefully this helps.

Related

Get nested property for ordering from Expression<Func<T,Tkey>> [duplicate]

I'm creating a Validator<T> class. I'm attempting to implement the Linq SelectMany extension methods for my validator to be able to compose expressions using a Linq query and validate the final result even when the underlying values change.
The following test code demonstrates my intent.
var a = 2;
var b = 3;
var va = Validator.Create(() => a, n => n >= 0 && n < 5);
var vb = Validator.Create(() => b, n => n >= 0 && n < 5);
var vc = from ia in va
from ib in vb
select ia + ib;
Debug.Assert(vc.Value == a + b); //2 + 3
Debug.Assert(vc.Value == 5);
Debug.Assert(vc.IsValid == true);
a = 7;
Debug.Assert(vc.Value == a + b); //7 + 3
Debug.Assert(vc.Value == 10);
Debug.Assert(va.IsValid == false);
Debug.Assert(vb.IsValid == true);
Debug.Assert(vc.IsValid == false);
I've seen the following question How do I compose existing Linq Expressions which shows me how to compose two Func<T, bool>'s together using an And expression, but I need to be able to compose functions together in a more, well, functional way.
I have, for example, the following two expressions:
public Expression<Func<T>> ValueExpression { get; private set; }
public Expression<Func<T, bool>> ValidationExpression { get; private set; }
I wish to create a new expression like this:
public Expression<Func<bool>> IsValidExpression
{
get
{
// TODO: Compose expressions rather than compile & invoke.
}
}
More succinctly I'm trying to create these functions:
// Specific case
Func<Expression<Func<T>>, Expression<Func<T, bool>>, Expression<Func<bool>>>
// General case
Func<Expression<Func<X, Y>>, Expression<Func<Y, Z>>, Expression<Func<X, Z>>>
The general case function can be modified to accept different numbers of generic arguments as needed to compose any function.
I've searched Stack Overflow (of course) and the web, but haven't an example that solves this issue.
My code for the Validator<T> class is below.
public class Validator<T>
{
public Validator(Expression<Func<T>> valueFunc,
Expression<Func<T, bool>> validationFunc)
{
this.ValueExpression = valueFunc;
this.ValidationExpression = validationFunc;
}
public Expression<Func<T>> ValueExpression { get; private set; }
public Expression<Func<T, bool>> ValidationExpression { get; private set; }
public T Value { get { return this.ValueExpression.Compile().Invoke(); } }
public bool IsValid { get { return this.IsValidExpression.Compile().Invoke(); } }
public Expression<Func<bool>> IsValidExpression
{
get
{
// TODO: Compose expressions.
}
}
}
My SelectMany extensions contain loads of yucky .Compile().Invoke() which I want to get rid of.
public static Validator<U> SelectMany<T, U>(this Validator<T> #this, Expression<Func<T, Validator<U>>> k)
{
Expression<Func<T>> fvtv = #this.ValueExpression;
Expression<Func<Validator<U>>> fvu = () => k.Compile().Invoke(fvtv.Compile().Invoke());
Expression<Func<U>> fvuv = fvu.Compile().Invoke().ValueExpression;
Expression<Func<U, bool>> fvtiv = u => #this.ValidationExpression.Compile().Invoke(fvtv.Compile().Invoke());
return fvuv.ToValidator(fvtiv);
}
public static Validator<V> SelectMany<T, U, V>(this Validator<T> #this, Expression<Func<T, Validator<U>>> k, Expression<Func<T, U, V>> s)
{
Expression<Func<Validator<U>>> fvu = () => #this.SelectMany(k);
Expression<Func<T>> fvtv = #this.ValueExpression;
Expression<Func<U>> fvuv = fvu.Compile().Invoke().ValueExpression;
Expression<Func<T, bool>> fvtiv = #this.ValidationExpression;
Expression<Func<U, bool>> fvuiv = u => fvu.Compile().Invoke().ValidationExpression.Compile().Invoke(u);
Expression<Func<V>> fvv = () => s.Compile().Invoke(fvtv.Compile().Invoke(), fvuv.Compile().Invoke());
Expression<Func<V, bool>> fvviv = v => fvtiv.Compile().Invoke(fvtv.Compile().Invoke()) && fvuiv.Compile().Invoke(fvuv.Compile().Invoke());
return fvv.ToValidator(fvviv);
}
Thanks in advance!
While dtb's answer works for several scenarios, it is suboptimal as such an expression cannot be used in Entity Framework, as it cannot handle Invoke calls. Unfortunately, to avoid those calls one needs a lot more code, including a new ExpressionVisitor derived class:
static Expression<Func<A, C>> Compose<A, B, C>(Expression<Func<B, C>> f,
Expression<Func<A, B>> g)
{
var ex = ReplaceExpressions(f.Body, f.Parameters[0], g.Body);
return Expression.Lambda<Func<A, C>>(ex, g.Parameters[0]);
}
static TExpr ReplaceExpressions<TExpr>(TExpr expression,
Expression orig,
Expression replacement)
where TExpr : Expression
{
var replacer = new ExpressionReplacer(orig, replacement);
return replacer.VisitAndConvert(expression, nameof(ReplaceExpressions));
}
private class ExpressionReplacer : ExpressionVisitor
{
private readonly Expression From;
private readonly Expression To;
public ExpressionReplacer(Expression from, Expression to)
{
From = from;
To = to;
}
public override Expression Visit(Expression node)
{
return node == From ? To : base.Visit(node);
}
}
This replaces every instance of the first parameter in the first expression with the expression in the second expression. So a call like this:
Compose((Class1 c) => c.StringProperty, (Class2 c2) => c2.Class1Property
Would yield the expression (Class2 c2) => c2.Class1Property.StringProperty.
The equivalent of Haskell's function composition operator
(.) :: (b->c) -> (a->b) -> (a->c)
f . g = \ x -> f (g x)
would in C# probably be something like
static Expression<Func<A, C>> Compose<A, B, C>(
Expression<Func<B, C>> f,
Expression<Func<A, B>> g)
{
var x = Expression.Parameter(typeof(A));
return Expression.Lambda<Func<A, C>>(
Expression.Invoke(f, Expression.Invoke(g, x)), x);
}
Is this what you're looking for?
Example:
Compose<int, int, string>(y => y.ToString(), x => x + 1).Compile()(10); // "11"

Getting an expression tree from inside a method's body

Context:
I'm making an Expression parser, which would take my LINQ queries, and turn them into specific byte arrays. Think ORM for a custom data storage, euhm, thing. I'll use SQL in my examples for familiarity.
class ExpressionParser<T>
{
public string ParseWhere(Expression<Func<T, bool>> predicate)
{
// Takes an expression, follows the expression tree, building an SQL query.
}
}
Example:
Take an example class FooData with a few dummy properties:
class FooData
{
public int Status { get; set; }
public bool Active { get; set; }
}
var parser = new ExpressionParser<FooData>();
var query = parser.ParseWhere(foo => foo.Active && (foo.Status == 3 || foo.Status == 4));
// Builds "WHERE active AND (status = 3 OR status = 4)"
This works great, my parser runs through the expression tree, builds a WHERE statement, and returns it.
Problem:
Now I see that, for example, Active && (Status == 3 || Status == 4) is a special case that will be used all over the whole project. So naturally I extract it to a computed property:
class FooData
{
public int Status { get; set; }
public bool Active { get; set; }
public bool IsSpecialThing => Active && (Status == 3 || Status == 4);
}
var query = parser.ParseWhere(foo => foo.IsSpecialThing);
Should the expression be evaluated, the result would be the same. However, this doesn't work any more. Instead of a full expression tree that I can make a query from, all I get is a tree with one PropertyExpression that tells me nothing.
I tried changing it to a method, adding a [MethodImpl(MethodImplOptions.AggressiveInlining)] attribute, nothing seems to make Expression look inside my method / property.
Question:
Is it possible to make an Expression look deeper - into a property getter / method body? If not - is there an alternative to Expression that would?
If it's not possible at all, what should one do in this case? It would really suck to copy-paste long parts of queries tens (hundreds?) of times in a project.
The problem here is that this:
public bool IsSpecialThing => Active && (Status == 3 || Status == 4);
Is equivalent to this:
public bool IsSpecialThing { get { return Active && (Status == 3 || Status == 4); } }
Note that they're both compiled methods. You can see this because the type is Func<FooData,bool>, rather than Expression<Func<FooData,bool>>. Short answer: No, you can't inspect it*
If you replace your class definition with this:
public class FooData
{
public int Status { get; set; }
public bool Active { get; set; }
public static Expression<Func<FooData, bool>> IsSpecialThing = (foo) => foo.Active && (foo.Status == 3 || foo.Status == 4);
}
You can then use it as follows:
var parser = new ExpressionParser<FooData>();
var query = parser.ParseWhere(FooData.IsSpecialThing);
Note that this raises more difficulties. I'm assuming you'd want to write something like:
ParseWhere(f => f.IsSpecialThing() && f.SomethingElse)
The problem here is that IsSpecialThing is it's own lambda function, with it's own parameters. So it would be equivalent of writing:
ParseWhere(f => (ff => IsSpecialThing(ff)) && f.SomethingElse)
To combat this, you'd need to write a few helper methods which let you AND and OR LambdaExpressions properly:
public class ParameterRewriter<TArg, TReturn> : ExpressionVisitor
{
Dictionary<ParameterExpression, ParameterExpression> _mapping;
public Expression<Func<TArg, TReturn>> Rewrite(Expression<Func<TArg, TReturn>> expr, Dictionary<ParameterExpression, ParameterExpression> mapping)
{
_mapping = mapping;
return (Expression<Func<TArg, TReturn>>)Visit(expr);
}
protected override Expression VisitParameter(ParameterExpression p)
{
if (_mapping.ContainsKey(p))
return _mapping[p];
return p;
}
}
The above will take a mapping between parameters, and replace them in the given expression tree.
Leveraging it:
public static class ExpressionExtensions
{
public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
var rewrittenRight = RewriteExpression(left, right);
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(left.Body, rewrittenRight.Body), left.Parameters);
}
public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
var rewrittenRight = RewriteExpression(left, right);
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left.Body, rewrittenRight.Body), left.Parameters);
}
private static Expression<Func<T, bool>> RewriteExpression<T>(Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
var mapping = new Dictionary<ParameterExpression, ParameterExpression>();
for (var i = 0; i < left.Parameters.Count; i++)
mapping[right.Parameters[i]] = left.Parameters[i];
var pr = new ParameterRewriter<T, bool>();
var rewrittenRight = pr.Rewrite(right, mapping);
return rewrittenRight;
}
}
What the above essentially does is, if you write this:
Expression<Func<FooData, bool>> a = f => f.Active;
Expression<Func<FooData, bool>> b = g => g.Status == 5;
Expression<Func<FooData, bool>> c = a.AndAlso(b);
Will return you f => f.Active && f.Status == 5 (note how the parameter g was replaced with f.
Putting it all together:
var parser = new ExpressionParser<FooData>();
var result = parser.ParseWhere(FooData.IsSpecialThing.AndAlso(f => f.Status == 6));
*Note it is technically possible to parse the generated IL, but you'll be in for a hell of a time.

Using linq to perform text-based search when number of search words can be variable [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
LINQ To SQL exception: Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains operator
I am trying the following query:
var data = (from bk in DataContext.Book
where ((searchArray.Count() == 0 || searchArray.ToList().Any(x => bk.Name.Contains(x))) ||
(searchArray.Count() == 0 || searchArray.ToList().Any(x => bk.Genre.Contains(x)))))
where searchArray is a Array containing the individual words that I want to search for, I split the string the user entered and put the results in this array. Whenever I try to run this I get the following error:
"Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator."
Can anyone tell me what I am doing wrong and what is the correct way to perform this search?
In a nutshell, I am trying to allow a user to enter a string like "Hello World" and for a query to be generated that will look for either hello or world or both. But, a user can enter any number of words.
The simplest option is probably to build the lambda expression by hand:
static class ContainsAny
{
private static readonly MethodInfo StringContains
= typeof(string).GetMethod("Contains", new[] { typeof(string) });
public static Builder<T> Words<T>(IEnumerable<string> words)
{
return new Builder<T>(words);
}
public static Builder<T> Words<T>(params string[] words)
{
return new Builder<T>(words);
}
public sealed class Builder<T>
{
private static readonly ParameterExpression Parameter
= Expression.Parameter(typeof(T), "obj");
private readonly List<Expression> _properties = new List<Expression>();
private readonly List<ConstantExpression> _words;
internal Builder(IEnumerable<string> words)
{
_words = words
.Where(word => !string.IsNullOrEmpty(word))
.Select(word => Expression.Constant(word))
.ToList();
}
public Builder<T> WithProperty(Expression<Func<T, string>> property)
{
if (_words.Count != 0)
{
_properties.Add(ReplacementVisitor.Transform(
property, property.Parameters[0], Parameter));
}
return this;
}
private Expression BuildProperty(Expression prop)
{
return _words
.Select(w => (Expression)Expression.Call(prop, StringContains, w))
.Aggregate(Expression.OrElse);
}
public Expression<Func<T, bool>> Build()
{
if (_words.Count == 0) return (T obj) => true;
var body = _properties
.Select(BuildProperty)
.Aggregate(Expression.OrElse);
return Expression.Lambda<Func<T, bool>>(body, Parameter);
}
}
private sealed class ReplacementVisitor : ExpressionVisitor
{
private ICollection<ParameterExpression> Parameters { get; set; }
private Expression Find { get; set; }
private Expression Replace { get; set; }
public static Expression Transform(
LambdaExpression source,
Expression find,
Expression replace)
{
var visitor = new ReplacementVisitor
{
Parameters = source.Parameters,
Find = find,
Replace = replace,
};
return visitor.Visit(source.Body);
}
private Expression ReplaceNode(Expression node)
{
return (node == Find) ? Replace : node;
}
protected override Expression VisitConstant(ConstantExpression node)
{
return ReplaceNode(node);
}
protected override Expression VisitBinary(BinaryExpression node)
{
var result = ReplaceNode(node);
if (result == node) result = base.VisitBinary(node);
return result;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (Parameters.Contains(node)) return ReplaceNode(node);
return Parameters.FirstOrDefault(p => p.Name == node.Name) ?? node;
}
}
}
With this code in place, you can call:
Expression<Func<Book, bool>> filter = ContainsAny
.Words<Book>(searchArray)
.WithProperty(book => book.Name)
.WithProperty(book => book.Genre)
.Build();
var data = DataContext.Book.Where(filter);
For example, if the searchArray contains { "Hello", "World" }, the generated lambda will be:
obj => (obj.Name.Contains("Hello") || obj.Name.Contains("World"))
|| (obj.Genre.Contains("Hello") || obj.Genre.Contains("World")))
If I understand what you're trying to do correctly, you should be able to condense your query down to:
from bk in DataContext.Book
where searchArray.Contains(bk.Name) || searchArray.Contains(bk.Genre)
select bk
This is basically equivalent to the SQL:
select bk.*
from Book bk
where bk.Name in (...) or bk.Genre in (...)
In your case you must combine interpreted and local queries which can hurt performance or use SQL CLR integration by creating CLR function on database.

How can I convert a lambda-expression between different (but compatible) models?

(based on an email conversation, now recorded for information sharing) I have two models used at different layers:
public class TestDTO {
public int CustomerID { get; set; }
}
//...
public class Test {
public int CustomerID { get; set; }
}
and a lambda in terms of my DTO layer:
Expression<Func<TestDTO, bool>> fc1 =
(TestDTO c1) => c1.CustomerID <= 100 && c1.CustomerID >= 10;
How can I convert that lambda (in the general case) to talking about the other model:
Expression<Func<Test, bool>> fc2 = {insert magic here, based on fc1}
(obviously, we're after the same test-condition, but using the Test type)
?
To do that, you'll have to rebuild the expression-tree completely; the parameters will need re-mapping, and all member-access that is now talking to different types will need to be reapplied. Fortunately, a lot of this is made easier by the ExpressionVisitor class; for example (doing it all in the general case, not just the Func<T,bool> predicate usage):
class TypeConversionVisitor : ExpressionVisitor
{
private readonly Dictionary<Expression, Expression> parameterMap;
public TypeConversionVisitor(
Dictionary<Expression, Expression> parameterMap)
{
this.parameterMap = parameterMap;
}
protected override Expression VisitParameter(ParameterExpression node)
{
// re-map the parameter
Expression found;
if(!parameterMap.TryGetValue(node, out found))
found = base.VisitParameter(node);
return found;
}
protected override Expression VisitMember(MemberExpression node)
{
// re-perform any member-binding
var expr = Visit(node.Expression);
if (expr.Type != node.Type)
{
MemberInfo newMember = expr.Type.GetMember(node.Member.Name)
.Single();
return Expression.MakeMemberAccess(expr, newMember);
}
return base.VisitMember(node);
}
}
Here, we pass in a dictionary of parameters to re-map, applying that in VisitParameter. We also, in VisitMember, check to see if we've switched type (which can happen if Visit involves a ParameterExpression or another MemberExpression, at any point): if we have, we'll try and find another member of the same name.
Next, we need a general purpose lambda-conversion rewriter method:
// allows extension to other signatures later...
private static Expression<TTo> ConvertImpl<TFrom, TTo>(Expression<TFrom> from)
where TFrom : class
where TTo : class
{
// figure out which types are different in the function-signature
var fromTypes = from.Type.GetGenericArguments();
var toTypes = typeof(TTo).GetGenericArguments();
if (fromTypes.Length != toTypes.Length)
throw new NotSupportedException(
"Incompatible lambda function-type signatures");
Dictionary<Type, Type> typeMap = new Dictionary<Type,Type>();
for (int i = 0; i < fromTypes.Length; i++)
{
if (fromTypes[i] != toTypes[i])
typeMap[fromTypes[i]] = toTypes[i];
}
// re-map all parameters that involve different types
Dictionary<Expression, Expression> parameterMap
= new Dictionary<Expression, Expression>();
ParameterExpression[] newParams =
new ParameterExpression[from.Parameters.Count];
for (int i = 0; i < newParams.Length; i++)
{
Type newType;
if(typeMap.TryGetValue(from.Parameters[i].Type, out newType))
{
parameterMap[from.Parameters[i]] = newParams[i] =
Expression.Parameter(newType, from.Parameters[i].Name);
}
else
{
newParams[i] = from.Parameters[i];
}
}
// rebuild the lambda
var body = new TypeConversionVisitor(parameterMap).Visit(from.Body);
return Expression.Lambda<TTo>(body, newParams);
}
This takes an arbitrary Expression<TFrom>, and a TTo, converting it to an Expression<TTo>, by:
finding which types are different between TFrom / TTo
using that to re-map the parameters
using the expression-visitor we just created
and finally constructing a new lambda expression for the desired signature
Then, putting it all together and exposing our extension method:
public static class Helpers {
public static Expression<Func<TTo, bool>> Convert<TFrom, TTo>(
this Expression<Func<TFrom, bool>> from)
{
return ConvertImpl<Func<TFrom, bool>, Func<TTo, bool>>(from);
}
// insert from above: ConvertImpl
// insert from above: TypeConversionVisitor
}
et voila; a general-purpose lambda conversion routine, with a specific implementation of:
Expression<Func<Test, bool>> fc2 = fc1.Convert<TestDTO, Test>();
You could use AutoMapper (no expression tree):
Mapper.CreateMap<Test, TestDTO>();
...
Func<TestDTO, bool> fc1 =
(TestDTO c1) => c1.CustomerID <= 100 && c1.CustomerID >= 10;
Func<Test, bool> fc2 =
(Test t) => fc1(Mapper.Map<Test, TestDTO>(t));

How do I compose Linq Expressions? ie Func<Exp<Func<X, Y>>, Exp<Func<Y, Z>>, Exp<Func<X, Z>>>

I'm creating a Validator<T> class. I'm attempting to implement the Linq SelectMany extension methods for my validator to be able to compose expressions using a Linq query and validate the final result even when the underlying values change.
The following test code demonstrates my intent.
var a = 2;
var b = 3;
var va = Validator.Create(() => a, n => n >= 0 && n < 5);
var vb = Validator.Create(() => b, n => n >= 0 && n < 5);
var vc = from ia in va
from ib in vb
select ia + ib;
Debug.Assert(vc.Value == a + b); //2 + 3
Debug.Assert(vc.Value == 5);
Debug.Assert(vc.IsValid == true);
a = 7;
Debug.Assert(vc.Value == a + b); //7 + 3
Debug.Assert(vc.Value == 10);
Debug.Assert(va.IsValid == false);
Debug.Assert(vb.IsValid == true);
Debug.Assert(vc.IsValid == false);
I've seen the following question How do I compose existing Linq Expressions which shows me how to compose two Func<T, bool>'s together using an And expression, but I need to be able to compose functions together in a more, well, functional way.
I have, for example, the following two expressions:
public Expression<Func<T>> ValueExpression { get; private set; }
public Expression<Func<T, bool>> ValidationExpression { get; private set; }
I wish to create a new expression like this:
public Expression<Func<bool>> IsValidExpression
{
get
{
// TODO: Compose expressions rather than compile & invoke.
}
}
More succinctly I'm trying to create these functions:
// Specific case
Func<Expression<Func<T>>, Expression<Func<T, bool>>, Expression<Func<bool>>>
// General case
Func<Expression<Func<X, Y>>, Expression<Func<Y, Z>>, Expression<Func<X, Z>>>
The general case function can be modified to accept different numbers of generic arguments as needed to compose any function.
I've searched Stack Overflow (of course) and the web, but haven't an example that solves this issue.
My code for the Validator<T> class is below.
public class Validator<T>
{
public Validator(Expression<Func<T>> valueFunc,
Expression<Func<T, bool>> validationFunc)
{
this.ValueExpression = valueFunc;
this.ValidationExpression = validationFunc;
}
public Expression<Func<T>> ValueExpression { get; private set; }
public Expression<Func<T, bool>> ValidationExpression { get; private set; }
public T Value { get { return this.ValueExpression.Compile().Invoke(); } }
public bool IsValid { get { return this.IsValidExpression.Compile().Invoke(); } }
public Expression<Func<bool>> IsValidExpression
{
get
{
// TODO: Compose expressions.
}
}
}
My SelectMany extensions contain loads of yucky .Compile().Invoke() which I want to get rid of.
public static Validator<U> SelectMany<T, U>(this Validator<T> #this, Expression<Func<T, Validator<U>>> k)
{
Expression<Func<T>> fvtv = #this.ValueExpression;
Expression<Func<Validator<U>>> fvu = () => k.Compile().Invoke(fvtv.Compile().Invoke());
Expression<Func<U>> fvuv = fvu.Compile().Invoke().ValueExpression;
Expression<Func<U, bool>> fvtiv = u => #this.ValidationExpression.Compile().Invoke(fvtv.Compile().Invoke());
return fvuv.ToValidator(fvtiv);
}
public static Validator<V> SelectMany<T, U, V>(this Validator<T> #this, Expression<Func<T, Validator<U>>> k, Expression<Func<T, U, V>> s)
{
Expression<Func<Validator<U>>> fvu = () => #this.SelectMany(k);
Expression<Func<T>> fvtv = #this.ValueExpression;
Expression<Func<U>> fvuv = fvu.Compile().Invoke().ValueExpression;
Expression<Func<T, bool>> fvtiv = #this.ValidationExpression;
Expression<Func<U, bool>> fvuiv = u => fvu.Compile().Invoke().ValidationExpression.Compile().Invoke(u);
Expression<Func<V>> fvv = () => s.Compile().Invoke(fvtv.Compile().Invoke(), fvuv.Compile().Invoke());
Expression<Func<V, bool>> fvviv = v => fvtiv.Compile().Invoke(fvtv.Compile().Invoke()) && fvuiv.Compile().Invoke(fvuv.Compile().Invoke());
return fvv.ToValidator(fvviv);
}
Thanks in advance!
While dtb's answer works for several scenarios, it is suboptimal as such an expression cannot be used in Entity Framework, as it cannot handle Invoke calls. Unfortunately, to avoid those calls one needs a lot more code, including a new ExpressionVisitor derived class:
static Expression<Func<A, C>> Compose<A, B, C>(Expression<Func<B, C>> f,
Expression<Func<A, B>> g)
{
var ex = ReplaceExpressions(f.Body, f.Parameters[0], g.Body);
return Expression.Lambda<Func<A, C>>(ex, g.Parameters[0]);
}
static TExpr ReplaceExpressions<TExpr>(TExpr expression,
Expression orig,
Expression replacement)
where TExpr : Expression
{
var replacer = new ExpressionReplacer(orig, replacement);
return replacer.VisitAndConvert(expression, nameof(ReplaceExpressions));
}
private class ExpressionReplacer : ExpressionVisitor
{
private readonly Expression From;
private readonly Expression To;
public ExpressionReplacer(Expression from, Expression to)
{
From = from;
To = to;
}
public override Expression Visit(Expression node)
{
return node == From ? To : base.Visit(node);
}
}
This replaces every instance of the first parameter in the first expression with the expression in the second expression. So a call like this:
Compose((Class1 c) => c.StringProperty, (Class2 c2) => c2.Class1Property
Would yield the expression (Class2 c2) => c2.Class1Property.StringProperty.
The equivalent of Haskell's function composition operator
(.) :: (b->c) -> (a->b) -> (a->c)
f . g = \ x -> f (g x)
would in C# probably be something like
static Expression<Func<A, C>> Compose<A, B, C>(
Expression<Func<B, C>> f,
Expression<Func<A, B>> g)
{
var x = Expression.Parameter(typeof(A));
return Expression.Lambda<Func<A, C>>(
Expression.Invoke(f, Expression.Invoke(g, x)), x);
}
Is this what you're looking for?
Example:
Compose<int, int, string>(y => y.ToString(), x => x + 1).Compile()(10); // "11"

Categories