Expression Tree for Enumerable.Select

c# expression-trees

Question

Edit I believe I can ask better (no code needed at all in this case). So, the overall query is: How can I create a call to a generic method using an Expression tree?(Select<TEntity,TResult> (In my situation)TResult is built during execution? Ignore the code and text below; they were put there since the question was vague and they wanted to avoid confusing the people who replied.

For a "Select" call, I need an example of how to generate an expression tree. The issue is that during compilation time, I'm not aware of the return type (it can be defined by user through some GUI in runtime). The code I'm using to do this is shown below (with in mind that I can't use any generics).

class Pet {
    public int Id { get; set; }
    public string Name { get; set; }
}

When Main uses this class:

List<Pet> list = new List<Pet>();                
Expression eList = Expression.Constant(list);
ParameterExpression pe = Expression.Parameter(typeof(Pet), "p");
MethodInfo method = typeof(Program).GetMethod("CreateObject", BindingFlags.Static | BindingFlags.NonPublic);
var properties = typeof(Pet).GetProperties().Where(pi => pi.Name == "Name"); //will be defined by user
Expression selectorBody = Expression.Call(method, Expression.Constant(properties));
Expression selector = Expression.Lambda(selectorBody, pe);
Expression res = Expression.Call(typeof(Enumerable), "Select", new[] { typeof(Pet), CreateType(properties) }, eList, selector);

I'm attempting to use Reflection to construct a Type at runtime. The code above uses the "CreateType" function, which I've used in a few of my projects and which seems to work OK. Emit it and then send it to the "Select" call, but I receive an exception:

No generic method 'Select' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments.

Any recommendations?

Upd my real problem is building an Expression tree for a "Join" call for runtime types which is more complicated, so I decided to ask about "Select", because I'm having the same exception in the last line (Expression. Call(...))

The primary issue is not that Upd2 altered the main code and added my helper functions.

static Type CreateType(IEnumerable<PropertyInfo> properties) {
        TypeBuilder typeBuilder = CreateTypeBuilder("ResultDynamicAssembly", "ResultModule", "ResultType");
        foreach (PropertyInfo propertyInfo in properties) {
            CreateAutoImplementedProperty(typeBuilder, propertyInfo.Name, propertyInfo.PropertyType);
        }
        return typeBuilder.CreateType();
    }

    static object CreateObject(IEnumerable<PropertyInfo> properties) {
        Type type = CreateType(properties); 
        return Activator.CreateInstance(type);
    }
1
2
6/14/2013 2:50:58 PM

Accepted Answer

By eliminating the dynamic type from the equation, this issue may be made simpler. The code following does the same task without the use of a dynamic type, allowing you to replicate the problem.

static class Program
{
    private static void Main(string[] args)
    {
        var list = new List<Pet>();
        var eList = Expression.Constant(list);
        var pe = Expression.Parameter(typeof(Pet), "p");
        var method = typeof(Program).GetMethod("CreateObject", BindingFlags.Static | BindingFlags.NonPublic);
        var properties = typeof(Pet).GetProperties().Where(pi => pi.Name == "Name"); //will be defined by user
        var selectorBody = Expression.Call(method, Expression.Constant(properties));
        var selector = Expression.Lambda(selectorBody, pe);
        var res = Expression.Call(typeof(Enumerable), "Select", new[] { typeof(Pet), CreateType(properties) }, eList, selector);
    }

    private static Type CreateType(IEnumerable<PropertyInfo> properties)
    {
        return typeof (DynamicType);
    }

    private static object CreateObject(IEnumerable<PropertyInfo> properties)
    {
        var type = CreateType(properties);
        return  Activator.CreateInstance(type);
    }

    class Pet
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

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

Therefore, CreateObject's method signature is the issue. The lambda is invalid since its return type isn't the dynamic type. This may be shown by altering the kind ofCreateObject .

    // this works fine
    private static DynamicType CreateObject(IEnumerable<PropertyInfo> properties)
    {
        var type = CreateType(properties);
        return  (DynamicType) Activator.CreateInstance(type);
    }

Due to the fact that you're working with a dynamic type, you must create an expression to cast the outcome ofCreateObject the dynamic type you use. Use something similar to this:

        // create dynamic type
        var properties = typeof(Pet).GetProperties().Where(pi => pi.Name == "Name"); //will be defined by user
        var dynamicType = CreateType(properties);

        // build expression
        var list = new List<Pet>();
        var eList = Expression.Constant(list);
        var pe = Expression.Parameter(typeof(Pet), "p");
        var createObjectMethod = typeof(Program).GetMethod("CreateObject", BindingFlags.Static | BindingFlags.NonPublic);
        var createObjectCall = Expression.Call(createObjectMethod, Expression.Constant(properties));
        var castExpression = Expression.Convert(createObjectCall, dynamicType);
        var selectorExpression = Expression.Lambda(castExpression, pe);
        var res = Expression.Call(typeof(Enumerable), "Select", new[] { typeof(Pet), dynamicType }, eList, selectorExpression);
4
6/14/2013 3:08:57 PM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow