C# Code Standards
Introduction
This document describes the coding standards for C# code in the City Skylines project.
Naming Conventions
General Naming Conventions
- Pascal Case: Use Pascal case for all public member, type, and namespace names consisting of multiple words. Pascal case is identical to camel case, but the first letter of the identifier is capitalized. For example,
BackColor
. - Camel Case: Use camel case for parameter names and local variables. Camel case is identical to Pascal case, but the first letter of the identifier is lowercase. For example,
backColor
. - Abbreviations: Do not use abbreviations in identifiers. For example, use
GetWindow
instead ofGetWin
. - Acronyms: Acronyms should be treated as words in identifiers. For example, use
XmlHttpRequest
instead ofXMLHTTPRequest
. - Underscores: Do not use underscores in identifiers. For example, use
backColor
instead ofback_Color
.
Namespace Naming Conventions
- Namespace Naming: Use a single, top-level namespace for the project. The namespace should be the name of the project. For example, the namespace for the City Skylines project is
CitySkylines
.
Type Naming Conventions
- Class Naming: Use nouns or noun phrases to name classes. Class names should be clear and descriptive. For example, use
Customer
instead ofData
. - Interface Naming: Use a noun or noun phrase to name interfaces. Interface names should be clear and descriptive. For example, use
ILogger
instead ofILog
. - Enum Naming: Use a singular noun for enum types. Enum names should be clear and descriptive. For example, use
DayOfWeek
instead ofDays
.
Member Naming Conventions
- Property Naming: Use nouns or noun phrases to name properties. Property names should be clear and descriptive. For example, use
FirstName
instead ofName
. - Method Naming: Use verbs or verb phrases to name methods. Method names should be clear and descriptive. For example, use
CalculateTotal
instead ofCalculate
. - Event Naming: Use a verb or verb phrase to name events. Event names should be clear and descriptive. For example, use
Click
instead ofOnClick
.
Parameter Naming Conventions
- Parameter Naming: Use camel case for parameter names. Parameter names should be clear and descriptive. For example, use
customerName
instead ofname
.
Bracing
-
Brace Placement: Place the opening brace on the same line as the statement it belongs to. Place the closing brace on a new line by itself. For example:
if (condition)
{
// Code here
}
Indentation
- Indentation: Use four spaces for indentation. Do not use tabs for indentation.
Comments
- Comments: Use comments to explain the intent of the code. Comments should be clear and concise. Use comments to explain complex algorithms, business rules, or design decisions. Comments should be written in English.
// Calculate the total price of the items in the cart
public decimal CalculateTotal() {
decimal total = 0;
foreach (var item in cartItems) {
total += item.Price;
}
return total;
}
Documentation Comments
- Documentation Comments: Use XML documentation comments to document types and members. Documentation comments should describe the purpose of the type or member, its parameters, return value, and exceptions that can be thrown. Documentation comments should be written in English.
/// <summary>
/// Represents a customer in the system.
/// </summary>
public class Customer {
/// <summary>
/// Gets or sets the customer's first name.
/// </summary>
public string FirstName { get; set; }
/// <summary>
/// Gets or sets the customer's last name.
/// </summary>
public string LastName { get; set; }
/// <summary>
/// Gets the customer's full name.
/// </summary>
public string FullName {
get {
return $"{FirstName} {LastName}";
}
}
}
Error Handling
- Error Handling: Use exceptions to handle errors and unexpected conditions. Do not use exceptions for normal control flow. Use specific exception types to indicate the type of error that occurred. Catch exceptions at the appropriate level and handle them appropriately.
try {
// Code that may throw an exception
} catch (Exception ex) {
// Handle the exception
}
throw new InvalidOperationException("Invalid operation");
- Exception Handling: Use specific exception types to indicate the type of error that occurred. Use
try-catch
blocks to handle exceptions. Usethrow
statements to rethrow exceptions.
try {
// Code that may throw an exception
} catch (ArgumentNullException ex) {
// Handle ArgumentNullException
} catch (InvalidOperationException ex) {
// Handle InvalidOperationException
} catch (Exception ex) {
// Handle other exceptions
throw;
}
- Custom Exceptions: Use custom exception types to represent specific errors in the application. Create custom exception classes that inherit from the
Exception
class.
public class CustomException : Exception {
public CustomException(string message) : base(message) {
}
}
- Logging Exceptions: Use a logging framework to log exceptions. Log exceptions at the appropriate level and include relevant information such as the exception message, stack trace, and inner exceptions.
try {
// Code that may throw an exception
} catch (Exception ex) {
logger.Error(ex, "An error occurred");
}
Variables
- Variable Declaration: Declare variables close to where they are used. Use meaningful variable names that describe the purpose of the variable. Use the
var
keyword for local variables when the type is obvious from the initialization expression.
var firstName = "John";
var lastName = "Doe";
Constants
- Constants: Use
const
for values that do not change. Usereadonly
for values that are initialized at runtime. Use uppercase letters and underscores for constant names.
public const int MaxItems = 10;
public readonly string ConnectionString = "Server=localhost;Database=Northwind;User=sa;Password=pass";
Properties
- Auto-Implemented Properties: Use auto-implemented properties for simple properties that do not require additional logic in the getter or setter.
public string FirstName { get; set; }
- Full Properties: Use full properties for properties that require additional logic in the getter or setter.
private string firstName;
public string FirstName {
get {
return firstName;
}
set {
firstName = value;
}
}
Loops
- For Loop: Use a
for
loop when the number of iterations is known. Use afor
loop to iterate over a range of values.
for (int i = 0; i < 10; i++) {
// Code here
}
- Foreach Loop: Use a
foreach
loop to iterate over a collection. Use aforeach
loop when the number of iterations is not known.
foreach (var item in items) {
// Code here
}
- While Loop: Use a
while
loop when the number of iterations is not known. Use awhile
loop to iterate until a condition is met.
while (condition) {
// Code here
}
Switch Statements
- Switch Statement: Use a
switch
statement to select one of several code blocks to execute. Use aswitch
statement when there are multiple cases to handle.
switch (day) {
case DayOfWeek.Monday:
// Code here
break;
case DayOfWeek.Tuesday:
// Code here
break;
default:
// Code here
break;
}
Using Statements
- Using Statements: Use
using
statements to ensure that resources are properly disposed of. Useusing
statements for types that implement theIDisposable
interface. Do not useusing
statements for types that do not implement theIDisposable
interface.
using (var stream = new FileStream("file.txt", FileMode.Open)) {
// Code here
}
Using Directives
- Using Directives: Use
using
directives to import namespaces at the top of the file. Use separateusing
directives for each namespace. Do not useusing
directives for namespaces that are not used in the file.
using System;
using System.Collections.Generic;
using System.Linq;
Code Formatting
- Code Formatting: Use a consistent code formatting style throughout the project. Use spaces around operators, after commas, and after colons. Use a single space between keywords and opening parentheses. Use a single space between the
//
characters and the comment text.
if (condition) {
// Code here
} else {
// Code here
}
Null Checking
- Null Checking: Use null checking to handle null values. Check for null values before accessing properties or methods on an object. Use the null-conditional operator (
?.
) to safely access properties or methods on an object that may be null.
if (customer != null) {
var fullName = customer.FullName;
}
var fullName = customer?.FullName;