Convert Expression<Func<T, object>> to Expression<Func<object>> - c#

How to convert : Expression<Func<T, object>> to Expression<Func<object>>?
For example:
public class Entity
{
public virtual long Id { get; set; }
}
Origin:
Expression<Func<Entity, object>> origin = x => x.Id;
Destination:
Entity alias = null;
Expression<Func<object>> destination = () => alias.Id;
Reason:
Actually I'm trying to create a custom cacheable ResultTransformer for Nhibernate. There is a method public QueryOverProjectionBuilder<T> WithAlias(Expression<Func<object>> alias); But in my classes for each particular entitites I would like to use more specific selector like Expression<Func<T, object>>

That's what Expression.Invoke is for.
Create a new lambda expression, and use Expression.Invoke on the original expression to compose the two expressions.
Sample:
Expression<Func<string, int>> inner = x => int.Parse(x);
var outer = Expression.Lambda<Func<int>>
(Expression.Invoke(inner, Expression.Constant("123")));
outer.Compile()().Dump(); // 123
Sadly, some expression parsers don't handle Invoke correctly - they assume it to be an invocation of a method, and reject it. In that case, you need to inline the expression. That means visiting the whole inner expression and replacing the ParameterExpressions with variables in the better case, or if parser doesn't support that either, inlining the argument in all the places.

You have two options:
Invoke the expression as Luaan suggested
Replace the parameters with the value you would like (a constant or a different expression)
Option 1 is as simple as Expression.Invoke but may not be compatible with libraries such as LINQ. Option 2 is best done using an expression visitor:
private class ExchangeParametersVisitor : ExpressionVisitor
{
public ParameterExpression Parameter { get; set; }
public Expression Value { get; set; }
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == Parameter)
{
return Value;
}
return node;
}
}
What you need to do is apply the visitor to the body of your lambda expression and use it to create a new lambda expression that contains all parameters as before except the one you replaced.

Related

Lambda expression inside another lambda expression [duplicate]

I have an existing expression of type Expression<Func<T, object>>; it contains values like cust => cust.Name.
I also have a parent class with a field of type T. I need a method that accepts the above as a parameter and generates a new expression that takes the parent class (TModel) as a parameter. This will be used as an expression parameter of an MVC method.
Thus, cust => cust.Name becomes parent => parent.Customer.Name.
Likewise, cust => cust.Address.State becomes parent => parent.Customer.Address.State.
Here's my initial version:
//note: the FieldDefinition object contains the first expression
//described above, plus the MemberInfo object for the property/field
//in question
public Expression<Func<TModel, object>> ExpressionFromField<TModel>(FieldDefinition<T> field)
where TModel: BaseModel<T>
{
var param = Expression.Parameter(typeof(TModel), "t");
//Note in the next line "nameof(SelectedItem)". This is a reference
//to the property in TModel that contains the instance from which
//to retrieve the value. It is unqualified because this method
//resides within TModel.
var body = Expression.PropertyOrField(param, nameof(SelectedItem));
var member = Expression.MakeMemberAccess(body, field.Member);
return Expression.Lambda<Func<TModel, object>>(member, param);
}
The error I'm currently receiving is when I have a field with multiple parts (i.e. cust.Address.State instead of just cust.Name). I get an error on the var member line that the specified member doesn't exist--which is true, since the body at that refers to the parent's child (Customer) and not the item that contains the member (Address).
Here's what I wish I could do:
public Expression<Func<TModel, object>> ExpressionFromField<TModel>(FieldDefinition<T> field)
where TModel: BaseModel<T>
{
var param = Expression.Parameter(typeof(TModel), "t");
var body = Expression.PropertyOrField(param, nameof(SelectedItem));
var IWantThis = Expression.ApplyExpressionToField(field.Expression, body);
return Expression.Lambda<Func<TModel, object>>(IWantThis, param);
}
Any help getting to this point would be greatly appreciated.
Edit: This was marked as a possible duplicate of this question; however, the only real similarity is the solution (which is, in fact, the same). Composing expressions is not an intuitive solution to accessing nested properties via expressions (unless one's inuition is guided by certain experience, which should not be assumed). I also edited the question to note that the solution needs to be suitable for a paramter of an MVC method, which limits the possible solutions.
What you're looking for is the ability to compose expressions, just as you can compose functions:
public static Expression<Func<T, TResult>> Compose<T, TIntermediate, TResult>(
this Expression<Func<T, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
return Expression.Lambda<Func<T, TResult>>(
second.Body.Replace(second.Parameters[0], first.Body),
first.Parameters[0]);
}
This relies on the following method to replace all instances of one expression with another:
public class ReplaceVisitor:ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression ex)
{
if(ex == from) return to;
else return base.Visit(ex);
}
}
public static Expression Replace(this Expression ex,
Expression from,
Expression to)
{
return new ReplaceVisitor(from, to).Visit(ex);
}
You can now take an expression selecting a property:
Expression<Func<Customer, object>> propertySelector = cust => cust.Name;
And an expression selecting that object from the model:
Expression<Func<CustomerModel, Customer>> modelSelector = model => model.Customer;
and compose them:
Expression<Func<Customer, object> magic = modelSelector.Compose(propertySelector);

