Generic method to get property values with Linq Expression and reflection
The problem is here:
if (response != null)
{
var expr = (MemberExpression)propertyExpression.Body;
var prop = (PropertyInfo)expr.Member;
return (T)prop.GetValue(response);
}
This only works if your expression references a property directly, otherwise propertyExpression.Body
will not be a MemberExpression
and you'll get a run-time cast error. The three that don't work do not reference a property directly - the first two reverence a method on top of a property (the indexer) and the last references a nested property.
Since all you want is the value of the expression, though, I think you can just do:
if (response != null)
{
Func<TEntity, T> func = propertyExpression.Compile();
return func(response);
}
If you intended to do other things with the expression (like get the name of the property), then you'll need to decide if you want to support expressions that don't reference a property directly and add handlers for that.
LINQ Expression to return Property value?
Easiest way to do this: Use LINQKit (Free, non-restrictive license)
Working version of code:
public static IEnumerable<T> SelectByParameterList<T, PropertyType>(this Table<T> items, IEnumerable<PropertyType> parameterList, Expression<Func<T, PropertyType>> propertySelector, int blockSize) where T : class
{
var groups = parameterList
.Select((Parameter, index) =>
new
{
GroupID = index / blockSize, //# of parameters per request
Parameter
}
)
.GroupBy(x => x.GroupID)
.AsEnumerable();
var selector = LinqKit.Linq.Expr(propertySelector);
var results = groups
.Select(g => new { Group = g, Parameters = g.Select(x => x.Parameter) } )
.SelectMany(g =>
/* AsExpandable() extension method requires LinqKit DLL */
items.AsExpandable().Where(item => g.Parameters.Contains(selector.Invoke(item)))
);
return results;
}
Example usage:
Guid[] local_refill_ids = Refills.Select(r => r.Id).Take(20).ToArray();
IEnumerable<Refill> results = Refills.SelectByParameterList(local_refill_ids, r => r.Id, 10); //runs 2 SQL queries with 10 parameters each
Thanks again for all your help!
How to create an expression getting a property dynamically using LinqExpression in c#?
Lambda body does not require all of their arguments to be expressions.
Remove the filter from the list of lambda params and turn the type of the filter arg to SearchFilter like this:
static void Main(string[] args)
{
...
var studentParamExpr = Expression.Parameter(typeof(Student), "s");
var lambdaExpr = Expression.Lambda(
CreateStudentAddressRuleAccessor(studentParamExpr, filter),
new ParameterExpression[] { studentParamExpr });
var expression = lambdaExpr.Compile().DynamicInvoke(student);
Console.WriteLine($"Lambda expression = {lambdaExpr}");
Console.WriteLine($"Expression = {expression}");
}
public static Expression CreateStudentAddressRuleAccessor(ParameterExpression student, SearchFilter filter)
{
var resultExpr = Expression.Property(Expression.Property(student, "Address"), filter.Rule);
return resultExpr;
}
c# Lambda Expression - Get property value from string
var parameterExp = Expression.Parameter(typeof(Product), "type");
var propertyExp = Expression.Property(parameterExp, propertyName);
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var someValue = Expression.Constant(propertyValue, typeof(string));
var containsMethodExp = Expression.Call(propertyExp, method, someValue);
Expression<Func<Product, bool>> predicate = Expression.Lambda<Func<T, bool>>
(containsMethodExp, parameterExp);
var query = query.Where(predicate);
Get property value with Expression without knowing target type at compile time
Yes:
var arg = Expression.Parameter(typeof(object));
var expr = Expression.Property(Expression.Convert(arg, type), propertyName);
Note: the return type (object
) means that many types will need to be boxed. Since you mention you are doing this for filtering: if possible, try to avoid this box by creating instead a Func<object,bool>
that does any comparisons etc internally without boxing.
How to set a property value from an expression tree?
As soon as the input lambda expression represents member accessor, you can use Expression.Assign passing the input lambda expression body and parameter representing the value, e.g.
static Action<double> GetSetterForX(Expression<Func<double>> expression)
{
var parameter = Expression.Parameter(typeof(double), "value");
var body = Expression.Assign(expression.Body, parameter);
var lambda = Expression.Lambda<Action<double>>(body, parameter);
return lambda.Compile();
}
Related Topics
How to Get the Full Url of the Page I am on in C#
Performance of Static Methods VS Instance Methods
How to Access Configuration in Any Class in ASP.NET Core
Copy Rows from One Datatable to Another Datatable
How to Return a Custom Http Status Code from a Wcf Rest Method
Remove Text In-Between Delimiters in a String (Using a Regex)
Updating an Observablecollection in a Separate Thread
Synchronized Scrolling of Two Scrollviewers Whenever Any One Is Scrolled in Wpf
The Mapping of Clr Type to Edm Type Is Ambiguous with Ef 6 & 5
Does C# Support a Variable Number of Arguments, and How
No Console Output When Using Allocconsole and Target Architecture X86
How to Find Out When You'Ve Been Loaded via Xml Serialization
Print Webbrowser Without Previewing I.E. Single Click Print
What Happens If I Don't Call Dispose on the Pen Object
String Concatenation VS String Builder. Performance
Sqlconnection SQLcommand SQLdatareader Idisposable
Create Dynamic Buttons in a Grid Layout - Create a Magic Square Ui