Update: This does work, I was being stupid :(
i have the following extension method
public static string ExtMethod(this object self, object myparameter);
at runtime this is called in any number of ways ways, i think these are all possibilities:
Expression<Func<T, string>> expr = x => x.property.ExtMethod(5);
Expression<Func<T, string>> expr = x => x.property.ExtMethod(new object());
Expression<Func<T, string>> expr = x => x.property.ExtMethod(someMethod());
Expression<Func<T, string>> expr = x => x.property.ExtMethod(x.someMethod());
Expression<Func<T, string>> expr = x => x.property.ExtMethod(x.OtherProperty);
what i need to do is evaluate the "myparameter", given "expr" and a "T"
because of the two cases where x is used in myparameter, i thought i needed to create a delegate of the form:
Expression<Func<T, object>> expr = x => [myparameter expression here]
i thought this would work:
var extMethodExpr = expr.Body as MethodCallExpression;
var myparameterExpr = extMethodExpr.Arguments[1];
var myparam = Expression.Lambda(myparameterExpr, expr.Parameters).Compile().Invoke(someT)
but for the expressions that do not involve x, i get TargetParameterCountException :(
in these cases, if i do:
var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT)
it works fine.
How do I solve this?
thanks
OK; got to the bottom of it; in the line:
var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT);
If you weren't trying to pass in a someT, this would work for those expressions that don't involve x in the argument; for those that do, you need to tell the lambda to include the parameter (the same one from the original lambda) - simply by:
var myparam = Expression.Lambda(myparameterExpr,
outerLambda.Parameters[0]).Compile().Invoke(someT);
Here's some working code that evaluates the inner parameter (given an instance of the argument type); note that I use the parameter even if it doesn't involve an x - otherwise, what would it do with the instance?
using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo {
public string Bar {get;set;}
public int someMethod() { return 4; }
public int OtherProperty { get { return 3; } }
}
static class Program
{
static int someMethod() { return 3; }
static void Main()
{
Foo foo = new Foo();
Test<Foo>(x => x.Bar.ExtMethod(5), foo);
Test<Foo>(x => x.Bar.ExtMethod(new object()), foo);
Test<Foo>(x => x.Bar.ExtMethod(someMethod()), foo);
Test<Foo>(x => x.Bar.ExtMethod(x.someMethod()), foo);
Test<Foo>(x => x.Bar.ExtMethod(x.OtherProperty), foo);
}
static void Test<T>(Expression<Func<T, string>> expr, T instance)
{
if (expr.Body.NodeType != ExpressionType.Call)
{
throw new InvalidOperationException("Call expected");
}
var call = ((MethodCallExpression)expr.Body);
if (call.Method != typeof(Program).GetMethod(
"ExtMethod", BindingFlags.Static | BindingFlags.NonPublic))
{
throw new InvalidOperationException("ExtMethod expected");
}
// we know that ExtMethod has 2 args; pick myParameter (the 2nd);
// then build an expression over arg, re-using our outer param
var newLambda = Expression.Lambda<Func<T, object>>(
call.Arguments[1], expr.Parameters[0]);
// evaluate it and show the argument value
object value = newLambda.Compile()(instance);
Console.WriteLine(value);
}
static string ExtMethod(this object self, object myParameter) {
return self.ToString();
}
}
What if you check expr.Parameters.Count and if it's 0, invoke without the parameters?
Related
I have the following problem in my lambda expression: I need to rename the property because it will be passed from entity to entity. In other words: I need to use the same expression in more than one query in different entities.
For example:
var expr = x => x.Id == converterId
To be
var expr = x => x.ConverterId == converterId
I have tried to do the following
var oldParam = expr.Parameters[0];
var newParam = Expression.Parameter(oldParam.Type, "ConverterId");
This code replaces x not Id`
This isn't trivial, but can be done my writing (subclassing) an ExpressionVisitor, and overriding VisitMember, making the substitution for a different Expression.Property, but using the original target expression (from the expression in the original lambda)
However, for simple cases, it is probably easier to forget that, and just build the expression-tree manually from first principles, rather than using a lambda.
The following shows both approaches:
using System;
using System.Linq.Expressions;
static class P
{
static void Main()
{
// the compiler-generated expression-tree from the question
Console.WriteLine(Baseline(42));
// build our own epression trees manually
Console.WriteLine(ByName(42, nameof(Foo.Id)));
Console.WriteLine(ByName(42, nameof(Foo.ConverterId)));
// take the compiler-generated expression tree, and rewrite it with a visitor
Console.WriteLine(Convert(Baseline(42), nameof(Foo.Id), nameof(Foo.ConverterId)));
}
static Expression<Func<Foo, bool>> Baseline(int converterId)
{
// note this uses a "captured variable", so the output
// looks uglier than you might expect
return x => x.Id == converterId;
}
static Expression<Func<Foo, bool>> ByName(int converterId, string propertyOrFieldName)
{
var p = Expression.Parameter(typeof(Foo), "x");
var body = Expression.Equal(
Expression.PropertyOrField(p, propertyOrFieldName),
Expression.Constant(converterId, typeof(int))
);
return Expression.Lambda<Func<Foo, bool>>(body, p);
}
static Expression<Func<Foo, bool>> Convert(
Expression<Func<Foo, bool>> lambda, string from, string to)
{
var visitor = new ConversionVisitor(from, to);
return (Expression<Func<Foo, bool>>)visitor.Visit(lambda);
}
class ConversionVisitor : ExpressionVisitor
{
private readonly string _from, _to;
public ConversionVisitor(string from, string to)
{
_from = from;
_to = to;
}
protected override Expression VisitMember(MemberExpression node)
{
if(node.Member.Name == _from)
{
return Expression.PropertyOrField(
node.Expression, _to);
}
return base.VisitMember(node);
}
}
}
class Foo
{
public int Id { get; set; }
public int ConverterId { get; set; }
}
I want to declare and reuse Expression with filter by variable y. In a method I have something like following:
Expression<Func<Item, int, bool>> exFilter = (x, y) => x.Item.Id == y;
Further on, in a code I'm trying to use declared expression (exFilter)
return context.Item.Select(x => new { data = exFilter.Where(exFilter))
Q: How do I pass parameter to the exFilter? I want to do select filtered by every item in a list(x).
This is just a sample what I'm trying to figure out. The problem and query is much bigger and complicated.
You can use LinqKit to reuse the expression that you have. Here is an example:
var result =
context.Item //The DbSet
.AsExpandable() //This method is defined in LinqKit and allows for expression expansion
.Where(x => exFilter.Invoke(x, 2)) //LinqKit will know how to translate this into an expression
.ToList();
I am using the value 2 here as an example.
You can rewrite you code like this:
Expression<Func<Item, bool>> exFilter(int y){ return (x) => x.item.Id == y;}
And use it like this:
int paramY = 456;
return context.Item.Select(exFilter(paramY))
You can try something like this:
public class Item
{
public Item(String str, Int32 #int)
{
this.StrValue = str;
this.IntValue = #int;
}
public String StrValue { get; }
public Int32 IntValue { get; }
public override string ToString() =>
$"{this.IntValue} = '{this.StrValue}'";
}
public static class ExpressionExtensions
{
public static Expression<Func<TItem, TResult>> Curry<TItem, TCurry, TResult>(
this Expression<Func<TItem, TCurry, TResult>> function,
TCurry value)
{
if (function == null)
throw new ArgumentNullException(paramName: nameof(function));
var itemParameter = Expression.Parameter(typeof(TItem));
var valueConstant = Expression.Constant(value);
return Expression.Lambda<Func<TItem, TResult>>(
Expression.Invoke(
function,
new Expression[]
{
itemParameter,
valueConstant
}),
new[] { itemParameter });
}
}
...
var items = new[]
{
new Item("one", 1),
new Item("two", 2),
new Item("two again", 2),
};
Expression<Func<Item, Int32, Boolean>> predicate = (item, intValue) =>
item.IntValue == intValue;
var curriedPredicate = predicate.Curry(2);
var filtered = items
.AsQueryable<Item>()
.Where(curriedPredicate)
.ToArray();
foreach (var item in filtered)
{
Console.WriteLine(item);
}
eg: x=> x.Name = "g"
I have code block like this
public Expression<Func<TEntity, bool>> SearchExpression()
{
var c = new ConstantExpression[_paramList.Count];
var b = new BinaryExpression[_paramList.Count];
BinaryExpression comparisonExpression = null;
var entity = Expression.Parameter(typeof(TEntity));
for (int i = 0; i < _paramList.Count; i++)
{
var value = Convert.ChangeType(_paramList[i].Item2 /*"g"*/, _paramList[i].Item3 /*System.String*/);
c[i] = Expression.Constant(value); //"g"
// PROBLEM IS HERE
b[i] = Expression.Equal(Expression.Property(entity, _paramList[i].Item1 /*Name*/, c[i]);
// PROBLEM IS HERE
}
_paramList.Clear();
comparisonExpression = b.Aggregate(Expression.And);
return Expression.Lambda<Func<TEntity, bool>>(comparisonExpression, entity);
}
works like charm but I need Expression.Like (Like "g" not Equal "g")
Expression.Like(Expression.Property(entity, _paramList[i].Item1), c[i])
but C# expression tree does not support Like method
UPDATE :
I wrote something like this :
Expression.Call(Expression.Property(entity, _paramList[i].Item1),
typeof(String).GetMethod("Contains"), new Expression[] { c[i] });
but I need BinaryExpression not MethodCallExpression
You can make your code work by adding an equals expression over the method call, like so:
b[i] = Expression.Equal(
Expression.Call(Expression.Property(entity, _paramList[i].Item1),
typeof (String).GetMethod("Contains"),
new Expression[] {c[i]}), Expression.Constant(true));
In pseudo code this reads as:
b[i] = entity => entity.someProperty.Contains(c[i]) == true;
Which will return a binary expression for you.
This answer does not consider your array and the 'and' aggregation, but this should be considered as a separate issue.
Consider this class:
class MyEntity { string Name { get; set; } }
We want to query:
select ... from MyEntity where Name like '%query%';
The following method is a general implementation of the above query pattern:
static Expression<Func<TEntity, bool>> Like<TEntity>(string propertyName, string queryText)
{
var parameter = Expression.Parameter(typeof (TEntity), "entity");
var getter = Expression.Property(parameter, propertyName);
//ToString is not supported in Linq-To-Entities, throw an exception if the property is not a string.
if (getter.Type != typeof (string))
throw new ArgumentException("Property must be a string");
//string.Contains with string parameter.
var stringContainsMethod = typeof (string).GetMethod("Contains", new[] {typeof (string)});
var containsCall = Expression.Call(getter, stringContainsMethod,
Expression.Constant(queryText, typeof (string)));
return Expression.Lambda<Func<TEntity, bool>>(containsCall, parameter);
}
If you want to have a pattern of query% or %query you can use string.StartsWith and string.EndsWith instead of Contains.
Also, you can share the parameter across multiple calls if you adjust the signature.
The current implementation throws an exception if the data type of the property is not a string. Look at this answer https://stackoverflow.com/a/3292773/668272 for converting numbers to strings.
I've done this in a scripting language I wrote, which allows you to say things like name like 'bob%'. The trick is that you need to map it to a method call which takes the value and regular expression and call this from within the Expression.
If you take a look at the LikeEvaluator class in my Wire scripting language you'll see how I did it:
static class LikeEvaluator
{
private static readonly MethodInfo ApplyLikeMethodInfo=typeof(LikeEvaluator).GetMethod("ApplyLike");
private static readonly MethodInfo ApplyLikeNoCaseMethodInfo=typeof(LikeEvaluator).GetMethod("ApplyLikeNoCase");
public static Expression Like(CaseMode caseMode, Expression lhs, Expression pattern)
{
Expression x=null;
if(caseMode==CaseMode.Sensitive)
{
x=Expression.Call(ApplyLikeMethodInfo,lhs,pattern);
}
else
{
x=Expression.Call(ApplyLikeNoCaseMethodInfo,lhs,pattern);
}
return x;
}
public static bool ApplyLike(string text, string likePattern)
{
string pattern=PatternToRegex(likePattern);
return Regex.IsMatch(text,pattern,RegexOptions.None);
}
public static bool ApplyLikeNoCase(string text, string likePattern)
{
string pattern=PatternToRegex(likePattern);
return Regex.IsMatch(text,pattern,RegexOptions.IgnoreCase);
}
public static string PatternToRegex(string pattern)
{
pattern=Regex.Escape(pattern);
pattern=pattern.Replace("%",#".*");
pattern=string.Format("^{0}$",pattern);
return pattern;
}
}
Considering this code:
public class Foo
{
public int a { get; set; }
public int b { get; set; }
}
private void Test()
{
List<Foo> foos = new List<Foo>();
foos.Add(new Foo());
foos.Add(new Foo());
Expression<Func<Foo, int>> exp0 = f => f.a * f.b;
Expression<Func<int>> exp1 = () => foos[0].a * foos[0].b;
Expression<Func<int>> exp2 = () => foos[1].a * foos[1].b;
}
How can you take exp0 and turn it into two expressions identical to exp1 and exp2. Note that I don't want to just evaluate exp0 for each Foo in foos, but instead get two new expressions.
[Update]:
Basically, I want to be able to expand or "flatten" an expression passed to a Linq extension method such as Sum into one expression per item in the enumeration since these enumerations will be static, and because I already have code that reads expressions that don't take parameters (and then turns them into another language).
I'm using the MetadataToken as a references to properties that have a certain attribute (in this case a and b would have this attribute) and using it with a dictionary that correlates C# properties to another language's variables:
Foo foo = new Foo();
Expression<Func<int>> exp = () => foo.a * foo.a + foo.b;
string result1 = GetResult(exp); // gets "v_001 * v_001 + v_002"
List<Foo> foes = new List<Foo>();
foes.Add(new Foo());
foes.Add(new Foo());
Expression<Func<int>> exp2 = () => foes.Sum(f => f.a * f.a + f.b);
string result2 = GetResult(exp2); // should get "(v_001 * v_001 + v_002) + (v_003 * v_003 + v_004)"
I would do it this way:
Write a parameter-replacer expression-visitor that manipulates the original expression as follows:
Gets rid of the parameter you don't want entirely from the lambda signature.
Replaces all uses of the parameter with the desired indexer expression.
Here's a quick and dirty sample I whipped up based on my earlier answer on a different question:
public static class ParameterReplacer
{
// Produces an expression identical to 'expression'
// except with 'source' parameter replaced with 'target' expression.
public static Expression<TOutput> Replace<TInput, TOutput>
(Expression<TInput> expression,
ParameterExpression source,
Expression target)
{
return new ParameterReplacerVisitor<TOutput>(source, target)
.VisitAndConvert(expression);
}
private class ParameterReplacerVisitor<TOutput> : ExpressionVisitor
{
private ParameterExpression _source;
private Expression _target;
public ParameterReplacerVisitor
(ParameterExpression source, Expression target)
{
_source = source;
_target = target;
}
internal Expression<TOutput> VisitAndConvert<T>(Expression<T> root)
{
return (Expression<TOutput>)VisitLambda(root);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
// Leave all parameters alone except the one we want to replace.
var parameters = node.Parameters
.Where(p => p != _source);
return Expression.Lambda<TOutput>(Visit(node.Body), parameters);
}
protected override Expression VisitParameter(ParameterExpression node)
{
// Replace the source with the target, visit other params as usual.
return node == _source ? _target : base.VisitParameter(node);
}
}
}
Usage for your scenario (tested):
var zeroIndexIndexer = Expression.MakeIndex
(Expression.Constant(foos),
typeof(List<Foo>).GetProperty("Item"),
new[] { Expression.Constant(0) });
// .ToString() of the below looks like the following:
// () => (value(System.Collections.Generic.List`1[App.Foo]).Item[0].a
// * value(System.Collections.Generic.List`1[App.Foo]).Item[0].b)
var exp1Clone = ParameterReplacer.Replace<Func<Foo, int>, Func<int>>
(exp0, exp0.Parameters.Single(), zeroIndexIndexer);
I have the following:
Expression<Func<Car, int>> myExpr = car => car.Wheel.Tyre.Pressure;
I want to remove the parameter, and make the first member the parameter for a sub-expression, so i end up with:
Expression<Func<Wheel, int>> mySubExpr = wheel => wheel.Tyre.Pressure;
This needs to work for any expression tree of the above format, including MemberExpression, MethodCallExpression and any other Expression which has a .Expression property. For example:
Expression<Func<Car, int>> myOtherExpr = car => car.GetRearLeftWheel().GetTyre().Pressure
or
Expression<Func<Car, int>> anotherExpr = car => car.Wheel.GetTyre().GetPressure();
How would I achieve this elegantly?
Thanks
Andrew
Start with the class from this page
Then sprinkle in this code and I think you have a solution (the test stuff was how I tested it, I think it is pretty much the same as what you did):
class Test
{
public Test()
{
Expression<Func<string, string>> trim2 = s => s.Substring(1).Substring(1);
var modifier = new PopModifier();
Expression<Func<string, string>> trim1 = (Expression<Func<string, string>>)modifier.Modify(trim2);
var test2 = trim2.Compile();
var test1 = trim1.Compile();
var input = "abc";
if (test2(input) != "c")
{
throw new Exception();
}
if (test1(input) != "bc")
{
throw new Exception();
}
}
}
public class PopModifier : ExpressionVisitor
{
bool didModify = false;
public Expression Modify(Expression expression)
{
return Visit(expression);
}
protected override Expression VisitMethodCall(MethodCallExpression m)
{
if (!didModify)
{
didModify = true;
return m.Object;
}
return base.VisitMethodCall(m);
}
}
Did you check out Metalinq and its EditableExpression?