How to assign a value from MemberExpression to a field according to another MemberExpression?

I would like write a method which accepts two MemberExpression, and generates a delegate which accepts two objects - source and target, and assigns the value from the source - according to it's MemberExpression, to the field of the target, according to the second MemberExpression. The objects does not have to be of the same type.
I'm looking for something like this:
public Action<TSource, TTarget> Map(Expression<Func<TSource, object>> getter, Expression<Func<TTarget, object>> setter)
{
var sourceField = getter.Body as MemberExpression;
var targetField = setter.Body as MemberExpression;
/*
* Now I would like to create a lambda expression which accepts TSource and TTarget instances,
* and assings TTarget according to the above getter and setter expressions. Kind of like:
* var assignExp = Expression.Assign(x, y);
* var lambda = Expression.Lambda<Action<TTarget, TSource>>( .... ).Compile();
* return lambda;
*/
}
Usage:
Target target;
Source source;
//...
var action = Map(p => p.NestedField.Dummy, x => x.TargetName);
action(source, target);
I don't understand how to build the expressions to send to Expression.Assign.
At this point, I don't mind about null values or initialization of fields. Please assume all fields are initialized.
Assign is used to generate assign expression, but in your case each lambda expression has own parameter, and both this parameters should be send to a new lambda expression.
So in my example i generate new assign expression, then create a new lambda expression, and send ParameterExpression from both getter and setter expressions to a new lambda.
So it should be like this:
Here is working sample - https://dotnetfiddle.net/uuPVAl and the code itself
using System;
using System.Linq.Expressions;
public class Program
{
public static void Main(string[] args)
{
Target target = new Target();
Source source = new Source()
{
NestedField = new NestedSource()
{
Dummy = "Hello world"
}
};
var action = Map<Source, Target>(p => p.NestedField.Dummy, x => x.TargetName);
action(source, target);
Console.WriteLine(target.TargetName);
}
public static Action<TSource, TTarget> Map<TSource, TTarget>(Expression<Func<TSource, object>> getter, Expression<Func<TTarget, object>> setter)
{
var sourceField = getter.Body as MemberExpression;
var targetField = setter.Body as MemberExpression;
// here we create new assign expression
var assign = Expression.Assign(targetField, sourceField);
// and then compile it with original two parameters
var lambda = Expression.Lambda<Action<TSource, TTarget>>(assign, getter.Parameters[0], setter.Parameters[0]);
return lambda.Compile();
}
}
public class Target
{
public string TargetName { get; set; }
}
public class NestedSource
{
public string Dummy { get; set; }
}
public class Source
{
public NestedSource NestedField { get; set; }
}
UPDATE
So each Lambda Expression can have any parameters. From code side it's ParameterExpression. When you write expression as typical code, then it means function parameters, so in your case (p) => p.NestedField.Dummy - (p) is parameter of that function. And expression inside body uses it - p.NestedField.Dummy, so to be able to compile it - lambda expression needs to know that parameter.
In this case you have two lambda expressions for target and source, and each of them have own parameter - (p) and (x) and each expression use own parameter. But in result function we need to use both of them, as we have two parameters in the function, so we need to resend original ParameterExpression from source and target to a new lambda. Or you can create a new ParameterExpression but then you need to create a new tree as old one will use old ParameterExpression. Usually such things are done with ExpressionVisitor class, but in your case we can just resend original expressions without tree body changes.
This will do:
public Action<TSource, TTarget> Map<TSource, TTarget>(Expression<Func<TSource, object>> getter, Expression<Func<TTarget, object>> setter)
{
var targetPropertyExpression = setter.Body as MemberExpression;
var targetProperty = targetPropertyExpression.Member as PropertyInfo;
return (src, tgt) => { targetProperty.SetValue(tgt, getter.Compile().Invoke(src)); };
}
It get's the property of the setter from the 1st lambda expression and just returns an action, which assigns the value to the property based on the 2nd lambda expression, which just needs to be invoked.
Take care of the <TSource, object> though, you maybe need an additional cast.

