4

I am trying to write a dynamic select statement. I have the following:

public class MainList
{
    public string Prop1{ get; set; }
    public string Prop2{ get; set; }
    public string Prop3{ get; set; }       
}

public class SearchObject
{
    public string Prop1{ get; set; }
}

I want build the expression like the following

var newList = MainList.Select(n => new SearchObject { Prop1 = n.Prop1});

The code I am using creates a list based on MainList. I then create the select expression by passing the SearchObject type and the parameters I want to populate, for now. It runs until the second to last line.

public void Start()
{
    List<MainList> newList = new List<MainList>(); //This has a ton list objects
    var result = newList.Select(CreateSelect<SearchObject>("Prop1"));
}

public static Func<MainList, T> CreateSelect<T>(string fields)
{
    var par = Expression.Parameter(typeof(T), "n");

    var newInstance= Expression.New(typeof(T));

    var bindings = fields.Split(',').Select(o => o.Trim())
        .Select(n => {

            var p = typeof(T).GetProperty(n);

            var original = Expression.Property(par, p);

            return Expression.Bind(p, original);
        }
    );

    var newT= Expression.MemberInit(newInstance, bindings);

    var lambda = Expression.Lambda<Func<MainList, T>>(newT, par); //ERROR HAPPENS HERE
    return lambda.Compile();
}

The error I get is:

Additional information: ParameterExpression of type 'WebApplication.SearchObject' cannot be used for delegate parameter of type 'WebApplication.MainList'

I am unsure on the meaning of the error and also how to resolve the issue.

1
  • I'm assuming you're trying to create an reporting application or something of some sort. You could use DynamicLinq, but you're better off either creating mapping, or using oData Commented Mar 2, 2017 at 15:39

2 Answers 2

5

The first issue is, as already mentioned by Jeroen van Langen, the type of the parameter must be MainList.

The second issue is the usage of the Expression.Bind. Since the source and target are different types, you cannot use one and the same PropertyInfo. The first argument must be a PropertyInfo of the target type T, while the second - expression coming from the source type MainList (in your case, Expression.Property on the parameter with the specified property name).

The correct implementation is something like this:

public static Func<MainList, T> CreateSelect<T>(string fields)
{
    var parameter = Expression.Parameter(typeof(MainList), "n");
    var bindings = fields.Split(',')
        .Select(name => name.Trim())
        .Select(name => Expression.Bind(
            typeof(T).GetProperty(name),
            Expression.Property(parameter, name)
        ));
    var newT = Expression.MemberInit(Expression.New(typeof(T)), bindings);
    var lambda = Expression.Lambda<Func<MainList, T>>(newT, parameter);
    return lambda.Compile();
}
Sign up to request clarification or add additional context in comments.

Comments

1

The exception ParameterExpression of type 'WebApplication.SearchObject' cannot be used for delegate parameter of type 'WebApplication.MainList' explained:

Meaning: There is a mismatch between the ParameterExpression type typeof(T) and the Expression.Lambda Func<MainList, T> --> MainList

Your:

var par = Expression.Parameter(typeof(T), "n");

should be:

var par = Expression.Parameter(typeof(MainList), "n");

4 Comments

When I change the code like that it fails at the following line: 'var original = Expression.Property(par, p);' with the error Property 'System.String Prop1' is not defined for type 'WebApplication.MainList'
var p = typeof(T).GetProperty(n); type (t) should be MainList also.
It then fails at line: var newT= Expression.MemberInit(newInstance, bindings); with the error 'Prop1' is not a member of type 'WebApplication.SearchObject'
You might consider what you are doing. We're close by rewriting the whole thing. I personally never used the 'bind' expression.

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.