如何编写要根据条件选择的 C# LINQ 代码



我希望通过转换方法将一种类型的列表转换为另一种类型,但只是有选择地(如果转换结果是否为 null(。它显示在下面的代码中。

private List<B> GetBList(List<A> aList)
{
List<B> bList = new List<B>();
foreach (A a in aList)
{
B b = GetB(a);
if (b != null)
{
bList.Add(b);
}
}
return bList;
}
private B GetB(A a)
{
if (a != null)
{
return new B();
}
return null;
}

有没有办法使用 LINQ 编写它,如下所示。以下函数的问题在于,即使转换结果为 null,它也将始终移动数据。结果必须是数组(B 的数组(,输入必须是列表(A 的列表(。

private B[] GetBList(List<A> aList)
{
return aList.Select(GetB)?.ToArray() ?? Array.Empty<A>();
}

请指教。提前感谢!

您可以使用Select(x => GetB(x))选择这将返回转换后的对象。然后你应该用Where(x => x != null)过滤它。然后将其转换为array.

请注意,我在aList之后使用了?作为aList?.Select,因此它将处理aList对象null的情况。

private B[] GetBList(List<A> aList)
{
return aList?.Select(x => GetB(x)).Where(x => x != null).ToArray() ?? Array.Empty<B>();
}

编辑如果Select(x => GetB(x))也可以改用Select(GetB)

private B[] GetBList(List<A> aList)
{
return aList?.Select(GetB).Where(x => x != null).ToArray() ?? Array.Empty<B>();
}

我遇到过很多需要这样的函数的情况,因此我编写了自己的扩展方法。与此同时,我不认为我这样做赢得了任何东西,你对卡兰的回答做得很好。一方面,你不会在性能上获得任何东西,另一方面,它只会增加代码的复杂性和可读性。

但是,它对我进入 LINQ 表达式、了解后面发生的事情以及了解 IEnumerable、ICollection 等的差异有很大帮助。

为了完整性和潜在的灵感,无论如何我都会分享我的代码:

public static IEnumerable<TResult> SelectByCondition<TInput, TResult>(this IEnumerable<TInput> input, Func<TInput, TResult> selector, Func<TResult, bool> checker) {
using var enumerator = input.GetEnumerator();
while (enumerator.MoveNext()) {
var selection = selector(enumerator.Current);
if (checker(selection)) {
yield return selection;
}
}
}

在您的情况下,您可以像这样使用它:

aList?.SelectByCondition(GetB, x => x != null).ToArray() ?? Array.Empty<B>();

如果您碰巧多次遇到 null 检查的方案,以下简化可能仍然有用:

public static IEnumerable<TResult> SelectIfNotNull<TInput, TResult>(this IEnumerable<TInput> input, Func<TInput, TResult> selector) {
using var enumerator = input.GetEnumerator();
while (enumerator.MoveNext()) {
var selection = selector(enumerator.Current);
if (selection != null) {
yield return selection;
}
}
}

然后可以简化实际调用:

aList?.SelectIfNotNull(GetB).ToArray() ?? Array.Empty<B>();

最新更新