Modern C# idioms and language features. File-scoped namespaces, records, pattern matching, primary constructors, collection expressions. Trigger: C# style, modern syntax, idioms, language features.
From dotnet-ai-kitnpx claudepluginhub faysilalshareef/dotnet-ai-kit --plugin dotnet-ai-kitThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides idea refinement into designs: explores context, asks questions one-by-one, proposes approaches, presents sections for approval, writes/review specs before coding.
| Feature | Minimum | C# Version |
|---|---|---|
| File-scoped namespaces | .NET 6 | C# 10 |
required modifier | .NET 7 | C# 11 |
| Primary constructors | .NET 8 | C# 12 |
| Collection expressions | .NET 8 | C# 12 |
field keyword | .NET 10 | C# 14 |
| Extension types | .NET 10 | C# 14 |
// PREFER — file-scoped (one less indent level)
namespace {Company}.{Domain}.Features.Orders;
public sealed class OrderService { }
// Immutable DTO
public sealed record OrderResponse(Guid Id, string CustomerName, decimal Total);
// Value object with behavior
public sealed record Money(decimal Amount, string Currency)
{
public Money Add(Money other)
{
if (Currency != other.Currency)
throw new InvalidOperationException("Cannot add different currencies");
return this with { Amount = Amount + other.Amount };
}
}
// Record struct for lightweight value types
public readonly record struct OrderId(Guid Value)
{
public static OrderId New() => new(Guid.NewGuid());
}
// Service with DI — no field declarations needed
public sealed class OrderService(
IOrderRepository repository,
ILogger<OrderService> logger)
{
public async Task<Order?> GetAsync(Guid id, CancellationToken ct)
{
logger.LogInformation("Fetching order {OrderId}", id);
return await repository.FindAsync(id, ct);
}
}
int[] numbers = [1, 2, 3];
List<string> merged = [..existing, ..additional, "extra"];
ReadOnlySpan<byte> bytes = [0x01, 0x02, 0x03];
// Empty collection
List<Order> orders = [];
// Switch expression
string label = order.State switch
{
OrderState.Pending when order.Total > 1000 => "Requires approval",
OrderState.Pending => "Awaiting processing",
OrderState.Shipped => "In transit",
OrderState.Delivered => "Complete",
_ => "Unknown"
};
// Property pattern
if (order is { Status: OrderStatus.Shipped, Total: > 500 })
ApplyDiscount(order);
// List pattern (C# 12)
var result = args switch
{
[var cmd, ..var rest] => ProcessCommand(cmd, rest),
[] => ShowHelp()
};
// is null / is not null (prefer over == null)
if (order is not null)
Process(order);
// Seal classes not designed for inheritance
public sealed class OrderValidator
{
// Expression body for single-line methods
public bool IsValid(Order order) => order.Items.Count > 0 && order.Total > 0;
// Expression body for properties
public string Name => nameof(OrderValidator);
}
namespace {Company}.{Domain}.Features.Orders;
public sealed class OrderService
{
// PascalCase: types, methods, properties, constants
private const string DefaultCurrency = "USD";
// _camelCase: private fields
private readonly IOrderRepository _repository;
// camelCase: parameters and locals
public async Task<OrderResponse?> GetOrderAsync(Guid orderId)
{
var order = await _repository.FindAsync(orderId);
return order is null ? null : MapToResponse(order);
}
// Async suffix on async methods
private static OrderResponse MapToResponse(Order order) => new(
Id: order.Id,
CustomerName: order.CustomerName,
Total: order.Total);
}
// Auto-property with validation — no backing field declaration
public string Name
{
get => field;
set => field = value?.Trim() ?? throw new ArgumentNullException(nameof(value));
}
== null instead of is null<LangVersion> in .csproj or Directory.Build.props<TargetFramework> for net8.0, net9.0, net10.0.cs files for primary constructor usagerecord keyword usage in model/DTO files.editorconfig for naming and style rules_camelCase vs camelCase).editorconfig if missing to enforce style rules:[*.cs]
csharp_style_namespace_declarations = file_scoped:warning
csharp_style_var_for_built_in_types = false:suggestion
csharp_style_prefer_pattern_matching = true:suggestion
dotnet_naming_rule.private_fields_should_be_camel_case.severity = warning
| Scenario | Recommendation |
|---|---|
| New DTO / response type | Use record |
| Service class with DI | Use primary constructor (.NET 8+) |
| Multiple type checks | Use switch expression with patterns |
| Null check | Use is null / is not null |
| New file | Use file-scoped namespace |
| Lightweight ID type | Use readonly record struct |