使用可为空的DateTime转换表达式会产生错误

时间:2015-11-16 12:10:11

标签: c# linq lambda

在类中,我有一个静态方法,通过提供表达式来获取PropertyInfo。

public static PropertyInfo GetPropertyInfo<T>(Expression<Func<T, object>> expressie)
        {
            MemberExpression me;
            switch (expressie.Body.NodeType)
            {
                case ExpressionType.Convert:
                case ExpressionType.ConvertChecked:
                    var ue = expressie.Body as UnaryExpression;
                    me = ((ue != null) ? ue.Operand : null) as MemberExpression;
                    break;
                default:
                    me = expressie.Body as MemberExpression;
                    break;
            }
            if (me == null)
            {
                throw new InvalidOperationException("Expression does not refer to a property: " + expressie.ToString());
            }

            return (PropertyInfo)me.Member;
        }

为了让我的代码更安全,我更改了我在调用此函数的部分方法中使用的表达式。

// Old
Expression<Func<T, Object>> expression;

// New (TProp instead of Object)
Expression<Func<T, TProp>> expression;

因此,我无法使用旧版的GetPropertyInfo&#39;方法,因为表达式与请求的参数不匹配。所以我创建了一个新的。

public static PropertyInfo GetPropertyInfo<T, TProp>(Expression<Func<T, TProp>> expressie)
        {
            MemberExpression me;
            switch (expressie.Body.NodeType)
            {
                case ExpressionType.Convert:
                case ExpressionType.ConvertChecked:
                    var ue = expressie.Body as UnaryExpression;
                    me = ((ue != null) ? ue.Operand : null) as MemberExpression;
                    break;
                default:
                    me = expressie.Body as MemberExpression;
                    break;
            }
            if (me == null)
            {
                throw new InvalidOperationException("Expression does not refer to a property: " + expressie.ToString());
            }

            return (PropertyInfo)me.Member;
        }

这个新表达式的主体与现有表达式完全相同。因为我想坚持使用DRY原则,所以我搜索了一种方法,在两种情况下使用一个方法体。这可以通过首先转换&lt;表达式&lt; Func&lt; T,TProp&gt;&gt;&#39;进入&#39;表达&lt; Func&lt; T,对象&gt;&gt;&#39;并将转换后的表达式传递给&#39; old&#39; GetPropertyInfo(...)方法。我无法完全删除旧的&#39; GetPropertyInfo&#39;方法,因为其他代码仍然依赖它。

我使用的转换方法如下:

private static Expression<Func<T, object>> convertToObjectExpression<T, TProp>(Expression<Func<T, TProp>> expression)
        {
            return Expression.Lambda<Func<T,object>>(
                    Expression.Convert(expression.Body, typeof(object)),
                    expression.Parameters);
        }

这很好用,除非我使用带有可空的DateTime(DateTime?)的表达式作为TProp的类型。在这种情况下,以下行会导致我&#39;为空。

me = ((ue != null) ? ue.Operand : null) as MemberExpression;

有人知道会导致这个问题的原因吗?

我有fiddle包含问题。

2 个答案:

答案 0 :(得分:2)

我建议你走另一条路。不要从新的类型安全方法转发到旧类型(包含所有附加问题),但是从旧方法转换到新方法:

// relay old interface to new one for compatibility
public static PropertyInfo GetPropertyInfo<T>(Expression<Func<T, object>> expressie)
{
    return GetPropertyInfo<T, object>(expressie);
}

public static PropertyInfo GetPropertyInfo<T, TProp>(Expression<Func<T, TProp>> expressie)
{ /* your code, as you provided it */ }

如果您仍然遇到此问题,请提供您的致电代码

修改

因与问题无关而被删除

答案 1 :(得分:1)

  

有人知道会导致这个问题的原因吗?

您调用新功能的方式(从普通DateTime属性投射convertToObjectExpression)以及实施方式(通过Convert)会导致两个{{1}表达式,因此问题。

为了解决此问题,请考虑用户 grek40 建议,和/或更改实施,如下所示

public static PropertyInfo GetPropertyInfo<T>(Expression<Func<T, object>> expressie)
{
    var body = expressie.Body;
    while (body.NodeType == ExpressionType.Convert || body.NodeType == ExpressionType.ConvertChecked)
        body = ((UnaryExpression)body).Operand;
    var me = body as MemberExpression;
    var property = me != null ? me.Member as PropertyInfo : null;
    if (property == null)
    {
        throw new InvalidOperationException("Expression does not refer to a property: " + expressie.ToString());
    }
    return property;
}