我有一个想要更改的 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"...(。
"单行"只有在行为明显的情况下才是优雅的,否则它会被混淆。
你的代码很好。 (海事组织;-(
安装NuGet
System.Linq.Dynamic
,您可以将property
名称作为string
传递给OrderBy
,如下所示。
用法list.AsQueryable().OrderBy("PropertyName1 SortOrder, ropertyName SortOrder")
.PropertyName
将在哪里ColA
ColB
.SortOrder
将是ASC
DESC
.
- 添加
using System.Linq.Dynamic;
foreach (var line in lines.AsQueryable().OrderBy(condition ? "ColB" : "ColA")
对于.Net Core
安装NuGet
System.Linq.Dynamic.Core
。
- 添加
using System.Linq.Dynamic.Core;
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);
前提是ColA
和ColB
的数据类型相同。否则,由于数据类型转换的开销,它不会有效。