Adding In and NotIn to System.Linq.Expressions.Expression, is it possible? - c#

I am trying to create an In and NotIn Expression operation or essentially extend System.Linq.Expressions.Expression to have the ability to check if the property value is in an array of list of property values but I don't know if it is even possible.
I was reading this article and it said "There is no way of performing a series of arbitrary operations". I don't know if creating those new operations is even possible or where to start. Any help or hint would be appreciated.
public static BinaryExpression MakeBinary(
ExpressionType binaryType,
Expression left,
Expression right)

You could just invoke the Enumerable.Contains method.
static Expression<Func<IEnumerable<string>, bool>> containsExpr = en => en.Contains(null);
static MethodInfo containsMethodInfo = ((MethodCallExpression)containsExpr.Body).Method.GetGenericMethodDefinition();
public static Expression In(this Expression value, Expression arrayOfValues)
{
return Expression.Call(containsMethodInfo.MakeGenericMethod(arrayOfValues.Type.GetElementType()),
arrayOfValues, value);
}
public static Expression NotIn(this Expression value, Expression arrayOfValues)
{
return Expression.Not(In(value, arrayOfValues));
}
Then you can call it like so:
public class Foo { public int FooValue { get; set; } }
public void ExpressionInArray()
{
var propertyReference = MemberExpression.Property(Expression.Constant(new Foo() { FooValue = 3 }), "FooValue");
var validValues = Expression.Constant(new[] { 3, 4, 5 });
var invalidValues = Expression.Constant(new[] { 6, 7, 8 });
var expressionEvaluatingToTrue = propertyReference.In(validValues);
var expressionEvaluatingToFalse = propertyReference.In(invalidValues);
var expressionEvaluatingToTrue2 = propertyReference.NotIn(invalidValues);
var expressionEvaluatingToFalse2 = propertyReference.NotIn(validValues);
}
That assumes that the type is an array and not just any old IEnumerable<T>. If you have to take any old IEnumerable<T>, you'd have to change arrayOfValues.Type.GetElementType() to something that takes arrayOfValues.Type and finds the appropriate IEnumerable<T> implementation on it and returns the generic parameter from that interface.

Related

Is there a way to map Func<T1, bool> to Func<T2, bool>?

So, I was wondering if it possible to do the next thing in c#:
I have a DB model - let's say it is Car:
public class Car {
public string Id {get;set;}
public string Name {get;set}
}
And a DbSet for this type in someDbContext:
public DbSet<Car> Cars {get;set;}
And also I have a CarDto
public class CarDto {
public string Id {get;set;}
public string Name {get;set}
}
And as result we get something like this:
var select = new Func<CarDto, bool>(car => car.Name == "BMW");
// And somehow use this expression for other type Car
someDbContext.Cars.Where(select);
Maybe there is an approach in which I could map these Funcs like this:
var newFunc = mapper.Map<Func<Car, bool>>(select);
Any thoughts?
If you just want to handle rewriting property accesses, you can use an ExpressionVisitor which looks a bit like this:
public class Program
{
public static void Main()
{
Expression<Func<Car, bool>> expr = x => x.Name == "BMW";
var replaced = ReplaceParameter<CarDto>(expr);
}
private static Expression<Func<T, bool>> ReplaceParameter<T>(LambdaExpression expr)
{
if (expr.Parameters.Count != 1)
throw new ArgumentException("Expected 1 parameter", nameof(expr));
var newParameter = Expression.Parameter(typeof(T), expr.Parameters[0].Name);
var visitor = new ParameterReplaceVisitor()
{
Target = expr.Parameters[0],
Replacement = newParameter,
};
var rewrittenBody = visitor.Visit(expr.Body);
return Expression.Lambda<Func<T, bool>>(rewrittenBody, newParameter);
}
}
public class ParameterReplaceVisitor : ExpressionVisitor
{
public ParameterExpression Target { get; set; }
public ParameterExpression Replacement { get; set; }
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression == this.Target)
{
// Try and find a property with the same name on the target type
var members = this.Replacement.Type.GetMember(node.Member.Name, node.Member.MemberType, BindingFlags.Public | BindingFlags.Instance);
if (members.Length != 1)
{
throw new ArgumentException($"Unable to find a single member {node.Member.Name} of type {node.Member.MemberType} on {this.Target.Type}");
}
return Expression.MakeMemberAccess(this.Replacement, members[0]);
}
return base.VisitMember(node);
}
}
We need to deconstruct the LambdaExpression into its body and parameters. We need to create a new parameter which has the correct type, and replace all usages of the old parameter with the new one. This is where the visitor comes in: whenever it sees you access a member on the old parameter, it tries to find the corresponding member on the new parameter, and access that instead.
We then construct a new LambdaExpression, using the rewritten body and the new parameter.
You have a whole bunch of options:
Derive your Dto class from the context class. That way you can use polymorphism as normal.
Extract an interface and implement it in both your Dto and context classes. Same as above then, use polymorphism.
Use duck-typing. In C#, that's done with the dynamic keyword. You lose Intellisense and compile-time error checking, but your code will work.
Reflection. It's a lot of code, it's slow, it's practically a much worse version of #3, but you can cobble it together if you really try.
Something like Automapper will help you map your context to your Dto piece-wise, but it won't help you translate your lambda function filters.

