[英]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.