Coding Standards
There are three supported .NET coding convention categories:
Language conventions
.NET code style settings
"this." qualifiers
This style rule can be applied to fields, properties, methods, or events.
Prefer the code element not to be prefaced with
this.
Prefer fields not to be prefaced with
this.
//Right capacity = 0;
//Wrong this.capacity = 0;
Prefer properties not to be prefaced with
this.
//Right ID = 0;
//Wrong this.ID = 0;
Prefer methods not to be prefaced with
this.
//Right Display();
//Wrong this.Display();
Prefer events not to be prefaced with
this.
//Right Elapsed += Handler;
//Wrong this.Elapsed += Handler;
Language keywords instead of framework type names for type references
This style rule can be applied to local variables, method parameters, and class members, or as a separate rule to type member access expressions.
Prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them.
//Right private int _member;
//Wrong private Int32 _member;
Prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them.
//Right var local = int.MaxValue;
//Wrong var local = Int32.MaxValue;
Modifier preferences
The style rules in this section concern modifier preferences, including requiring accessibility modifiers, specifying the desired modifier sort order, and requiring the read-only modifier.
Prefer accessibility modifiers to be declared except for public interface members.
//Right class MyClass { private const string thisFieldIsConst = "constant"; }
//Wrong class MyClass { const string thisFieldIsConst = "constant"; }
Prefer the specified ordering:
public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:silent
//Right class MyClass { private static readonly int _daysInYear = 365; }
Parentheses preferences
The style rules in this section concern parentheses preferences, including the use of parentheses for arithmetic, relational, and other binary operators.
Prefer parentheses to clarify arithmetic operator (*, /, %, +, -, <<, >>, &, ^, |) precedence
//Right var v = a + (b * c);
//Wrong var v = a + b * c;
Prefer parentheses to clarify relational operator (>, <, <=, >=, is, as, ==, !=) precedence
//Right var v = (a < b) == (c > d);
//Wrong var v = a < b == c > d;
Prefer parentheses to clarify other binary operators (&&, ||, ??) precedence
//Right var v = a || (b && c);
//Wrong var v = a || b && c;
Prefer to not have parentheses when operator precedence is obvious
//Right var v = a.b.Length;
//Wrong var v = (a.b).Length;
Expression-level preferences
The style rules in this section concern expression-level preferences, including the use of object initializers, collection initializers, explicit or inferred tuple names, and inferred anonymous types.
Prefer objects to be initialized using object initializers when possible
//Right var c = new Customer() { Age = 21 };
//Wrong var c = new Customer(); c.Age = 21;
Prefer collections to be initialized using collection initializers when possible
//Right var list = new List<int> { 1, 2, 3 };
//Wrong var list = new List<int>(); list.Add(1); list.Add(2); list.Add(3);
Prefer tuple names to ItemX properties
//Right (string name, int age) customer = GetCustomer(); var name = customer.name;
//Wrong (string name, int age) customer = GetCustomer(); var name = customer.Item1;
Prefer inferred tuple element names
//Right var tuple = (age, name);
//Wrong var tuple = (age: age, name: name);
Prefer explicit anonymous type member names
//Right var anon = new { age = age, name = name };
//Wrong var anon = new { age, name };
Prefer auto-properties over properties with private backing fields
//Right private int Age { get; }
//Wrong private int age; public int Age { get { return age; } }
Prefer using a null check with pattern-matching over
object.ReferenceEquals
//Right if (value is null) return;
//Wrong if (object.ReferenceEquals(value, null)) return;
Prefer assignments with a ternary conditional over an if-else statement
//Right string s = expr ? "hello" : "world";
//Wrong string s; if (expr) { s = "hello"; } else { s = "world"; }
Prefer return statements to use a ternary conditional over an if-else statement
//Right return expr ? "hello" : "world";
//Wrong if (expr) { return "hello"; } else { return "world"; }
Prefer compound assignment expressions
//Right x += 1;
//Wrong x = x + 1;
Null-checking preferences
The style rules in this section concern null-checking preferences.
Prefer null coalescing expressions to ternary operator checking
//Right var v = x ?? y;
//Wrong var v = x != null ? x : y; // or var v = x == null ? y : x;
Prefer to use a null-conditional operator when possible
//Right var v = o?.ToString();
//Wrong var v = o == null ? null : o.ToString(); // or var v = o != null ? o.String() : null;
C# code style settings
Implicit and explicit types
The style rules in this section concern the use of the var keyword versus an explicit type in a variable declaration. This rule can be applied separately to built-in types, when the type is apparent, and elsewhere.
Prefer
var
is used to declare variables with built-in system types such asint
//Right var x = 5;
//Wrong int x = 5;
Prefer
var
when the type is already mentioned on the right-hand side of a declaration expression//Right var obj = new Customer();
//Wrong Customer obj = new Customer();
Prefer
var
over explicit type in all cases, unless overridden by another code style rule//Right var f = this.Init();
//Wrong bool f = this.Init();
Expression-bodied members
The style rules in this section concern the use of expression-bodied members when the logic consists of a single expression. This rule can be applied to methods, constructors, operators, properties, indexers, and accessors.
Prefer block bodies for methods
//Right public int GetAge() { return this.Age; }
//Wrong public int GetAge() => this.Age;
Prefer block bodies for constructors
//Right public Customer(int age) { Age = age; }
//Wrong public Customer(int age) => Age = age;
Prefer block bodies for operators
//Right public static ComplexNumber operator + (ComplexNumber c1, ComplexNumber c2) { return new ComplexNumber(c1.Real + c2.Real, c1.Imaginary + c2.Imaginary); }
//Wrong public static ComplexNumber operator + (ComplexNumber c1, ComplexNumber c2) => new ComplexNumber(c1.Real + c2.Real, c1.Imaginary + c2.Imaginary);
Prefer expression bodies for properties when they will be a single line
//Right public int Age => _age;
//Wrong public int Age { get { return _age; }}
Prefer expression bodies for indexers
//Right public T this[int i] => _values[i];
//Wrong public T this[int i] { get { return _values[i]; } }
Prefer expression bodies for accessors
//Right public int Age { get => _age; set => _age = value; }
//Wrong public int Age { get { return _age; } set { _age = value; } }
Prefer expression bodies for lambdas
//Right Func<int, int> square = x => x * x;
//Wrong Func<int, int> square = x => { return x * x; };
Pattern matching
The style rules in this section concern the use of pattern matching in C#.
Prefer pattern matching instead of is expressions with type casts
//Right if (o is int i) {...}
//Wrong if (o is int) {var i = (int)o; ... }
Prefer pattern matching instead of
as
expressions with null checks to determine if something is of a particular type//Right if (o is string s) {...}
//Wrong var s = o as string; if (s != null) {...}
Inlined variable declarations
This style rule concerns whether out variables are declared inline or not. Starting in C# 7, you can declare an out variable in the argument list of a method call, rather than in a separate variable declaration.
Prefer
out
variables to be declared inline in the argument list of a method call when possible//Right if (int.TryParse(value, out int i)) {...}
//Wrong int i; if (int.TryParse(value, out i)) {...}
C# expression-level preferences
This style rule concerns using the default literal for default value expressions when the compiler can infer the type of the expression.
Prefer
default
overdefault(T)
//Right void DoWork(CancellationToken cancellationToken = default) { ... }
//Wrong void DoWork(CancellationToken cancellationToken = default(CancellationToken)) { ... }
C# null-checking preferences
These style rules concern the syntax around null checking, including using throw expressions or throw statements, and whether to perform a null check or use the conditional coalescing operator (?.) when invoking a lambda expression.
Prefer to use throw expressions instead of throw statements
//Right this.s = s ?? throw new ArgumentNullException(nameof(s));
//Wrong if (s == null) { throw new ArgumentNullException(nameof(s)); } this.s = s;
Prefer to use the conditional coalescing operator (?.) when invoking a lambda expression, instead of performing a null check
//Right func?.Invoke(args);
//Wrong if (func != null) { func(args); }
Code block preferences
This style rule concerns the use of curly braces { } to surround code blocks.
Prefer no curly braces if allowed
//Right if (test) this.Display();
//Wrong if (test) { this.Display(); }
Formatting conventions
.NET formatting settings
Organize using directives
These formatting rules concern the sorting and display of using
directives and Imports
statements.
Sort
System.*
using
directives alphabetically, and place them before other using directives.//Right using System.Collections.Generic; using System.Threading.Tasks; using Octokit;
//Wrong using System.Collections.Generic; using Octokit; using System.Threading.Tasks;
Do not place a blank line between using directive groups.
//Right using System.Collections.Generic; using System.Threading.Tasks; using Octokit;
//Wrong using System.Collections.Generic; using System.Threading.Tasks; using Octokit;
C# formatting settings
The formatting rules in this section apply only to C# code.
New-line options
These formatting rules concern the use of new lines to format code.
Require braces to be on a new line for all expressions ("Allman" style).
//Right void MyMethod() { if (...) { ... } }
//Wrong void MyMethod() { if (...) { ... } }
Place else statements on a new line.
//Right if (...) { ... } else { ... }
//Wrong if (...) { ... } else { ... }
Place catch statements on a new line.
//Right try { ... } catch (Exception e) { ... }
//Wrong try { ... } catch (Exception e) { ... }
Require finally statements to be on a new line after the closing brace.
//Right try { ... } catch (Exception e) { ... } finally { ... }
//Wrong try { ... } catch (Exception e) { ... } finally { ... }
Require members of object initializers to be on separate lines
//Right var z = new B() { A = 3, B = 4 }
//Wrong var z = new B() { A = 3, B = 4 }
Require members of anonymous types to be on separate lines
//Right var z = new { A = 3, B = 4 }
//Wrong var z = new { A = 3, B = 4 }
Require elements of query expression clauses to be on separate lines
//Right var q = from a in e from b in e select a * b;
//Wrong var q = from a in e from b in e select a * b;
Indentation options
These formatting rules concern the use of indentation to format code.
Indent
switch
case contents//Right switch(c) { case Color.Red: Console.WriteLine("The color is red"); break; case Color.Blue: Console.WriteLine("The color is blue"); break; default: Console.WriteLine("The color is unknown."); break; }
//Wrong switch(c) { case Color.Red: Console.WriteLine("The color is red"); break; case Color.Blue: Console.WriteLine("The color is blue"); break; default: Console.WriteLine("The color is unknown."); break; }
Indent
switch
labels//Right switch(c) { case Color.Red: Console.WriteLine("The color is red"); break; case Color.Blue: Console.WriteLine("The color is blue"); break; default: Console.WriteLine("The color is unknown."); break; }
//Wrong switch(c) { case Color.Red: Console.WriteLine("The color is red"); break; case Color.Blue: Console.WriteLine("The color is blue"); break; default: Console.WriteLine("The color is unknown."); break; }
Labels are placed at the same indent as the current context
//Right class C { private string MyMethod(...) { if (...) { goto error; } error: throw new Exception(...); } }
//Wrong class C { private string MyMethod(...) { if (...) { goto error; } error: throw new Exception(...); } }
//Wrong class C { private string MyMethod(...) { if (...) { goto error; } error: throw new Exception(...); } }
Spacing options
These formatting rules concern the use of space characters to format code.
Remove space between the cast and the value
//Right int y = (int)x;
//Wrong int y = (int) x;
Place a space character after a keyword in a control flow statement such as a
for
loop//Right for (int i;i<x;i++) { ... }
//Wrong for(int i;i<x;i++) { ... }
Place a space character before the colon for bases or interfaces in a type declaration
//Right interface I { } class C : I { }
//Wrong interface I { } class C: I { }
Place a space character after the colon for bases or interfaces in a type declaration
//Right interface I { } class C : I { }
//Wrong interface I { } class C :I { }
Insert space before and after the binary operator
//Right return x * (x - y);
//Wrong return x*(x-y);
//Wrong return x * (x-y);
Remove space characters after the opening parenthesis and before the closing parenthesis of a method declaration parameter list
//Right void Bark(int x) { ... }
//Wrong void Bark( int x ) { ... }
Remove space within empty parameter list parentheses for a method declaration
//Right void Goo() { Goo(1); } void Goo(int x) { Goo(); }
//Wrong void Goo( ) { Goo(1); } void Goo(int x) { Goo(); }
Remove space characters between the method name and opening parenthesis in the method declaration
//Right void M() { }
//Wrong void M () { }
Remove space characters after the opening parenthesis and before the closing parenthesis of a method call
//Right MyMethod(argument);
//Wrong MyMethod( argument );
Remove space within empty argument list parentheses
//Right void Goo() { Goo(1); } void Goo(int x) { Goo(); }
//Wrong void Goo() { Goo(1); } void Goo(int x) { Goo( ); }
Remove space between method call name and opening parenthesis
//Right void Goo() { Goo(1); } void Goo(int x) { Goo(); }
//Wrong void Goo() { Goo(1); } void Goo(int x) { Goo (); }
Insert space after a comma
//Right int[] x = new int[] { 1, 2, 3, 4, 5 };
//Wrong int[] x = new int[] { 1,2,3,4,5 };
Remove space before a comma
//Right int[] x = new int[] { 1, 2, 3, 4, 5 };
//Wrong int[] x = new int[] { 1 , 2 , 3 , 4 , 5 };
Insert space after each semicolon in a for statement
//Right for (int i = 0; i < x.Length; i++)
//Wrong for (int i = 0;i < x.Length;i++)
Remove space before each semicolon in a for statement
//Right for (int i = 0; i < x.Length; i++)
//Wrong for (int i = 0 ; i < x.Length ; i++)
Remove extra space characters in declaration statements
//Right int x = 0;
//Wrong int x = 0 ;
Remove space before opening square brackets
[
//Right int[] numbers = new int[] { 1, 2, 3, 4, 5 };
//Wrong int [] numbers = new int [] { 1, 2, 3, 4, 5 };
Remove space between empty square brackets
[]
//Right int[] numbers = new int[] { 1, 2, 3, 4, 5 };
//Wrong int[ ] numbers = new int[ ] { 1, 2, 3, 4, 5 };
Remove space characters in non-empty square brackets
[0]
//Right int index = numbers[0];
//Wrong int index = numbers[ 0 ];
Wrap options
These formatting rules concern the use of single lines versus separate lines for statements and code blocks.
Leave statements and member declarations on different lines
//Right int i = 0; string name = "John";
//Wrong int i = 0; string name = "John";
Leave code block on a single line
//Right public int Foo { get; set; }
//Wrong public int MyProperty { get; set; }
Naming conventions
Constants are named only in capital letters with a delimiter
_
//Right const int TEST_CONSTANT = 1;
//Wrong const int Test_Constant = 1;
Fields with
public
access are referred to as PascalCase notation//Right public int TestField;
//Wrong public int testField;
Interface names must be in PascalCase notation and have the prefix
I
//Right public interface ITestInterface;
//Wrong public interface testInterface;
The names of classes, structures, methods, enums, events, properties, namespaces, and delegates should be in PascalCase notation
//Right public class SomeClass;
//Wrong public class someClass;
Assigned to the parameter of a generic type a descriptive name in the notation PascalCase, unless enough of a letter and a descriptive name has no practical value
//Right public interface ISessionChannel<TSession> { /*...*/ } public delegate TOutput Converter<TInput, TOutput>(TInput from); public class List<T> { /*...*/ }
Use the name of the type
T
parameter for types that contain only a single letter type parameter//Right public int IComparer<T>() { return 0; } public delegate bool Predicate<T>(T item); public struct Nullable<T> where T : struct { /*...*/ }
Use the prefix
T
for descriptive names of type parameters//Right public interface ISessionChannel<TSession> { TSession Session { get; } }
Specify the constraints associated with the type parameter in its name. For example, an
ISession
constraint parameter may be calledTSession
.Private and protected class fields must begin with the prefix
_
//Right private int _testField; protected int _testField;
//Wrong private int testField; protected int testField;
All other code elements such as variables, method parameters, and class fields (except open ones) are named in camelCase notation.
//Right var testVar = new Object(); public void Foo(int firstParam, string secondParam)
//Wrong var TestVar = new Object(); public void Foo(int FirstParam, string SecondParam)