dvdsgl / csharp-in-style

A style guide for C#.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Introduction

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.

Guiding Principles

  • 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.

The Rundown

  • 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 (.

Specific Guides

General Guidelines

File Layout

Layout your .cs files like this:

File Header

Using Directives

Namespace Declaration

    Type Declaration

        Constants
        Static Fields
        Static Auto-Properties
        Static Delegates
        Static Events
        Static Enums
        Static Constructors
        Static Complex Properties
        Static Methods
        Static Structs
        Static Interfaces
        Static Classes
        Fields
        Auto-Properties
        Delegates
        Events
        Enums
        Constructors
        Finalizers (Destructors)
        Complex Properties
        Methods
        Structs
        Interfaces
        Classes

Within each of these groups order by access:

public
internal
protected
private

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; }
}

using Directives

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.

Declaring Types

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
{
}

Enums

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,
}

Member Declarations

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 preceded by an empty line:

class Person
{
	string Name { get; set; }
	int Age { get; set; }
	
	...
}

Methods

public async Task<string[]> Query<TDatabase>(User user, TDatabase database, Role role = Role.Admin)
	: where TDatabase : IDatabase
{
}

Properties

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;
	}
}

Type Inference

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 });

Object and Collection Initializers

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 },
};

Indentation

switch statements have the case at the same indentation as the switch:

switch (x) {
case 'a':
	...
case 'b':
	...
}

Where to put spaces[1]

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 identifier what casting:

// Great.
var person = (Person) sender;

// Bad.
var person = (Person)sender;

Where to put braces

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

Long Argument Lists

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))

Casing

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)

Instance Fields

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.

this

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;
	}
}

Credits

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.

About

A style guide for C#.

License:Other