簡體   English   中英

謂詞表達式作為過濾器參數

[英]Predicate Expression as Filter Parameter

我正在嘗試創建一種包裝LINQ Where調用(在IQueryable上)的方法,以對集合中的特定字段進行過濾,並且使該方法工作不知所措。

例如,我有一個類似於以下內容的Job對象:

public class Job
{
    public int Id { get; set; }
    public int StatusId { get; set; }
}

public class StatusItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsAvailable { get; set; }

    public static readonly StatusItem Canceled = new StatusItem() { Id = (int)StatusEnum.Canceled, Name = StatusEnum.Canceled.ToString(), IsAvailable = true };
    public static readonly StatusItem Created = new StatusItem() { Id = (int)StatusEnum.Created, Name = StatusEnum.Created.ToString(), IsAvailable = true };
    public static readonly StatusItem Open = new StatusItem() { Id = (int)StatusEnum.Open, Name = StatusEnum.Open.ToString(), IsAvailable = true };
    public static readonly StatusItem Assigned = new StatusItem() { Id = (int)StatusEnum.Assigned, Name = StatusEnum.Assigned.ToString(), IsAvailable = false };
}

我希望有一種服務方法僅使用系統定義的狀態來強制執行過濾,如下所示:

IEnumerable<Job> GetAll(Expression<Func<StatusItem, bool>> statusFilter)
{
    // Jobs is IQueryable<job>. How do I apply statusFilter to Job.StatusId?
    return jobs.Where(/* some magic here? */);
}

通話類似於:

return JobService.GetAll(s => s > StatusItem.Open && s < StatusItem.Assigned);

編輯:盯着這個太久了。 現在大腦糊塗了。 試圖修復先前的錯誤

我不知道這是否是您需要的,但是請檢查以下內容:

jobs.Where(x => statusFilter.Compile().Invoke((StatusEnum)x.StatusId));

還考慮將屬性StatusId更改為StatusEnum。 屬性也應該是公共的。

class Job
{
    public int Id { get; set; }
    public StatusEnum StatusId { get; set; }
}

通過這種聲明,不需要強制轉換為StatusEnum:

jobs.Where(x => statusFilter.Compile().Invoke(x.StatusId));

最簡單的方法是使用Expression<Func<Job, bool>>而不是Expression<Func<StatusEnum, bool>> ,這將使您編寫如下內容:

IEnumerable<Job> GetAll(Expression<Func<Job, bool>> jobFilter)
{
    return jobs.Where(jobFilter);
}

如果您要通過狀態以外的內容進行過濾,它還具有更靈活的優勢。

如果您確實要使用Expression<Func<StatusEnum, bool>> ,它會變得更加復雜,因為您需要重寫表達式以從Expression<Func<StatusEnum, bool>>創建一個Expression<Func<Job, bool>>Expression<Func<StatusEnum, bool>> 這是一種方法:

IEnumerable<Job> GetAll(Expression<Func<StatusEnum, bool>> statusFilter)
{
    var job = Expression.Parameter(typeof(Job), "job");
    var visitor = new ParameterReplacementVisitor(
        statusFilter.Parameters[0],
        Expression.Property(job, nameof(Job.StatusId)));
    Expression<Func<Job, bool>> jobFilter =
        Expression.Lambda<Func<Job, bool>>(
            visitor.Visit(statusFilter.Body),
            job);
    return jobs.Where(jobFilter);
}

class ParameterReplacementVisitor : ExpressionVisitor
{
    private readonly ParameterExpression _parameter;
    private readonly Expression _replacement;

    public ParameterReplacementVisitor(ParameterExpression parameter, Expression replacement)
    {
        _parameter = parameter;
        _replacement = replacement;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (node == _parameter)
            return _replacement;
        return node;
    }
}

暫無
暫無

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

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