| # 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. | |
| <!-- mdformat off --> | |
| * TOC | |
| {:toc} | |
| <!-- mdformat on --> | |
| ## Formatting guidelines | |
| ### Naming rules | |
| Naming rules follow | |
| [Microsoft's C# naming guidelines](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines). | |
| Where Microsoft's naming guidelines are unspecified (e.g. private and local | |
| variables), rules are taken from the | |
| [CoreFX C# coding guidelines](https://github.com/dotnet/runtime/blob/HEAD/docs/coding-guidelines/coding-style.md) | |
| Rule summary: | |
| #### Code | |
| * Names of classes, methods, enumerations, public fields, public properties, | |
| namespaces: `PascalCase`. | |
| * Names of local variables, parameters: `camelCase`. | |
| * Names of private, protected, internal and protected internal fields and | |
| properties: `_camelCase`. | |
| * Naming convention is unaffected by modifiers such as const, static, | |
| readonly, etc. | |
| * For casing, a "word" is anything written without internal spaces, including | |
| acronyms. For example, `MyRpc` instead of ~~`MyRPC`~~. | |
| * Names of interfaces start with `I`, e.g. `IInterface`. | |
| #### Files | |
| * Filenames and directory names are `PascalCase`, e.g. `MyFile.cs`. | |
| * Where possible the file name should be the same as the name of the main | |
| class in the file, e.g. `MyClass.cs`. | |
| * In general, prefer one core class per file. | |
| ### Organization | |
| * Modifiers occur in the following order: `public protected internal private | |
| new abstract virtual override sealed static readonly extern unsafe volatile | |
| async`. | |
| * Namespace `using` declarations go at the top, before any namespaces. `using` | |
| import order is alphabetical, apart from `System` imports which always go | |
| first. | |
| * Class member ordering: | |
| * Group class members in the following order: | |
| * Nested classes, enums, delegates and events. | |
| * Static, const and readonly fields. | |
| * Fields and properties. | |
| * Constructors and finalizers. | |
| * Methods. | |
| * Within each group, elements should be in the following order: | |
| * Public. | |
| * Internal. | |
| * Protected internal. | |
| * Protected. | |
| * Private. | |
| * Where possible, group interface implementations together. | |
| ### Whitespace rules | |
| Developed from Google Java style. | |
| * A maximum of one statement per line. | |
| * A maximum of one assignment per statement. | |
| * Indentation of 2 spaces, no tabs. | |
| * Column limit: 100. | |
| * No line break before opening brace. | |
| * No line break between closing brace and `else`. | |
| * Braces used even when optional. | |
| * Space after `if`/`for`/`while` etc., and after commas. | |
| * No space after an opening parenthesis or before a closing parenthesis. | |
| * No space between a unary operator and its operand. One space between the | |
| operator and each operand of all other operators. | |
| * Line wrapping developed from Google C++ style guidelines, with minor | |
| modifications for compatibility with Microsoft's C# formatting tools: | |
| * In general, line continuations are indented 4 spaces. | |
| * Line breaks with braces (e.g. list initializers, lambdas, object | |
| initializers, etc) do not count as continuations. | |
| * For function definitions and calls, if the arguments do not all fit on | |
| one line they should be broken up onto multiple lines, with each | |
| subsequent line aligned with the first argument. If there is not enough | |
| room for this, arguments may instead be placed on subsequent lines with | |
| a four space indent. The code example below illustrates this. | |
| ### Example | |
| ```c# | |
| 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 | |
| * Variables and fields that can be made `const` should always be made `const`. | |
| * If `const` isn't possible, `readonly` can be a suitable alternative. | |
| * Prefer named constants to magic numbers. | |
| ### Containers: IEnumerable vs IList vs IReadOnlyList | |
| * Declare (input) parameters using a type that grants the fewest capabilities | |
| required by the implementation (eg. `IReadOnlyCollection`). | |
| * Use `IEnumerable` only if the implementation can iterate over the | |
| collection at most once. This indicates that it is safe for the caller | |
| to supply a generator. | |
| * For outputs, if passing ownership of the returned container to the caller, | |
| use the interface type that conveys the maximum capabilities to the caller | |
| without revealing the concrete type. Prefer `IList` over `List`. If not | |
| transferring ownership, prefer the most restrictive, as for inputs. | |
| ### Generators vs containers | |
| * Use your best judgement, bearing in mind: | |
| * Generator code is often less readable than filling in a container. | |
| * Generator code can be more performant if the results are going to be | |
| processed lazily, e.g. when not all the results are needed. | |
| * Generator code that is directly turned into a container via `ToList()` | |
| will be less performant than filling in a container directly. | |
| * Generator code that is called multiple times will be considerably slower | |
| than iterating over a container multiple times. | |
| ### Property styles | |
| * For single line read-only properties, prefer expression body properties | |
| (`=>`) when possible. | |
| * For everything else, use the older `{ get; set; }` syntax. | |
| ### Expression body syntax | |
| For example: | |
| <div class='goodcode'></div> | |
| ```c# | |
| int SomeProperty => _someProperty | |
| ``` | |
| <div class='goodcode'></div> | |
| ```c# | |
| void SomeMethod() => throw new NotImplementedException(); | |
| ``` | |
| * Judiciously use expression body syntax in lambdas and properties. | |
| * For method definitions, prefer using expression body syntax only for | |
| single-statement methods - e.g. forwarding to delegates or throwing | |
| exceptions. | |
| * As with methods and other scoped blocks of code, align the closing with the | |
| first character of the line that includes the opening brace. See sample code | |
| for examples. | |
| ### Structs and classes: | |
| * Structs are very different from classes: | |
| * Structs are always passed and returned by value. | |
| * Assigning a value to a member of a returned struct doesn’t modify the | |
| original - e.g. `transform.position.x = 10` doesn’t set the transform’s | |
| position.x to 10; `position` here is a property that returns a `Vector3` | |
| by value, so this just sets the x parameter of a copy of the original. | |
| * Almost always use a class. | |
| * Consider struct when the type can be treated like other value types - for | |
| example, if instances of the type are small and commonly short-lived or are | |
| commonly embedded in other objects. Good examples include Vector3, | |
| Quaternion and Bounds. | |
| * Note that this guidance may vary from team to team where, for example, | |
| performance issues might force the use of structs. | |
| ### Lambdas vs named methods | |
| * If a lambda is non-trivial (e.g. more than a couple of statements, excluding | |
| declarations), or is reused in multiple places, it should probably be a | |
| named method. | |
| ### Field initializers | |
| * Field initializers are generally encouraged. | |
| ### Extension methods | |
| * Only use an extension method when the source of the original class is not | |
| available, or else when changing the source is not feasible. | |
| * Only use an extension method if the functionality being added is a ‘core’ | |
| general feature that would be appropriate to add to the source of the | |
| original class. | |
| * Note - if we have the source to the class being extended, and the | |
| maintainer of the original class does not want to add the method, prefer | |
| not using an extension method. | |
| * Only put extension methods into core libraries that are available | |
| everywhere - extensions that are only available in some code will become a | |
| readability issue. | |
| * Be aware that using extension methods always obfuscates the code, so err on | |
| the side of not adding them. | |
| ### ref and out | |
| * Use `out` for additional returns that are not also inputs. | |
| * Place `out` parameters after all other parameters in the method definition. | |
| * `ref` should be used rarely, when mutating an input is necessary. | |
| * Do not use `ref` as an optimisation for passing structs. | |
| * Do not use `ref` to pass a modifiable container into a method. `ref` is only | |
| required when the supplied container needs be replaced with an entirely | |
| different container instance. | |
| ### LINQ | |
| * In general, prefer single line LINQ calls and imperative code, rather than | |
| long chains of LINQ. Mixing imperative code and heavily chained LINQ is | |
| often hard to read. | |
| * Prefer member extension methods over SQL-style LINQ keywords - e.g. prefer | |
| `myList.Where(x)` to `myList where x`. | |
| * Avoid `Container.ForEach(...)` for anything longer than a single statement. | |
| ### Array vs List | |
| * In general, prefer `List<>` over arrays for public variables, properties, | |
| and return types (keeping in mind the guidance on `IList` / `IEnumerable` / | |
| `IReadOnlyList` above). | |
| * Prefer `List<>` when the size of the container can change. | |
| * Prefer arrays when the size of the container is fixed and known at | |
| construction time. | |
| * Prefer array for multidimensional arrays. | |
| * Note: | |
| * array and `List<>` both represent linear, contiguous containers. | |
| * Similar to C++ arrays vs `std::vector`, arrays are of fixed capacity, | |
| whereas `List<>` can be added to. | |
| * In some cases arrays are more performant, but in general `List<>` is | |
| more flexible. | |
| ### Folders and file locations | |
| * Be consistent with the project. | |
| * Prefer a flat structure where possible. | |
| ### Use of tuple as a return type | |
| * In general, prefer a named class type over `Tuple<>`, particularly when | |
| returning complex types. | |
| ### String interpolation vs `String.Format()` vs `String.Concat` vs `operator+` | |
| * In general, use whatever is easiest to read, particularly for logging and | |
| assert messages. | |
| * Be aware that chained `operator+` concatenations will be slower and cause | |
| significant memory churn. | |
| * If performance is a concern, `StringBuilder` will be faster for multiple | |
| string concatenations. | |
| ### `using` | |
| * Generally, don’t alias long typenames with `using`. Often this is a sign | |
| that a `Tuple<>` needs to be turned into a class. | |
| * e.g. `using RecordList = List<Tuple<int, float>>` should probably be a | |
| named class instead. | |
| * Be aware that `using` statements are only file scoped and so of limited use. | |
| Type aliases will not be available for external users. | |
| ### Object Initializer syntax | |
| For example: | |
| <div class='goodcode'></div> | |
| ```c# | |
| var x = new SomeClass { | |
| Property1 = value1, | |
| Property2 = value2, | |
| }; | |
| ``` | |
| * Object Initializer Syntax is fine for ‘plain old data’ types. | |
| * Avoid using this syntax for classes or structs with constructors. | |
| * If splitting across multiple lines, indent one block level. | |
| ### Namespace naming | |
| * In general, namespaces should be no more than 2 levels deep. | |
| * Don't force file/folder layout to match namespaces. | |
| * For shared library/module code, use namespaces. For leaf 'application' code, | |
| such as `unity_app`, namespaces are not necessary. | |
| * New top-level namespace names must be globally unique and recognizable. | |
| ### Default values/null returns for structs | |
| * Prefer returning a ‘success’ boolean value and a struct `out` value. | |
| * Where performance isn't a concern and the resulting code significantly more | |
| readable (e.g. chained null conditional operators vs deeply nested if | |
| statements) nullable structs are acceptable. | |
| * Notes: | |
| * Nullable structs are convenient, but reinforce the general ‘null is | |
| failure’ pattern Google prefers to avoid. We will investigate a | |
| `StatusOr` equivalent in the future, if there is enough demand. | |
| ### 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: | |
| * If all that is required is to remove items that satisfy some condition, | |
| `someList.RemoveAll(somePredicate)` is recommended. | |
| * If other work needs to be done in the iteration, `RemoveAll` may not be | |
| sufficient. A common alternative pattern is to create a new container | |
| outside of the loop, insert items to keep in the new container, and swap the | |
| original container with the new one at the end of iteration. | |
| ### Calling delegates | |
| * When calling a delegate, use `Invoke()` and use the null conditional | |
| operator - e.g. `SomeDelegate?.Invoke()`. This clearly marks the call at the | |
| callsite as ‘a delegate that is being called’. The null check is concise and | |
| robust against threading race conditions. | |
| ### The `var` keyword | |
| * Use of `var` is encouraged if it aids readability by avoiding type names | |
| that are noisy, obvious, or unimportant. | |
| * Encouraged: | |
| * When the type is obvious - e.g. `var apple = new Apple();`, or | |
| `var request = Factory.Create<HttpRequest>();` | |
| * For transient variables that are only passed directly to other methods - | |
| e.g. `var item = GetItem(); ProcessItem(item);` | |
| * Discouraged: | |
| * When working with basic types - e.g. `var success = true;` | |
| * When working with compiler-resolved built-in numeric types - e.g. | |
| `var number = 12 * ReturnsFloat();` | |
| * When users would clearly benefit from knowing the type - e.g. | |
| `var listOfItems = GetList();` | |
| ### Attributes | |
| * Attributes should appear on the line above the field, property, or method | |
| they are associated with, separated from the member by a newline. | |
| * Multiple attributes should be separated by newlines. This allows for easier | |
| adding and removing of attributes, and ensures each attribute is easy to | |
| search for. | |
| ### Argument Naming | |
| Derived from the | |
| [Google C++ style guide](https://google.github.io/styleguide/cppguide.html#Function_Argument_Comments). | |
| When the meaning of a method argument is nonobvious, consider one of the | |
| following remedies: | |
| * If the argument is a literal constant, and the same constant is used in | |
| multiple method calls in a way that tacitly assumes they're the same, use a | |
| named constant to make that constraint explicit, and to guarantee that it | |
| holds. | |
| * Consider changing the method signature to replace a `bool` argument with an | |
| `enum` argument. This will make the argument values self-describing. | |
| * Replace large or complex nested expressions with named variables. | |
| * Consider using | |
| [Named Arguments](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments) | |
| to clarify argument meanings at the call site. | |
| * For methods that have several configuration options, consider defining a | |
| single class or struct to hold all the options and pass an instance of that. | |
| This approach has several advantages. Options are referenced by name at the | |
| call site, which clarifies their meaning. It also reduces method argument | |
| count, which makes method calls easier to read and write. As an added | |
| benefit, call sites don't need to be changed when another option is added. | |
| Consider the following example: | |
| <div class='badcode'></div> | |
| ```c# | |
| // What are these arguments? | |
| DecimalNumber product = CalculateProduct(values, 7, false, null); | |
| ``` | |
| versus: | |
| <div class='goodcode'></div> | |
| ```c# | |
| 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: | |
| * What the inputs and outputs are. If method argument names are provided in | |
| `backticks`, then code-indexing tools may be able to present the | |
| documentation better. | |
| * Whether the object remembers arguments beyond the duration of the method | |
| call. | |
| * Whether any of the arguments can be null. | |
| * If there are any performance implications of how a method is used. | |
| 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. | |
| [Google C++ style guide]: https://google.github.io/styleguide/cppguide.html#Comments |