为了账号安全,请及时绑定邮箱和手机立即绑定

重写表达式的类型<T>

重写表达式的类型<T>

C#
偶然的你 2022-08-20 16:08:12
是否可以动态重写 一个 ,用另一种类型替换 一个元素?Expression<T>T例如,在以下情况下将 替换为:DocumentTypeADocumentTypeBExpression<Func<DocumentTypeA, bool>> expression = m => m.Details.Id == "an-id"Expression<Func<DocumentTypeA, bool>> expression = m => m.Details.Id == "an-id" && m.AnInt == 42Expression<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 == 42Expression<Func<DocumentTypeB, bool>> expression = m => m.AString == "I'm a string"因此,表达式的实际比较部分保持不变,只有顶级类型已更改。
查看完整描述

2 回答

?
慕尼黑8549860

TA贡献1818条经验 获得超11个赞

可以使用表达式访问器替换该类型。


class ParameterRewriter<T, U> : ExpressionVisitor

{

    protected override Expression VisitParameter(ParameterExpression node)

    {

        if (node.Type.Equals(typeof(T)))

        {

            return Expression.Parameter(typeof(U), node.Name);

        }


        return base.VisitParameter(node);

    }


    protected override Expression VisitMember(MemberExpression node)

    {

        if (node.Expression is ParameterExpression paramExp && paramExp.Type.Equals(typeof(T)))

        {

            return Expression.MakeMemberAccess(

                Expression.Parameter(typeof(U), paramExp.Name),

                typeof(U).GetMember(node.Member.Name).Single());

        }


        return base.VisitMember(node);

    }


    protected override Expression VisitLambda<L>(Expression<L> node)

    {

        var parameters = node.Parameters.ToList();

        var found = false;


        for (var i = 0; i < parameters.Count; i++)

        {

            if (parameters[i].Type.Equals(typeof(T)))

            {

                parameters[i] = Expression.Parameter(typeof(U), parameters[i].Name);

                found = true;

            }

        }


        if (found)

        {

            return Expression.Lambda(node.Body, parameters);

        }


        return base.VisitLambda(node);

    }

}

在这种情况下,创建一个实例并访问原始表达式树,您将获得所需的内容。扩展方法可能更具可读性:new ParameterRewriter<DocumentTypeA, DocumentTypeB>()


public static class ExpressionExtensions

{

    public static Expression<Func<U, R>> RewriteParameter<T, U, R>(this Expression<Func<T, R>> expression)

    {

        var rewriter = new ParameterRewriter<T, U>();

        return (Expression<Func<U, R>>)rewriter.Visit(expression);

    }

}

用法很简单:


Expression<Func<A, bool>> expA = x => x.Id == 1;

Expression<Func<B, bool>> expB = expA.RewriteParameter<A, B, bool>();


查看完整回答
反对 回复 2022-08-20
?
PIPIONE

TA贡献1829条经验 获得超9个赞

使用两个类都继承的接口,并包含两个类中相同的属性,例如


interface IDocumentTypes

{

    string AString { get; set; } //indicates that both classes need to implement this

    //etc...

}


class DocumentTypeA : IDocumentTypes

{

    //your class

}

然后,您的两个类都可以在实现接口时使用,并且仍然是强类型。除了实现接口中定义的属性/函数之外,这些类不需要有任何共同点。ExpressionIDocumentTypes


查看完整回答
反对 回复 2022-08-20
  • 2 回答
  • 0 关注
  • 87 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信