These documents contain guidelines for writing consistent, lucid, enticing, modern C#.
If you take issue with anything here, please open a pull request with your recommended changes and include an argument for and against their adoption; explain the benefits of your proposed change, and also any drawbacks.
- Be consistent.
- Don't rewrite existing code to follow this guide.
- Don't violate a guideline without a good reason.
- A reason is good when you can convince a teammate, not just when you like it.
- Assume your reader knows C# and English.
- Prefer clarity to 'performance'.
- Prefer clarity to .NET dogma.
- Write comments that people want to read, with correct spelling and grammar.
- Indent with tabs.
- Max line length is 100 columns.
- Use spaces and empty lines precisely.
- Braces generally go on their own lines.
- Never put a space before
[
. - Always put a space before
{
. - Always put a space before
(
except for method invocations or when following another(
.
Layout your .cs
files like this:
File Header
Using Directives
Namespace Declaration
Type Declaration
Constants
Static Fields
Static Auto-Properties
Static Constructor
Complex Static Properties
Static Methods
Fields
Auto-Properties
Constructors
Destructor
Complex Properties
Methods
An exception to this layout is manual properties with a backing field used exclusively via the property; these members should occur in the file together in the properties section. If your backing field is accessed anywhere other than inside the property definition, stick to normal layout rules.
string name;
public string Name {
get { return name; }
set { name = value; }
}
Group using directives by common prefix, with shorter namespaces coming before longer ones, creating neat clusters of statements separated by single empty lines.
Namespaces should be ordered in increasing order of platform specificity, with .NET namespaces first, then library or component namespaces, then Xamarin namespaces, then application namespaces:
// Beautiful:
using System;
using System.Linq;
using System.Collections.Generic;
using MyLib;
using MyLib.Extensions;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using MyApp;
// Disaster:
using MyLib.Extensions;
using MonoTouch.Foundation;
using System.Collections.Generic;
using System;
using System.Linq;
using MonoTouch.UIKit;
using MyLib;
Prune redundant namespaces aggressively.
Leave an empty line between every type definition:
// Perfect.
namespace MyApp
{
enum Direction { Left, Right }
class ImportantThing
{
...
}
}
// Wrong - missing and empty line between type definitions.
namespace MyApp
{
enum Direction { Left, Right }
class ImportantThing
{
...
}
}
// Wrong - more than one empty line.
namespace MyApp
{
enum Direction { Left, Right }
class ImportantThing
{
...
}
}
Put a space before and after :
when listing base classes and interfaces.
// Perfect.
class MyClass : BaseClass, IDoesThis
{
}
// Wrong.
class MyClass: BaseClass, IDoesThis
{
}
Simple enums may be defined on a single line:
enum Edge { Left, Right, Bottom, Top }
Larger enums should list entries on separate lines and always end in a comma:
enum StringSplitOptions
{
None = 0,
RemoveEmptyEntries = 1,
}
Leave an empty line before every method, property, indexer, constructor, and destructor:
class Person
{
string name;
public Person(string name)
{
this.name = name;
}
}
Automatic properties don't need to be preceeded by an empty line:
class Person
{
string Name { get; set; }
int Age { get; set; }
...
}
public async Task<string[]> Query<TDatabase>(User user, TDatabase database, Role role = Role.Admin)
: where TDatabase : IDatabase
{
}
Declare automatic properties on a single line with the exact spacing shown below:
// Perfect.
string Name { get; set; }
Simple properties may define get
and set
on a single line each, with get
first:
// Perfect.
string Name {
get { return name; }
set { name = value; }
}
Also note the single spaces before and after {
, and the space before }
.
Complex properties go like this:
// Perfect.
string Name {
get {
return name;
}
set {
name = value;
}
}
Use it. Less typing is almost always better than more typing, with some important exceptions.
Use var
when the type is repeated on the right-hand side of the assignment:
// Perfect!
var users = new Dictionary<UserId, User>();
// Bloated.
Dictionary<UserId, User> users = new Dictionary<UserId, User>();
Don't use var
for capturing the return type of a method or property when the type is not evident:
// Horrendous.
var things = Interpret(data);
// Much better.
HashMap<Thing> things = Interpret(data);
// Even better.
var things = InterpretAs<Thing>(data);
Omit the type when using array initializers:
// Could be better:
database.UpdateUserIds(new int[] { 1, 2, 3 });
// Better:
database.UpdateUserIds(new [] { 1, 2, 3 });
Use them.
For simple initializers, you may do a one-liner:
// Perfect.
var person = new Person("Vinny") { Age = 50 };
// Acceptable.
var person = new Person("Vinny") {
Age = 50,
};
Omit the ()
when using parameterless constructors:
// Perfect.
var person = new Person { Name = "Bob", Age = 75 };
// Wrong.
var person = new Person() { Name = "Bob", Age = 75 };
In general, each expression should be on a separate line, and every line should end with a comma ,
:
// Very nice collection initializer.
var entries = new Dictionary<string, int> {
{ "key1", 1 },
{ "key2", 2 },
};
// Very nice object initializer.
var contact = new Person {
Name = "David Siegel",
SocialSecurityNumber = 123456789,
Address = "1234 Montgomery Circle Drive East",
};
// Bad collection initializer – multiple entries on one line.
var entries = new Dictionary<string, int> {
{ "key1", 1 }, { "key2", 2 },
};
switch
statements have the case at the same indentation as the switch
:
switch (x) {
case 'a':
...
case 'b':
...
}
We prefer to put a space before an open parenthesis only in control flow statements, but not in normal method/delegate/lambda calls, or expressions. This makes method invocations stand out from simple logical groupings. For example, this is good:
// Flow control...
if (awesome) ...
foreach (var foo in foos) ...
while (hazMonkeys) ...
// Logical grouping...
var result = b * (4 + i);
// Method invocation.
Foo(database);
Debug.Assert(5 + (3 * 4) && "laws of math are failing me");
// Consider
A = result ?? (int) compute (foo (b + 1));
// At first glance it Looks very similar to:
A = result ?? (int) compute (foo) (b + 1);
// Whereas:
A = result ?? (int) compute(foo(b + 1));
// Looks more immediately distinct from
A = result ?? (int) compute(foo)(b + 1);
The reason for doing this is not completely arbitrary. This style makes control flow operators stand out more, and makes expressions flow better. The function call operator binds very tightly as a postfix operator. In some cases, such as when C# is embedded in Razor markup, inserting a space before an opening parenthesis will cause compilation to fail.
[1] Adapted from http://llvm.org/docs/CodingStandards.html#spaces-before-parentheses
Do not put a space before the left angle bracket in a generic type:
// Perfect.
var scores = new List<int>();
// Incorrect.
var scores = new List <int>();
Do not put spaces inside parentheses, square brackets, or angle brackets:
// Wrong - spaces inside.
Initialize( database );
products[ i ];
new List< int >();
Separate type parameters to generic types by a space:
// Excellent.
var users = new Dictionary<UserId, User>();
// Worthless.
var users = new Dictionary<UserId,User>();
Put a space between the type and the indentifier what casting:
// Great.
var person = (Person) sender;
// Bad.
var person = (Person)sender;
Inside a code block, put the opening brace on the same line as the statement:
// Lovely.
if (you.Love (someone)) {
someone.SetFree();
}
// Wrong.
if (you.Love (someone))
{
someone.SetFree();
}
Omitting braces for single line if statements is fine, however braces are always acceptable:
// Lovely.
if (you.Like (it))
it.PutOn(ring);
// Acceptable.
if (you.Like (it)) {
it.PutOn(ring);
}
Very short statements may be one-liners, especially when the body is a return
:
// Lovely.
if (condition) return;
// Acceptable, but a little complex for a one-liner.
if (people.All(p => p.IsAdmin)) return new AdminPage();
// Wrong - too complex for a single line:
if (people.Where(p => p.IsAdmin).Average(p => p.Age) > 21) return DrinkDispenser.FireWater;
Always use braces with nested or multi-line conditions:
// Perfect.
if (a) {
if (b) {
code();
}
}
// Acceptable.
if (a) {
if (b)
code();
}
// Wrong.
if (a)
if (b)
code ();
When defining a method, put the opening brace on its own line:
// Correct.
void LaunchRockets()
{
}
// Wrong.
void LaunchRockets() {
}
When defining a property, keep the opening brace on the same line:
// Perfect.
double AverageAge {
get {
return people.Average (p => p.Age);
}
}
// Wrong.
double AverageAge
{
get {
return people.Average(p => p.Age);
}
}
Notice how get
keeps its brace on the same line.
For very small properties, you can compress things:
// Preferred.
int Property {
get { return value; }
set { x = value; }
}
// Acceptable.
int Property {
get {
return value;
}
set {
x = value;
}
}
Empty methods should have the body of code using two lines, in consistency with the rest:
// Good.
void EmptyMethod()
{
}
// These are wrong.
void EmptyMethod() {}
void EmptyMethod()
{}
Generic method type parameter constraints are on separate lines, one line per type parameter, indented once:
static bool TryParse<TEnum>(string value, out TEnum result)
where TEnum : struct
{
...
}
If statements with else clauses are formatted like this:
good:
if (dingus) {
...
} else {
...
}
bad:
if (dingus)
{
...
}
else
{
...
}
bad:
if (dingus) {
...
}
else {
...
}
Namespaces, types, and methods all put braces on their own line:
// Correct.
namespace MyApp
{
class FluxCapacitor
{
...
}
}
// Wrong - opening braces are not on their own lines.
namespace MyApp {
class FluxCapacitor {
...
}
}
To summarize:
Statement | Brace position |
---|---|
Namespace | new line |
Type | new line |
Methods | new line |
Constructors | new line |
Destructors | new line |
Properties | same line |
Control blocks (if, for...) | same line |
Anonymous types and methods | same line |
When your argument list grows too long, split your method invocation across multiple lines, with the first argument on a new line after the opening parenthesis of the method invocation, the closing parenthesis of the invocation on its own line at the same indentation level as the line with the opening parenthesis. This style works especially well for methods with named parameters.
// Lovely.
Console.WriteLine(
"Connect to {0} via {1} with extra data: {2} {3}",
database.Address,
database.ConnectionMethod.Description,
data.FirstPart,
data.SecondPart
);
It's also acceptable to put multiple arguments on a single line when they belong together:
// Acceptable.
Console.WriteLine(
"Connect to {0} via {1} with extra data: {2} {3}",
database.Address,
database.ConnectionMethod.Description,
data.FirstPart, data.SecondPart
);
When chaining method calls, each method call in the chain should be on a separate line indented once:
void M() {
IEnumerable<int> items = Enumerable.Range(0, 100)
.Select(e => e * 2);
}
Use single spaces in expressions liberally:
good:
// Good.
if (a + 5 > method(blah() + 4))
// Bad.
if (a+5>method(blah()+4))
Argument names should use the camel casing for identifiers, like this:
good:
// Good.
void Method(string myArgument)
// Bad.
void Method(string lpstrArgument)
void Method(string my_string)
Don't use m_
or _
as prefixes for instance fields. Just use normal parameter naming conventions:
// Perfect.
class Person
{
string name;
}
// Wrong.
class Person
{
string m_name;
}
Don't write private
for private members, as this is the default visibility in C#:
// Perfect.
class Person
{
string name;
}
// Wrong.
class Person
{
private string name;
}
An exception to this rule is serializable classes. In this case, if we desire to have our serialized data be compatible with Microsoft's, we must use the same field name.
The use of "this." as a prefix in code is discouraged, it is mostly redundant. In general, since internal variables are lowercase and anything that becomes public starts with an uppercase letter, there is no ambiguity between what the "Foo" and "foo" are. The first is a public property or field, the second is internal property or field.
Good:
class Foo
{
int bar;
void Update(int newValue)
{
bar = newValue;
}
void Clear()
{
Update();
}
}
Bad:
class Foo
{
int bar;
void Update(int newValue)
{
this.bar = newValue;
}
void Clear()
{
this.Update();
}
}
An exception is made for this
when the parameter name is the same as an instance variable, this happens sometimes in constructors or if naming is difficult:
Good:
class Message
{
char text;
public Message(string text)
{
this.text = text;
}
}
This guide was adapted from the Mono coding guidelines with inspiration from thoughtbot's excellent guide for programming in style and The LLVM Coding Standards.