将 List.foreach 替换为 LINQ

本文关键字:LINQ 替换 foreach List | 更新日期: 2023-09-27 18:35:42

我是LINQ的新手,正在用它做一些实验。

抱歉,如果它是重复的,但我似乎找不到合适的指南(对我来说)

我想替换此代码:

DataTable table
List<string> header = new List<string>();
table.Columns.Cast<DataColumn>().ToList().ForEach(col => header.Add(col.ColumnName));

使用类似 LINQ 的内容:

var LINQheader = from mycol in table.Columns select mycol.ColumnName;
LINQheader.tolist();

但它甚至不编译。我想要的不是单行解决方案,而是希望一些逻辑来理解如何在更复杂的环境中构建它(例如在XML中选择具有某些逻辑的许多节点)

将 List.foreach 替换为 LINQ

这里是原始代码

table.Columns.Cast<DataColumn>().ToList().ForEach(col => header.Add(col.ColumnName));

为什么使用Cast
因为它允许您将DataColumnCollection项视为DataColumn而不是对象。

为什么使用ToList
因为它将您的IEnumerable转换为List并允许您调用ForEach因为此函数是存在于List类中的特殊方法。

为什么使用ForEach
因为它允许您对列表中的每个元素执行所需的操作(在您的情况下,它将每列的列名添加到另一个列表( header ))。

简体版:

现在假设您要将列名称添加到以"学生"开头的header你可以写这样的东西

DataTable table = new DataTable();
List<string> header = new List<string>();
foreach (DataColumn col in table.Columns)
{
    if (col.ColumnName.StartsWith("Id")) // you can remove this line if you want to add all of them
       header.Add(col.ColumnName);
}

你也可以使用这个

table.Columns.Cast<DataColumn>()
    .ToList()
    .ForEach(col =>
    {
        if (col.ColumnName.StartsWith("Id"))
            header.Add(col.ColumnName)
    });

var headers = table.Columns.Cast<DataColumn>()
        .Where(col => col.ColumnName.StartsWith("Id"))
        .Select(col => col.ColumnName);
header.AddRange(headers);

您可以使用Enumerable.Aggregate()

var header = table.Columns.Cast<DataColumn>().Aggregate(new List<string>(), (list, col) => { list.Add(col.ColumnName); return list; });

通常,Linq 允许从数据源检索和转换数据序列。 在这个问题中,您要做的是遍历一个序列并返回一个即时结果。 这不是 Linq 的主要关注点,但有一些方法可以执行这样的任务,包括 Aggregate()Average()Count()Max() 等。

var LINQheader = from mycol in table.column select mycol.ColumnName;
LINQheader.tolist();

这不会编译,因为DataTable中没有这样的属性,如column,只有Columns,你必须使用.Cast()方法,因为它们没有实现正确的接口(参见@Uriil的答案)。

试试这个:

var LINQheader = from mycol in table.Columns.Cast<DataColumn>()
                  select mycol.ColumnName;
LINQheader.tolist();

如果要在扩展方法中使用包装,可以这样做:

public static IEnumerable<string> GetHeaderColumns (this DataTable dataTable) 
{
    if (dataTable == null || !dataTable.Columns.Any())
    {
        yield break;
    }
    foreach (var col in dataTable.Columns.Cast<DataColumn>())
    {
        yield return col.ColumnName;
    }
}
    static void Main(string[] args)
    {
        DataTable tbl = new DataTable();
        tbl.Columns.Add("A");
        tbl.Columns.Add("B");
        var p = from DataColumn col in tbl.Columns select col.ColumnName;
        foreach(string a in p)
        {
            Console.WriteLine(a);
        }
    }

这里有一些代码示例。如果您想List<string>,请使用 ToList()

编辑:

就像@Grundy说你缺少指定列的类型,即数据列。

List<string> columnList = (from DataColumn mycol in table.Columns select mycol.ColumnName).ToList();

在这里,这将是您的一行。

为什么不简单选择喜欢

DataTable table;
IEnumerable<string> header = from mycol in table.Columns.Cast<DataColumn>()
                             select mycol.ColumnName;

您遇到了一些问题,需要解决方法:

  1. ForEach 是 List specifict 方法,所以不能将其转换为 LINQ
  2. LINQ 用于数据选择、聚合,但不用于数据修改
  3. table.Columns ,返回 DataColumnCollection ,它不实现IEnumerable<T>,所以无论如何你都必须强制转换它:

    var LINQheader = from mycol in table.Columns.Cast<DataColumn>()
                     select name.ColumnName;