styleguide

C# at Google Style Guide

This style guide is for C# code developed internally at Google, and is the default style for C# code at Google. It makes stylistic choices that conform to other languages at Google, such as Google C++ style and Google Java style.

Formatting guidelines

Naming rules

Naming rules follow Microsoft’s C# naming guidelines. Where Microsoft’s naming guidelines are unspecified (e.g. private and local variables), rules are taken from the CoreFX C# coding guidelines

Rule summary:

Code

Files

Organization

Whitespace rules

Developed from Google Java style.

Example

using System; // `using` goes at the top, outside the // namespace. namespace MyNamespace { // Namespaces are PascalCase. // Indent after namespace. public interface IMyInterface { // Interfaces start with 'I' public int Calculate(float value, float exp); // Methods are PascalCase // ...and space after comma. } public enum MyEnum { // Enumerations are PascalCase. Yes, // Enumerators are PascalCase. No, } public class MyClass { // Classes are PascalCase. public int Foo = 0; // Public member variables are // PascalCase. public bool NoCounting = false; // Field initializers are encouraged. private class Results { public int NumNegativeResults = 0; public int NumPositiveResults = 0; } private Results _results; // Private member variables are // _camelCase. public static int NumTimesCalled = 0; private const int _bar = 100; // const does not affect naming // convention. private int[] _someTable = { // Container initializers use a 2 2, 3, 4, // space indent. } public MyClass() { _results = new Results { NumNegativeResults = 1, // Object initializers use a 2 space NumPositiveResults = 1, // indent. }; } public int CalculateValue(int mulNumber) { // No line break before opening brace. var resultValue = Foo * mulNumber; // Local variables are camelCase. NumTimesCalled++; Foo += _bar; if (!NoCounting) { // No space after unary operator and // space after 'if'. if (resultValue < 0) { // Braces used even when optional and // spaces around comparison operator. _results.NumNegativeResults++; } else if (resultValue > 0) { // No newline between brace and else. _results.NumPositiveResults++; } } return resultValue; } public void ExpressionBodies() { // For simple lambdas, fit on one line if possible, no brackets or braces required. Func<int, int> increment = x => x + 1; // Closing brace aligns with first character on line that includes the opening brace. Func<int, int, long> difference1 = (x, y) => { long diff = (long)x - y; return diff >= 0 ? diff : -diff; }; // If defining after a continuation line break, indent the whole body. Func<int, int, long> difference2 = (x, y) => { long diff = (long)x - y; return diff >= 0 ? diff : -diff; }; // Inline lambda arguments also follow these rules. Prefer a leading newline before // groups of arguments if they include lambdas. CallWithDelegate( (x, y) => { long diff = (long)x - y; return diff >= 0 ? diff : -diff; }); } void DoNothing() {} // Empty blocks may be concise. // If possible, wrap arguments by aligning newlines with the first argument. void AVeryLongFunctionNameThatCausesLineWrappingProblems(int longArgumentName, int p1, int p2) {} // If aligning argument lines with the first argument doesn't fit, or is difficult to // read, wrap all arguments on new lines with a 4 space indent. void AnotherLongFunctionNameThatCausesLineWrappingProblems( int longArgumentName, int longArgumentName2, int longArgumentName3) {} void CallingLongFunctionName() { int veryLongArgumentName = 1234; int shortArg = 1; // If possible, wrap arguments by aligning newlines with the first argument. AnotherLongFunctionNameThatCausesLineWrappingProblems(shortArg, shortArg, veryLongArgumentName); // If aligning argument lines with the first argument doesn't fit, or is difficult to // read, wrap all arguments on new lines with a 4 space indent. AnotherLongFunctionNameThatCausesLineWrappingProblems( veryLongArgumentName, veryLongArgumentName, veryLongArgumentName); } } } 

C# coding guidelines

Constants

IEnumerable vs IList vs IReadOnlyList

Generators vs containers

Property styles

Expression body syntax

For example:

int SomeProperty => _someProperty 

Structs and classes:

Lambdas vs named methods

Field initializers

Extension methods

ref and out

LINQ

Array vs List

Folders and file locations

Use of tuple as a return type

String interpolation vs String.Format() vs String.Concat vs operator+

using

Object Initializer syntax

For example:

var x = new SomeClass { Property1 = value1, Property2 = value2, }; 

Namespace naming

Default values/null returns for structs

Removing from containers while iterating

C# (like many other languages) does not provide an obvious mechanism for removing items from containers while iterating. There are a couple of options:

Calling delegates

The var keyword

Attributes

Argument Naming

Derived from the Google C++ style guide.

When the meaning of a function argument is nonobvious, consider one of the following remedies:

Consider the following example:

// Bad - what are these arguments? DecimalNumber product = CalculateProduct(values, 7, false, null); 

versus:

// Good ProductOptions options = new ProductOptions(); options.PrecisionDecimals = 7; options.UseCache = CacheUsage.DontUseCache; DecimalNumber product = CalculateProduct(values, options, completionDelegate: null);