Returning filtered IQueryable<T> with anonymous types

I have a set of Reports which I need to perform filtering on before returning the output. I would like to perform this with a single anonymous method to avoid duplicating the same code in different repositories. I'm using Entity Framework so the model types all related to the database and inherit from a base class called ReportBase.
This is what how I currently implement the filtering, each report type has to implement this method with a different context and returning a different IQueryable type.
private IQueryable<ReviewAgreement> GetFiltered(ReportFilter filter)
{
IQueryable<ReviewAgreement> reviewAgreementQueryable = Context.ReviewAgreements.Where(p => p.ClientWorkflowId == filter.ClientWorkflowId);
if (filter.AppraisalLevelId.HasValue)
{
reviewAgreementQueryable = reviewAgreementQueryable.Where(p => p.AppraisalLevelId == filter.AppraisalLevelId.Value);
}
return reviewAgreementQueryable;
}
I've been trying to implement this anonymously so I can reuse it, as in this non functional example.
public IQueryable<T> GetFiltered(ReportFilter filter)
{
IQueryable<T> reportQueryable = Context.Set<T>();
reportQueryable = reportQueryable.Where(p => p.ClientWorkflowId == filter.ClientWorkflowId);
if (filter.AppraisalLevelId.HasValue)
{
reportQueryable = reportQueryable.Where(p => p.AppraisalLevelId == filter.AppraisalLevelId.Value);
}
return reportQueryable;
}
The issue I am having is of course that the use of Where is ambiguous, so it cannot resolve p.ClientWorkflowId.
I have tried using a Func<T, TResult> delegate to pass in the filtering options this but the Where operation seems to want to return a list.
Is there actually a method I can use to achieve the effect I want?
Declare an interface that has the two ID properties that you need to perform this operation.
Ensure that your entities implement that interface.
Add a constraint to the generic argument that it implements that interface.
Note that if your base class defines both of the properties in question then you don't need an interface, and can simply constrain the type to that base class:
public IQueryable<T> GetFiltered<T>(ReportFilter filter) where T : ReportBase
{
// body unchanged
}
If you want to go down the route of accepting parameters to represent these properties than it's also possible. The first thing is that you'll need to accept expressions, not Func objects, so that the query provider can analyze them. This means changing the function signature to:
public IQueryable<T> GetFiltered<T>(ReportFilter filter,
Expression<Func<T, int>> clientIdSelector,
Expression<Func<T, int>> appraisalIdSelector)
{
Next, to turn these selectors into predicates that compare the value to an ID that we have is a bit more involved for expressions than it is for regular delegates. What we really need here is a Compose method; for delegates it's simple enough, to compose one method with another you just invoke it with the parameter being the result of the first. With expressions this means taking the body of one expression and replacing all instance of the parameter with the body of another, and then wrapping the whole thing up in a new Lambda.
public static Expression<Func<TFirstParam, TResult>>
Compose<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
This itself is dependent on the ability to replace all instances of one expression with another. To do that we'll need to use the following:
public 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)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
Now that we have all of this in place we can actually compose our selectors with a comparison to the ID values of the filter:
IQueryable<T> reportQueryable = Context.Set<T>();
reportQueryable = reportQueryable
.Where(clientIdSelector.Compose(id => id == filter.ClientWorkflowId));
if (filter.AppraisalLevelId.HasValue)
{
reportQueryable = reportQueryable
.Where(clientIdSelector.Compose(id => id == filter.AppraisalLevelId.Value));
}
return reportQueryable;

Creating a dynamic Linq select clause from Expressions

