Create New Expression from Existing Expression - c#

I have an Expression<Func<T,DateTime>> I want to take the DateTime part of the expression and pull the Month off of it. So I would be turning it into a Expression<Func<T,int>> I'm not really sure how to do this. I looked at the ExpressionTree Visitor but I can't get it to work like I need. Here is an example of the DateTime Expression
DateTimeExpression http://img442.imageshack.us/img442/6545/datetimeexpression.png
Here is an example of what I want to create
MonthExpression http://img203.imageshack.us/img203/8013/datetimemonthexpression.png
It looks like I need to create a new MemberExpression that is made up of the Month property from the DateTime expression but I'm not sure.

Yes, that's exactly what you want - and using Expression.Property is the easiest way to do that:
Expression func = Expression.Property(existingFunc.Body, "Month");
Expression<Func<T, int>> lambda =
Expression.Lambda<Func<T, int>>(func, existingFunc.Parameters);
I believe that should be okay. It works in this simple test:
using System;
using System.Linq.Expressions;
class Person
{
public DateTime Birthday { get; set; }
}
class Test
{
static void Main()
{
Person jon = new Person
{
Birthday = new DateTime(1976, 6, 19)
};
Expression<Func<Person,DateTime>> dateTimeExtract = p => p.Birthday;
var monthExtract = ExtractMonth(dateTimeExtract);
var compiled = monthExtract.Compile();
Console.WriteLine(compiled(jon));
}
static Expression<Func<T,int>> ExtractMonth<T>
(Expression<Func<T,DateTime>> existingFunc)
{
Expression func = Expression.Property(existingFunc.Body, "Month");
Expression<Func<T, int>> lambda =
Expression.Lambda<Func<T, int>>(func, existingFunc.Parameters);
return lambda;
}
}

Related

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

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.

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]

Converting Expression<Func<DTO,bool>> to Expression<Func<Domain, bool>>

I'm using Expression Tree Serializer for sending Expression< FuncDTO,bool>> to WCF services and
my repository is working with Domain type. I want to apply this expression for my repository
Expression<Func<UserDto,bool>> expression = new ExpressionSerializer().Deserialize<Func<UserDto, bool>>(xmlElement);
var addressBookEntries = addressBooksRepository.Where(expression); //accepts Expression<Func<UserDomain,bool>>
How can I fix this problem?
I used dynamic linq and it solved my problem, only little issue property names must be equals. I converted dynamic linq to string and sent it thorough wcf service and using it as string
using System.Linq;
using System.Linq.Dynamic;
public ICollection<UserDto> GetUsersByFilter(string filter)
{
var addressBooksRepository = new AddressBooksRepository();
var addressBookEntries = addressBooksRepository.GetAll().Where(filter);
//return data
}
Try create new expression with your type arguments based on existed one.
public class UserDto : UserDomain
{ }
public class UserDomain
{ }
void YourMethod()
{
Expression<Func<UserDto, bool>> expression = new ExpressionSerializer().Deserialize<Func<UserDto, bool>>(xmlElement);
Func<UserDto, bool> func = expression.Compile();
Expression<Func<UserDomain, bool>> newExpression = x => func(x as UserDto);
var addressBookEntries = addressBooksRepository.Where(newExpression);
}

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();
}

Lambda Expression to be used in Select() query

I am trying to build a lambda expression, containing two assignments (as shown further down), that I can then pass to a Queryable.Select() method.
I am trying to pass a string variable into a method and then use that variable to build up the lambda expression so that I can use it in a LINQ Select query.
My reasoning behind it is that I have a SQL Server datasource with many column names, I am creating a charting application that will allow the user to select, say by typing in the column name, the actual column of data they want to view in the y-axis of my chart, with the x-axis always being the DateTime. Therefore, they can essentially choose what data they chart against the DateTime value (it’s a data warehouse type app).
I have, for example, a class to store the retrieved data in, and hence use as the chart source of:
public class AnalysisChartSource
{
public DateTime Invoicedate { get; set; }
public Decimal yValue { get; set; }
}
I have (purely experimentaly) built an expression tree for the Where clause using the String value and that works fine:
public void GetData(String yAxis)
{
using (DataClasses1DataContext db = new DataClasses1DataContext())
{
var data = this.FunctionOne().AsQueryable<AnalysisChartSource>();
//just to get some temp data in....
ParameterExpression pe = Expression.Parameter(typeof(AnalysisChartSource), "p");
Expression left = Expression.MakeMemberAccess(pe,
typeof(AnalysisChartSource).GetProperty(yAxis));
Expression right = Expression.Constant((Decimal)16);
Expression e2 = Expression.LessThan(left, right);
Expression expNew = Expression.New(typeof(AnalysisChartSource));
LambdaExpression le = Expression.Lambda(left, pe);
MethodCallExpression whereCall = Expression.Call(
typeof(Queryable), "Where", new Type[] { data.ElementType },
data.Expression,
Expression.Lambda<Func<AnalysisChartSource, bool>>(e2, new ParameterExpression[] { pe }));
}
}
However……I have tried a similar approach for the Select statement, but just can’t get it to work as I need the Select() to populate both X and Y values of the AnalysisChartSource class, like this:
.Select(c => new AnalysisChartSource
{ Invoicedate = c.Invoicedate, yValue = c.yValue}).AsEnumerable();
How on earth can I build such an expression tree….or….possibly more to the point…..is there an easier way that I have missed entirely?
I find that the best way to work out how to build expression trees is to see what the C# compiler does. So here's a complete program:
using System;
using System.Linq.Expressions;
public class Foo
{
public int X { get; set; }
public int Y { get; set; }
}
class Test
{
static void Main()
{
Expression<Func<int, Foo>> builder =
z => new Foo { X = z, Y = z };
}
}
Compile that, open the results in Reflector and set the optimisation to .NET 2.0. You end up with this generated code for the Main method:
ParameterExpression expression2;
Expression<Func<int, Foo>> expression =
Expression.Lambda<Func<int, Foo>>(
Expression.MemberInit(
Expression.New((ConstructorInfo) methodof(Foo..ctor), new Expression[0]),
new MemberBinding[] { Expression.Bind((MethodInfo) methodof(Foo.set_X),
expression2 = Expression.Parameter(typeof(int), "z")),
Expression.Bind((MethodInfo) methodof(Foo.set_Y),
expression2) }
),
new ParameterExpression[] { expression2 });
Basically, I think Expression.MemberInit is what you're after.

Categories

Resources