First of all I want to make you know that I've searched another questions and answers before making this one, but I cound't find any that would help me in this specific problem I am facing.
I need to filter registers based in two properties of its class, one of them being the field corresponding to the search, and the other one being a numeric code of another entity to which the register must be referenced in the database.
My search function has the following signature:
public List<TView> SearchByField(int parentCode, string fieldName, string filter);
I've tried to implement this using Expression Trees, and got it to get two expressions, but now I didn't get to combine these expressions to build one to pass to the final
Expression.AndAlso(parentCodeFilterExpression, textFilterExpression);
that will combine the too expressions in only one.
What I got so far was the code shown below (sorry for the long snippet, but I think this was necessary to make it easier to understand the question):
public List<TView> SearchPerField(int parentCode, string fieldName, string filter)
{
var lambdaExpression = GetLambdaExpressionForSearchByField(fieldName, filter, parentCode);
return new PersistenciaImpl<TView>().Where(lambdaExpression).ToList();
}
private Expression<Func<TView, bool>> GetLambdaExpressionForSearchByField(string fieldName, string filter, int parentCode)
{
Expression<Func<TView, bool>> textFilterExpression = GetTextFilterExpression(fieldName, filter);
Expression<Func<TView, bool>> parentCodeFilterExpression = GetParentCodeFilterExpression(parentCode);
Expression.Lambda<Func<TView, bool>>(textFilterExpression, parentCodeFilterExpression);
// THIS IS THE POINT. HOW TO MAKE THIS WORK?
Expression.AndAlso(parentCodeFilterExpression, textFilterExpression);
return textFilterExpression;
}
private Expression<Func<TView, bool>> GetParentCodeFilterExpression(int parentCode)
{
ParameterExpression parameter = Expression.Parameter(typeof(TView), "x");
Expression parent = Expression.Property(parameter, "Parent");
Expression parentCodeExpression = Expression.Property(parent, "Code");
Expression target = Expression.Constant(parentCode);
Expression containsMethod = Expression.Call(parentCodeExpression, "Equals", null, target);
Expression<Func<TView, bool>> textFilterExpression =
Expression.Lambda<Func<TView, bool>>(containsMethod, parameter);
return textFilterExpression;
}
private Expression<Func<TView, bool>> GetTextFilterExpression(string fieldName, string filter)
{
ParameterExpression parameter = Expression.Parameter(typeof(TView), "x");
Expression property = Expression.Property(parameter, fieldName);
Expression target = Expression.Constant(filter.ToUpper());
Expression containsMethod = Expression.Call(property, "Contains", null, target);
Expression<Func<TView, bool>> textFilterExpression =
Expression.Lambda<Func<TView, bool>>(containsMethod, parameter);
return textFilterExpression;
}
Thanks for any suggestion.
I've tried to implement this using Expression Trees, and got it to get two expressions, but now I didn't get to combine these expressions to build one to pass to the final
First, you need to declare a parameter for your final (outer) lambda. Then you need to invoke your two filter (inner) lambdas independently, passing in the same argument to each:
// using E = System.Linq.Expressions.Expression;
var item = E.Parameter(typeof(TView));
var combined = E.Lambda<Func<TView, bool>>(
E.AndAlso(
E.Invoke(parentCodeFilterExpression, item),
E.Invoke(textFilterExpression, item)),
item);
If you need these expressions to be compatible with a query provider like Entity Framework, things get a bit messier because Invoke expressions probably aren't supported. You'll have to manually inline the two filter lambdas, which requires walking each filter's body and replacing the inner parameter references with references to the outer lambda's parameter:
// using E = System.Linq.Expressions.Expression;
sealed class ParameterReplacementVisitor : ExpressionVisitor
{
private readonly IDictionary<E, E> _replacements;
public ParameterReplacementVisitor(IDictionary<E, E> replacements)
{
_replacements = replacements;
}
protected override Expression VisitParameter(ParameterExpression node)
{
E replacement;
if (_replacements.TryGetValue(node, out replacement))
return this.Visit(replacement);
return base.VisitParameter(node);
}
}
// ...
var item = E.Parameter(typeof(TView));
var visitor = new ParameterReplacementVisitor(
new Dictionary<E, E> {
{ parentCodeFilterExpression.Parameters[0], item },
{ textFilterExpression.Parameters[0], item }
}
);
var combined = E.Lambda<Func<TView, bool>>(
E.AndAlso(
visitor.Visit(parentCodeFilterExpression.Body),
visitor.Visit(textFilterExpression.Body)),
item);
Alternatively, if you are composing the inner expressions in a closed environment as your post suggests, you could simply pass the outer lambda parameter as an argument to the methods that construct the inner expressions, and return just the bodies (don't bother wrapping the inner filters in lambdas).
I think you need something like this:
MethodCallExpression where = Expression.Call((
typeof(Queryable),
"Where",
new Type[] { TView },
lambdaExpression );
Please note that I don't consider this a solution; it's merely an idea or example. Maybe this link will help you out.
You can compile an Expression<TDelegate> into a TDelegate by using the Compile method on the Expression:
Expression<Func<TView, bool>> lambdaExpression =
GetLambdaExpressionForSearchByField(fieldName, filter, parentCode);
Func<TView, bool> func = lambdaExpression.Compile();
Once you have that you can use it as a parameter for the Where function.
With the code above you can then use
return new PersistenciaImpl<TView>().Where(func).ToList();
Related
I have a generic method and I want to add a search capability to my method. as parameter I get the name of property(string) and the value(string) it should search for in the list. how can I achieve this?
**This code is not the exact code I have so it may seem that I can use other options like Expression functions which is not possible in my case cause it should be consumed in an Api Controller
**I use unit of work with repository pattern in real project and for sake of simplicity I have tryed to add it up in one simple function
public async Task<ActionResult<List<T>>> GetAll(string? filterProperty = null, string? filterValue = null)
{
IQueryable<T> query = dbSet;
if (filterProperty != null)
{
PropertyInfo property = typeof(T).GetProperty(filterProperty);
query = query. Where(u=> u.property.Contains(filterValue));
}
return await query.ToListAsync();
}
For IQueryable you'll want to create a LambdaExpression for the filter predicate. (For IEnumerable you can compile that expression into an appropriate Func<>.)
This all works by building an expression tree that represents the action you want to perform. In this case you're calling Contains on the result of getting the property value, passing a constant for the filter value.
Let's start with the Contains method, which you can reuse. Rather than basic reflection, here's how you can get it using an expression:
static readonly MethodInfo _contains =
(((Expression<Func<string, bool>>)(s => s.Contains("a"))).Body as MethodCallExpression)
.Method;
While that might look a little confusing, it's leveraging the compiler to do the reflection work for us. Sometimes it's easier than searching for the right version of a method with multiple overloads, or when it's not obvious which extension method is involved. The result here is that _contains gets initialized with the method info we need.
You've already got the property info for the target property, so let's put them together:
// The parameter for the predicate
var row = Expression.Parameter(typeof(T), "row");
// Constant for the filter value
var filter = Expression.Constant(filterValue);
// Get the value of the property
var prop = Expression.Property(property);
// Call 'Contains' on the property value
var body = Expression.Call(prop, _contains, filter);
// Finally, generate the lambda
var predicate = Expression.Lambda<Func<T, bool>(body, row);
// Apply to the query
query = query.Where(predicate);
Or in slightly more compact form:
var row = Expression.Parameter(typeof(T), "row");
var predicate =
Expression.Lambda<Func<T, bool>
(
Expression.Call
(
Expression.Property(row, property),
_contains,
Expression.Constant(filterValue)
),
row
);
When you're working on data via IEnumerable<T> instead, predicate.Compile() will produce a working Func<T, bool> to pass to IEnumerable.Where():
private static readonly MethodInfo _tostring = typeof(Object).GetMethod("ToString");
static readonly MethodInfo _compare = (((Expression<Func<string, bool>>)(s => s.Contains(""))).Body as MethodCallExpression).Method;
public static IEnumerable<T> Search<T>(this IEnumerable<T> items, string propertyName, string filterValue)
{
var property = typeof(T).GetProperty(propertyName);
var row = Expression.Parameter(typeof(T), "row");
// Let's make sure we're actually dealing with a string here
Expression prop = Expression.Property(row, property);
if (property.PropertyType != typeof(string))
prop = Expression.Call(prop, _tostring);
var func =
Expression.Lambda<Func<T, bool>>
(
Expression.Call
(
prop,
_compare,
Expression.Constant(filterValue)
),
row
).Dump().Compile();
return items.Where(func);
}
Expressions are pretty versatile, and there are a lot of places where they come in handy. It can be more efficient to compose a function and call it multiple times than to go through reflection all the time, and you can do interesting things with merging expressions and so on.
I am following this question Returning a nested generic Expression<Func<T, bool>>
And I am interested in how compiler reads and compile it to
for example
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
PropertyInfo pi = typeof(T).GetProperty(prop);
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
ConstantExpression ce = Expression.Constant(val);
BinaryExpression be = Expression.Equal(me, ce);
return Expression.Lambda<Func<T, bool>>(be, pe);
Update Also need explanation of each method
My question is what lamda expression should I expect after it compiles?
See the comments in the code below.
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
var myType = new MyType();
myType.p = "Some Value";
var compareMethod = DoWork<MyType>("Some Value", "p");
var isEqual = compareMethod(myType);
}
public static Func<T, bool> DoWork<T>(object val, string prop)
{
//The code below will construct an expression like 'p => p.prop == value'
//Creates the parameter part of an expression. So the 'p =>' part of the expression.
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
//Get access to the property info, like the getter and setter.
PropertyInfo pi = typeof(T).GetProperty(prop);
// // Constructs the part of the expression where the member is referenced, so the 'p.prop' part.
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
//Creates the constant part of the expression, the 'value' part.
ConstantExpression ce = Expression.Constant(val);
//creates the comparison part '==' of the expression.
//So this requires the left and right side of 'left == right'
//Which is the property and the constant value.
//So 'p.prop == value'
BinaryExpression be = Expression.Equal(me, ce);
//Puts the 'p => ' and 'p.prop == value' parts of the expression together to form the
//complete lambda
//Compile it to have an executable method according to the same signature, as
//specified with Func<T, bool>, so you put a class in of type T and
//the 'p.prop == value' is evaluated, and the result is returned.
return Expression.Lambda<Func<T, bool>>(be, pe).Compile();
}
}
public class MyType
{
public string p { get; set; }
}
}
That said, I think it is a complex way of only comparing. The usage case you have in mind may justify it. Are you working with LINQ-to-SQL or so that you have to work with expressions? In most cases from my epxerience, you can solve this with Funcs and interfaces, maybe in combination with a wrapper class in case of 3rd party classes. The code itself probably creates some in memory MSIL, which is then compiled in memory to native code using the Just-In-Time compiler of the CLR, where the allocation of the memory is marked as executable. I do not have detailed knowledge of how that works, this is just a guess. For more information on how memory allocation can be marked for different purposes see Memory Protection Constants.
I need to turn an string that represents a property name on an interface into an expression. I have most of it working, there is just 1 piece that I can't figure out at the end.
static Expression<Func<T, int>> MakeGetter<T>(string propertyName)
{
var input = Expression.Parameter(typeof(T));
var property = typeof(T).GetProperty(propertyName) ??
GetProperty(propertyName, typeof(T));
var expr = Expression.Property(input, property);
var propType = property.PropertyType.Name;
switch (propType.ToLower())
{
case "string":
return Expression.Lambda<Func<T, string>>(expr, input);
case "int":
return Expression.Lambda<Func<T, int>>(expr, input);
}
}
private static PropertyInfo GetProperty(string propertyName, Type i)
{
var baseInterfaces = i.GetInterfaces();
foreach (var baseInterface in baseInterfaces)
{
var property = baseInterface.GetProperty(propertyName);
return property ?? GetProperty(propertyName, baseInterface);
}
return null;
}
The one problem that I have is at the end of the MakeGetter function I don't know if the function is a string or int or some other type and have no way of knowing until after I do all of the reflection, so how can I create this method, so that it is generic and will return an Expression correctly.
Have a look here at an example of generating lambda expressions at runtime. These lines from the article show how to generate lambda expression:
var parameterExpression = Expression.Parameter(typeof(TEntity), "x");
var memberExpression = Expression.PropertyOrField(parameterExpression, prop.Name);
var memberExpressionConversion = Expression.Convert(memberExpression, typeof(object));
var lambda = Expression.Lambda<Func<TEntity, object>>(memberExpressionConversion, parameterExpression);
Now that you've declared your intent for this in the comments, I believe that the accepted answer here is what you're looking for. Even if it's not doing exactly what you're looking for, these lines can carry over:
// TODO: Get 'type' from the property you want.
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
You could return LambdaExpression, or just use the extension methods found in that answer, or use DynamicLinq. I guess the moral of the story (as it often is) is that its probably been done already :).
I'm currently have Lambda Expresion: http://pastebin.com/ZGCiQdHe
And i get ArgumentException in 53 line
http://msdn.microsoft.com/en-us/library/bb340145(v=vs.90).aspx
var lExpresion = Expression.Lambda<Func<TEntity, bool>>(body, parametrsNumber, parametrsTyp, parametrsLp);
But i not understand what i do wrong.
I want to get:
WHERE ((twr_gidnumer =1 and twr_gidtyp = 1 and twr_gidlp = 1) OR
(twr_gidnumer =1 and twr_gidtyp = 1 and twr_gidlp = 2))
--ANSWERR FULL
Based on article:
http://blogs.msdn.com/b/mattwar/archive/2007/07/31/linq-building-an-iqueryable-provider-part-ii.aspx
https://stackoverflow.com/Converting 2 argument Lambda expression to 1 argument Lambda expression
public static Expression<Func<CDNXL_TwrKarty, bool>> Bind2nd(Expression<Func<CDNXL_TwrKarty, CDNXL_TwrKarty,CDNXL_TwrKarty, bool>> source)
{
Expression newBody = new Rewriter(source.Parameters[0]).Visit(source.Body);
return Expression.Lambda<Func<CDNXL_TwrKarty, bool>>(newBody, source.Parameters[0]);
}
internal class Rewriter : ExpressionVisitor
{
private readonly ParameterExpression candidate_;
public Rewriter(ParameterExpression candidate)
{
candidate_ = candidate;
}
protected override Expression VisitParameter(ParameterExpression p)
{
return candidate_;
}
}
//REPLACE EXECUTING PLACE
var retMultiLamnda = Expression.Lambda<Func<CDNXL_TwrKarty, CDNXL_TwrKarty, CDNXL_TwrKarty, bool>>(body, parametrsNumber, parametrsTyp, parametrsLp);
var retOneLambda = Bind2nd(retMultiLamnda);
var retQuery = query.Where(retOneLambda);
return retQuery;
Thanx Rafal for Help.
First thing that I see is that your delegate type does not math with your invocation list. You expect to create function that receives one argument of type TEntity and yet you pass tree parameter expressions to function. Note that you execute this overload of Lablda method.
OK, I'll try to be more clear:
Expression.Lambda<Func<Arg1Type,...,ArgNType,ReturnType>>
(body,parameterExpressionForArg1,...,parameterExpressionForArgN);
Those generic arguments ArgType must match with parameterExpressionsForArg. There must be equal number of generic types for argumetnts as parameterExpressions for arguments. And types of those must also match.
So if you want to have tree parameterExpressions for some reason then you have to have tree arguments in your method:
Expression.Lambda<Func<CDNXL_TwrKarty,CDNXL_TwrKarty,CDNXL_TwrKarty, bool>>(body, parametrsNumber, parametrsTyp, parametrsLp);
might be correct call in this case obviously it wont match the Where call.
If you want to merge tree expressions into one matching Where argument then you have to replace all redundant ParamteterExpressions.
You can use Lambda Expression Objects to represent a lambda as an expression.
How do you create a Lambda Expression Object representing a generic method call, if you only know the type -that you use for the generic method signature- at runtime?
For example:
I want to create a Lambda Expression Objects to call:
public static TSource Last<TSource>( this IEnumerable<TSource> source )
But I only know what TSource is at runtime.
static Expression<Func<IEnumerable<T>, T>> CreateLambda<T>()
{
var source = Expression.Parameter(
typeof(IEnumerable<T>), "source");
var call = Expression.Call(
typeof(Enumerable), "Last", new Type[] { typeof(T) }, source);
return Expression.Lambda<Func<IEnumerable<T>, T>>(call, source)
}
or
static LambdaExpression CreateLambda(Type type)
{
var source = Expression.Parameter(
typeof(IEnumerable<>).MakeGenericType(type), "source");
var call = Expression.Call(
typeof(Enumerable), "Last", new Type[] { type }, source);
return Expression.Lambda(call, source)
}
I don't fully understand the question, but the code that dtb wrote could be written simply as:
class MyUtils {
public static Expression<Func<IEnumerable<T>, T>> CreateLambda<T>() {
return source => source.Last();
}
}
The code in the sample by dtb is pretty much the same thing as what the C# compiler automatically generates for you from this lambda expression (compiled as expression tree, because the return type is Expression).
If you know the type at runtime, then you can either use the solution by dtb or you can invoke the CreateLambda method (above) using Reflection, which may be slower, but allows you to write the code in the lambda in the natural C#:
var createMeth = typeof(MyUtils).GetMethod("CreateLambda");
LambdaExpression l = createMeth.MakeGenericMethod(yourType).Invoke();
The nice thing about this approach is that the code in CreateLambda can be much more complicated, which would be really hard to do using expression trees explicitly.