| name | dotnet-csharp-best-practices |
| description | C# coding conventions, idiomatic patterns, performance, and async best practices for both .NET 8 (C# 12) and .NET 10 (C# 14). Use when writing, reviewing, refactoring, or designing C# code — including async code that uses Task, Task<T>, ValueTask, CancellationToken, Task.WhenAll/WhenAny, Task.Run, ConfigureAwait, async void, or fire-and-forget. Trigger on `.Result`, `.Wait()`, deadlocks, cancellation propagation, ASP.NET Core background work, UI responsiveness, exception flow, and performance-sensitive async API design.
|
| metadata | {"category":"technique","platform":".NET 8 (C# 12) and .NET 10 (C# 14)","triggers":["c#","csharp",".net",".net 8",".net 10","async","task","valuetask","cancellationtoken","configureawait",".result",".wait()","async void","fire-and-forget","task.run","whenall","whenany","asp.net core","deadlock"]} |
C# Best Practices — .NET 8 + .NET 10
Target: .NET 8 (C# 12) and .NET 10 (C# 14), nullable enabled. GrECo has no .NET 9 projects.
Step 0 — Detect the target framework
Before emitting code, follow ../../references/detect-target-framework.md. The detection result decides which examples below apply:
net8.0 → emit the .NET 8 / C# 12 code block in every side-by-side pair; never use the C# 14-only syntax (field, extension(...), ?. assignment, partial constructors) or .NET 10-only APIs (HybridCache, AddValidation, EF Core named filters, first-party Microsoft.AspNetCore.OpenApi, Identity passkeys).
net10.0 → prefer the .NET 10 / C# 14 code block.
- Multi-target (
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>) → emit the .NET 8 version, or wrap .NET 10-only code in #if NET10_0_OR_GREATER.
- Unknown → ask the user.
Sources: MS C# Conventions · .NET Runtime Style · C# language versioning · C# 14 What's New · C# 12 What's New
Naming
| Element | Style | Example |
|---|
| Type, method, property, const, enum member | PascalCase | PacketHandler, MaxRetries, GameMode.Survival |
| Interface | I + PascalCase | IChatBot |
| Private instance field | _camelCase | _handler |
| Private static field | s_camelCase | s_defaultTimeout |
| Thread-static field | t_camelCase | t_cachedBuffer |
| Local, parameter | camelCase | packetId |
| Type parameter | T + PascalCase | TResult |
| Namespace | PascalCase | SomeNamespace.SomeClasses |
| Async methods | Suffix Async | ConnectAsync(), ReadPacketAsync() |
private readonly Dictionary<int, Entity> _entities = new();
private static readonly TimeSpan s_reconnectDelay = TimeSpan.FromSeconds(5);
public int PacketCount { get; private set; }
public async Task<bool> ConnectAsync(CancellationToken ct) { }
private Dictionary<int, Entity> entities = new();
private static TimeSpan reconnectDelay;
public int packet_count { get; set; }
public async Task<bool> Connect(CancellationToken ct) { }
C# 14 Features (.NET 10 only — with .NET 8 / C# 12 fallbacks)
Every feature in this section requires <TargetFramework>net10.0</TargetFramework>. On net8.0 use the fallback shown alongside. Authoritative reference: C# 14 what's new.
Extension Members
Declare extension methods, properties, and operators inside extension(...) blocks.
public static class EntityExtensions
{
extension(Entity entity)
{
public bool IsAlive => entity.Health > 0;
public void Heal(int amount) => entity.Health = Math.Min(entity.Health + amount, 20);
}
extension<T>(IEnumerable<T> items)
{
public bool IsEmpty => !items.GetEnumerator().MoveNext();
}
}
public static class EntityExtensions
{
public static bool IsAlive(this Entity entity) => entity.Health > 0;
public static void Heal(this Entity entity, int amount)
=> entity.Health = Math.Min(entity.Health + amount, 20);
public static bool IsEmpty<T>(this IEnumerable<T> items)
=> !items.GetEnumerator().MoveNext();
}
field Keyword in Properties
Access the auto-generated backing field without declaring it.
public string DisplayName => field ??= ComputeDisplayName();
public bool IsConnected
{
get;
set
{
if (field == value) return;
field = value;
OnPropertyChanged();
}
}
private string? _displayName;
public string DisplayName => _displayName ??= ComputeDisplayName();
private bool _isConnected;
public bool IsConnected
{
get => _isConnected;
set
{
if (_isConnected == value) return;
_isConnected = value;
OnPropertyChanged();
}
}
Null-Conditional Assignment
player?.Health = 20;
connection?.OnDisconnect += HandleDisconnect;
inventory?[slot] = newItem;
if (player is not null) player.Health = 20;
if (connection is not null) connection.OnDisconnect += HandleDisconnect;
if (inventory is not null) inventory[slot] = newItem;
Simple Lambda Parameters with Modifiers
TryParse<int> parse = (text, out result) => int.TryParse(text, out result);
ProcessSpan((scoped span) => span.Length);
TryParse<int> parse = (string text, out int result) => int.TryParse(text, out result);
ProcessSpan((scoped ReadOnlySpan<int> span) => span.Length);
First-Class Span Types
int[] data = [1, 2, 3];
bool found = data.StartsWith(1);
ReadOnlySpan<byte> span = stackalloc byte[4];
int[] data = [1, 2, 3];
bool found = data.AsSpan().StartsWith(stackalloc int[] { 1 });
ReadOnlySpan<byte> span = stackalloc byte[4];
Unbound Generics in nameof
string name = nameof(Dictionary<,>);
string prop = nameof(List<>.Count);
string name = nameof(Dictionary<object, object>);
string prop = nameof(List<int>.Count);
Partial Events and Constructors
partial class ServerConnection
{
partial ServerConnection(string host, int port);
}
partial class ServerConnection
{
partial ServerConnection(string host, int port) { }
}
partial class ServerConnection
{
public ServerConnection(string host, int port) => InitGenerated(host, port);
private partial void InitGenerated(string host, int port);
}
partial class ServerConnection
{
private partial void InitGenerated(string host, int port) { }
}
#: Ignored Directives / file-based programs
C# 14 / .NET 10 SDK only — no .NET 8 equivalent. dotnet run app.cs requires the .NET 10 SDK.
#!/usr/bin/dotnet run
#:package System.CommandLine@2.0.0-*
Console.WriteLine("Hello");
C# 13 Features — require .NET 9+ (NOT available on .NET 8)
GrECo has no .NET 9 projects, so the only way to use C# 13 features in production is to be on .NET 10. On .NET 8, use the .NET 8 fallback shown below.
Lock Object
private readonly Lock _gate = new();
public void Enqueue(ChatMessage msg) { lock (_gate) _queue.Add(msg); }
private readonly object _gate = new();
public void Enqueue(ChatMessage msg) { lock (_gate) _queue.Add(msg); }
params Collections (params ReadOnlySpan<T>)
The runtime overloads accepting params ReadOnlySpan<T> ship in the .NET 9 BCL. On .NET 8 use params T[].
public void Log(params ReadOnlySpan<string> messages)
{
foreach (var msg in messages) Console.WriteLine(msg);
}
public void Log(params string[] messages)
{
foreach (var msg in messages) Console.WriteLine(msg);
}
Partial Properties
partial class Config
{
public partial string Host { get; set; }
}
partial class Config
{
public partial string Host { get => _host; set => _host = value; }
private string _host = "";
}
partial class Config
{
public string Host { get; set; } = "";
}
C# 12 Features (.NET 8+ — available on both targets)
Primary Constructors
Use for simple parameter capture. Parameters are camelCase, mutable — assign to readonly fields when immutability matters.
public class ChatLogger(string logFilePath, bool appendMode) : ChatBot
{
private readonly StreamWriter _writer = new(logFilePath, appendMode);
public override void GetText(string text) => _writer.WriteLine(text);
}
public class ChatLogger : ChatBot
{
private readonly StreamWriter _writer;
public ChatLogger(string logFilePath, bool appendMode)
{
_writer = new StreamWriter(logFilePath, appendMode);
}
public override void GetText(string text) => _writer.WriteLine(text);
}
Collection Expressions
Use [...] and .. spread for arrays, lists, spans.
int[] ids = [1, 2, 3];
List<string> names = ["Steve", "Alex"];
ReadOnlySpan<byte> header = [0xFE, 0x01];
int[] combined = [..firstArray, ..secondArray, 42];
IReadOnlyList<string> empty = [];
int[] ids = new int[] { 1, 2, 3 };
var names = new List<string> { "Steve", "Alex" };
ReadOnlySpan<byte> header = new byte[] { 0xFE, 0x01 };
var combined = firstArray.Concat(secondArray).Append(42).ToArray();
Type Aliases
using Coordinate = (int X, int Y, int Z);
using PacketMap = System.Collections.Generic.Dictionary<int, System.Action<byte[]>>;
Default Lambda Parameters
var greet = (string name, string prefix = "Player") => $"{prefix} {name}";
Modern Syntax (C# 10–14)
File-Scoped Namespaces
namespace SomeNamespace.SomeClasses;
public class SomeClass : SomeInterface { }
namespace SomeNamespace.SomeClasses
{
public class SomeClass : SomeInterface { }
}
Target-Typed new
Use when the type is obvious from the left-hand side.
private readonly Dictionary<string, int> _scores = new();
List<Entity> entities = new(capacity: 256);
private readonly Dictionary<string, int> _scores = new Dictionary<string, int>();
Pattern Matching
Prefer patterns over type-casting chains and complex boolean logic.
if (entity is Player { Health: > 0 } player)
SendMessage($"{player.Name} is alive");
if (entity is Player)
{
var player = (Player)entity;
if (player.Health > 0)
SendMessage($"{player.Name} is alive");
}
public string GetStatusLabel(GameMode mode) => mode switch
{
GameMode.Survival => "Survival",
GameMode.Creative => "Creative",
GameMode.Adventure => "Adventure",
GameMode.Spectator => "Spectator",
_ => throw new ArgumentOutOfRangeException(nameof(mode))
};
public string GetStatusLabel(GameMode mode)
{
switch (mode)
{
case GameMode.Survival: return "Survival";
case GameMode.Creative: return "Creative";
default: throw new ArgumentOutOfRangeException(nameof(mode));
}
}
if (response is { StatusCode: >= 200 and < 300, Content.Length: > 0 })
ProcessResponse(response);
if (response != null && response.StatusCode >= 200
&& response.StatusCode < 300 && response.Content != null
&& response.Content.Length > 0)
ProcessResponse(response);
if (health is > 0 and <= 6) LogToConsole("Low health!");
if (args is [var command, var target, ..]) ProcessCommand(command, target);
Raw String Literals
Use for JSON, regex, multi-line strings.
string json = """
{ "username": "Steve", "action": "connect" }
""";
string pattern = """<\w+>""";
string json = "{ \"username\": \"Steve\", \"action\": \"connect\" }";
Records
Use record for immutable data carriers and DTOs. Use record struct for small value types.
public record PlayerInfo(string Name, Guid Uuid, GameMode Mode);
public record struct ChunkCoord(int X, int Z);
var updated = info with { Mode = GameMode.Creative };
public class PlayerInfo
{
public string Name { get; set; } = string.Empty;
public Guid Uuid { get; set; }
public GameMode Mode { get; set; }
}
public record OrderItem(string ProductId, int Quantity, decimal UnitPrice)
{
public OrderItem
{
ArgumentException.ThrowIfNullOrWhiteSpace(ProductId);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(Quantity);
ArgumentOutOfRangeException.ThrowIfNegative(UnitPrice);
}
}
Required Members
public class ServerConfig
{
public required string Host { get; init; }
public required int Port { get; init; }
public string? Password { get; init; }
}
var config = new ServerConfig { Host = "mc.example.com", Port = 25565 };
Nullable Reference Types
Project has nullable enabled. Follow these rules:
public void Connect(string host, IProtocolHandler handler)
{
ArgumentNullException.ThrowIfNull(handler);
ArgumentException.ThrowIfNullOrEmpty(host);
}
if (handler == null) throw new ArgumentNullException(nameof(handler));
if (string.IsNullOrWhiteSpace(host))
throw new ArgumentException("Host is required", nameof(host));
if (currentPlayer is not null)
currentPlayer.Update();
if (currentPlayer != null)
currentPlayer.Update();
public Entity? FindEntity(int id)
{
return _entities.TryGetValue(id, out var entity) ? entity : null;
}
string name = player?.CustomName ?? player?.Name ?? "Unknown";
string val = GetRequiredValue()!;
[return: MaybeNull]
public T Find<T>(Predicate<T> match) { }
[MemberNotNull(nameof(_connection))]
private void EnsureConnected() { }
public string GetName(Player? player)
{
return player!.Name;
}
Async / Await
1. correctness and cancellation semantics
2. context-specific API design (library vs app, UI vs ASP.NET Core)
3. concurrency behavior and failure handling
4. performance tuning only when the hot path is real
Treat blanket advice as suspect. Separate official runtime behavior from expert interpretation and from your own recommendation for the case at hand.
Review defaults
Start from these defaults unless case-specific evidence says otherwise:
| Topic | Default judgment |
|---|
Blocking on async (.Result, .Wait, GetAwaiter().GetResult()) | usually a defect or interop boundary smell |
async void | only acceptable for event handlers |
ValueTask | avoid by default; justify with measurements or a very hot path |
ConfigureAwait(false) | good library default, not an app-wide default |
Task.Run | use to offload CPU work when needed, not to fake async I/O |
| Fire-and-forget | assume unsafe until lifecycle, scope, and exception handling are explicit |
Task.WhenAll | prefer for independent concurrent operations |
Task.WhenAny | always inspect the winner task and define what happens to losers |
| Cancellation | accept and propagate the token until the point of no cancellation |
| Method naming | Async suffix for awaitable-returning methods (unless an interface/event contract dictates otherwise) |
Concrete patterns
public async Task<string> FetchDataAsync(Uri uri, CancellationToken ct = default)
{
using var response = await _httpClient.GetAsync(uri, ct);
return await response.Content.ReadAsStringAsync(ct);
}
public async Task<string> FetchDataAsync(Uri uri)
{
using var response = await _httpClient.GetAsync(uri, default);
return await response.Content.ReadAsStringAsync(default);
}
public ValueTask<int> GetCachedCountAsync()
{
if (_cache.TryGetValue("count", out int count))
return ValueTask.FromResult(count);
return new ValueTask<int>(LoadCountFromDbAsync());
}
public async Task<int> GetCachedCountAsync()
{
if (_cache.TryGetValue("count", out int count))
return count;
return await LoadCountFromDbAsync();
}
public async Task HandleEventAsync(GameEvent e, CancellationToken ct)
=> await notificationService.SendAsync(e.PlayerId, ct);
public async void HandleEvent(GameEvent e)
=> await notificationService.SendAsync(e.PlayerId, default);
var packet = await reader.ReadPacketAsync(ct);
var packet = reader.ReadPacketAsync(ct).Result;
var packet2 = reader.ReadPacketAsync(ct).GetAwaiter().GetResult();
var data = await stream.ReadAsync(buffer, ct).ConfigureAwait(false);
var userTask = repo.GetUserAsync(id, ct);
var ordersTask = repo.GetOrdersAsync(id, ct);
await Task.WhenAll(userTask, ordersTask);
return new Dashboard(await userTask, await ordersTask);
public async IAsyncEnumerable<ChatMessage> ReadChatStreamAsync(
[EnumeratorCancellation] CancellationToken ct = default)
{
while (!ct.IsCancellationRequested)
yield return await _reader.ReadNextAsync(ct);
}
await using var conn = new McConnection(host, port);
Common traps
- Calling
.Result, .Wait(), or GetAwaiter().GetResult() inside normal async-capable code
- Recommending
ConfigureAwait(false) everywhere because "it is .NET Core" or "it prevents deadlocks"
- Recommending
Task.Run inside ASP.NET Core request code just to make code "more async" — request code already runs on the thread pool
- Recommending
ValueTask for every hot-looking method without checking completion behavior, call frequency, or single-consumer assumptions
- Ignoring cancellation after plumbing a
CancellationToken (accepting it but never checking or propagating)
- Using
Task.WhenAny without awaiting the returned winner task or handling the remaining tasks
- Treating fire-and-forget as harmless when it touches scoped services,
HttpContext, or unobserved failures
- Awaiting the same
ValueTask twice, or mixing AsTask() with await on the same instance
Rationalization traps
| Rationalization | Better reasoning |
|---|
"It works, so .Result is fine." | Lack of failure under one context does not make blocking safe or scalable. |
"ValueTask is always faster." | It trades simplicity for niche allocation wins and stricter consumption rules. |
"ConfigureAwait(false) everywhere is modern guidance." | Library and app code have different constraints. Blanket rules are weak. |
"Task.Run makes server code asynchronous." | It only queues work; it does not turn blocking I/O into true async I/O. |
| "Fire-and-forget is okay because logging exists." | Logging does not solve scope lifetime, shutdown, retries, or error propagation. |
Hard boundaries
- Do not endorse sync-over-async as a normal design choice
- Do not suggest
async void except for event handlers
- Do not suggest
ValueTask unless single-consumer / hot-path / measurement constraints are met
- Do not claim
ConfigureAwait(false) is always needed or always unnecessary
- Do not approve fire-and-forget unless ownership, exception handling, and lifetime are explicit
Output contract for review and design
When you review or design async code, label your reasoning:
- Fact — official runtime or API behavior
- Expert guidance — interpretation from strong experts (Stephen Toub, Stephen Cleary, Andrew Arnott) when it adds design meaning
- Synthesis — your recommendation for this exact case
Do not present contextual advice as a universal law.
References for deep async work
Load on demand:
LINQ
Prefer Method Syntax for Most Operations
var onlinePlayers = players
.Where(p => p.IsOnline)
.OrderBy(p => p.Name)
.Select(p => new PlayerListItem(p.Id, p.Name))
.ToList();
var onlinePlayers = (
from p in players
where p.IsOnline
orderby p.Name
select new PlayerListItem(p.Id, p.Name)
).ToList();
Use Query Syntax for Joins
var results =
from entity in entities
join player in players on entity.OwnerId equals player.Id
where entity.Health > 0
select new { entity.Name, player.Name };
var results = entities
.Join(players,
e => e.OwnerId,
p => p.Id,
(e, p) => new { e, p })
.Where(x => x.e.Health > 0)
.Select(x => new { x.e.Name, PlayerName = x.p.Name });
Materialize to Avoid Multiple Enumeration
var online = players.Where(p => p.IsOnline).ToList();
Console.WriteLine(online.Count);
foreach (var p in online) { }
var filtered = players.Where(p => p.IsOnline);
Console.WriteLine(filtered.Count());
foreach (var p in filtered) { }
Use Any() Over Count() > 0
if (entities.Any(e => e.IsHostile))
TriggerAlert();
if (entities.Count(e => e.IsHostile) > 0)
TriggerAlert();
Prefer FirstOrDefault with Null Handling
var target = players.FirstOrDefault(p => p.Name == name)
?? throw new InvalidOperationException($"Player '{name}' not found");
TryGetNonEnumeratedCount
if (source.TryGetNonEnumeratedCount(out int count))
buffer = new Entity[count];
Avoid LINQ in Hot Paths
Span<byte> data = stackalloc byte[256];
int found = 0;
for (int i = 0; i < data.Length; i++)
if (data[i] == target) found++;
int found = data.ToArray().Count(b => b == target);
Performance (.NET 8+ — works on both targets)
All APIs below ship in .NET 8 and continued unchanged in .NET 10. For benchmarks and rationale see Stephen Toub's deep dives:
Performance Improvements in .NET 8 ·
Performance Improvements in .NET 10 (covers JIT array-interface devirtualisation that speeds up many LINQ paths in .NET 10).
Span<T> / Memory<T>
ReadOnlySpan<char> command = input.AsSpan()[1..];
public static int ParseVarInt(ReadOnlySpan<byte> data, out int bytesRead)
{
int result = 0; bytesRead = 0; byte cur;
do { cur = data[bytesRead]; result |= (cur & 0x7F) << (bytesRead * 7); bytesRead++; }
while ((cur & 0x80) != 0);
return result;
}
FrozenDictionary / FrozenSet (.NET 8)
Build once, read many — ~50% faster lookups than Dictionary.
using System.Collections.Frozen;
private static readonly FrozenDictionary<int, string> s_blockNames =
new Dictionary<int, string> { [0] = "air", [1] = "stone" }.ToFrozenDictionary();
SearchValues<T> (.NET 8)
Hardware-accelerated set search.
private static readonly SearchValues<char> s_separators = SearchValues.Create(" \t\n\r,;");
int idx = input.AsSpan().IndexOfAny(s_separators);
CompositeFormat (.NET 8)
Parse format string once, reuse.
private static readonly CompositeFormat s_logFmt = CompositeFormat.Parse("[{0:HH:mm:ss}] {1}: {2}");
string msg = string.Format(CultureInfo.InvariantCulture, s_logFmt, DateTime.Now, player, text);
ArrayPool / stackalloc
byte[] buf = ArrayPool<byte>.Shared.Rent(4096);
try { int n = stream.Read(buf.AsSpan(0, 4096)); ProcessPacket(buf.AsSpan(0, n)); }
finally { ArrayPool<byte>.Shared.Return(buf); }
Span<byte> header = stackalloc byte[5];
String Handling
bool match = name.Equals("Steve", StringComparison.OrdinalIgnoreCase);
int idx = text.IndexOf("hello", StringComparison.Ordinal);
bool match = name.ToLower() == "steve";
string hex = string.Create(data.Length * 2, data, static (span, bytes) =>
{
for (int i = 0; i < bytes.Length; i++)
bytes[i].TryFormat(span[(i * 2)..], out _, "X2");
});
var sb = new StringBuilder(256);
foreach (var item in inventory)
sb.Append(item.Name).Append(" x").Append(item.Count).AppendLine();
string combined = "";
foreach (var s in items) combined += s + ", ";
Collections — Choosing the Right Type
| Scenario | Type | Notes |
|---|
| General key-value | Dictionary<K,V> | O(1) lookup |
| Build once, read many | FrozenDictionary<K,V> | .NET 8+; faster reads |
| Thread-safe | ConcurrentDictionary<K,V> | Lock-free reads |
| Immutable snapshots | ImmutableDictionary<K,V> | Persistent structure |
| Membership test | HashSet<T> / FrozenSet<T> | FrozenSet for static |
| Priority queue | PriorityQueue<E,P> | .NET 6+ |
| Synchronization | System.Threading.Lock / lock(object) | Lock is .NET 9+ only — on .NET 8 use private readonly object _gate = new(); |
| Producer-consumer | Channel<T> | Over BlockingCollection<T> |
| Temp buffer | ArrayPool<T> / stackalloc | Zero/low alloc |
Error Handling
if (int.TryParse(input, out int value)) ProcessValue(value);
if (_registry.TryGetValue(packetId, out var handler)) handler.Invoke(data);
try { return dict[key]; }
catch (KeyNotFoundException) { return null; }
try { await ConnectAsync(ct); }
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionRefused)
{
LogToConsole("Connection refused, retrying...");
}
ArgumentNullException.ThrowIfNull(handler);
ArgumentOutOfRangeException.ThrowIfNegative(timeout);
ArgumentOutOfRangeException.ThrowIfGreaterThan(timeout, MaxTimeout);
ObjectDisposedException.ThrowIf(_disposed, this);
throw new Exception($"Entity {id} not found");
throw new EntityNotFoundException(id);
return await FindEntityAsync(id, ct)
?? throw new EntityNotFoundException(id);
try { DoWork(); }
catch (Exception) { }
Warning Suppression
public string GetDisplayName(Player? player)
{
return player?.DisplayName ?? "Unknown";
}
#pragma warning disable CS8602
public string GetDisplayName(Player? player)
{
return player.DisplayName;
}
#pragma warning restore CS8602
[SuppressMessage("Usage", "CA1062:Validate arguments of public methods")]
public void Process(Packet packet)
{
}
Project-wide .editorconfig is the only acceptable place for warning policy:
# .editorconfig - project-wide policy decisions only
dotnet_diagnostic.CA2007.severity = none
Resource Management
using var stream = new FileStream(path, FileMode.Open);
using var reader = new StreamReader(stream);
await using var conn = await CreateConnectionAsync();
public class PacketReader : IDisposable
{
private Stream? _stream;
private bool _disposed;
public void Dispose()
{
if (_disposed) return;
_stream?.Dispose(); _stream = null; _disposed = true;
}
}
Security
byte[] token = RandomNumberGenerator.GetBytes(32);
bool valid = CryptographicOperations.FixedTimeEquals(expected, actual);
if (Uri.TryCreate(userInput, UriKind.Absolute, out var uri)
&& uri.Scheme is "http" or "https")
await FetchAsync(uri);
var rng = new Random();
bool eq = secret1.SequenceEqual(secret2);
Miscellaneous Idioms
var entities = new Dictionary<int, Entity>();
var timer = Stopwatch.StartNew();
Stream responseStream = GetResponse();
int count = items.Count;
public override string ToString() => $"[{X}, {Y}, {Z}]";
public bool IsAlive => Health > 0;
_ = int.TryParse(s, out int result);
(_, int y, _) = GetCoordinates();
throw new ArgumentException("Invalid value", nameof(packetId));
LogToConsole($"{nameof(AutoEat)}: eating {item.Name}");
string typeName10 = nameof(Dictionary<,>);
string typeName8 = nameof(Dictionary<object, object>);
list.Sort(static (a, b) => a.Id.CompareTo(b.Id));
var last = items[^1];
var slice = data[3..^1];
var (x, y, z) = GetPosition();
LogToConsole($"Health: {health,6:F1} | Hunger: {hunger,6:F1}");