DataTable
LINQ
Predicate
C#
Programming

Get all column names of a DataTable into string array using LINQ/Predicate

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Extracting column names from a DataTable is a simple metadata task, but it exposes a common ADO.NET detail: DataColumnCollection is not strongly typed for LINQ by default. The usual pattern is to cast the columns to DataColumn, project ColumnName, and optionally filter with a predicate before converting the result to a string array.

Basic LINQ Solution

The standard LINQ approach is concise and readable.

csharp
1using System;
2using System.Data;
3using System.Linq;
4
5class Program
6{
7    static void Main()
8    {
9        var table = new DataTable();
10        table.Columns.Add("Id", typeof(int));
11        table.Columns.Add("Name", typeof(string));
12        table.Columns.Add("CreatedAt", typeof(DateTime));
13
14        string[] names = table.Columns
15            .Cast<DataColumn>()
16            .Select(column => column.ColumnName)
17            .ToArray();
18
19        Console.WriteLine(string.Join(", ", names));
20    }
21}

Cast<DataColumn>() is the important part. Without it, LINQ extension methods cannot treat the collection as an IEnumerable<DataColumn>.

Filter Columns with a Predicate

If you only want some columns, insert a filter before Select.

csharp
1using System;
2using System.Data;
3using System.Linq;
4
5class Program
6{
7    static void Main()
8    {
9        var table = new DataTable();
10        table.Columns.Add("Id", typeof(int));
11        table.Columns.Add("Name", typeof(string));
12        table.Columns.Add("InternalFlag", typeof(bool));
13
14        string[] visibleNames = table.Columns
15            .Cast<DataColumn>()
16            .Where(column => !column.ColumnName.StartsWith("Internal"))
17            .Select(column => column.ColumnName)
18            .ToArray();
19
20        Console.WriteLine(string.Join(", ", visibleNames));
21    }
22}

This is the most direct way to translate “all column names that match a rule” into code.

Using a Reusable Predicate Variable

If you want the filter logic to be reusable or configurable, keep it in a delegate.

csharp
1using System;
2using System.Data;
3using System.Linq;
4
5class Program
6{
7    static void Main()
8    {
9        var table = new DataTable();
10        table.Columns.Add("Id", typeof(int));
11        table.Columns.Add("Name", typeof(string));
12        table.Columns.Add("CreatedAt", typeof(DateTime));
13
14        Predicate<DataColumn> include = column => column.DataType != typeof(DateTime);
15
16        string[] names = table.Columns
17            .Cast<DataColumn>()
18            .Where(column => include(column))
19            .Select(column => column.ColumnName)
20            .ToArray();
21
22        Console.WriteLine(string.Join(", ", names));
23    }
24}

A Predicate<DataColumn> is not required by LINQ itself, but it is sometimes convenient when filter logic is shared with older APIs or configuration code.

Why Not Just Use a Loop

A loop is still fine.

csharp
1using System;
2using System.Collections.Generic;
3using System.Data;
4
5class Program
6{
7    static void Main()
8    {
9        var table = new DataTable();
10        table.Columns.Add("Id", typeof(int));
11        table.Columns.Add("Name", typeof(string));
12
13        var names = new List<string>();
14        foreach (DataColumn column in table.Columns)
15        {
16            names.Add(column.ColumnName);
17        }
18
19        Console.WriteLine(string.Join(", ", names));
20    }
21}

The LINQ version is shorter and composes better with filtering, ordering, and projection, which is why it is usually preferred in modern C# code.

Common Uses

Column-name arrays are often needed for:

  • export headers
  • generic table renderers
  • validation rules
  • dynamic mapping code
  • excluding internal columns before serialization

That is why this small pattern shows up often in utilities and data-access helpers. If you need deterministic UI or export output, remember that DataTable preserves column order. The LINQ projection will follow that existing order unless you add an explicit OrderBy, which is usually what you want for headers and mapping code.

Common Pitfalls

A common mistake is forgetting Cast<DataColumn>(), which makes the LINQ query fail at compile time. Another is using AsEnumerable(), which applies to rows, not columns. Developers also sometimes overcomplicate the task with reflection even though DataTable already exposes the metadata directly. Finally, if the filtering rule is expensive or repeated often, keep it explicit and readable rather than hiding it in a deeply nested query chain.

Summary

  • Use table.Columns.Cast<DataColumn>() to work with LINQ.
  • Select ColumnName and finish with ToArray().
  • Add Where(...) when only some columns should be included.
  • A reusable Predicate<DataColumn> can be wrapped inside the LINQ filter.
  • Prefer the simplest query that makes the column-selection rule obvious.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.