C# Linq OrderBy 基于条件



我有一个想要更改的 foreach 循环:

foreach (var line in lines.OrderBy(x=> x.ColA))

如果满足条件,那么我想按 ColB 订购,而不是按 ColA 订购。

我知道这可以像下面这样完成:

var orderLines = new List<OrderLines>();
if (condition)
orderLines = lines.OrderBy(x => x.ColB).ToList();
else
orderLines = lines.OrderBy(x => x.ColA).ToList(); ;
foreach (var line in orderLines)

但我相信有一个更优雅的解决方案。

几种解决方案。

(1(不要在你之前做ToList(),只创建IEnumerable。

IEnumerable<OrderLines> orderLines = condition ?
lines.OrderBy(orderLine => orderLine.ColB) :
lines.OrderBy(orderLine => orderLine.ColA);
foreach(OrderLine orderlLine in orderLines) {...}

(2( 如果要在多个位置使用它,请考虑创建一个扩展方法。这样,您的方法看起来就像任何其他 LINQ 方法一样。 请参阅揭秘的扩展方法

public static IEnumerable<OrderLine> OrderBy(
this IEnumerable<OrderLine> source,
bool condition)
{
return condition ?
lines.OrderBy(orderLine => orderLine.ColB) :
lines.OrderBy(orderLine => orderLine.ColA);
}

用法:

如果操作员选中 chexBox1,则按 colB 排序,否则按 colA 排序:

IEnumerable<OrderLine> lines = ...
foreach(var sortedOrderLine in lines.OrderBy(this.CheckBox1.IsChecked))
{
...
}

因为它是IEnumerable<OrderLine>的扩展方法,您甚至可以将其与其他 LINQ 方法交织在一起:

var result = lines.Where(orderLine => orderLine.Date.Year >= 2020)
.OrderBy(this.checkBox1.IsChecked)
.Select(orderLine => new
{
Id = orderLine.Id,
Price = orderLine.Price,
});

但总而言之,它不会为您节省大量代码。唯一的优势是,如果您将其用于多种方法。在这种情况下,只需在一个位置更改您希望按 OrderBy 条件的方式进行更改。但同样:如果您希望在一个地方使用它,将其移动到单独的方法可能无法帮助读者理解会发生什么。

这可能已经足够好了。

请记住,在 lambda 表达式的背后,发生了魔术,它(有效地(绑定到一个Comparer<T>,其中 T 取决于要比较的列的类型。

使它更简洁可能会降低效率。 特别是转换和比较字符串会使它既慢又可能给您带来麻烦(ints 排序为 1,2,3,...10,11,...与他们的字符串 "1"、"10"、"11",..."19","2","20","21"...(。

"单行"只有在行为明显的情况下才是优雅的,否则它会被混淆

你的代码很好。 (海事组织;-(

安装NuGetSystem.Linq.Dynamic,您可以将property名称作为string传递给OrderBy,如下所示。

用法list.AsQueryable().OrderBy("PropertyName1 SortOrder, ropertyName SortOrder").PropertyName将在哪里ColAColB.SortOrder将是ASCDESC.

  1. 添加using System.Linq.Dynamic;
  2. foreach (var line in lines.AsQueryable().OrderBy(condition ? "ColB" : "ColA")

对于.Net Core安装NuGetSystem.Linq.Dynamic.Core

  1. 添加using System.Linq.Dynamic.Core;
  2. foreach (var line in lines.AsQueryable().OrderBy(condition ? "ColB" : "ColA")

为了更好的做法,而不是像您的情况那样nameof(OrderLines.ColA)使用PropertyName字符串使用nameof(Class.Property)。因此,如果您更改ColA属性,它将显示Build错误,并且您将不会得到run time exception

  • foreach (var line in lines.AsQueryable().OrderBy(condition ? nameof(OrderLines.ColB) : nameof(OrderLines.ColA))

正如@AlanK所提到的,我们能得到的最接近的简化OrderBy是这样的:

Func<OrderLines, string> selector = (orderLine) => condition ? orderLine.ColB : orderLine.ColA;
List<OrderLines> orderLines = lines.OrderBy(selector);

前提是ColAColB的数据类型相同。否则,由于数据类型转换的开销,它不会有效。

最新更新