从对象集合动态构建 lambda 表达式?

Posted

技术标签:

【中文标题】从对象集合动态构建 lambda 表达式?【英文标题】:Dynamically build lambda expression from a collection of objects? 【发布时间】:2018-08-07 17:29:41 【问题描述】:

我有一个以这种格式存储的排序列表:

public class ReportSort

    public ListSortDirection SortDirection  get; set; 
    public string Member  get; set; 

我需要把它变成Action<DataSourceSortDescriptorFactory<TModel>>类型的lambda表达式

所以假设我有以下报告排序集合:

new ReportSort(ListSortDirection.Ascending, "LastName"),
new ReportSort(ListSortDirection.Ascending, "FirstName"),

我需要将其转换为这样的语句才能像这样使用:

.Sort(sort =>  
        sort.Add("LastName").Ascending();
        sort.Add("FirstName").Ascending();
      )

排序方法签名是:

public virtual TDataSourceBuilder Sort(Action<DataSourceSortDescriptorFactory<TModel>> configurator)

所以我现在有一些方法:

public static Action<DataSourceSortDescriptorFactory<TModel>> ToGridSortsFromReportSorts<TModel>(List<ReportSort> sorts) where TModel : class
    
        Action<DataSourceSortDescriptorFactory<TModel>> expression;
        //stuff I don't know how to do
        return expression;
    

...我不知道在这里做什么。

编辑:答案是:

var expression = new Action<DataSourceSortDescriptorFactory<TModel>>(x =>
        
            foreach (var sort in sorts)
            
                if (sort.SortDirection == System.ComponentModel.ListSortDirection.Ascending)
                
                    x.Add(sort.Member).Ascending();
                
                else
                
                    x.Add(sort.Member).Descending();
                
            
        );

起初我在想我必须使用 Expression 类从头开始动态构建一个 lambda 表达式。幸运的是,情况并非如此。

【问题讨论】:

【参考方案1】:

...我不知道在这里做什么。

好吧,推理出来。

你手里有什么? List&lt;ReportSort&gt; 称为 sorts

你需要什么?一个Action&lt;Whatever&gt;

您已经迈出了第一步:您已经创建了一个方法来获取您拥有的东西并返回您需要的东西。伟大的第一步。

    Action<DataSourceSortDescriptorFactory<TModel>> expression;
    //stuff I don't know how to do
    return expression;

而且你已经说出了你不知道该怎么做的事情——但是。这是一个很好的技术。

首先填写一些可以编译但不能正常工作的内容。

Action<DataSourceSortDescriptorFactory<TModel>> expression = 
  sort =>          
    sort.Add("LastName").Ascending();
    sort.Add("FirstName").Ascending();
  ;
return expression;

非常好。 现在您有了一个编译程序,这意味着您可以运行您的测试并验证如果这种情况是预期的,则测试通过,如果预期其他任何情况,则测试失败。

现在想想,我手里有什么?我有一个东西清单,我正在做一个Action。这意味着正在发生副作用,可能涉及列表中的每个项目。所以那里可能有一个foreach

Action<DataSourceSortDescriptorFactory<TModel>> expression = 
  sort =>          
    sort.Add("LastName").Ascending();
    sort.Add("FirstName").Ascending();
    foreach(var sort in sorts)  
      // Do something
    
  ;
return expression;

编译它。它失败。啊,我们混淆了我们正在添加的类别和我们正在添加的新类别。解决问题。

Action<DataSourceSortDescriptorFactory<TModel>> expression = 
  existingSort =>          
    existingSort.Add("LastName").Ascending();
    existingSort.Add("FirstName").Ascending();
    foreach(var newSort in sorts)  
      // Do something
    
  ;
return expression;

太好了,现在我们又可以编译和运行测试了。

这里的模式应该很清楚。 继续编译,继续运行测试,逐渐让你的程序越来越正确,推理你可以对你手头的值执行的操作。

你能完成它吗?

【讨论】:

是的,我能够弄清楚,感谢您发布详细的答案。我以为我必须从头开始手动构建一个 lambda 表达式,这就是我试图理解它时头晕目眩的地方,这并不像我担心的那么难。 @SventoryMang:可以完全从头构建一个 lambda 并使用各种技术对其进行编译。但通常没有必要。【参考方案2】:

您可以使用可以分配给Action&lt;T&gt; 委托的以下 lambda 表达式。在该 lambda 表达式中,捕获 List&lt;T&gt; 变量并对其进行循环:

public static Action<DataSourceSortDescriptorFactory<TModel>> ToGridSortsFromReportSorts<TModel>(List<ReportSort> sorts) where TModel : class

    Action<DataSourceSortDescriptorFactory<TModel>> expression = 
       result  => 
       
           foreach (var sort in sorts)
           
                if (sort.SortDirection == ListSortDirection.Ascending)
                    result.Add(sort.Member).Ascending();
                else // or whatever other methods you want to handle here
                    result.Add(sort.Member).Descending();
           
       ;
    return expression;

【讨论】:

请注意,delegate (T t) ... 在 C# 3 发布后编写的代码风格不佳。而是使用(T t) =&gt; ... @EricLippert 是的,我知道我为什么写这个。固定

以上是关于从对象集合动态构建 lambda 表达式?的主要内容,如果未能解决你的问题,请参考以下文章

从另外两个创建动态表达式 lambda(链接表达式)

动态构建Lambda表达式实现EF动态查询

Lambda 表达式 - 根据集合中另一个属性的值设置对象集合中一个属性的值

基于Expression Lambda表达式树的通用复杂动态查询构建器——《剧透一下》

如何使用动态对象作为 lambda 表达式的输入?

基于Expression Lambda表达式树的通用复杂动态查询构建器——《构思篇二》已开源