4

So let's say that I have a method of the following manners:

public T Get<T, U>(Expression<Func<T, U>> expr) {
    // use the expression to retrieve cool stuff.
}

Now I want to invoke this method with only string values. That is, I need to compile an expression in runtime.

So, let's say that I have a class Foo:

public class Foo {
    public string Name { get; set; }
}

and then have another class Bar:

public class Bar {
    public string AnotherName { get; set; }
}

Now I want to compile an expression that would look like this:

Foo foo = new Foo { Name = "AName" };
Expression<Func<Bar, string>> expr = p => p.AnotherName == foo.Name;

However, the only information I got in runtime is:

  • The name of the property "AnotherName"
  • The name of the class "Bar"
  • The value of the property "Name" in Foo
  • The name of the class "Foo"

So, after some lurking I found out that there is a System.Linq.Dynamic library where I could compile an expr of the string:

@"Bar.AnotherName == AName";

Example:

var sourceValue = "AName";
var targetClassName = "Bar";
var targetPropertyName = "AnotherName";

var expr = string.Format("{0}.{1} == {2}", 
    targetClassName, targetPropertyName, sourceValue);

var p = Expression.Parameter(typeof(Bar), "Target");
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, expr);
var lambda = e.Compile();

However, this will only result in a delegate to a lambda expression.

My question is now, is it actually possible to invoke the Get method by creating an expression in runtime like this?

1
  • Search for CSharpCodeProvider. Maybe overkill, but it will solve your problem. Commented Mar 3, 2015 at 9:17

1 Answer 1

3

I don't think you need dynamic:

var sourceValue = "AName";

// You will need the namespace of Bar here!
var namespaceTargetClassName = "ExpressionProblem";
var targetClassName = "Bar";
var targetPropertyName = "AnotherName";

{
    var targetType = Type.GetType(namespaceTargetClassName + "." + targetClassName);
    var p = Expression.Parameter(targetType, "Target");
    var pr = Expression.PropertyOrField(p, targetPropertyName);
    var e = Expression.Equal(pr, Expression.Constant(sourceValue));
    var lambda = Expression.Lambda(e, p); // It would be an Expression<Func<Bar, bool>>
}

Note that this first solution has a problem: the delegate type you are generating is a Func<targetClassName, bool>, so you can't easily compile and use it.

It's easier to create a Func<object, bool> that internally does the cast.

{
    var targetType = Type.GetType(namespaceTargetClassName + "." + targetClassName);
    var p = Expression.Parameter(typeof(object), "Target");

    // I'm using the as operator here, if you prefer a "strong" 
    // cast (the cast operator that throws if the object is of
    // invalid type), use Expression.Convert with the same syntax 
    var pcasted = Expression.TypeAs(p, targetType); 
    var pr = Expression.PropertyOrField(pcasted, targetPropertyName);
    var e = Expression.Equal(pr, Expression.Constant(sourceValue));
    var lambda = Expression.Lambda<Func<object, bool>>(e, p);

    Func<object, bool> func = lambda.Compile();

    Bar obj = new Bar { AnotherName = "AName" };
    bool res = func(obj);
}
Sign up to request clarification or add additional context in comments.

Comments

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.