Getting Started with LINQ in .NET

Language Integrated Query (LINQ), introduced in .NET Framework 3.5 and Visual Studio 2008, provides a unified query syntax directly in C# for working with data across different sources. It operates on any collection implementing IEnumerable<T> and returns a new enumerable sequence, leveraging deferred execution in many cases.

Consider a task to find common elements between two integer arrays:

int[] seriesX = { 1, 2, 3, 4, 5, 6, 7, 8, 0 };
int[] seriesY = { 2, 4, 7, 8, 9 };

A traditional nested loop approach is verbose and imperative:

var sharedItems = new List<int>();
for (int i = 0; i < seriesX.Length; i++)
{
    for (int j = 0; j < seriesY.Length; j++)
    {
        if (seriesX[i] == seriesY[j])
        {
            sharedItems.Add(seriesX[i]);
        }
    }
}

Using LINQ, the intent becomes declarative and concise:

var commonNumbers = from x in seriesX
                    from y in seriesY
                    where x == y
                    select x;

The System.Linq namespace contains the core machinery. The fundamental clause order differs from SQL: every LINQ expression starts with from to define a range varible and the source, and ends with select or group.

Key operators include:

  • from – declares the data source and iteration variable.
  • where – filters elements using boolean predicates.
  • select – projects result elements into a new shape.
  • group – partitions results based on a key.
  • orderby – sorts ascending or descending, with optional secondary sort keys separated by commas.
  • join and equals – correlate two sequences on matching keys.
  • let – stores a computed value for reuse within the query.
  • into – continues a query after a group, join, or select clause.
var highValues = from item in source
                 where item.Weight > 30
                 orderby item.Name
                 select new { item.Id, item.Name };

Several C# language features enhance LINQ readability:

Implicitly typed variables (var) let the compiler infer the result type, avoiding explicit IEnumerable<T> declarations:

var filtered = from e in entries where e.Active select e.Title;

Anonymous types enable on-the-fly projections without defining a separate class:

var shaped = from p in products
             where p.Price > 50
             select new { p.Sku, p.DisplayName };

Query Patterns

Basic Projection

var titles = from doc in documents select doc.Title;

Filtered Retrieval

var cheapItems = from item in inventory
                 where item.Cost < 10
                 select item;

Grouping

var categoryGroups = from prod in products
                     group prod by prod.Category into grouped
                     orderby grouped.Key
                     select grouped;

Inner Join

var joinedData = from cust in customers
                 join ord in orders on cust.Id equals ord.CustomerId
                 select new { CustomerName = cust.Name, OrderId = ord.Id };

Left Outer Join

var leftJoinResult = from emp in employees
                     join dept in departments on emp.DeptId equals dept.Id into deptGroup
                     from d in deptGroup.DefaultIfEmpty()
                     select new { EmployeeName = emp.Name, Department = d?.Name };

The DefaultIfEmpty() method supplies a default element when the right side has no matching records.

Mastering these patterns enables effetcive use of LINQ across objects, databases, and XML, far beyond the limited association with LINQ to SQL.

Tags: LINQ .NET C# Query IEnumerable

Posted on Mon, 21 Sep 2026 16:46:30 +0000 by lzylzlz