C# Class Structure: A Developer's Memory Guide
I always have that moment of "I think I know how to code... but do I remember the class structure order?" So I wrote this down for myself.
This is the mental model I use when I want a clean, readable C# class file.
Why bother with order?
It helps with:
- Readability: easier to scan
- Maintenance: less time hunting for things
- Professionalism: it just looks cleaner
The UNC-SFICN mnemonic
To remember the order, I use "UNC-SFICN" (I say it like "Uncle Sficin" in my head):
U - Usings - File imports/references
N - Namespace declaration
C - Class declaration - Including attributes and XML documentation
S - Statics - Constants, Static Fields, Static Properties, Static Events and Static Methods
F - Fields (instance fields only)
I - Initialization (constructors)
C - Class behaviors - Instance Properties, Events and Methods
N - Nested types (inner classes, structs, interfaces, enums)
Quick breakdown below.
U - Usings
Start with all your using directives, usually system first, then your own:
using System;
using System.Collections.Generic;
using System.Linq;
using MyCompany.Services;
using MyCompany.Utilities;
N - Namespace Declaration
Declare your namespace to organize your types:
namespace MyCompany.Core
{
// Everything else goes inside here
}
C - Class Declaration
Define your class and any documentation/attributes:
/// docs
public class DataManager : IDataProcessor
{
// Class members go here
}
S - Statics
Static members up top (constants, fields, properties, methods):
// Constants
public const string DefaultConnectionString = "";
// Static fields
private static readonly HttpClient _httpClient = new HttpClient();
// Static properties
public static TimeSpan DefaultTimeout { get; set; } = TimeSpan.FromSeconds(30);
// Static methods
public static bool IsValidConfiguration(Configuration config)
{
// method logic here
}
F - Fields
Instance fields next:
// Private fields
protected readonly ILogger _logger;
private readonly IRepository _repository;
private bool _isInitialized;
I - Initialization
Constructors and setup:
// Main constructor
public DataManager(IRepository repository, ILogger logger)
{
// Initialization logic here
}
// Parameterless constructor
public DataManager() : this(new DefaultRepository(), LogManager.GetCurrentClassLogger())
{
}
C - Class Behaviors
Instance properties, events, and methods:
// Properties
public bool IsConnected { get; private set; }
public ConnectionStatus Status => _isInitialized ? ConnectionStatus.Ready : ConnectionStatus.Pending;
// Methods
public async Task<DataResult> ProcessDataAsync(DataRequest request)
{
// method logic here
}
N - Nested Types
Nested enums/classes/interfaces at the bottom:
// Nested enum
public enum ConnectionStatus
{
Pending,
Ready,
Failed
}
// Nested class
private class DataRequestValidator
{
public bool Validate(DataRequest request)
{
// method logic here
}
}
Access Modifier Order
One last thing I try to keep straight: order members from most accessible to least accessible:
public- Accessible by any codeprotected- Accessible by the class and its subclassesinternal- Accessible within the same assemblyprotected internal- Accessible by the assembly or derived classesprivate protected- Accessible by derived classes within the same assemblyprivate- Accessible only within the declaring class
Hopefully this helps me (and you) keep things tidy.