【问题标题】:Dynamically build lambda expression from a collection of objects?从对象集合动态构建 lambda 表达式?
【发布时间】: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 表达式。幸运的是,情况并非如此。

【问题讨论】:

    标签: c# linq lambda linq-to-objects kendo-ui-mvc


    【解决方案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 是的,我知道我为什么写这个。固定
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多