# C# Cheat Sheet: Syntax, LINQ and .NET 10 Essentials

Source: https://srvscripts.com/guides/csharp-cheat-sheet/
Updated: 2026-10-09
Publisher: srvScripts (https://srvscripts.com/)

**Short answer:** Modern C# code uses `var` and nullable reference types, collection expressions such as `[1, 2, 3]`, switch expressions with pattern matching, records for data, and LINQ methods such as `Where` and `Select` for queries. Asynchronous work uses `async`/`await` with `Task`. The current release is C# 14 on .NET 10 (LTS), which adds the `field` keyword, extension properties and `dotnet run app.cs` for single-file scripts.

The examples in this C# cheat sheet were run with the .NET 10 SDK 10.0.401 (runtime 10.0.12, C# 14) on Linux on 9 October 2026. Each feature notes the C# version that introduced it, so you can tell what works on older projects: C# 12 shipped with .NET 8 and C# 13 with .NET 9.

## Running C# with the dotnet CLI

| Command | What it does |
| --- | --- |
| dotnet --list-sdks | Installed SDKs (.NET 10 is the current LTS) |
| dotnet new console -n app | New console project with top-level statements |
| dotnet run · dotnet build · dotnet test | Run, build or test the project in the current folder |
| dotnet run app.cs | Run a single C# file with no project file (.NET 10) |
| dotnet publish -c Release -r linux-x64 --self-contained | Build a folder you can copy to a server without installing .NET |
| dotnet add package Serilog | Add a NuGet package to the project |

New projects enable `<Nullable>enable</Nullable>` and implicit `using` directives, so `Program.cs` can start straight away with `Console.WriteLine("Hi");`.

## Variables, types and strings

| Syntax | What it does |
| --- | --- |
| int port = 443; · long big = 10_000_000_000L; | Integers; underscores aid readability |
| double load = 0.75; · decimal price = 9.99m; | Binary float · exact decimal for money |
| var host = "web01"; · const int Max = 3; | Inferred type · compile-time constant |
| string? maybe = null; | Nullable reference type; the compiler warns on unsafe use |
| maybe?.Length ?? 0 · maybe ??= "set"; | Null-conditional, null-coalescing, assign if null |
| int.Parse("42") · int.TryParse(s, out var n) | Parse (throws) · parse and return bool |
| $"{host}:{port}" | Interpolated string |
| $"{1234567:N0}" · $"{port,6}" · $"{d:yyyy-MM-dd}" | Format specifiers: thousands, width, date |
| @"C:\temp\new" | Verbatim string: backslashes are literal |
| s.Trim() · s.Split(',') · string.Join("-", list) | Trim, split, join |
| s.Contains("ell") · s.StartsWith("he") · s[1..3] · s[^1] | Search, range slice, last character |
| string.IsNullOrWhiteSpace(s) | Null, empty or spaces |
| a.Equals(b, StringComparison.OrdinalIgnoreCase) | Case-insensitive compare |
| new StringBuilder().Append(i) | Build strings in a loop |

```
string json = """
    {
      "host": "db01",
      "port": 3306
    }
    """;                                    // raw string literal (C# 11)

string tpl = $$"""{"host": "{{host}}", "port": {{port}}}""";   // {{ }} interpolates, { } is literal
```

## Collections and collection expressions

| Syntax | What it does |
| --- | --- |
| int[] nums = [5, 1, 4]; · List hosts = ["web01", "db01"]; | Collection expressions (C# 12) |
| int[] more = [.. nums, 6, 7]; | Spread one collection into another |
| hosts.Add(x) · hosts.Insert(0, x) · hosts.Remove(x) · hosts.Count | List operations |
| hosts[^1] · nums[1..3] | Index from the end · range |
| var ports = new Dictionary { ["ssh"] = 22 }; | Dictionary with an initialiser |
| ports.TryGetValue("https", out var p) | Read without risking KeyNotFoundException |
| ports.GetValueOrDefault("smtp", 25) · ports.TryAdd(k, v) | Read with default · add only if missing |
| foreach (var (k, v) in ports) | Deconstruct key-value pairs |
| counts[w] = counts.GetValueOrDefault(w) + 1; | Count occurrences |
| new HashSet() · new Queue() · new Stack() | Set, FIFO queue, LIFO stack |
| void Log(params ReadOnlySpan items) | params with any collection type (C# 13) |

## Control flow and pattern matching

```
string status = code < 500 ? "up" : "down";

string cls = code switch                     // switch expression with relational patterns
{
    >= 200 and < 300 => "ok",
    301 or 302 => "redirect",
    >= 400 and < 500 => "client error",
    _ => "server error",
};

static string Describe(object? o) => o switch
{
    null => "null",
    int i when i > 1000 => "big int",
    int i => $"int {i}",
    string { Length: > 0 } s => $"string of {s.Length}",      // property pattern
    Server { Port: 443 } sv => $"https server {sv.Name}",
    int[] and [1, .., var last] => $"array ending {last}",    // list pattern
    _ => "other",
};

if (o is string str && str.Length > 3) Console.WriteLine(str.ToUpper());
if (o is not null) { ... }
```

Loops are `for (int i = 0; i < 3; i++)`, `foreach (var h in hosts)`, `while` and `do ... while`. Use `_` to discard a value you do not need, as in `var (name, ip, _) = srv;`.

## Classes, records and properties

```
record Server(string Name, string Ip, int Port = 22)        // value equality, ToString, with
{
    public string Address => $"{Ip}:{Port}";
}
var copy = srv with { Port = 8443 };

readonly record struct Point(int X, int Y);                   // small immutable value type

class Db(string host, int port = 3306)                        // primary constructor (C# 12)
{
    public string Status { get; private set; } = "down";
    public override string ToString() => $"Db({host}:{port})";
}

class Options
{
    public required string Host { get; init; }                // must be set, then read-only
    public int Port { get; init; } = 3306;
}

class Config
{
    public string Name { get; set => field = value?.Trim()   // field keyword (C# 14)
        ?? throw new ArgumentNullException(nameof(value)); } = "";
}

enum Level { Info = 1, Warn, Error }
```

C# 14 also adds null-conditional assignment (`customer?.Order = order;` does nothing when `customer` is null) and extension blocks, which can declare extension properties as well as methods:

```
static class Extensions
{
    public static bool IsPrivateIp(this string ip) => ip.StartsWith("10.");   // classic extension method

    extension(IEnumerable source)                                       // C# 14 extension block
    {
        public bool IsEmpty => !source.Any();                                 // hosts.IsEmpty
    }
}
```

## LINQ and lambdas

| Syntax | What it does |
| --- | --- |
| nums.Where(x => x > 2).Select(x => x * 10) | Filter and transform (lazy until enumerated) |
| nums.Sum() · nums.Max() · nums.Average() · nums.Count(x => x % 2 == 0) | Aggregates |
| nums.Any(fn) · nums.All(fn) · nums.FirstOrDefault(fn) | Tests and first match (0 or null if none) |
| OrderBy(h => h.Length).ThenBy(h => h) · OrderByDescending(fn) | Sort |
| Take(2) · Skip(3) · Distinct() · Chunk(2) | Paging, de-duplication, batches |
| hosts.GroupBy(h => h[..2]) | Groups with Key |
| hosts.CountBy(h => h[..2]) | Key and count pairs (.NET 9+) |
| hosts.Index() | Item with its position (.NET 9+) |
| ToList() · ToArray() · ToDictionary(h => h, h => h.Length) | Materialise results |
| from h in hosts where h.StartsWith("db") select h | Query syntax; compiles to the same methods |
| Func sq = x => x * x; · Action log = m => ...; | Delegate types for lambdas |

## Async, exceptions and using

```
var results = await Task.WhenAll(Check("web01"), Check("web02"));   // run in parallel

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
await Task.Delay(1000, cts.Token);           // throws OperationCanceledException on timeout

using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
var res = await http.GetAsync("https://example.com/");
Console.WriteLine((int)res.StatusCode);

try
{
    ParsePort("abc");
}
catch (ConfigException e) when (e.InnerException is FormatException)   // exception filter
{
    Console.WriteLine(e.Message);
}
finally
{
    Console.WriteLine("cleanup");
}

ArgumentException.ThrowIfNullOrEmpty(name);   // guard clauses
ArgumentOutOfRangeException.ThrowIfNegative(port);
```

A `using var` declaration disposes the object at the end of the enclosing scope. In a long-running service, reuse one `HttpClient` (or `IHttpClientFactory`) instead of creating one per request.

## For server admins: files, processes and single-file scripts

| Syntax | What it does |
| --- | --- |
| File.ReadAllText(p) · File.ReadAllLines(p) | Whole file · array of lines (small files) |
| File.ReadLines(p).Count(l => l.Contains("ERROR")) | Stream a large file lazily |
| await foreach (var line in File.ReadLinesAsync(p)) | Async line-by-line read |
| File.WriteAllText(p, s) · File.AppendAllText(p, s) | Overwrite · append |
| Directory.CreateDirectory(d) · Directory.EnumerateFiles(d, "*.log", SearchOption.AllDirectories) | mkdir -p · recursive search |
| Path.Combine("/var", "log", "x.log") · Path.GetExtension(p) | Build and split paths |
| new ProcessStartInfo("df") { ArgumentList = { "-h", "/" }, RedirectStandardOutput = true } | Run a command without a shell; then Process.Start(psi) and WaitForExitAsync() |
| JsonSerializer.Deserialize(json, new JsonSerializerOptions(JsonSerializerDefaults.Web)) | Parse JSON into a record, case-insensitive |
| Environment.GetEnvironmentVariable("HOME") · Environment.ProcessorCount | Environment and host facts |
| DateTimeOffset.ParseExact(s, "dd/MMM/yyyy:HH:mm:ss zzz", CultureInfo.InvariantCulture) | Parse an Apache or Nginx log timestamp |

.NET 10 can run one `.cs` file as a script, with packages declared at the top. Make it executable and it runs like a shell script:

```
#!/usr/bin/env dotnet
#:package Humanizer@2.14.1
using Humanizer;

var drive = new DriveInfo("/");
Console.WriteLine($"Free on /: {drive.AvailableFreeSpace.Bytes().Humanize()}");
```

```
chmod +x diskcheck.cs
./diskcheck.cs                 # or: dotnet run diskcheck.cs
```

The first run restores packages and compiles, which takes a few seconds; later runs use a cache. Format strings such as `P1` and `N0` follow the server’s culture, so pass `CultureInfo.InvariantCulture` when output is parsed by another tool.

**Official documentation (checked 9 October 2026):** [C# language reference](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/) · [What’s new in C# 14](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14) · [What’s new in C# 13](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13) · [What’s new in C# 12](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-12) · [Pattern matching: patterns](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns) · [What’s new in .NET 10](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10/overview) · [File-based apps](https://learn.microsoft.com/en-us/dotnet/core/sdk/file-based-apps)

## C# Cheat Sheet at a glance

In short: A compact C# reference for C# 12 to 14 on .NET 10, covering syntax, collections, pattern matching, records, LINQ, async and file handling, run on the .NET 10 SDK.

C# Cheat Sheet: what this guide covers.

**Related guides:** [Java Cheat Sheet: Syntax, Collections, Records and Streams](https://srvscripts.com/guides/java-cheat-sheet/) · [PowerShell Cheat Sheet for Windows Server Admins](https://srvscripts.com/guides/powershell-cheat-sheet-windows-server/) · [TypeScript Cheat Sheet: Types, Generics and tsconfig](https://srvscripts.com/guides/typescript-cheat-sheet/).
