C# General Cheat Sheet
Writing beautiful, understandable code is just as important as writing a production code. There are many different guides and guidelines on the Internet.
I tried to go through all of them and put together a little cheat sheet. I have included only those rules that affect the style of the code and cover most of the key points.
Hope you find this very useful!
Layout
- A maximum of one statement per line.
- A maximum of one assignment per statement.
- Indentation of 4 spaces, no tabs.
- Column limit: 120.
- Line break before opening brace.
- Line break between closing brace and
else
. - Space after
if
/for
/while
etc., and after commas. - No space after an opening parenthesis or before a closing parenthesis.
- One space between the operator and each operand of all other operators.
- Add at least one blank line between method definitions and property definitions.
Comments
- Place the comment on a separate line, not at the end of a line of code.
- Insert one space between the comment delimiter (//) and the comment text.
Naming
Do:
- Names of classes, methods, enumerations, public fields, public properties, namespaces:
PascalCase
. - Names of local variables, parameters:
camelCase
. - Names of private, protected, internal and protected internal fields and properties:
_camelCase
. - Naming convention is unaffected by modifiers such as const, static, readonly, etc.
- Names of interfaces start with
I
, e.g.IInterface
. - Filenames and directory names are
PascalCase
, e.g.MyFile.cs
. - Choose easily readable identifier names, e.g. a property named
HorizontalAlignment
is more English-readable thanAlignmentHorizontal
. - Favor readability over brevity, e.g. a property name
CanScrollHorizontally
is better thanScrollableX
(an obscure reference to the X-axis). - Use semantically interesting names rather than language-specific keywords for type names, e.g.
GetLength
is a better name thanGetInt
.
Do NOT:
- Use underscores, hyphens, or any other nonalphanumeric characters.
- Use Hungarian notation.
- Use identifiers that conflict with keywords of widely used programming languages.
- Use abbreviations or contractions as part of identifier names.
- Use any acronyms that are not widely accepted, and even if they are, only when necessary.
Argument:
- If the argument is a literal constant, and the same constant is used in multiple function calls in a way that tacitly assumes they’re the same, use a named constant to make that constraint explicit, and to guarantee that it holds.
- Replace large or complex nested expressions with named variables.
- Consider using Named Arguments to clarify argument meanings at the call site.
The
var
keyword
- Use of
var
is encouraged if it aids readability by avoiding type names that are noisy, obvious, or unimportant. - When the type is obvious — e.g.
var apple = new Apple();
, orvar request = Factory.Create<HttpRequest>();
- For transient variables that are only passed directly to other methods — e.g.
var item = GetItem(); ProcessItem(item);
ref and out
- Use
out
for returns that are not also inputs. - Place
out
parameters after all other parameters in the method definition. -
ref
should be used rarely, when mutating an input is necessary. - Do NOT use
ref
as an optimisation for passing structs. - Do NOT use
ref
to pass a modifiable container into a method.ref
is only required when the supplied container needs be replaced with an entirely different container instance. - Do NOT use
ref
orout
modifiers to overload members.
Use of tuple as a return type
- In general, prefer a named class type over
Tuple<>
, particularly when returning complex types.
Default values/null returns for structs
- Prefer returning a ‘success’ boolean value and a struct
out
value.
Attributes
- Name custom attribute classes with the suffix “Attribute.”
- Attributes should appear on the line above the field, property, or method they are associated with, separated from the member by a newline.
- Multiple attributes should be separated by newlines. This allows for easier adding and removing of attributes, and ensures each attribute is easy to search for.
Structs and classes:
- Almost always use a class.
- Consider struct when the type can be treated like other value types — for example, if instances of the type are small and commonly short-lived or are commonly embedded in other objects.
Class member ordering
Group class members in the following order:
- Nested classes, enums, delegates and events.
- Static, const and readonly fields.
- Fields and properties.
- Constructors and finalizers.
- Methods.
Within each group, elements should be in the following order:
- Public.
- Internal.
- Protected internal.
- Protected.
- Private.
Property styles
- For single line read-only properties, prefer expression body properties (
=>
) when possible. - For everything else, use the older
{ get; set; }
syntax.
Constants
- Variables and fields that can be made
const
should always be madeconst
. - If
const
isn’t possible,readonly
can be a suitable alternative.
Exceptions
- Do NOT return error codes.
- Use the prefix “Try” and Boolean return type for methods implementing this pattern.
String interpolation vs
String.Format()
vs
String.Concat
vs
operator+
- In general, use whatever is easiest to read, particularly for logging and assert messages.
- Be aware that chained
operator+
concatenations will be slower and cause significant memory churn. - If performance is a concern,
StringBuilder
will be faster for multiple string concatenations.
LINQ
- In general, prefer single line LINQ calls and imperative code, rather than long chains of LINQ. Mixing imperative code and heavily chained LINQ is often hard to read.
- Prefer member extension methods over SQL-style LINQ keywords — e.g. prefer
myList.Where(x)
tomyList where x
.
Array vs List
- In general, prefer
List<>
over arrays for public variables, properties, and return types. - Prefer
List<>
when the size of the container can change. - Prefer arrays when the size of the container is fixed and known at construction time.
- Prefer array for multidimensional arrays.
IEnumerable vs IList vs IReadOnlyList
- For inputs use the most restrictive collection type possible, for example
IReadOnlyCollection
/IReadOnlyList
/IEnumerable
as inputs to methods when the inputs should be immutable. - For outputs, if passing ownership of the returned container to the owner, prefer
IList
overIEnumerable
. If not transferring ownership, prefer the most restrictive option.
You can find more rules and guidelines below:
- C# Coding Conventions from Microsoft — https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions
- .Net Design Guidelines from Microsoft — https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
- C# Style Guide from Google — google.github.io
Thanks for reading !!!