Is there a way to set 'DeclaringType' in an expression tree?

我与影子孤独终老i 提交于 2019-12-23 09:19:30

问题


I am doing a Func -> Expression -> Func conversion. It works fine if I create the Func<>() from a method(first example below) however if I create the function using an expression tree(2nd example) it fails with a NullReferenceException when accessing func2.Method.DeclaringType.FullName. And this is because DeclaringType is null. (NJection uses reflection so I think that is why it needs DeclaringType.)

How can I fill in DeclaringType type for the Func<> that was created by compiling an Expression Tree? (maybe its not possible?) DeclaringType is set in the first example.

Using a Func<> from a Method... (works well)

// Build a Func<> 
Func<int, int> add = Add;
// Convert it to an Expression using NJection Library
Expression<Func<int, int>> expr = ToExpr<Func<int, int>>(add);
// Convert it back to a Func<>
Func < int, int> func = expr.Compile();
// Run the Func<>
int result = func(100);

Using an Expression tree (does not work)...

// Build a Func<> using an Expression Tree
ParameterExpression numParam = Expression.Parameter(typeof(int));
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numAddFive = Expression.Add(numParam, five);
Func<int, int> func2 = 
    Expression.Lambda<Func<int, int>>(
        numAddFive, 
        new ParameterExpression[] { numParam }).Compile();
// Convert to an Expression using NJection (EXCEPTION ON NEXT LINE)
// ToExpr is trying to access func2.Method.DeclaringType.FullName(DeclaringType is null)
Expression<Func<int, int>> exp2 = ToExpr<Func<int, int>>(func2);
// Convert it back to a Func<>
Func<int, int> func2b = exp2.Compile();
// Run the Func<>
int result2 = func2b(100);

回答1:


I don't know what NJection library is used for since their website is down and there is no source code available at their Codeplex.

If you just need to get an Expression that you can compile back to the function, you can create it yourself. E.g. like this:

static Expression<T> ToExpr<T>(T func)
{
    var type = typeof(T);
    var method = type.GetMethod("Invoke"); // Delegate.Invoke() has parameters types matching delegate parameters types
    var pars = method.GetParameters()
        .Select(pi => Expression.Parameter(pi.ParameterType))
        .ToArray();

    return Expression.Lambda<T>(
        Expression.Call(Expression.Constant(func), method, pars),
        pars
    );
}

With this ToExpr, your above code compiles and runs without problems.




回答2:


I'm guessing no.

When you compile an expression to an executable Func, it's technically a dynamic method. You can see this if you were to call func2.Method.GetType(). That returns type DynamicMethod which always has null as the Declaring Type.



来源:https://stackoverflow.com/questions/34277542/is-there-a-way-to-set-declaringtype-in-an-expression-tree

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!