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);
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With