.NET Naming Conventions
Pascal case and Camel case
There are several naming conventions to consider when writing code. We use these two practices: PascalCasing
or camelCasing
.
-
Pascal Case
Use pascal casing (“PascalCasing”) when naming a
namespace
,class
,record
, orstruct
. -
Camel Case
Use camel casing (“camelCasing”) when naming
private
orinternal
fields, and prefix them with_
.
Example
public class DataService
{
private IWorkerQueue _workerQueue;
public bool IsValid;
public event Action EventProcessing;
public int Add(int first, int second)
{
return first + second;
}
}
Examples:
Item | Case | Example |
---|---|---|
Namespace | Pascal | System.File.Directory |
Class | Pascal | AppDomain |
Class Exception | Pascal | WebException (suffix Exception ) |
Interface | Pascal | IDisposable (prefix I ) |
Event | Pascal | ValueChange |
Enum Type | Pascal | ErrorLevel |
Enum Value | Pascal | FatalError |
Variable Private | Camel | _lastName (prefix _ ) |
Variable Local | Camel | lastName |
Read Only | Pascal | RedColor |
Constant | UPPER | BLUE |
Method | Pascal | ToString() |
Property | Pascal | BackColor |
Parameter | Camel | typeName |
File organizations
Organize your files in separate folders to respect these rules:
- One class = one file.
- Class name = file name.
- Each namespace into folders with same names.
-
A few dozen lines… otherwise, split into methods or partial classes.
File: C:\Dev\MyCompany\MyProject\Blazor\Foo.cs namespace MyCompany.MyProject.Blazor { public class Foo { } }
Item naming
To avoid confusion and to write clean code, all items created must be defined:
- Explicitly: with understandable names adapted to the field of use. (don’t use
MyVariable
orItem
). - Without abbreviation: to avoid confusion with other developers, other domains. (don’t use
Msg
orPR
). - Without prefix. (don’t use
The
orA
). - In English only.
For Boolean variables and properties, add the prefix
Is
orHas
before the name.
Layout conventions
Good layout uses formatting to emphasize the structure of your code and to make the code easier to read:
-
Use the default Code Editor settings: smart indenting, four-character indents, tabs saved as spaces. For more information, see Options, Text Editor, C#, Formatting.
-
Write only one statement per line.
-
Write only one declaration per line.
-
If continuation lines are not indented automatically, indent them one tab stop (four spaces).
-
Add at least one blank line between method definitions and property definitions… to improve readability.
public class Foo { public int Width { get; set; } public void DoSomething(int width, int height) { int x = width * height; } }
-
Always put brackets on a new line and parentheses at the end of the line (without space).
public class Math { private void Increment() { } }
-
Keep the length of each line under 130 characters. See AV2400.
-
Break long lines after the period sign, like this:
var dto = service.GetEmployees() .Where(i => i.Id > 1000) .OrderBy(i => i.Name) .ToArray()
-
Keep one space between keywords like if and the expression, but don’t add spaces after ( and before ) such as:
if (condition == null)
. -
Add a space around operators like +, -, ==, etc.
var z = x + y;
-
Always put opening and closing curly braces on a new line.
-
Don’t indent object/collection initializers and initialize each property on a new line, so use a format like this:
var dto = new ConsumerDto { Id = 123, Name = "Microsoft", PartnerShip = PartnerShip.Gold, ShoppingCart = new() { VisualStudio = 1, }, };
-
Don’t indent lambda statement blocks and use a format like this:
methodThatTakesAnAction.Do(source => { // do something like this }
-
Keep expression-bodied-members on one line. Break long lines after the arrow sign, like this:
private string GetShortText => "ABC ABC ABC"; private string GetLongText => "ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC";
Postfix asynchronous methods with Async
By convention, methods that return commonly awaitable types (for example, Task
, Task<T>
, ValueTask
, ValueTask<T>
)
should have names that end with “Async”: AV1755
or VSTHRD200.
Example:
async Task DoSomethingAsync()
{
await MyFirstMethodAsync();
await MySecondMethodAsync();
}
bool DoSomethingElse()
{
return false;
}
Eliding Async
and Await
If it’s possible, it is more efficient to elide async
and await
. By not including these keywords, the compiler can skip generating the async state machine. This means that there are fewer compiler-generated types in your assembly, less pressure on the garbage collector, and fewer CPU instructions to execute.
We suggest:
- Do not elide by default. Use the async and await for natural, easy-to-read code.
- Do consider eliding when the method is just a passthrough or overload.
Example:
Task DoSomethingAsync()
{
return MyMethodAsync();
}
More:
- https://blog.stephencleary.com/2016/12/eliding-async-await.html
- https://docs.microsoft.com/en-us/archive/msdn-magazine/2011/october/asynchronous-programming-async-performance-understanding-the-costs-of-async-and-await
Place members in a well-defined order
Maintaining a common order allows other team members to find their way in your code more easily. In general, a source file should be readable from top to bottom, as if reading a book, to prevent readers from having to browse up and down through the code file.
See AV2406
- Private fields and constants
- Public constants
- Public static read-only fields
- Factory methods
- Constructors and the finalizer
- Events
- Public and protected properties
- Other methods and private properties in calling order
Declare local functions at the bottom of their containing method bodies (after all executable code).
Do not use #region
.
Regions require extra work without increasing the quality or the readability of code. Instead they make code harder to view and refactor.
Variables
-
Write only one declaration per line.
-
Use only an explicit name and without abreviation.
-
Use implicit typing for local variables when the type of the variable is obvious from the right side of the assignment, or when the precise type is not important.
var fullname = "Scott Guthrie"; var age = 27;
-
Don’t use var when the type is not apparent from the right side of the assignment. Don’t assume the type is clear from a method name. A variable type is considered clear if it’s a new operator or an explicit cast.
-
Don’t use dynamic.
-
use the correct access modifier (
private
,public
,protected
,internal
) withvirtual
if it’s possible.As proposed in this article, do not provide instance fields that are public or protected. You should provide properties for accessing fields instead of making them public or protected.
-
You can use insignificant name
i, j, k, x, y, z
with local loops or very short lambda expression. -
Initialize your local variables as soon as possible:
var name = string.Empty
. -
⚠️ Use
string.Empty
and not""
to represent an empty string.
Commenting conventions
-
Place the comment on a separate line, not at the end of a line of code.
-
Begin comment text with an uppercase letter.
-
End comment text with a period.
-
Insert one space between the comment delimiter (//) and the comment text, as shown in the following example.
// The following declaration creates a query. It does not run // the query.
-
Don’t create formatted blocks of asterisks around comments.
-
Ensure all public members have the necessary XML comments providing appropriate descriptions about their behavior.
Using and namespace
To respect naming conventions used by other Microsoft Teams (.NET team, AspNetCore Team, …), we decided to use thse rules:
- IDE0065 - Prefer using directives to be placed outside the namespace
- SA1210 - using directives must be sorted alphabetically by namespace
- IDE0161 - Namespace declarations should be file scoped
The last rule (IDE0161) solves the question asked this StackOverflow article.
using using Microsoft.AspNetCore.Components;
using System;
namespace MyNamespace;
public class Foo
{
}
If pattern
Prefer positive conditionals and method names: if (a > b)
is better than if (a !<= b)
.
See https://www.codeproject.com/Articles/1073387/Robert-s-Rules-of-Coders-sharp-Avoid-Negative-Cond
a. Braces
Always use braces with if
statement, including when you have only one line of code.
if (condition)
{
DoSomething();
}
else
{
DoSomethingOther();
}
if (condition)
{
DoSomething();
DoSomething();
...
}
else if (condition)
{
DoSomethingOther();
DoSomethingOther();
...
}
else
{
DoSomethingOtherAgain();
DoSomethingOtherAgain();
...
}
b. No Else Return
You can skip the else block if your if block always executes a return statement.
if (condition)
{
return ReturnSomething();
}
return ReturnSomethingOther();
See https://www.samanthaming.com/tidbits/23-no-else-return
c. Guard pattern
The guard clause is a block of code that is at the begining of the function that returns early, and stop all execution(s),if the statment is met.
if (isSeparated)
{
return null;
}
return ReturnSomething();
See https://refactoring.guru/replace-nested-conditional-with-guard-clauses
String data type
Use string interpolation to concatenate short strings, as shown in the following code.
string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";
To append strings in loops, especially when you’re working with large amounts of text, use a StringBuilder object.
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
{
manyPhrases.Append(phrase);
}
Console.WriteLine($"tra{manyPhrases");
Exception handler
Don’t swallow errors by catching generic exceptions: see AV1210.
Avoid swallowing errors by catching non-specific exceptions, such as Exception
, SystemException
, and so on, in application code. Only in top-level code, such as a last-chance exception handler, you should catch a non-specific exception for logging purposes and a graceful shutdown of the application.
If it’s possible, avoid to use
try ... catch
and prefer checking your data or your environment before to execute an action. For example, useFile.Exists
before to read a file, usemyArray.Length
before to read an item, useInt32.TryParse
before to convert a string.
More detail in this article.
Operators allowed
C# provides a number of operators. Many of them are supported by the built-in types and allow you to perform basic operations with values of those types.
To keep a clean code, use only these operators.
Allowed
- Primary:
x.y, f(x), a[x], x++, x--, new, typeof, default(T)
- Unary:
+, -, !, (T)x, await
- Math:
x * y, x / y, x % y, x + y, x - y
- Testing:
x < y, x > y, x <= y, x >= y, x == y, x != y, is, as
- Conditional:
x && y, x || y, x | y, x ? y : z, x?.y
- Null-coalescing:
x ?? y
- Assignment:
x = y, x += y, x -= y, x => y
Denied
- Primary:
checked, unchecked, sizeof, ->
- Unary:
++x, --x, ~x, &x, *x
- Shift:
x << y, x >> y
- Logical:
x & y, x ^ y
- Assignment:
x *= y, x /= y, x %= y, x &= y, x |= y, x ^= y, x <<= y, x >>= y
Data Convertion
Always use one of these method to convert an item from a datatype to another one:
Convert
class.- Explicit casting via
(...)
. as
operator.$"{x}"
Examples:
var a = Convert.ToString(myVariable);
var b = (string) myVariable;
var c = Convert.ToString(myVariable);
var d = $"{myVariable}"
⚠️ Never to use
.ToString()
to cast an object to a string
Convert.ToString()
handles null, whileToString()
doesn’t.
DateTime
To improve the quality of unit tests, prefer the use of a DateTimeProvider.
Always to use DateTimeProvider (and not DateTime) to allow UnitTest and date mocks.
int trimester = (DateTimeProvider.Today.Month - 1) / 3 + 1;
More details at: https://dvoituron.com/2020/01/22/UnitTest-DateTime
Static
Avoid static classes and static methods. See AV1008 With the exception of extension method containers, static classes very often lead to badly designed code. They are also very difficult, if not impossible, to test in isolation, unless you’re willing to use some very hacky tools.
Note: If you really need that static class, mark it as static so that the compiler can prevent instance members and instantiating your class. This relieves you of creating an explicit private constructor.