表达式<func <in t,=“”bool =“”>&gt;或表达式<func <tbase,bool>&gt;表达式<func <t,bool>&gt;转换器</FUNC <t时,布尔> </FUNC <TBASE,布尔> </FUNC <位置>

时间:2011-05-30 13:53:45

标签: c# generics expression-trees

有没有简单的转换方式

Expression<Func<TBase,bool>> 

Expression<Func<T,bool>>

其中T是从TBase继承的吗?

3 个答案:

答案 0 :(得分:3)

只要T派生自TBase,您就可以直接使用原始表达式的主体和参数创建所需类型的表达式。

Expression<Func<object, bool>> x = o => o != null;
Expression<Func<string, bool>> y = Expression.Lambda<Func<string, bool>>(x.Body, x.Parameters);

答案 1 :(得分:2)

您可能需要手动转换。这样做的原因是,您可以有效地转换为可能的子集。所有T都是TBase,但并非所有TBase都是T

好消息是,您可以使用Expression.Invoke执行此操作,并手动将适当的转换/转换应用于TBase(当然可以捕获任何类型的安全问题)。

编辑:我为误解你想要进入的方向而道歉。我认为简单地转换表达式仍然是你最好的路线。它使您能够根据需要处理转换。 Marc Gravell's answer here是我见过的最紧凑,最清晰的方式。

答案 2 :(得分:0)

为了实现这个目的,我编写了ExpressionVisitor,重载了VisitLambda和VisitParameter

这是:

public class ConverterExpressionVisitor<TDest> : ExpressionVisitor
{
    protected override Expression VisitLambda<T>(Expression<T> node)
    {
        var readOnlyCollection = node.Parameters.Select(a => Expression.Parameter(typeof(TDest), a.Name));
        return Expression.Lambda(node.Body, node.Name, readOnlyCollection);
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return Expression.Parameter(typeof(TDest), node.Name);
    }
}

public class A { public string S { get; set; } }
public class B : A { }

static void Main(string[] args)
{
    Expression<Func<A, bool>> ExpForA = a => a.S.StartsWith("Foo");
    Console.WriteLine(ExpForA); // a => a.S.StartsWith("Foo");

    var converter = new ConverterExpressionVisitor<B>();
    Expression<Func<B, bool>> ExpForB = (Expression<Func<B, bool>>)converter.Visit(ExpForA);
    Console.WriteLine(ExpForB); // a => a.S.StartsWith("Foo"); - same as for A but for B
    Console.ReadLine();
}