Entity Framework execute query with not mapped properties. Expression tree

I want to execute linq method on iqueryable with an expression tree from function where I'm passing name of linq method and name of property. But my sample method works only with mapped properties. It throws an exception when I try to for example to find max of calculated property.
My classes:
public partial class Something
{
public int a { get; set; }
public int b { get; set; }
}
public partial class Something
{
public int calculated { get { return a * b; } }
}
Sample method:
public static object ExecuteLinqMethod(IQueryable<T> q, string Field, string Method)
{
var param = Expression.Parameter(typeof(T), "p");
Expression prop = Expression.Property(param, Field);
var exp = Expression.Lambda(prop, param);
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable),Method,types,q.Expression,exp);
return q.Provider.Execute(mce);
}
To be able to query on calculated properties, you have at least 2 options:
1) you store the calculated values in the db with the rows (or in a different table), and use them in your queries of course this requires datamodel change, and redundancy in data, but is the most performant way. But is not that exciting, so lets move on to
2) you need to be able to express the way you "calculate" the properties in a way that sql will understand, meaning the property needs to be replaced with a linq expression in the final query. I found in 2009 an amazing article from Eric Lippert on registering inline such properties, but I cannot find it anymore. As such here is a link to another, that has the same idea. Basically you define your calculation as an expression tree, and use the compiled version in your code.
To make it more convenient, you would attribute your property with a
[AttributeUsage(AttributeTargets.Property)]
class CalculatedByAttribute: Attribute
{
public string StaticMethodName {get; private set;}
public CalculatedByAttribute(string staticMethodName)
{
StaticMethodName = staticMethodName;
}
}
Like:
public partial class Something
{
[CalculatedBy("calculatedExpression")]
public int calculated { get { return calculatedExpression.Compile()(this); } }
public static Expression<Func<Something, int>> calculatedExpression = s => s.a * s.b;
}
(of course you can cache the compilation) :)
Then in your method, if the property has your attribute, you get the static property value, and use that in your queries. Something along:
public static object ExecuteLinqMethod<T>(IQueryable<T> q, string Field, string Method)
{
var propInfo = typeof(T).GetProperty(Field);
LambdaExpression exp;
var myAttr = propInfo.GetCustomAttributes(typeof(CalculatedByAttribute), true).OfType<CalculatedByAttribute>().FirstOrDefault();
if (myAttr != null)
exp = (LambdaExpression)typeof(T).GetField(myAttr.StaticMethodName, BindingFlags.Static | BindingFlags.Public).GetValue(null);
else
{
var param = Expression.Parameter(typeof(T), "p");
Expression prop = Expression.Property(param, Field);
exp = Expression.Lambda(prop, param);
}
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable),Method,types,q.Expression,exp);
return q.Provider.Execute(mce);
}

Create New Expression With Different Lambda Signature From Existing Expression Body

