重写表达式的类型<T>

是否可以动态重写 一个 ,用另一种类型替换 一个元素?Expression<T>T

例如,在以下情况下将 替换为:DocumentTypeADocumentTypeB

  • Expression<Func<DocumentTypeA, bool>> expression = m => m.Details.Id == "an-id"

  • Expression<Func<DocumentTypeA, bool>> expression = m => m.Details.Id == "an-id" && m.AnInt == 42

  • Expression<Func<DocumentTypeA, bool>> expression = m => m.AString == "I'm a string"

我需要决定在运行时使用哪种类型,而不是编译时。

同样值得注意的是,它们之间并不相关,除了它们的属性是相同的。DocumentTypeADocumentTypeB

最终结果是重新处理它们,使它们现在看起来像

  • Expression<Func<DocumentTypeB, bool>> expression = m => m.Details.Id == "an-id"

  • Expression<Func<DocumentTypeB, bool>> expression = m => m.Details.Id == "an-id" && m.AnInt == 42

  • Expression<Func<DocumentTypeB, bool>> expression = m => m.AString == "I'm a string"

因此,表达式的实际比较部分保持不变,只有顶级类型已更改。


偶然的你
浏览 88回答 2
2回答

慕尼黑8549860

可以使用表达式访问器替换该类型。class ParameterRewriter<T, U> : ExpressionVisitor{&nbsp; &nbsp; protected override Expression VisitParameter(ParameterExpression node)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (node.Type.Equals(typeof(T)))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Expression.Parameter(typeof(U), node.Name);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return base.VisitParameter(node);&nbsp; &nbsp; }&nbsp; &nbsp; protected override Expression VisitMember(MemberExpression node)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (node.Expression is ParameterExpression paramExp && paramExp.Type.Equals(typeof(T)))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Expression.MakeMemberAccess(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Expression.Parameter(typeof(U), paramExp.Name),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; typeof(U).GetMember(node.Member.Name).Single());&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return base.VisitMember(node);&nbsp; &nbsp; }&nbsp; &nbsp; protected override Expression VisitLambda<L>(Expression<L> node)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var parameters = node.Parameters.ToList();&nbsp; &nbsp; &nbsp; &nbsp; var found = false;&nbsp; &nbsp; &nbsp; &nbsp; for (var i = 0; i < parameters.Count; i++)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (parameters[i].Type.Equals(typeof(T)))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parameters[i] = Expression.Parameter(typeof(U), parameters[i].Name);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; found = true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if (found)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Expression.Lambda(node.Body, parameters);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return base.VisitLambda(node);&nbsp; &nbsp; }}在这种情况下,创建一个实例并访问原始表达式树,您将获得所需的内容。扩展方法可能更具可读性:new ParameterRewriter<DocumentTypeA, DocumentTypeB>()public static class ExpressionExtensions{&nbsp; &nbsp; public static Expression<Func<U, R>> RewriteParameter<T, U, R>(this Expression<Func<T, R>> expression)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var rewriter = new ParameterRewriter<T, U>();&nbsp; &nbsp; &nbsp; &nbsp; return (Expression<Func<U, R>>)rewriter.Visit(expression);&nbsp; &nbsp; }}用法很简单:Expression<Func<A, bool>> expA = x => x.Id == 1;Expression<Func<B, bool>> expB = expA.RewriteParameter<A, B, bool>();

PIPIONE

使用两个类都继承的接口,并包含两个类中相同的属性,例如interface IDocumentTypes{&nbsp; &nbsp; string AString { get; set; } //indicates that both classes need to implement this&nbsp; &nbsp; //etc...}class DocumentTypeA : IDocumentTypes{&nbsp; &nbsp; //your class}然后,您的两个类都可以在实现接口时使用,并且仍然是强类型。除了实现接口中定义的属性/函数之外,这些类不需要有任何共同点。ExpressionIDocumentTypes
打开App,查看更多内容
随时随地看视频慕课网APP