从对象转换功能的前pression树 [英] Cast function expression tree from object

查看:194
本文介绍了从对象转换功能的前pression树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经结束了的情况下的功能EX pression树防爆pression< Func键< TClass,TProperty>> 分配给类型的全局变量的对象的,然后后来在code我需要调用不同的方法与前pression。我不能改变全局对象类型;它必须是对象

当试图调用第二种方法与全局对象,除非我投的对象为的code不能编译防爆pression< Func键< TClass,TProperty>> 。问题是我不知道是什么的 TProperty 的是在该点第二个方法被调用。

我创建了一个快速演示应用程序来说明这一点(用VS2010编写C#控制台应用程序) - 在真正的应用程序看起来没有像这样

 使用系统;
使用System.Linq.Ex pressions;

命名空间FuncEx pressionTree
{
    公共类视图模型
    {
        公共字符串StringProperty {获得;组; }
        公众诠释IntProperty {获得;组; }
    }

    公共类助手< T>
        其中T:视图模型
    {
        私有对象_global;

        公共无效执行()
        {
            AssignToGlobal((T VM)=> vm.StringProperty);

            ProcessGlobal();

            AssignToGlobal((T VM)=> vm.IntProperty);

            ProcessGlobal();
        }

        公共无效AssignToGlobal< TClass,TProperty>(出pression< Func键< TClass,TProperty>>除权pression)
        {
            _global = EX pression;
        }

        公共无效ProcessGlobal()
        {
            //无效转换异常时抛出IntProperty分配给_global
            AssignToGlobal((前pression< Func键< T,字符串>>)_全球);
        }
    }

    类节目
    {
        静态无效的主要(字串[] args)
        {
            (新助手<视图模型>())。执行();
        }
    }
}
 

如果我们把重点放在执行()方法。

  1. 第一的全球的分配EX pression的字符串属性。
  2. ProcessGlobal执行和工作,因为我铸造防爆pression< Func键< T,字符串>>
  3. 在接下来的全球的分配EX pression为整型属性。
  4. ProcessGlobal重新执行,但它在这一点上,一个无效的转换异常。它会工作,如果我把它改为投防爆pression< Func键< T,INT>> ,而不是后来的字符串属性是行不通的。此外防爆pression< Func键< T,对象>> 抛出一个无效的转换异常

我觉得林失去了一些东西,它应该可以做一些与 System.Linq.Ex pressions 命名空间来动态地调用第二个方法(例如AssignToGlobal内ProcessGlobal在上面的例子)。

所以,我怎么能得到这个在一个通用的方式工作?

解决方案

 公共无效ProcessGlobal()
    {
        变种globalType = _global.GetType(); // globalType =前pression< Func键< TClass,TProperty>>
        变种函数类型= globalType.GetGenericArguments()[0]; //函数类型= Func键< TClass,TProperty>
        变种functionGenericArguments = functionType.GetGenericArguments(); // V =​​ [TClass,TProperty]
        VAR方法= this.GetType()GetMethod的(AssignToGlobal)MakeGenericMethod(functionGenericArguments)。 // functionGenericArguments = AssignToGlobal< TClass,TProperty>
        method.Invoke(这一点,新的[] {this._global}); //调用AssignToGlobal< TClass,TProperty>)(this._global);
    }
 

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.

  1. First global is assigned expression for the string property.
  2. ProcessGlobal executes and works because I'm casting to Expression<Func<T, string>>.
  3. Next global is assigned expression for int property.
  4. ProcessGlobal again executes but its at this point that an invalid cast exception is thrown. It would work if I changed it to cast 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);
    }

这篇关于从对象转换功能的前pression树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