Let's say I have defined the following variables:
IQueryable<MyClass> myQueryable;
Dictionary<string, Expression<Func<MyClass, bool>>> extraFields;
// the dictionary is keyed by a field name
Now, I want to tack on some dynamic fields to the IQueryable, so that it returns an IQueryable<ExtendedMyClass>, where ExtendedMyClass is defined as:
class ExtendedMyClass
{
public MyClass MyObject {get; set;}
public IEnumerable<StringAndBool> ExtraFieldValues {get; set;}
}
class StringAndBool
{
public string FieldName {get; set;}
public bool IsTrue {get; set;}
}
In other words, for every value in extraFields, I want to have a value in ExtendedMyClass.ExtraFieldValues representing whether that expression evaluates to True or not for that row.
I have a feeling this should be doable in dynamic Linq and LinqKit, though I've never used that seriously before. I'm also open to other suggestions, especially if this can be done in good ol' strong-typed Linq.
I am using Linq to Entities, so the query needs to translate to SQL.
So, we'll have a lot of steps here, but each individual step should be fairly short, self-contained, reusable, and relatively understandable.
The first thing we'll do is create a method that can combine expressions. What it will do is take an expression that accepts some input and generates an intermediate value. Then it will take a second expression that accepts, as input, the same input as the first, the type of the intermediate result, and then computes a new result. It will return a new expression taking the input of the first, and returning the output of the second.
public static Expression<Func<TFirstParam, TResult>>
Combine<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TFirstParam, TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], param)
.Replace(second.Parameters[1], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
To do this we simply replace all instances of the second parameter in the second expression's body with the body of the first expression. We also need to ensure both implementations use the same parameter instance for the main parameter.
This implementation requires having a method to replace all instances of one expression with another:
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
Next we'll write a method that accepts a sequences of expressions that accept the same input and compute the same type of output. It will transform this into a single expression that accepts the same input, but computes a sequence of the output as a result, in which each item in the sequence represents the result of each of the input expressions.
This implementation is fairly straightforward; we create a new array, use the body of each expression (replacing the parameters with a consistent one) as each item in the array.
public static Expression<Func<T, IEnumerable<TResult>>> AsSequence<T, TResult>(
this IEnumerable<Expression<Func<T, TResult>>> expressions)
{
var param = Expression.Parameter(typeof(T));
var body = Expression.NewArrayInit(typeof(TResult),
expressions.Select(selector =>
selector.Body.Replace(selector.Parameters[0], param)));
return Expression.Lambda<Func<T, IEnumerable<TResult>>>(body, param);
}
Now that we have all of these general purpose helper methods out of the way, we can start working on your specific situation.
The first step here is to turn your dictionary into a sequence of expressions, each accepting a MyClass and creating a StringAndBool that represents that pair. To do this we'll use Combine on the value of the dictionary, and then use a lambda as the second expression to use it's intermediate result to compute a StringAndBool object, in addition to closing over the pair's key.
IEnumerable<Expression<Func<MyClass, StringAndBool>>> stringAndBools =
extraFields.Select(pair => pair.Value.Combine((foo, isTrue) =>
new StringAndBool()
{
FieldName = pair.Key,
IsTrue = isTrue
}));
Now we can use our AsSequence method to transform this from a sequence of selectors into a single selector that selects out a sequence:
Expression<Func<MyClass, IEnumerable<StringAndBool>>> extrafieldsSelector =
stringAndBools.AsSequence();
Now we're almost done. We now just need to use Combine on this expression to write out our lambda for selecting a MyClass into an ExtendedMyClass while using the previous generated selector for selecting out the extra fields:
var finalQuery = myQueryable.Select(
extrafieldsSelector.Combine((foo, extraFieldValues) =>
new ExtendedMyClass
{
MyObject = foo,
ExtraFieldValues = extraFieldValues,
}));
We can take this same code, remove the intermediate variable and rely on type inference to pull it down to a single statement, assuming you don't find it too unweidly:
var finalQuery = myQueryable.Select(extraFields
.Select(pair => pair.Value.Combine((foo, isTrue) =>
new StringAndBool()
{
FieldName = pair.Key,
IsTrue = isTrue
}))
.AsSequence()
.Combine((foo, extraFieldValues) =>
new ExtendedMyClass
{
MyObject = foo,
ExtraFieldValues = extraFieldValues,
}));
It's worth noting that a key advantage of this general approach is that the use of the higher level Expression methods results in code that is at least reasonably understandable, but also that can be statically verified, at compile time, to be type safe. There are a handful of general purpose, reusable, testable, verifiable, extension methods here that, once written, allows us to solve the problem purely through composition of methods and lambdas, and that doesn't require any actual expression manipulation, which is both complex, error prone, and removes all type safety. Each of these extension methods is designed in such a way that the resulting expression will always be valid, so long as the input expressions are valid, and the input expressions here are all known to be valid as they are lambda expressions, which the compiler verifies for type safety.
I think it's helpful here to take an example extraFields, imagine how would the expression that you need look like and then figure out how to actually create it.
So, if you have:
var extraFields = new Dictionary<string, Expression<Func<MyClass, bool>>>
{
{ "Foo", x => x.Foo },
{ "Bar", x => x.Bar }
};
Then you want to generate something like:
myQueryable.Select(
x => new ExtendedMyClass
{
MyObject = x,
ExtraFieldValues =
new[]
{
new StringAndBool { FieldName = "Foo", IsTrue = x.Foo },
new StringAndBool { FieldName = "Bar", IsTrue = x.Bar }
}
});
Now you can use the expression trees API and LINQKit to create this expression:
public static IQueryable<ExtendedMyClass> Extend(
IQueryable<MyClass> myQueryable,
Dictionary<string, Expression<Func<MyClass, bool>>> extraFields)
{
Func<Expression<Func<MyClass, bool>>, MyClass, bool> invoke =
LinqKit.Extensions.Invoke;
var parameter = Expression.Parameter(typeof(MyClass));
var extraFieldsExpression =
Expression.Lambda<Func<MyClass, StringAndBool[]>>(
Expression.NewArrayInit(
typeof(StringAndBool),
extraFields.Select(
field => Expression.MemberInit(
Expression.New(typeof(StringAndBool)),
new MemberBinding[]
{
Expression.Bind(
typeof(StringAndBool).GetProperty("FieldName"),
Expression.Constant(field.Key)),
Expression.Bind(
typeof(StringAndBool).GetProperty("IsTrue"),
Expression.Call(
invoke.Method,
Expression.Constant(field.Value),
parameter))
}))),
parameter);
Expression<Func<MyClass, ExtendedMyClass>> selectExpression =
x => new ExtendedMyClass
{
MyObject = x,
ExtraFieldValues = extraFieldsExpression.Invoke(x)
};
return myQueryable.Select(selectExpression.Expand());
}

Passing an expression tree as a parameter to another expression tree

I have two expression trees defined like this:
private Expression<Func<TEntity, TPropertyResult>> PropertyAccessor { get; set; }
and
private Expression<Func<TPropertyResult, bool>> TestExpression { get; set; }
I need to create a new expression tree that will result in the equivalent of:
var expression = p => this.TestExpression(this.PropertyAccessor(p));
When using Expression.Invoke(this.TestExpression, this.PropertyAccessor), I get the following error
{"Expression of type
'System.Func`2[MyEntity,System.String]'
cannot be used for parameter of type
'System.String'"}
TPropertyResult is a string during my test.
I tried using Expression.Call or Expression.Invoke. No luck. What should I use?
I think this does what you are asking for:
Expression<Func<TEntity, bool>> Combined
{
get
{
var entity = Expression.Parameter(typeof(TEntity));
var pa = Expression.Invoke(PropertyAccessor, entity);
var te = Expression.Invoke(TestExpression, pa);
return (Expression<Func<TEntity, bool>>) Expression.Lambda(te, entity);
}
}
I tested this and it works as I would expect.
However, re-reading your original question (before my edits), I am beginning to get the impression that you asked the wrong question and that you probably don’t need expression trees. If all you need is functions, then you can use them without Expression:
private Func<TEntity, TPropertyResult> PropertyAccessor { get; set; }
private Func<TPropertyResult, bool> TestExpression { get; set; }
private Func<TEntity, bool> Combined
{
get
{
return entity => TestExpression(PropertyAccessor(entity));
}
}
Example of use:
// Set up the original functions
PropertyAccessor = entity => GenerateResult(entity);
TestExpression = result => result.IsCool();
// This stores a reference to the combined function
var fn = Combined;
// This actually evaluates the function
bool isCool = fn(myEntity);
// Alternatively, you could evaluate the function directly, without the variable
bool isCool = Combined(myEntity);
The easiest way I found to do this is by using LinqKit (https://github.com/scottksmith95/LINQKit)
With it you can actually do
var expression = p => this.TestExpression.Invoke(this.PropertyAccessor(p));
db.Users.Where(expression.Expand());
Expand comes with LinqKit and does the magic here, it allows EF to be able to do the translation to SQL despite having the Invoke in your expression.

Categories