Create a Dynamic Linq to EF Expression to Select I

2019-07-04 15:58发布

I am trying to dynamically create the equivalent of the following Linq.

IQueryable<TypeOne> ones;
ones.Select(i => new TypeTwo { TwoProp = i.OneProp });

So far I have the following code but it isn't.

public class TypeOne
{
    public string OneProp { get; set; }
}

public class TypeTwo
{
    public string TwoProp { get; set; }
}

public static IQueryable<TypeTwo> Tester(IQueryable<TypeOne> data)
{
    ConstructorInfo constructor = typeof(TypeTwo ).GetConstructor(new Type[] { });
    Expression body = Expression.New(constructor);

    ParameterExpression oneParam = Expression.Parameter(typeof(TypeOne), "one");
    Expression prop1 = Expression.Property(oneParam, "OneProp");

    ParameterExpression twoParam = Expression.Parameter(typeof(TypeTwo ), "two");
    Expression prop2 = Expression.Property(twoParam, "TwoProp");

    Expression assign = Expression.Assign(prop2, prop1);
    body = Expression.Block(body, assign);

    return data.Select(Expression.Lambda<Func<TypeOne, TypeTwo >>(body, oneParam));
}

However I get the following exception-:

Additional information: Expression of type 'System.String' cannot be used for return type 'TypeTwo'

1条回答
SAY GOODBYE
2楼-- · 2019-07-04 16:15

You should use Expression.MemberInit for that, like this:

public static IQueryable<TypeTwo> Tester(IQueryable<TypeOne> data)
{
    var source = Expression.Parameter(typeof(TypeOne), "source");
    var selector = Expression.Lambda<Func<TypeOne, TypeTwo>>(
        Expression.MemberInit(Expression.New(typeof(TypeTwo)),
            Expression.Bind(typeof(TypeTwo).GetProperty("TwoProp"), Expression.Property(source, "OneProp"))),
        source);
    return data.Select(selector);
}

You can include as many Expression.Bind expressions (i.e. property assignments) as you want.

查看更多
登录 后发表回答