7

I have extension method:

public static IQueryable<TResult> WithFieldLike<TResult>(
   this IQueryable<TResult> query,
   Func<TResult, string> field,
   string value)
{
   Expression<Func<TResult, bool>> expr = 
       trans => field(trans).Contains(value);
   return query.Where(expr);
}

I need change parameter field to type: Expression>. Will be something like.

public static IQueryable<TResult> WithFieldLike<TResult>(
   this IQueryable<TResult> query,
   Expression<Func<TResult, string>> field,
   string value)
{
   Expression<Func<TResult, bool>> expr = ???
   return query.Where(expr);
}

The call of this method is:

var query7 = query.WithFieldLike(trans => trans.DeviceModelNumber, "ber_3");

How should I build the "expr" in this case? Please help.

1
  • Please add the language to the tags. Commented Mar 24, 2009 at 15:06

3 Answers 3

6

Deconstruct field and create a new expression, something like this:

var expr = Expression.Lambda<Func<TResult, bool>> (
    Expression.Call (field.Body, typeof (string).GetMethod ("Contains"),
        Expression.Constant (value)), field.Parameters) ;

(edited as per Maxs's refinement in comments)

Sign up to request clarification or add additional context in comments.

3 Comments

The point is that I can't build "Contains" expression. How to build "Equals" expression I know.
The final result is: var expr1 = Expression.Lambda<Func<TResult, bool>>( Expression.Call(field.Body, typeof(string).GetMethod("Contains"), Expression.Constant(value)) , field.Parameters);
Oh, sheesh. I didn't see Expression.Lambda<>() in ildasm ^ω^
4

You'll need to use Expression.Invoke; something like (untested):

public static IQueryable<TResult> WithFieldLike<TResult>(
   this IQueryable<TResult> query,
   Expression<Func<TResult, string>> field,
   string value)
{
    var param = Expression.Parameter(typeof(TResult), "x");
    var expr = Expression.Lambda<Func<TResult, bool>>(
        Expression.Call(Expression.Invoke(field, param),
            "Contains", null, Expression.Constant(value)), param);

    return query.Where(expr);
}

(edit: fixed)

2 Comments

Thanks. This works too. But generates expression incompatible with ADO.NET Data Services call.
Gotta love the Law of Leaky Abstractions... it works with some but not all ;-p
1

Use Compile to get the lambda back out:

Expression<Func<TResult, bool>> expr = 
   trans => field.Compile()(trans).Contains(value);

Edit: Whoops - my air compiler failed me. After compiling, you get the delegate. But, you still need to call it to get the string to call Contains.

2 Comments

Will be compilation error: 'System.Func<TResult,string>' does not contain a definition for 'Contains' and no extension method 'Contains' accepting a first argument of type 'System.Func<TResult,string>' could be found (are you missing a using directive or an assembly reference?)
@Maxs: Yeah - I kind of screwed up the whole "converting it to another expression" part. Point stands though - use Compile to get the lambda, and use it as normal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.