You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中将Expression<Func<A, bool>>转换为Expression<Func<B, bool>>

在C#中转换Expression<Func<A, bool>>到Expression<Func<B, bool>>的实现方法

要实现无共同父类的A、B两类之间的表达式属性映射,核心是通过**自定义ExpressionVisitor**重写表达式的成员访问逻辑,将针对A类属性的访问替换为B类对应的属性访问。以下是具体实现步骤:

1. 定义属性映射关系

首先明确A和B的属性对应规则,用字典存储映射关系:

var propertyMap = new Dictionary<string, string>
{
    { nameof(A.AProperty1), nameof(B.BProperty1) },
    { nameof(A.AProperty2), nameof(B.BProperty2) }
};

2. 自定义ExpressionVisitor实现替换逻辑

继承ExpressionVisitor,重写两个关键方法:

  • VisitParameter:将原表达式中的A类型参数替换为B类型参数
  • VisitMember:将A类的属性访问替换为B类对应的属性访问
public class PropertyMappingVisitor<TSource, TTarget> : ExpressionVisitor
{
    private readonly Dictionary<string, string> _propertyMap;
    private readonly ParameterExpression _targetParameter;

    public PropertyMappingVisitor(Dictionary<string, string> propertyMap, ParameterExpression targetParameter)
    {
        _propertyMap = propertyMap;
        _targetParameter = targetParameter;
    }

    // 替换参数类型:从TSource换成TTarget
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node.Type == typeof(TSource) ? _targetParameter : base.VisitParameter(node);
    }

    // 替换属性访问:将TSource的属性换成TTarget对应属性
    protected override Expression VisitMember(MemberExpression node)
    {
        // 仅处理TSource类型的属性访问
        if (node.Expression is ParameterExpression param && param.Type == typeof(TSource))
        {
            if (_propertyMap.TryGetValue(node.Member.Name, out var targetPropertyName))
            {
                // 获取TTarget的对应属性
                var targetProperty = typeof(TTarget).GetProperty(targetPropertyName);
                if (targetProperty != null)
                {
                    // 构建新的属性访问表达式
                    return Expression.Property(_targetParameter, targetProperty);
                }
            }
        }
        return base.VisitMember(node);
    }
}

3. 封装表达式转换方法

写一个工具方法,将Expression<Func<TSource, bool>>转换为Expression<Func<TTarget, bool>>:

public static class ExpressionConverter
{
    public static Expression<Func<TTarget, bool>> Convert<TSource, TTarget>(
        Expression<Func<TSource, bool>> sourceExpr,
        Dictionary<string, string> propertyMap)
    {
        // 创建TTarget类型的参数表达式
        var targetParam = Expression.Parameter(typeof(TTarget), "p");
        var visitor = new PropertyMappingVisitor<TSource, TTarget>(propertyMap, targetParam);
        
        // 遍历并替换原表达式的所有节点
        var convertedBody = visitor.Visit(sourceExpr.Body);
        
        // 构建新的表达式
        return Expression.Lambda<Func<TTarget, bool>>(convertedBody, targetParam);
    }
}

4. 在业务代码中使用转换

修改你的FindAsync方法,将传入的A类型表达式转换为B类型后再用于查询:

public async Task<B> FindAsync(Expression<Func<A, bool>> where, CancellationToken cancellationToken = default)
{
    // 定义属性映射
    var propertyMap = new Dictionary<string, string>
    {
        { nameof(A.AProperty1), nameof(B.BProperty1) },
        { nameof(A.AProperty2), nameof(B.BProperty2) }
    };
    
    // 转换表达式
    var convertedWhere = ExpressionConverter.Convert<A, B>(where, propertyMap);
    
    // 使用转换后的表达式查询B类数据
    return await _dbContext.B.Where(convertedWhere).SingleOrDefaultAsync(cancellationToken);
}

验证转换效果

针对示例表达式:

Expression<Func<A, bool>> where = p => p.AProperty1 == "x" && p.AProperty2 == "2";

转换后会得到等价的B类表达式:

Expression<Func<B, bool>> result = p => p.BProperty1 == "x" && p.BProperty2 == "2";

内容的提问来源于stack exchange,提问作者Szyszka947

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 05:05:37