【问题标题】:How to cast Expression<Func<T, DateTime>> to Expression<Func<T, object>>如何将 Expression<Func<T, DateTime>> 转换为 Expression<Func<T, object>>
【发布时间】:2009-04-08 09:50:30
【问题描述】:

我一直在搜索,但找不到如何从类型转换

Expression<Func<T, DateTime>>

到类型:

Expression<Func<T, object>>

所以我必须再次求助于如此广泛的知识;)

【问题讨论】:

    标签: c# lambda


    【解决方案1】:

    您不能只在它们之间进行转换,因为它们不是同一种东西。但是,您可以有效地在表达式树中添加转换:

    using System;
    using System.Linq.Expressions;
    
    class Test
    {
        // This is the method you want, I think
        static Expression<Func<TInput,object>> AddBox<TInput, TOutput>
            (Expression<Func<TInput, TOutput>> expression)
        {
            // Add the boxing operation, but get a weakly typed expression
            Expression converted = Expression.Convert
                 (expression.Body, typeof(object));
            // Use Expression.Lambda to get back to strong typing
            return Expression.Lambda<Func<TInput,object>>
                 (converted, expression.Parameters);
        }
    
        // Just a simple demo
        static void Main()
        {
            Expression<Func<string, DateTime>> x = text => DateTime.Now;
            var y = AddBox(x);        
            object dt = y.Compile()("hi");
            Console.WriteLine(dt);
        }        
    }
    

    【讨论】:

    • @JonSkeet Expression.Convert 并不总是一个好主意。看我的回答。
    • 这会产生与在声明 x => x.TodayValue 时创建 Expression> 相同的输出。它最终创建了一个在正文中包含“Convert()”方法的表达式,并使一些东西像 Linq to Entities 崩溃。有没有办法让它适用于这种情况?谢谢。
    • @CesarD:这不是我尝试过的事情,恐怕,所以我没有什么建议。
    【解决方案2】:

    RobJon Skeet 的答案有一个问题。

    你会得到类似 x =&gt; Convert(x.PropertyName) 的东西,但通常对于 ASP.NET MVC 你想要这样的表达式 x =&gt; x.PropertyName

    所以Expression.Convert“污染”在某些情况下的表达。

    解决方案:

    public static class LambdaExpressionExtensions
    {
        public static Expression<Func<TInput, object>> ToUntypedPropertyExpression<TInput, TOutput> (this Expression<Func<TInput, TOutput>> expression)
        {
            var memberName = ((MemberExpression)expression.Body).Member.Name;
    
            var param = Expression.Parameter(typeof(TInput));
            var field = Expression.Property(param, memberName);
            return Expression.Lambda<Func<TInput, object>>(field, param);
        }
    }
    

    用法:

    Expression<Func<T, DateTime>> expression = ...;
    Expression<Func<T, object>> expr = expression.ToUntypedPropertyExpression();
    

    【讨论】:

    • 这似乎不起作用。例如,我似乎无法将Int32 转换为object;这就是Convert 调用的目的。没有它我会得到一个ArgumentException。尝试DateTime 版本,同样的事情。如果这对你有用,我猜你是用引用类型做的。
    • @rookian 您能否建议一种将您的解决方案用于嵌套属性的方法?截至目前,它就像直接属性的魅力,但我需要访问嵌套或子属性。所以请尽可能提供更新版本。谢谢
    【解决方案3】:

    基于 Jon 的代码(感谢 btw),您可以更进一步以获得完全的灵活性:

    public static Expression<Func<TModel, TToProperty>> Cast<TModel, TFromProperty, TToProperty>(Expression<Func<TModel, TFromProperty>> expression)
    {
        Expression converted = Expression.Convert(expression.Body, typeof(TToProperty));
    
        return Expression.Lambda<Func<TModel, TToProperty>>(converted, expression.Parameters);
    }
    

    【讨论】:

    • 有这个的使用例子吗?
    • 它不起作用。看起来 Expression.Convert 不会转换任何东西。
    【解决方案4】:

    只需将out TResult定义为对象并编译表达式,它适用于所有数据类型;

    Expression<Func<string, object>> dateExp = text => DateTime.Now;
    object dt = dateExp.Compile()("hi");
    Console.WriteLine(dt);
    

    Fiddle sample here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多