转换表达式<func <tdocument,object =“”>&gt;表达式<func <tdocument,toutput =“”>&gt;

时间:2016-10-21 06:07:54

标签: c# expression

我有以下表达式Expression<Func<TDocument, object>>

x => x.Name

现在,我在编译时并不知道x.Name的类型,但我现在在运行时因为它存储在Type中。

如何将我的表达式转换为Expression<Func<TDocument, TOutput>>类型TOutputType且在编译时不知道?

1 个答案:

答案 0 :(得分:3)

您只需将原始表达式的Body包装在Convert表达式中,然后重建lambda。如果我可以使用泛型,我就会这样做:

Expression<Func<TInput, TReturn>> ConvertReturnValue<TInput, TReturn>(
    Expression<Func<TInput, object>> inputExpression)
{
    Expression convertedExpressionBody = Expression.Convert(
        inputExpression.Body, typeof(TReturn)
    );

    return Expression.Lambda<Func<TInput, TReturn>>(
        convertedExpressionBody, inputExpression.Parameters
    );
}

用法:

Expression<Func<TDocument, object>> inputExpression = d => d.Name;

Expression<Func<TDocument, string>> convertedExpression
    = ConvertReturnValue<TDocument, string>(inputExpression);

// Test.
TDocument doc = new TDocument { Name = "Zzz" };
string name = convertedExpression.Compile().Invoke(doc);

Assert.Equal("Zzz", name);

没有泛型

如果由于在编译时不知道返回类型而无法使用泛型,Expression.Lambda实际上提供了非泛型重载,您可以像这样使用:

Expression ConvertReturnValue<TInput>(Expression<Func<TInput, object>> inputExpression, Type returnType)
{
    Expression convertedExpressionBody = Expression.Convert(inputExpression.Body, returnType);

    return Expression.Lambda(convertedExpressionBody, inputExpression.Parameters);
}

上述内容仍会返回Expression<Func<TInput, TReturn>>(向上转换为非通用Expression)。如果您需要,可以稍后再转发它:

Expression<Func<TDocument, object>> inputExpression = d => d.Name;

Expression<Func<TDocument, string>> convertedExpression
    = (Expression<Func<TDocument, string>>)ConvertReturnValue(inputExpression, typeof(string));

// Test.
TDocument doc = new TDocument { Name = "Zzz" };
string name = convertedExpression.Compile().Invoke(doc);

Assert.Equal("Zzz", name);

<强>附录

请注意,对于struct返回类型,最终表达式最终可能如下所示:

(TDocument d) => (int)(object)d.ID;