首页 文章

从对象转换函数表达式树

提问于
浏览
1

我最终遇到的情况是函数表达式树 Expression<Func<TClass, TProperty>> 被分配给object类型的全局变量,然后在代码中我需要用表达式调用不同的方法 . 我无法改变全局对象类型;它必须是对象 .

尝试使用全局对象调用第二个方法时,代码将无法编译,除非我将对象转换为 Expression<Func<TClass, TProperty>> . 问题是我不知道TProperty在调用第二种方法时是什么 .

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

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();
        }
    }
}

如果我们专注于 Execute() 方法 .

  • 为字符串属性分配第一个全局表达式 .

  • ProcessGlobal执行并运行,因为我正在转向 Expression<Func<T, string>> .

  • 下一个全局被赋予int属性的表达式 .

  • ProcessGlobal再次执行,但此时抛出了无效的强制转换异常 . 如果我将其更改为转换 Expression<Func<T, int>> ,但是字符串属性不起作用,它会工作 . 另外 Expression<Func<T, object>> 会抛出无效的强制转换异常 .

我觉得我错过了一些东西,应该可以用 System.Linq.Expressions 命名空间来动态调用第二种方法(例如上面例子中ProcessGlobal中的AssignToGlobal) .

那么如何才能以通用方式实现这一目标呢?

1 回答

  • 1
    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);
        }
    

相关问题