Is it possible to do what I'm looking for here:
namespace ExpressionProblem
{
class Program
{
private static readonly List<dynamic> Items = new List<dynamic>
{
new { Name = "Foo" },
new { Name = "Bar" }
};
static void Main()
{
var result = DoSomething<Item>(p => p.Name == "Foo");
Console.WriteLine(result.Name);
}
static T DoSomething<T>(Expression<Func<T, bool>> expression)
{
//change expression lambda from Func<T, bool> to Func<dynamic, bool> so below will compile and work
return Items.FirstOrDefault(expression);
}
}
public class Item
{
public string Name { get; set; }
}
}
Basically I need to take the given expression with has a signature of
Expression<Func<T, bool>>
and get and expression which performs the same action but has the signature
Expression<Func<dynamic, bool>>.
Is this even possible? From what I've read I don't think you can change an existing expression as most places I've researched have said you basically have to build a new expression from an existing one. I tried to do the following:
var newExpression = Expression.Lambda<Func<dynamic, bool>>(expression.Body);
...but am getting the error "Incorrect number of parameters supplied for lambda declaration" when trying to create the new expression.
Any ideas on how to get this to work or am I trying to do something that can't (or shouldn't) be done?
Thanks in advance for any help you can provide.
Regards,
Craig
[EDIT] - I know some will ask why I don't just make the list of type Item - in my particular case I am not able to as the list to be queried will be in an app domain that has no knowledge of the Item type. I'm just including it in the same namespace/class here for brevity's sake.[/EDIT]

C# - How to access instances of a particular type that are used in Func<int> delegate

In Factory.Process(..) method, I want get hold of instances of MyClass that are being used in the lambda expression of the Func delegate. But, How?
Can someone help me find a way to do it.
Edit: This is an artificial example that demonstates my need. My intention behind this approach is that, I want to keep track of (or subscribe to) all the MyClass objects that are used in the delegate definition. So that, I can recalculate my total value whenever any MyClass object value is changed. Please suggest as to how to go about to solve this.
Note: Expression tree doesnt seem to help in my case because I cant modify my parameter type at this moment and it restricts the usage of my complex function definitions.
public class MyClass
{
public int Value;
public MyClass(int value)
{
Value = value;
}
}
public class TestClass
{
public void TestMethod()
{
var obj1 = new MyClass(10);
var obj2 = new MyClass(20);
Factory.Process(() => obj1.Value + obj2.Value);
}
}
public static class Factory
{
public static void Process(Func<int> function)
{
var total = function.Invoke();
// Here, apart from invoke, I want to access the all the instances of MyClass that are used in 'function'
// but how do I get to obj1 and obj2 objects through the 'function' delegate?
}
}
First of all, if you type an input parameter as just Func<T> it's not an expression, but just a lambda syntax for delegates.
If you want to be able to access the expression and do some reflection and/or analysis, you need to type your parameters as Expression<T>. For example: Expression<Func<int>>. This turns your expression into an expression tree.
Expression trees enable you to access the expression like a data structure. Once you've finished analyzing your expression tree, you can call yourExpression.Compile(), and this will compile your expression tree into a delegate that can be invoked as any other delegate (either named and anonymous ones).
For example, obj1 would be accessed this way:
public class MyClass
{
public int Value { get; set; }
}
static void Main(string[] args)
{
var obj1 = new MyClass { Value = 1 };
var obj2 = new MyClass { Value = 2 };
Expression<Func<int>> expr = () => obj1.Value + obj2.Value;
BinaryExpression binaryExpr = (BinaryExpression)expr.Body;
MemberExpression memberExpr = (MemberExpression)binaryExpr.Left;
MemberExpression fieldExpr = (MemberExpression)memberExpr.Expression;
ConstantExpression constantExpr = (ConstantExpression)fieldExpr.Expression;
dynamic value = constantExpr.Value;
MyClass some = value.obj1;
}
Update
OP said in some comment:
unfortunately, changing from parameter Func to
Expression> doesnt seem to work well in my situation because,
expression tree is restricting my function delegate definition from
using assignment operators and statement body.
My answer to this is you want an unexisting universal solution, because any other solution might compromise maintainability.
Maybe there's an alternative that will allow you to stay with delegates instead of expression trees: a delegate with an out parameter which would contain a collection of objects involved in there...
Since standard BCL Func delegates don't come with output parameters, you can declare your own Func delegate as follows:
public delegate TResult Func<out T>(out IDictionary<string, object> objects);
...and your delegate should set the so-called out parameter:
using System;
using System.Collections.Generic;
public class Program
{
public class MyClass
{
public int Value { get; set; }
}
public delegate void Func<out T>(out IDictionary<string, object> objects);
public static void Main()
{
Func<int> someFunc = (out IDictionary<string, object> objects) =>
{
var obj1 = new MyClass { Value = 1 };
var obj2 = new MyClass { Value = 2 };
int result = obj1.Value + obj2.Value;
objects = new Dictionary<string, object> { { "obj1", obj1 }, { "obj2", obj2 } };
};
IDictionary<string, object> objectsInFunc;
someFunc(out objectsInFunc);
}
}
As written, it cannot be done, because you're trying to access information about the exact code and would thus need to examine the incoming IL (since the actual C# code is gone after compilation).
However, it WOULD be possible using the metacode libraries of System.Linq.Expression namespace, but only if you swap out Func<int> for Expression<Func<int>>. With this, you would then be able to walk the expressions tree created by your lambda call. Using an Expression in place of another delegate type also tells the compiler to make an expression tree, rather than actually compiling the code, so this won't work if you pass a direct method or try to examine non-expression tree objects the same way.
You can if you change the parameter type of Process to Expression<Func<int>> expr:
public static void Process(Expression<Func<int>> expr)
{
Func<int> function = expr.Compile();
var total = function();
Expression left = ((BinaryExpression)expr.Body).Left;
Expression leftObjExpr = ((MemberExpression)left).Expression;
Expression<Func<MyClass>> leftLambda =
Expression.Lambda<Func<MyClass>>(leftObjExpr);
Func<MyClass> leftFunc = leftLambda.Compile();
MyClass obj1 = leftFunc();
int value = obj1.Value; // ==> 10
// Same with right operand...
}
Note that you can still invoke the function; you just have to compile the lambda expression to get a callable function.
However, this will only work with a binary expression. If you want to parse all kinds of expressions, this becomes quite complicated. You best solve this problem with the Visitor pattern.

