一键导入
csharp-idioms
Use when applying modern C# idioms — records, pattern matching, primary constructors, collection expressions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when applying modern C# idioms — records, pattern matching, primary constructors, collection expressions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when designing gRPC services, proto files, or adding gRPC-Web or JSON transcoding.
Use when writing async code, propagating CancellationTokens, or fixing async/await pitfalls.
Use when applying or enforcing C# coding style — namespaces, sealed classes, var usage, XML docs.
Use when registering services, choosing lifetimes, or implementing DI patterns like decorator or keyed services.
Use when selecting or implementing design patterns in C# — factory, builder, strategy, decorator, or mediator.
Use when implementing error handling with domain exceptions, ProblemDetails, or RpcException mapping.
| name | csharp-idioms |
| description | Use when applying modern C# idioms — records, pattern matching, primary constructors, collection expressions. |
| when_to_use | Use when applying modern C# idioms — records, pattern matching, primary constructors, collection expressions. |
| metadata | {"category":"core","agent":"dotnet-architect"} |
| 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 |