| name | csharp-standards |
| description | C# coding standards and conventions including naming, formatting, and best practices. Use when working with .cs files, writing C# code, or when the user asks about C# naming conventions, code structure, XML documentation, or .NET development patterns. |
| metadata | {"author":"devbyray","version":"1.0","language":"csharp","framework":"dotnet"} |
C# Coding Standards & Conventions
Apply these standards when writing C# code for .NET projects.
Naming Conventions
1. PascalCase
Use for classes, interfaces, enums, methods, properties, and events:
public class UserService { }
public interface IUserRepository { }
public enum OrderStatus { }
public void ProcessOrder() { }
public string FirstName { get; set; }
2. camelCase
Use for local variables, parameters, and private fields:
public void CalculateTotal(int itemCount)
{
var totalPrice = itemCount * 10;
var discount = 0.1;
}
private int _orderCount;
3. Interface Naming
Prefix interfaces with I:
public interface IRepository { }
public interface IUserService { }
public interface ILogger { }
Access Modifiers
4. Explicit Access Modifiers
Always specify access modifiers:
Good:
public class UserService
{
private readonly IUserRepository _repository;
public UserService(IUserRepository repository)
{
_repository = repository;
}
public async Task<User> GetUserAsync(int id)
{
return await _repository.FindByIdAsync(id);
}
private bool ValidateUser(User user)
{
return !string.IsNullOrEmpty(user.Email);
}
}
Bad:
class UserService
{
IUserRepository _repository;
}
Modern C# Features
5. Expression-Bodied Members
Use for simple properties and methods:
public string FullName => $"{FirstName} {LastName}";
public bool IsActive => Status == UserStatus.Active;
public int Add(int a, int b) => a + b;
public void LogError(string message) => _logger.LogError(message);
public User(string name) => Name = name;
6. Var Keyword
Use var when the type is obvious:
Good:
var user = new User();
var count = GetCount();
var items = new List<string>();
Questionable:
var result = repository.GetData();
Better:
List<User> users = repository.GetUsers();
7. Pattern Matching
Use modern pattern matching features:
if (obj is User user)
{
Console.WriteLine(user.Name);
}
var discount = orderTotal switch
{
< 100 => 0,
< 500 => 0.05,
< 1000 => 0.10,
_ => 0.15
};
var shipping = customer switch
{
{ IsPremium: true } => 0,
{ OrderCount: > 10 } => 5,
_ => 10
};
8. Null-Coalescing and Null-Conditional
var name = user?.Name ?? "Guest";
var length = user?.Address?.City?.Length;
_cache ??= new Dictionary<string, object>();
Code Structure
9. Always Use Braces
Use braces even for single statements:
Good:
if (user != null)
{
ProcessUser(user);
}
foreach (var item in items)
{
Console.WriteLine(item);
}
Bad:
if (user != null)
ProcessUser(user);
10. Avoid Magic Numbers
Use named constants or enums:
Bad:
if (status == 1)
{
}
Good:
private const int ActiveStatus = 1;
if (status == ActiveStatus)
{
}
Better:
public enum UserStatus
{
Inactive = 0,
Active = 1,
Suspended = 2
}
if (status == UserStatus.Active)
{
}
11. String Literals
Use double quotes for strings, single quotes for chars:
string message = "Hello, World!";
char delimiter = ',';
Documentation
12. XML Documentation Comments
Document public APIs, classes, and methods:
public static int Add(int a, int b)
{
return checked(a + b);
}
public class User
{
public int Id { get; set; }
public string Email { get; set; }
}
Async/Await
13. Async Method Naming
Suffix async methods with Async:
public async Task<User> GetUserAsync(int id)
{
return await _repository.FindByIdAsync(id);
}
public async Task SaveUserAsync(User user)
{
await _repository.SaveAsync(user);
}
14. Async Best Practices
public async Task ProcessOrderAsync(Order order)
{
await ValidateOrderAsync(order);
await SaveOrderAsync(order);
await SendConfirmationAsync(order);
}
public async Task<Data> FetchDataAsync()
{
var response = await _httpClient.GetAsync(url).ConfigureAwait(false);
return await response.Content.ReadAsAsync<Data>().ConfigureAwait(false);
}
Complete Example
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MyApp.Services
{
public class UserService : IUserService
{
private readonly IUserRepository _repository;
private readonly ILogger<UserService> _logger;
private const int MaxRetryAttempts = 3;
public UserService(IUserRepository repository, ILogger<UserService> logger)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task<User?> GetUserByIdAsync(int id)
{
if (id <= 0)
{
throw new ArgumentException("ID must be greater than zero.", nameof(id));
}
try
{
var user = await _repository.FindByIdAsync(id);
return user;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving user with ID {UserId}", id);
throw;
}
}
public async Task<User> CreateUserAsync(User user)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
if (!IsValidUser(user))
{
throw new ValidationException("Invalid user data.");
}
var createdUser = await _repository.AddAsync(user);
_logger.LogInformation("User created with ID {UserId}", createdUser.Id);
return createdUser;
}
private bool IsValidUser(User user)
{
return !string.IsNullOrWhiteSpace(user.Email)
&& !string.IsNullOrWhiteSpace(user.Name);
}
public string GetDisplayName(User user) =>
user?.Name ?? "Guest";
}
}
Best Practices Summary
- ✅ Use PascalCase for public members, camelCase for private
- ✅ Always use explicit access modifiers
- ✅ Prefer expression-bodied members for simple code
- ✅ Use
var when type is obvious
- ✅ Always use braces for control flow
- ✅ Document public APIs with XML comments
- ✅ Suffix async methods with
Async
- ✅ Use pattern matching and modern C# features
- ✅ Avoid magic numbers
- ✅ End every statement with a semicolon
When to Apply
Apply these standards when:
- Writing C# code
- Creating classes and interfaces
- Reviewing C# code
- Setting up new .NET projects
- User asks about C# conventions