【问题标题】:Cast function expression tree from object从对象转换函数表达式树
【发布时间】:2012-07-16 22:17:54
【问题描述】:

我遇到了这样一种情况:函数表达式树 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() 方法。

  1. 第一个global 被赋值为字符串属性的表达式。
  2. ProcessGlobal 执行并正常工作,因为我正在投射到 Expression&lt;Func&lt;T, string&gt;&gt;
  3. 下一个 global 被赋值为 int 属性的表达式。
  4. ProcessGlobal 再次执行,但此时抛出了无效的强制转换异常。如果我将其更改为强制转换为 Expression&lt;Func&lt;T, int&gt;&gt; 它将起作用,但字符串属性将不起作用。 Expression&lt;Func&lt;T, object&gt;&gt; 也会抛出一个无效的强制转换异常。

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

那么我怎样才能让它以一种通用的方式工作呢?

【问题讨论】:

    标签: c# .net linq lambda expression-trees


    【解决方案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);
        }
    

    【讨论】:

    • 感谢这对我有用,虽然我需要调整它以使用 2 个参数调用,即 TClass 实例和全局。
    猜你喜欢
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多