簡體   English   中英

替換lambda表達式中的參數類型

[英]Replace parameter type in lambda expression

我試圖將lambda表達式中的參數類型從一種類型替換為另一種類型。

我在stackoverflow上找到了其他答案,即這個,但我沒有運氣。

想象一下你有一個域對象和一個存儲庫,你可以從中檢索域對象。

但是,存儲庫必須處理自己的數據傳輸對象,然后映射並返回域對象:

ColourDto.cs

public class DtoColour {

    public DtoColour(string name)
    {
        Name = name;
    }

    public string Name { get; set; }
}

DomainColour.cs

public class DomainColour {

    public DomainColour(string name)
    {
        Name = name;
    }

    public string Name { get; set; }
}

Repository.cs

public class ColourRepository {
    ...
    public IEnumerable<DomainColour> GetWhere(Expression<Func<DomainColour, bool>> predicate)
    {
        // Context.Colours is of type ColourDto
        return Context.Colours.Where(predicate).Map().ToList();
    }
}

正如您所看到的,這將不起作用,因為謂詞是針對域模型的,而存儲庫中的Collection是數據傳輸對象的集合。

我曾嘗試使用ExpressionVisitor來執行此操作,但無法弄清楚如何在不拋出異常的情況下更改ParameterExpression的類型,例如:

測試場景

public class ColourRepository {
    ...
    public IEnumerable<DomainColour> GetWhere(Expression<Func<DomainColour, bool>> predicate)
    {
        var visitor = new MyExpressionVisitor();
        var newPredicate = visitor.Visit(predicate) as Expression<Func<ColourDto, bool>>;
        return Context.Colours.Where(newPredicate.Complie()).Map().ToList();
    }
}


public class MyExpressionVisitor : ExpressionVisitor
{
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return Expression.Parameter(typeof(ColourDto), node.Name);
    }
}

最后這里是例外:

System.ArgumentException:未為類型'ColourDto'定義屬性'System.String Name'

希望有人能提供幫助。

編輯:這是一個dotnetfiddle

還是不行。

編輯:這是一個工作的dotnetfiddle

謝謝Eli Arbel

你需要做一些事情來實現這個目的:

  • Expression.Lambda和它們出現在正文中的任何位置替換參數實例 - 並對兩者使用相同的實例。
  • 更改lambda的委托類型。
  • 替換屬性表達式。

這是代碼,添加了泛型:

public static Func<TTarget, bool> Convert<TSource, TTarget>(Expression<Func<TSource, bool>> root)
{
    var visitor = new ParameterTypeVisitor<TSource, TTarget>();
    var expression = (Expression<Func<TTarget, bool>>)visitor.Visit(root);
    return expression.Compile();
}

public class ParameterTypeVisitor<TSource, TTarget> : ExpressionVisitor
{
    private ReadOnlyCollection<ParameterExpression> _parameters;

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return _parameters?.FirstOrDefault(p => p.Name == node.Name) ?? 
            (node.Type == typeof(TSource) ? Expression.Parameter(typeof(TTarget), node.Name) : node);
    }

    protected override Expression VisitLambda<T>(Expression<T> node)
    {
        _parameters = VisitAndConvert<ParameterExpression>(node.Parameters, "VisitLambda");
        return Expression.Lambda(Visit(node.Body), _parameters);
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.Member.DeclaringType == typeof(TSource))
        {
            return Expression.Property(Visit(node.Expression), node.Member.Name);
        }
        return base.VisitMember(node);
    }
}

為每種類型單獨定義屬性。

發生該錯誤是因為您無法從ColourDto類型的值獲取DomainColour定義的屬性的值。

您需要訪問使用該參數的每個MemberExpression ,並返回一個使用新類型的該屬性的新MemberExpression

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM