I've ended up with a situation where an function expression tree Expression<Func<TClass, TProperty>>
is assigned to a global variable of type object and then later in the code I need to call a different method with the expression. I can't change the global objects type; it has to be object.
The code won't compile when trying to call the second method with the global object unless I cast the object as Expression<Func<TClass, TProperty>>
. The problem is I don't know what TProperty is at the point that the second method is called.
I've created a quick demo app to illustrate the point (c# console app written in VS2010) - the real application looks nothing like this.
using System;
using System.Linq.Expressions;
namespace FuncExpressionTree
{
public class ViewModel
{
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
public class Helper<T>
where T : ViewModel
{
private object _global;
public void Execute()
{
AssignToGlobal((T vm) => vm.StringProperty);
ProcessGlobal();
AssignToGlobal((T vm) => vm.IntProperty);
ProcessGlobal();
}
public void AssignToGlobal<TClass, TProperty>(Expression<Func<TClass, TProperty>> expression)
{
_global = expression;
}
public void ProcessGlobal()
{
// invalid cast exception thrown when IntProperty is assigned to _global
AssignToGlobal((Expression<Func<T, string>>)_global);
}
}
class Program
{
static void Main(string[] args)
{
(new Helper<ViewModel>()).Execute();
}
}
}
If we focus on the Execute()
method.
Expression<Func<T, string>>
.Expression<Func<T, int>>
instead but then the string property wouldn't work. Also Expression<Func<T, object>>
throws an invalid cast exception.I feel like Im missing something and that it should be possible to do something with the System.Linq.Expressions
namespace to dynamically invoke the the second method (eg AssignToGlobal within ProcessGlobal in the above example).
So how can I get this to work in a generic way?
public void ProcessGlobal()
{
var globalType = _global.GetType(); // globalType = Expression<Func<TClass, TProperty>>
var functionType = globalType.GetGenericArguments()[0]; // functionType = Func<TClass, TProperty>
var functionGenericArguments = functionType.GetGenericArguments(); // v = [TClass, TProperty]
var method = this.GetType().GetMethod("AssignToGlobal").MakeGenericMethod(functionGenericArguments); //functionGenericArguments = AssignToGlobal<TClass, TProperty>
method.Invoke(this, new[] { this._global }); // Call AssignToGlobal<TClass, TProperty>)(this._global);
}