In general, follow the Microsoft C# Coding Guidelines described in the following links:
- https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines
- https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/identifier-names
- https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions
The following guidelines supersede the Microsoft C# Coding Guidelines, and should be used.
Use type inference (var) wherever possible. This can improve readability and ease of refactoring.
A Controller method with return type IActionResult, may return an OkObjectResult. If the method returns with
Ok(<something>), the type of <something> is specified in
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(<type>))]but nowhere is that type enforced.
If <type> is (e.g.), string, considering using something like
string thingId = _service.Update(thing);
return Ok(thingId);Using string thingId instead of var thingId is a guard in case the return type of Update changes.
If the type is otherwise inferred, prefer [] over (e.g.) new List<string>() or new Dictionary<string, int>(), for
the sake of concision.
Add braces to one-line if statements;
// Yes:
if (isEmpty)
{
callFun();
}
// No:
if (isEmpty)
callFun();Avoiding braces can cause developers to miss bugs, such as Apple's infamous goto-fail bug
As an example, to loop 0, 1, 2, 3:
// Yes:
using static System.Linq.Enumerable;
foreach (var i in Range(0, 4))
// No:
for (var i = 0; i < 4; i++)The signature of Range is:
Range (int start, int count);Another example that loops 1, 2, 3:
// Yes:
using static System.Linq.Enumerable;
foreach (var i in Range(1, 3))
// No:
for (var i = 1; i < 4; i++)- Only need to mention loop variable (e.g.
i) once - Remove some error-prone boilerplate (
i++) - Remove the possibility of incrementing the wrong value (e.g. incrementing
iinstead ofjin an inner loop) - Express clearly the intent
var str = "Am I empty?";
// Yes
if (string.IsNullOrEmpty(str))
if (!string.IsNullOrEmpty(str))
// No
if (str == "")
if (str != string.Empty)
if (str.Equals(""))Uniform style, and still works if variable being checked becomes nullable.
Prefer asserts with Is.InstanceOf over Is.TypeOf to allow for inheritance, unless the specific type is needed.
If you want to make sure an async method finishes but don't need what it returns, use .Wait() rather than assigning it
to an unused _ variable.
In async tests, prefer await over either of the above.
Prefer Assert.That(..., Is.Not.Null) over using ? or !.
var nullableObj = getObjOrNull();
// Yes
Assert.That(nullableObj, Is.Not.Null);
Assert.That(nullableObj.Id, Is.EqualTo(expectedId));
// No
Assert.That(nullableObj?.Id, Is.EqualTo(expectedId));
// No
Assert.That(nullableObj!.Id, Is.EqualTo(expectedId));Clear assert failure, rather than error, if thing is unexpected null.
When type casting is necessary on something that might be null, use soft cast together with a non-null assertion.
// Yes
var nullableWord = getWordOrNull() as Word;
Assert.That(nullableWord, Is.Not.Null);
Assert.That(nullableWord.Id, Is.EqualTo(expectedId));
// No
var nullableWord = (Word)getWordOrNull();
Assert.That(nullableWord.Id, Is.EqualTo(expectedId));
// No
var nullableWord = getWordOrNull();
Assert.That(nullableWord, Is.InstanceOf<Word>());
Assert.That(((Word)nullableWord).Id, Is.EqualTo(expectedId));Clear assert failure if thing is unexpectedly null, and only have to specify the type once.