The goal of this article is to define guidelines to enforce consistent style and formatting and help C# developers to avoid common pitfalls and mistakes.
The purpose of coding conventions:
- They create a consistent look to the code, so that readers can focus on content, not layout.
- They enable readers to understand the code more quickly by making assumptions based on previous experience.
- They facilitate copying, changing, and maintaining the code.
- They demonstrate C# best practices.
Terminology & Definitions
- Camel Case: A word with the first letter lowercase, and the first letter of each subsequent word-part capitalized. (Example: customerName)
- Pascal Case: A word with the first letter capitalized, and the first letter of each subsequent word-part capitalized. (Example: CustomerName)
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.
- Use parentheses to make clauses in an expression apparent, as shown in the following code.
if ((val1 > val2) && (val1 > val3)) { // Take appropriate action. }
Formatting
- Never declare more than 1 namespace per file.
- Avoid putting multiple classes in a single file.
- Always place curly braces
{
and}
on a new line. - Always use curly braces
{
and}
in conditional statements. - Always use a Tab & Indention size of 4.
- Declare each variable independently – not in the same statement.
- Place namespace
using
statements together at the top of file. Group .NET namespaces above custom namespaces. - Segregate interface Implementation by using
#region
statements. - Recursively indent all code blocks contained within braces.
- Only declare related attribute declarations on a single line, otherwise stack each attribute as a separate declaration.
Code Commenting
- 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.
- Do not create formatted blocks of asterisks around comments.
- All comments should be written in the same language, be grammatically correct, and contain appropriate punctuation.
- Use inline-comments to explain assumptions, known issues, and algorithm insights.
- Do not use inline-comments to explain obvious code. Well written code is self documenting.
- Always apply C# comment-blocks (///) to public, protected, and internal declarations.
- Only use C# comment-blocks for documenting the API.
- Always include
<summary>
comments. Include<param>
,<return>
, and<exception>
comment sections where applicable. - Include
<see cref=""/>
and<seeAlso cref=""/>
where possible
Language Usage
String Data Type
- Use string interpolation to concatenate short strings.
- To append strings in loops, especially when you are working with large amounts of text, use a
StringBuilder
object.
Implicitly Typed Local Variables
- 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.
// When the type of a variable is clear from the context, use var // in the declaration. var var1 = "This is clearly a string."; var var2 = 27; var var3 = Convert.ToInt32(Console.ReadLine());
- Do not use
var
when the type is not apparent from the right side of the assignment.
// When the type of a variable is not clear from the context, use an // explicit type. int var4 = ExampleClass.ResultSoFar();
- Do not rely on the variable name to specify the type of the variable. It might not be correct.
// Naming the following variable inputInt is misleading. // It is a string. var inputInt = Console.ReadLine(); Console.WriteLine(inputInt);
- Avoid the use of
var
in place ofdynamic
.
- Use implicit typing
var
to determine the type of the loop variable infor
andforeach
loops.
The following example uses implicit typing in a for
statement.
var syllable = "ha"; var laugh = ""; for (var i = 0; i < 10; i++) { laugh += syllable; Console.WriteLine(laugh); }
The following example uses implicit typing in a foreach
statement.
foreach (var ch in laugh) { if (ch == 'h') Console.Write("H"); else Console.Write(ch); } Console.WriteLine();
New Operator
- Use the concise form of object instantiation, with implicit typing, as shown in the following declaration.
var instance1 = new ExampleClass();
The previous line is equivalent to the following declaration.
ExampleClass instance2 = new ExampleClass();
- Use object initializers to simplify object creation.
// Object initializer. var instance3 = new ExampleClass { Name = "Desktop", ID = 37414, Location = "Redmond", Age = 2.3 }; // Default constructor and assignment statements. var instance4 = new ExampleClass(); instance4.Name = "Desktop"; instance4.ID = 37414; instance4.Location = "Redmond"; instance4.Age = 2.3;
Static Members
- Call
static
members by using the class name:ClassName.StaticMember
. This practice makes code more readable by making static access clear. Do not qualify a static member defined in a base class with the name of a derived class. While that code compiles, the code readability is misleading, and the code may break in the future if you add a static member with the same name to the derived class.
Variables & Types
- Try to initialize variables where you declare them.
- Always choose the simplest data type, list, or object required
- Declare
readonly
orstatic readonly
variables instead of constants for complex types. - Only declare constants for simple types.
- Only declare member variables as
private
. Use properties to provide access to them withpublic
,protected
, orinternal
access modifiers. - Only use
long
for variables potentially containing values too large for anint
. - Try to use
double
for fractional numbers to ensure decimal precision in calculations. - Only use
float
for fractional numbers that will not fitdouble
ordecimal
. - Avoid using
float
unless you fully understand the implications upon any calculations. - Avoid boxing and unboxing value types.
- Prefer
String.Format()
orStringBuilder
over string concatenation. - Never concatenate strings inside a loop.
- Do not compare strings to
String.Empty
or""
to check for empty strings. Instead, compare by usingString.Length == 0
.
Exception Handling
- Do not use exceptions for flow control.
- Use
throw;
notthrow e;
when re-throwing. - Only
catch
exceptions that you can handle. - Use validation to avoid exceptions.
- Never declare an empty
catch
block. - Avoid nesting a
try/catch
within acatch
block. - Only use the
finally
block to release resources from a try statement. - Derive from
Exception
notApplicationException
.
Naming Conventions
General Guidelines
- Always use Camel Case or Pascal Case names.
- Never prefix with
Get
orSet
properties. - Use a maximum of 7 parameters in methods.
- Always check for
null
before invoking Events. - Avoid evaluating Boolean conditions against
true
orfalse
. - Avoid ALL CAPS and all lowercase names. Single lowercase words or letters are acceptable.
- Variables and Properties should describe an entity not the type or size.
- Do not use names that begin with a numeric character.
- Avoid adding redundant or meaningless prefixes and suffixes to identifiers.
- Do not use Hungarian Notation.
- Variables and Properties should describe an entity not the type or size.
- Any Abbreviations must be widely known and accepted.
- Avoid using abbreviations unless the full name is excessive.
- Avoid abbreviations longer than 5 characters.
- Do not use C# reserved words as names.
- Avoid naming conflicts with existing .NET Framework namespaces, or types.
- Do not include the parent class name within a property name. Example: Customer.Name NOT Customer.CustomerName
- Avoid adding redundant or meaningless prefixes and suffixes to identifiers.
- Try to prefix Boolean variables and properties with "Can", "Is" or "Has".
- Append computational qualifiers to variable names like Average, Count, Sum, Min, and Max where appropriate.
- When defining a root namespace, use a Product, Company, or Developer Name as the root. Example: LanceHunt.StringUtilities
The naming guidelines for using properties, events, methods, naming types, constructors, fields, and parameters in class libraries.
Type | Rule | Naming Guidelines |
---|---|---|
Local Variable | camelCase |
The following rules outline the naming guidelines for local field:
|
Private Field | _camelCase |
The following rules outline the naming guidelines for private field:
|
Public Field | PascalCase |
The following rules outline the naming guidelines for public field:
|
Protected Field | PascalCase |
The following rules outline the naming guidelines for protected field:
|
Internal Field | PascalCase |
The following rules outline the naming guidelines for internal field:
|
Constants | UpperCase |
The following rules outline the naming guidelines for constants:
|
Property | PascalCase |
The following rules outline the naming guidelines for properties:
|
Method | PascalCase |
The following rules outline the naming guidelines for methods:
|
Classes and Structs | PascalCase |
The following rules outline the naming guidelines for classes:
|
Interface | IPascalCase |
The following rules outline the naming guidelines for interfaces:
|
Parameter | camelCase |
The following rules outline the naming guidelines for parameters:
|
Namespaces | PascalCase |
The following rules outline the naming guidelines for namespaces:
|
No comments:
Post a Comment