csharp-patterns
Modern C# 13/15 patterns, LINQ mastery, async/await, records, pattern matching, .NET 10/11 features, and .NET AI integration
What this skill does
# Modern C# Patterns
## Dependency Injection Patterns
### Primary Constructors (.NET 10)
```csharp
public sealed class OrderService(
IOrderRepository repo,
IPaymentGateway payments,
ILogger<OrderService> logger) : IOrderService
{
public async Task<OrderResult> ProcessAsync(CreateOrderCommand cmd, CancellationToken ct)
{
logger.LogInformation("Processing order for customer {CustomerId}", cmd.CustomerId);
var order = await repo.CreateAsync(cmd, ct);
var payment = await payments.ChargeAsync(order.Total, ct);
return new OrderResult(order.Id, payment.TransactionId);
}
}
```
### Options Pattern
```csharp
public sealed class EmailOptions
{
public const string SectionName = "Email";
public required string SmtpHost { get; init; }
public required int SmtpPort { get; init; }
public required string FromAddress { get; init; }
}
// Registration
builder.Services.Configure<EmailOptions>(builder.Configuration.GetSection(EmailOptions.SectionName));
// Usage
public sealed class EmailService(IOptions<EmailOptions> options)
{
private readonly EmailOptions _config = options.Value;
}
```
## Result Pattern (instead of exceptions for expected failures)
```csharp
public abstract record Result<T>
{
public sealed record Success(T Value) : Result<T>;
public sealed record Failure(string Error) : Result<T>;
public TOut Match<TOut>(Func<T, TOut> onSuccess, Func<string, TOut> onFailure) =>
this switch
{
Success s => onSuccess(s.Value),
Failure f => onFailure(f.Error),
_ => throw new InvalidOperationException()
};
}
// Usage
public async Task<Result<OrderDto>> CreateOrderAsync(CreateOrderCommand cmd)
{
if (await _repo.ExistsAsync(cmd.Sku))
return new Result<OrderDto>.Failure("Duplicate SKU");
var order = await _repo.CreateAsync(cmd);
return new Result<OrderDto>.Success(order.ToDto());
}
```
## Repository Pattern with Specification
```csharp
public interface IRepository<T> where T : class
{
Task<T?> GetByIdAsync(int id, CancellationToken ct = default);
Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec, CancellationToken ct = default);
Task<T> AddAsync(T entity, CancellationToken ct = default);
Task UpdateAsync(T entity, CancellationToken ct = default);
Task DeleteAsync(T entity, CancellationToken ct = default);
}
public interface ISpecification<T>
{
Expression<Func<T, bool>>? Criteria { get; }
List<Expression<Func<T, object>>> Includes { get; }
Expression<Func<T, object>>? OrderBy { get; }
int? Take { get; }
int? Skip { get; }
}
```
## Guard Clauses
```csharp
public static class Guard
{
public static T NotNull<T>(T? value, [CallerArgumentExpression(nameof(value))] string? name = null)
where T : class =>
value ?? throw new ArgumentNullException(name);
public static string NotEmpty(string? value, [CallerArgumentExpression(nameof(value))] string? name = null) =>
string.IsNullOrWhiteSpace(value)
? throw new ArgumentException("Cannot be empty", name)
: value;
}
```
## Extension Methods
```csharp
public static class EnumerableExtensions
{
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int size)
{
var batch = new List<T>(size);
foreach (var item in source)
{
batch.Add(item);
if (batch.Count == size)
{
yield return batch;
batch = new List<T>(size);
}
}
if (batch.Count > 0) yield return batch;
}
}
```
## Async Patterns
```csharp
// Parallel execution
var (users, products) = await (GetUsersAsync(ct), GetProductsAsync(ct));
// Async streams
await foreach (var item in GetItemsAsync(ct))
{
await ProcessAsync(item, ct);
}
// Channel for producer/consumer
var channel = Channel.CreateBounded<WorkItem>(100);
// Producer
await channel.Writer.WriteAsync(new WorkItem(...), ct);
// Consumer
await foreach (var item in channel.Reader.ReadAllAsync(ct))
{
await HandleAsync(item, ct);
}
```
## C# 15 New Features
### Extension Members (Extension Everything)
```csharp
// Extension properties, methods, and static members
public static extension StringExtensions for string
{
public bool IsNullOrEmpty => string.IsNullOrEmpty(this);
public string Reversed => new(this.Reverse().ToArray());
}
// Usage: "hello".Reversed → "olleh"
```
### Field-Backed Properties
```csharp
public class Person
{
// 'field' keyword accesses the auto-generated backing field
public string Name
{
get => field;
set => field = value?.Trim() ?? throw new ArgumentNullException(nameof(value));
}
}
```
### Null-Conditional Assignment
```csharp
// Only assigns if left side is not null
object?.Property = value;
list?.Add(item);
```
## .NET 10 Key Features
- **AOT improvements**: Faster startup, smaller binaries for cloud-native
- **Blazor Web App enhancements**: Improved render mode handling, streaming SSR
- **Minimal API improvements**: Better parameter binding, endpoint filters
- **EF Core improvements**: Bulk operations, compiled models
- **Aspire GA**: Production-ready orchestration
- **.NET AI libraries**: Microsoft.Extensions.AI for unified AI integration
## .NET AI Integration
```csharp
// Microsoft.Extensions.AI - unified AI abstraction
using Microsoft.Extensions.AI;
// Register AI chat client (works with OpenAI, Azure OpenAI, Ollama, etc.)
builder.Services.AddChatClient(new AzureOpenAIClient(
new Uri(builder.Configuration["AI:Endpoint"]!),
new DefaultAzureCredential())
.GetChatClient("gpt-4o"));
// Use in services
public sealed class SmartSearchService(IChatClient chatClient)
{
public async Task<string> SummarizeAsync(string content, CancellationToken ct)
{
var response = await chatClient.GetResponseAsync(
$"Summarize this: {content}", cancellationToken: ct);
return response.Text;
}
}
```
```csharp
// Semantic Kernel for AI orchestration
using Microsoft.SemanticKernel;
var kernel = Kernel.CreateBuilder()
.AddAzureOpenAIChatCompletion("gpt-4o", endpoint, credential)
.Build();
var result = await kernel.InvokePromptAsync(
"Analyze this order data: {{$input}}", new() { ["input"] = orderJson });
```
## Reference
- C# 15 what's new: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-15
- .NET 10 overview: https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10/overview
- .NET what's new: https://learn.microsoft.com/en-us/dotnet/whats-new/
- .NET AI: https://learn.microsoft.com/en-us/dotnet/ai/
- Semantic Kernel: https://learn.microsoft.com/en-us/semantic-kernel/
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.