Convert Expression<Func<TDocument, object>> to E

本文关键字:gt lt to object Func Expression Convert TDocument | 更新日期: 2023-09-27 18:14:03

我有以下类型为Expression<Func<TDocument, object>>的表达式

x => x.Name

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

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

Convert Expression<Func<TDocument, object>> to E

您只需要将原始表达式的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);

附录

注意,对于结构返回类型,最终表达式可能看起来像这样:

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