Google Style Guides

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

Containers: IEnumerable vs IList vs IReadOnlyList

Generators vs containers

Property styles

Expression body syntax

For example:

int SomeProperty => _someProperty
void SomeMethod() => throw new NotImplementedException();

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 method argument is nonobvious, consider one of the following remedies:

Consider the following example:

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

versus:

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

Comments

(Derived from the Google C++ style guide.)

Comments are absolutely vital to keeping our code readable. The following rules describe what you should comment and where. But remember: while comments are very important, the best code is self-documenting. Giving sensible names to types and variables is much better than using obscure names that you must then explain through comments.

When writing your comments, write for your audience: the next person who will need to understand your code. Be generous — the next one may be you!

Class Comments

Every non-obvious class should have an accompanying comment that describes what it is for and how it should be used.

The class comment should provide the reader with enough information to know how and when to use the class, as well as any additional considerations necessary to correctly use the class.

Method Comments

Almost every method should have comments immediately preceding it that describe what the method does and how to use it. These comments may be omitted only if the method is simple and obvious (e.g., simple accessors). Method comments should be written with an implied subject of This method and should start with the verb phrase; for example, “Opens the file”, rather than “Open the file”.

Types of things to mention in comments:

However, do not be unnecessarily verbose or state the completely obvious.

When documenting method overrides, focus on the specifics of the override itself, rather than repeating the comment from the overridden method. In many of these cases, the override needs no additional documentation and thus no comment is required.

When commenting constructors, remember that the person reading your code knows what constructors are for, so comments that just say something like “creates this object” are not useful.

Class Members

The purpose of each class data member must be clear. If there are any invariants (special values, relationships between members, lifetime requirements) not clearly expressed by the type and name, they must be commented. However, if the type and name suffice, no comment is needed.

Variable Comments

In general the actual name of the variable should be descriptive enough to give a good idea of what the variable is used for. In certain cases, more comments are required.

Explanatory Comments

Tricky or complicated code blocks should have comments before them.