Skip to main content

C#

We use the dotnet-format tool to format our C# code. Run it as follows:

dotnet format

However, since it’s fairly rudimentary we also follow some additional code styling guidelines.

We try to follow C# community standards (with a few exceptions). Review the following articles for a general overview.

  1. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions
  2. https://stackoverflow.com/a/310967/1090359

Private fields​

Private fields should be camelCased and prefixed with _.

Example:

private readonly IUserService _userService;

See the following article on how to configure Visual Studio code generation shortcuts to assist with this naming convention: https://stackoverflow.com/q/45736659/1090359

Public properties​

  • Properties should be PascalCased and not have a prefix
  • Properties should be spelled out and not use abbreviations or rely on brevity, e.g. "OrganizationConfiguration" (good) vs. "OrgConfig" (bad)
  • Properties should include blank line between the group of properties and the methods below

Whitespace​

  • We use spaces (not tabs) for all code-files, including C#. Indentations should be a standard 4 spaces.
  • Code files should end with a newline after the final }
  • Blank lines should separate each group of code composition types (fields, constructors, properties, public methods, private methods, sub-classes)

Constructors​

  • Multiple constructors should be separated by a newline (empty line between)
  • Constructors with multiple arguments should have 1 argument listed per line
  • Empty constructors, when necessary, should be all 1-line, i.e., public ClassName() { }

Control Blocks​

  • Control blocks should always use curly braces (even 1-line braces)
  • using and foreach blocks should declare contextual variables with var
  • Always include a space after the control keyword and the ()

Conditionals​

Long conditionals should use trailing operators when separated across multiple lines.

// Good example
if (someBooleanExpression &&
someVariable != null &&
someVariable.IsTrue)
{
}

// Bad examples (don't do)
if (someBooleanExpression
&& someVariable != null
&& someVariable.IsTrue)
{
}
// Too long, separate
if (someBooleanExpression && someVariable != null && someVariable.IsTrue)
{
}

Nullable Reference Types​

Nullable reference types can be used to make safer code.

Null forgiving operator​

It may sometimes be needed to assert to the compiler that you know something is not null even when it thinks it might be - to do that you can use the ! operator. You may want to do this for properties that you know are populated elsewhere; for example:

public class User
{
public string Email { get; set; }
}

the compiler will complain that Email isn't guaranteed to be non-null but since we know that the database enforces this column as non-null. One way to fix this is to add a = null! after the property. Another option will be to use the required modifier after the access modifier.

required modifier​

The required modifier can be nice to place on properties that are required to have a value during construction but you don't want to include it in the constructor. The compiler ensures that those properties are always set and will therefore not warn about a possible null reference.

required modifier vs [Required] attribute​

When using the required modifier it's important to understand the difference between it and how it affects model binding and validation. Read more.

Null attributes​

There are a suite of attributes that help inform the compiler about the null-state for your code.

Debug.Assert​

Another thing to help the compiler with null state awareness is Debug.Assert. You can use it to place a null check that as long as business rules haven't changed will always be true. For example you might have an assertion like Debug.Assert(user.IsVerified) in a part of the app that only expects verified users. Debug.Assert works by using one of the aforementioned attributes [DoesNotReturnIf(false)] to make it work in case you want to implement your own assertion.