liveBook · Manning

LINQ

As explained in .NET in Action, Second Edition

Language Integrated Query (LINQ) is a .NET language-integrated query technology for querying collections and data sources with a common syntax.

Language Integrated Query (LINQ) is a C# feature for querying data with a common syntax. In an ASP.NET Core service, it can turn a collection of reflected properties into the names returned by an endpoint. The same approach can later query a database, but the example here operates on an array. section 3.1.1 section 3.3

Listing 3.8 Property getting all fonts with reflection
public static class AsciiArt
{
  public static Lazy<IEnumerable<string>> AllFonts =     #1
    new (() =>                                           #2
      from p in typeof(FiggleFonts)                      #3
      .GetProperties(                                    #4
        BindingFlags.Public | BindingFlags.Static)
      select p.Name);                                    #5
  // ...
}

The query starts with the source: public static properties returned by reflection. `select p.Name` projects each property into its name. Placing `from` before `select` also lets an editor know the source while suggesting available members. section 3.1.1

LINQ query syntax is not a separate collection engine. The compiler translates this projection into a method call resembling `GetProperties(...).Select(p => p.Name)`. The returned array implements `IEnumerable`, the collection interface used here to enumerate its elements. `Lazy` delays creation of the collection until its value is first requested; for this small font list, that optimization is optional. section 3.1.1

Listing 3.9 LINQ query translated to methods
public static Lazy<IEnumerable<string>> AllFonts =
  new (() =>
    typeof(FiggleFonts)                             #1
    .GetProperties(
      BindingFlags.Public | BindingFlags.Static)
    .Select(p => p.Name));                          #2

Compare the method form with the query above: the lambda `p => p.Name` performs the same projection as `select p.Name`. Choose the form that makes the surrounding service code easiest to follow. section 3.1.1

The collection becomes more useful as the endpoint accepts query parameters:

  • Return `AllFonts.Value` from a root `MapGet` handler to expose the names. section 3.1.1
  • Apply `Skip(skip ?? 0)` and `Take(take ?? 100)` to provide optional paging with defaults. section 3.1.1
  • For richer results, project each property into a name-and-font tuple, then filter by name or direction and order by name. section 3.1.1
Listing 3.14 Adding paging, sorting, and filtering to font list
using Figgle;                                              #1
const StringComparison SCIC =                              #2
  StringComparison.OrdinalIgnoreCase;                      #2
  
app.MapGet("/", 
  (
    int? skip,
    int? take,
    FiggleTextDirection? dir,                             #3
    string? name,                                         #4
    string? order                                         #5
  ) => {
    var query = from f in AsciiArt.AllFonts.Value         #6
      where                                               #7
        (name == null || f.Name.Contains(name, SCIC))     #8
        && (dir == null || f.Font.Direction == dir)       #9
      select f;
    if (string.Equals("desc", order, SCIC))               #10
    {
      query = query.OrderByDescending(f => f.Name);       #11
    }
    else 
    {
      query = query.OrderBy(f => f.Name);                 #11
    }
  
    return query                                          #12
      .Skip(skip ?? 0)
      .Take(take ?? 200)
      .Select(f => f.Name);
  });

The service query combines optional filters before choosing an ordering. Its name check uses an ordinal, case-insensitive comparison, so filtering does not depend on the caller matching letter case. section 3.1.1

How .NET in Action, Second Edition covers it

How deep it goes
Works through projection, method translation, paging, filtering, and sorting; defers database querying to a later chapter.
Examples
Shows reflected font names, equivalent query and method forms, and endpoint handlers with paging and optional filters.
What it assumes
Introduces LINQ through C# listings and a SQL comparison without requiring prior LINQ knowledge.
What you can do after
Apply it via C# LINQ and ASP.NET Core minimal APIs to project, filter, sort, and page a collection.
How it connects
Connects LINQ with SQL, reflection, IEnumerable, lazy initialization, and ASP.NET Core minimal APIs.

Also explained in

Compare how 3 books explain LINQ →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of .NET in Action, Second Edition. The section links point to the parts of the book it draws on.