Trying to use parent property as parameter in child collection expression; LinqKit throws "Unable to cast MethodCallExpressionN to LambdaExpression"

I'm trying to dynamically construct an expression similar to the one below, where I can use the same comparison function, but where the values being compared can be passed in, since the value is passed from a property 'higher-up' in the query.
var people = People
.Where(p => p.Cars
.Any(c => c.Colour == p.FavouriteColour));
I believe I've constructed the query correctly, but the ExpressionExpander.VisitMethodCall(..) method throws the following exception when I try to use it:
"Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'"
In real-world code, using Entity Framework and actual IQueryable<T>, I often get:
"Unable to cast object of type 'System.Linq.Expressions.MethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'" as well.
I've constructed a LinqPad-friendly example of my problem, as simple as I could make it.
void Main()
{
var tuples = new List<Tuple<String, int>>() {
new Tuple<String, int>("Hello", 4),
new Tuple<String, int>("World", 2),
new Tuple<String, int>("Cheese", 20)
};
var queryableTuples = tuples.AsQueryable();
// For this example, I want to check which of these strings are longer than their accompanying number.
// The expression I want to build needs to use one of the values of the item (the int) in order to construct the expression.
// Basically just want to construct this:
// .Where (x => x.Item1.Length > x.Item2)
var expressionToCheckTuple = BuildExpressionToCheckTuple();
var result = queryableTuples
.AsExpandable()
.Where (t => expressionToCheckTuple.Invoke(t))
.ToList();
}
public Expression<Func<string, bool>> BuildExpressionToCheckStringLength(int minLength) {
return str => str.Length > minLength;
}
public Expression<Func<Tuple<string, int>, bool>> BuildExpressionToCheckTuple() {
// I'm passed something (eg. Tuple) that contains:
// * a value that I need to construct the expression (eg. the 'min length')
// * the value that I will need to invoke the expression (eg. the string)
return tuple => BuildExpressionToCheckStringLength(tuple.Item2 /* the length */).Invoke(tuple.Item1 /* string */);
}
If I'm doing something obviously wrong, I'd really appreciate a nudge in the right direction! Thanks.
Edit: I know that the following would work:
Expression<Func<Tuple<string, int>, bool>> expr = x => x.Item1.Length > x.Item2;
var result = queryableTuples
.AsExpandable()
.Where (t => expr.Invoke(t))
.ToList();
However, I'm trying to separate the comparison from the location of the parameters, since the comparison could be complex and I would like to re-use it for many different queries (each with different locations for the two parameters). It is also intended that one of the parameters (in the example, the 'min length') would actually be calculated via another expression.
Edit: Sorry, I've just realised that some answers will work when attempted against my example code since my example is merely masquerading as an IQueryable<T> but is still a List<T> underneath. The reason I'm using LinqKit in the first place is because an actual IQueryable<T> from an EntityFramework DbContext will invoke Linq-to-SQL and so must be able to be parsed by Linq-to-SQL itself. LinqKit enables this by expanding everything to expressions.
Solution! Thanks to Jean's answer below, I think I've realised where I'm going wrong.
If a value has come from somewhere in the query (i.e. not a value that is known before-hand.) then you must build the reference/expression/variable to it into the expression.
In my original example, I was trying to pass the 'minLength' value taken from within the expression and pass it to a method. That method call could not be done before-hand, since it used a value from the expression, and it could not be done within the expression, since you can't build an expression within an expression.
So, how to get around this? I chose to write my expressions so that they can be invoked with the additional parameters. Though this has the downside that the parameters are no longer 'named' and I could end up with an Expression<Func<int, int, int, int, bool>> or something down the line.
// New signature.
public Expression<Func<string, int, bool>> BuildExpressionToCheckStringLength() {
// Now takes two parameters.
return (str, minLength) => str.Length > minLength;
}
public Expression<Func<Tuple<string, int>, bool>> BuildExpressionToCheckTuple() {
// Construct the expression before-hand.
var expression = BuildExpressionToCheckStringLength();
// Invoke the expression using both values.
return tuple => expression.Invoke(tuple.Item1 /* string */, tuple.Item2 /* the length */);
}
OK, so what you are trying to do (the transformation from a function that takes a single argument, that returns another function that takes a single argument f(x)(y) into a function that takes two arguments f(x, y)) is known as uncurrying. Look it up! :)
Now, the issue that you have in your code is that, in the expression returned by BuildExpressionToCheckTuple, there is a method call to BuildExpressionToCheckStringLength, which is not resolved. And you cannot resolve it because it takes an argument that is embedded in the tuple parameter.
The solution is, instead of using a method call, to use a lambda expression that will be equivalent to that method call.
That is:
public Expression<Func<int, Func<string, bool>>> ExpressionToCheckStringLengthBuilder() {
return minLength =>
str => str.Length > minLength;
}
public Expression<Func<Tuple<string, int>, bool>> BuildExpressionToCheckTuple() {
// I'm passed something (eg. Tuple) that contains:
// * a value that I need to construct the expression (eg. the 'min length')
// * the value that I will need to invoke the expression (eg. the string)
// Putting builder into a variable so that the resulting expression will be
// visible to tools that analyze the expression.
var builder = ExpressionToCheckStringLengthBuilder();
return tuple => builder.Invoke(tuple.Item2 /* the length */).Invoke(tuple.Item1 /* string */);
}
So you are looking for something like this:
public static class Program
{
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public static IQueryable<T> WherePropertyEquals<T, TProperty>(
this IQueryable<T> src, Expression<Func<T, TProperty>> property, TProperty value)
{
var result = src.Where(e => property.Invoke(e).Equals(value));
return result;
}
public static IQueryable<T> WhereGreater<T, TProperty>(
this IQueryable<T> src, Expression<Func<T, TProperty>> property, TProperty value)
where TProperty : IComparable<TProperty>
{
var result = src.Where(e => property.Invoke(e).CompareTo(value) > 0);
return result;
}
public static IQueryable<T> WhereGreater<T, TProperty>(
this IQueryable<T> src, Expression<Func<T, TProperty>> left, Expression<Func<T, TProperty>> right)
where TProperty : IComparable<TProperty>
{
var result = src.Where(e => left.Invoke(e).CompareTo(right.Invoke(e)) > 0);
return result;
}
public static void Main()
{
var persons = new List<Person>()
{
new Person
{
FirstName = "Jhon",
LastName = "Smith"
},
new Person
{
FirstName = "Chuck",
LastName = "Norris"
},
new Person
{
FirstName = "Ben",
LastName = "Jenkinson"
},
new Person
{
FirstName = "Barack",
LastName = "Obama"
}
}
.AsQueryable()
.AsExpandable();
var chuck = persons.WherePropertyEquals(p => p.FirstName, "Chuck").First();
var ben = persons.WhereGreater(p => p.LastName.Length, 6).First();
var barack = persons.WhereGreater(p => p.FirstName.Length, p => p.LastName.Length).First();
}

Categories

Resources