CS Coding Standards Full
CS Coding Standards Full
CS Coding Standards Full
C# Coding Standards
Distribution List:
Dallas Kidd
Alistair McElligot
James Mah
Stephen Lum
AHF Development Team
Document Acceptance:
An original document carries original signatures on this page. Photocopies may be out
of date. Please refer to the Project Office Manager for the latest version.
Table of Contents
1 Introduction
1.1 Background
1.2 Document Purpose
1.3 Scope
1.4 Document Structure
1.5 Document Key
1.6 References
2 File Organisation
2.1 Solution Files
2.2 Project Files
2.3 C# Source Files
2.4 Using Directive
2.5 Directory Layout
3 Layout
3.1 Objectives of Good Layout
3.2 Braces and Parentheses
3.3 Indentation
3.4 Spaces
3.5 Line Length
3.6 Line Breaks and Long Statements
3.7 Line Spacing or Grouping
3.8 Laying Out Classes and Interfaces
3.9 Using Regions
3.10 Laying Out Comments
4 Naming Conventions
4.1 Capitalisation Styles
4.2 Naming Guidelines
5 Declarations
5.1 Number per Line
5.2 Initialisation
5.3 Placement
5.4 Attributes
6 Statements
6.1 Simple Statements
6.2 Return Statements
6.3 Break Statements
6.4 If, if-else, if else-if Statements
6.5 For / Foreach Statements
6.6 While/do-while Statements
6.7 Switch Statements
6.8 Try-catch statements
6.9 Properties and Indexers
Annexes
C Change History
1 Introduction
1.1 Background
Coding standards promote consistency with arbitrary decisions such as indentation width or
how to format a comment. This consistency frees the developer from having to make these
decisions (often differently to any other developer on a given project) in every case.
Coding standards also help promote readability in programs. Readability has a positive
affective on the following aspects of a program:
a) Comprehensibility
b) Reviewability
c) Error rate
d) Debugging
e) Modifiability
f) Development time
g) External quality
1.3 Scope
This document is limited to discussing C# coding style and standards. It does not address
architectural or design standards relating to C# programs. See
http://vsp/trac/val/wiki/ApplicationDesignStandards for the most current document
addressing design standards.
Symbol Description
→ Tab character
▫ Space character
[<stuff>] <stuff> is optional
<stuff> <stuff> is mandatory
1.5.2 Conventions
Conventions used throughout this document:
Courier New will be used to represent code
1.6 References
EXPERT03 - Coding Standards and Guidelines for Visual C# .Net (Infosys).
KRÜGER 03 - C# Coding Style Guide for ICSharp by Mike Krüger.
MCCONNELL04 Code Complete Second Edition by Steve McConnell
ROBERTS05 - Article on How to setup a .Net Development Tree by Mike Roberts.
FOWLER99 – Refactoring: Improving the Design of Existing Code by Martin Fowler.
2 File Organisation
2.1 Solution Files
All solution files for a project are to reside in the following folder:
<SourceControlRoot>\<ProjectRoot>\Source\SolutionFolder\<SolutionFileName>
Where:
a) SourceControlRoot is the root folder for your source control package. Eg SvnRoot for
the Subversion root or VSSRoot for the Visual Source Safe root.
b) ProjectRoot is the root folder for your project. Under this will also be your
documentation, tools used on the project etc.
c) Source\SolutionFolder is always used as your Solution root folder. There will be a
solution per unit of unrelated functionality. For example, one folder may contain the
database solution while the other contains the application solution. This structure will
be defined per project by the technical lead.
d) SolutionFileName is the name of your solution file name. At a very minimum all
projects will have a solution file called [ProjectName]Master.sln (Master.sln is also
fine). This solution file will contain all .Net projects including setup and deployment
projects. If the solution has enough projects, smaller sub-solutions can be created that
only included the co-dependant projects.
b) Third-party namespaces
c) Vero Common or Application Library namespaces
d) Project-specific namespaces
Use a blank between each of these groups. This setting can be set within Resharper allowing
the reformatting option to do this for you. See Standard Resharper Settings for information
on configuring your Resharper environment.
3 Layout
3.1 Objectives of Good Layout
A good layout scheme should achieve the following:
a) Accurately represent the logical structure of the code.
b) Consistently represent the logical structure of the code.
c) Improve readability.
d) Withstand modifications. That is modifying one line of code shouldn’t require modifying
several others.
Much of the layout specified in this section can be configured within Resharper so that the
code reformatting command can implement these standards automatically. See Annex A for
information on Visual Studio settings.
class Sample
{
int _duration;
int _count;
else
{
_duration = 0;
}
}
}
3.3 Indentation
Your indentation width and character (that is a tab or spaces) can be set using Visual Studio.
When indenting:
a) Do not use tabs for indentation. Set your tab size to 4 spaces (from this point in the
document “tab” refers to the four spaces generated by your editor when hitting the tab
key). The reasons are as follows:
i) Spaces always make the code appear the same way; whether you view the
code within Visual Studio or Notepad (Notepad has a tab size set to 8 spaces).
ii) Tabs do not align neatly under function call parameter lists. You end up
needing a combination of tabs and spaces. This leads to differences in
appearance when viewed in a different editor or on a developer environment
with a different tab size setting.
b) Do not indent namespace definitions.
c) Indent class definitions one tab from the left margin.
d) Indent methods and properties one tab from the left of the current class definition.
e) Indent region directives at the same indentation level as the encapsulated region.
Example:
namespace Vero.Sample
{
class SampleClass
{
#region Constructors
public SampleClass()
{
// Initialise something
}
#endregion
3.4 Spaces
Apply the following when using spaces:
a) Follow a key word with a space where a conditional-expression follows the key word.
This helps to distinguish keywords from method calls.
For example:
while ( condition )
{
// do stuff
...
}
b) Separate all binary operators except “.” from their operands by a single space. Do not
use a space to separate unary operators.
c) A single space should appear directly after a comma in an argument list. There should
be no space before the comma.
a += c + d;
a = ( a + b ) / ( c * d );
Instead of:
Or instead of:
Or instead of:
Instead of:
{
// Comment describing the first statement
CodeStatementZero;
CodeStatementOne;
4 Naming Conventions
4.1 Capitalisation Styles
4.1.1 Pascal Casing
This convention capitalises the first character or each word (as in ClassName).
4.1.2 Camel Casing
This convention capitalises the first character of each word except the first one (as in
parameterName).
4.1.3 Upper Case
Use upper case in the following scenarios:
a) Where an identifier consists of an abbreviation which is one or two characters long.
Abbreviated identifiers with three or more characters should use Pascal Casing.
b) Any constant identifier that is not part of an enumeration or class with ONLY public
static constants should use ALL_CAPS. This helps distinguish the constant in code.
4.1.4 Capitalisation Table
Apply the guidelines in the following table when capitalising program elements
Type Case Notes
Class / Struct Pascal Casing
Interface Pascal Casing Use a prefix of “I”
Enum Values Pascal Casing
Enum Type Pascal Casing
Events Pascal Casing
Exception Pascal Casing Use a “Exception” suffix
Class
Public Fields Pascal Casing Should only exist in data only classes or
Structs.
Methods Pascal Casing
Namespace Pascal Casing
Property Pascal Casing
Protected Camel Casing Reference within methods using “this.”
Fields
Private Fields Camel Casing Use a prefix of “_”
Parameters Camel Casing
For example:
System.Windows.Forms.Button _cancelButton;
System.Windows.Forms.TextBox _nameTextBox;
j += i;
}
}
Indexer variables should generally be called i, j, k etc. But in cases like this, it may make
sense to reconsider this rule. In general when the same counters or indexers are reused,
give them meaningful names.
5 Declarations
5.1 Number per Line
Use only one declaration per line for the following reasons:
a) It’s easier to put a comment next to each declaration. Note a better variable name is
preferable to a variable that requires an explanatory comment.
b) It’s easier to modify declarations because each declaration is self contained.
c) It’s easier to find variables because it’s easier to scan a column than it is to scan a
line.
d) It’s easier to find and fix syntax errors because the line number the compiler gives you
has only one declaration on it.
5.2 Initialisation
Initialise all local variables where they are declared.
Initialise class instance fields in constructor code. If the instance field has a public setter
property, use the property’s set method to initialise the value. This guarantees only a single
point where that instance field is altered.
If you are initialising any object that implements System.IDisposable, try the using
statement:
5.3 Placement
Declare each variable as close as possible to where it’s first used for the following reasons:
a) This reduces the “average span” of a variable. Span is the number of lines between
references to a variable. Average span is the average of all such references. By
reducing average span you enable the reader of your code to focus on a single section
of the code at a time. You also reduce the window of vulnerability. That is the
opportunity for subsequent developers to inadvertently change the variable to an
unexpected value.
b) It also reduces the “live time” of a variable. Live time is similar to span except the
number is calculated as the number of lines between the first reference and the last
reference regardless of the number of times it is used in between. Reduced live time
reduces the window of vulnerability; it also allows a developer to show all references
to a variable on the screen at the same time making the code more readable. See ref
MCCONNELL04 Section 10.4 for more detail this and the previous point.
c) This facilitates refactoring code into smaller routines when necessary. This is achieved
in Resharper by highlighting the code and selecting Refactor | Extract Method from
the shortcut menu. If the variables where declared in a block at the top of the method
this would not be done easily.
Avoid local declarations that hide declarations at a higher level.
Example:
int count;
...
MyMethod()
{
if ( condition )
{
int count = 0; // Avoid!
...
}
...
}
5.4 Attributes
Align an attribute with the type or member it applies to. Place the attribute above in all
cases. For example:
6 Statements
6.1 Simple Statements
Each line should contain at most one statement, for example:
lineCount++; // Correct
pageCount++; // Correct
lineCount++; pageCount++; // Avoid!!
return;
return myDisk.Size();
return ( ( size > 0 ) ? size : DEFAULT_SIZE );
Use only one return statement at the end of the method if possible. Otherwise clearly
identify the other return statement with comments.
Example:
If ( param == null )
{
// EARLY RETURN – bad parameters
return null;
}
if ( condition )
{
StatementOrStatements;
}
if ( condition )
{
StatementOrStatements;
}
else
{
StatementOrStatements;
}
if ( condition )
{
StatementOrStatements;
}
else if
{
StatementOrStatements;
}
else
{
StatementOrStatements;
}
Generally, in conditional expressions, put constants on the right side of the relation. Putting
them on the left was a handy standard for C and C++ standards because the languages
allowed you to make an assignment within a conditional expression (this always evaluates as
true). Since C# does not allow this, the more naturally readable standard now applies.
Example:
// for statement
for ( initialisation; condition; update )
{
StatementOrStatements;
}
// foreach statement
foreach ( int k in MyList )
{
StatementOrStatements;
}
while ( condition )
{
StatementOrStatements;
}
while ( condition )
{
}
do
{
StatementOrStatements;
} while ( condition );
switch ( condition )
{
case A:
statements;
break;
case B:
statements;
break;
default:
statements;
break;
}
// Simple try-catch
try
{
StatementOrStatements;
}
catch ( ExceptionClass e ) // Only declare e if it is used!
{
StatementOrStatements;
}
// Try-catch-finally
try
{
StatementOrStatements;
}
catch ( ExceptionClass e ) // Only declare e if it is used!
{
StatementOrStatements;
}
finally
{
StatementOrStatements;
}
7 Comments
Comments come in a number of different forms as outlined in the following sections.
/// <summary>
/// <para>
/// Adds a new instance of an <see cref="DB2Parameter"/> object
/// to the command set as <see cref="ParameterDirection"/> value of
/// Input.
/// </para>
/// </summary>
/// <param name="name">
/// <para>The name of the parameter.</para>
/// </param>
/// <param name="dbType">
/// <para>One of the <see cref="DbType"/> values.</para>
/// </param>
/// <remarks>
C#_Coding_Standards_CH07.doc CONFIDENTIAL Version 0.1 (DRAFT)
Standards and Procedures Chapter 7 - Page 2 of 5
C# Coding Standards
/// <para>
/// This version of the method is used when you can have the same parameter
/// object multiple times with different values.
/// </para>
/// </remarks>
public override void AddInParameter( string name, DbType dbType )
{
...
• http://ndoc.sourceforge.net/
The tags can be set using the Tools | Options menu and selecting Environment | Task
List:
The tokens in the screen shot are self explanatory. If adding new tokens they must be
agreed upon by the entire project, so the build results in the same Task List entries for all
developers.
Comment token tasks are not shown by default in the Task List after a build. To enable task
list generation, right click in the task list and select Show Tasks | All.
/*****************************************************************************************
*
* Description : <Declaration Description>
*
*
* Configuration Record
*
* Review Version Author Date Chg No.
* 000 1.0 <Developer name> <Date> <Change No>
*
*****************************************************************************************
*
* History
*
* Version Description
* 1.0 Original
*
****************************************************************************************/
a) Description is a brief description of the object. If there are any low level design issues
to mention here is the place to do it.
b) The review number should be assigned to you when you work on a piece of work. This
is usually done by maintaining an index document. See your project lead for
information on how this is done on your project.
c) The version number is incremented arbitrarily here. I.e. it does not relate to the
version of the resultant assembly or revision number in your source control tool. It is
incremented prior to submitting your code for review.
d) The author name should be your full name. Not your LAN user id or your nick name.
e) Change number is only required when you make a change beyond the originally
specified requirement. When coding the original version the change number is
“Original”. It is assigned to you using what ever mechanism your project has in place.
This can either be a change number from a Notes database or a Ticket number from
Trac. See your project lead for information on how this is done on your project.
f) The history section is used to fit a meaningful description of why the code was
changed. The version number in this section should link with the version number you
created in the Configuration Record section. This prevents tiny descriptions from being
included in a configuration record or descriptions that run over a few lines in a small
column.
8 Programming Practices
8.1 Visibility
Do not make any instance or class variables public. Make them private and use Properties to
access the data. Resharper will allow you to generate Properties from instance variables
automatically so there is little overhead in having to create the Properties.
The only exception is the data string constant class that contains only static members.
Example:
8.3 Refactoring
Martin Fowler defines Refactoring as “a change made to the internal structure of the software
to make it easier to understand and cheaper to modify without changing its observable
behaviour” (FOWLER99). The idea stems from the reality that software development does
not flow from static requirements that are never altered until after implementation. It’s
about being able to cope with the reality that changes are inevitable and that better solutions
present themselves during successive changes to units of work. Refactoring offers a formal
repeatable method one can use to improve the quality of code.
The purpose of this section is to make you aware of the resources available both as learning
aids and as tools.
8.3.2 Learning
The following are the written resources we have available in the Systems and Projects
Library:
a) Martin Fowler’s Refactoring book. This book describes Refactoring by example and has
a catalogue of refactorings. The first sections walk you through a small sample
program and how refactoring can improve the program’s quality. The later sections are
the refactorings catalogue.
b) http://www.refactoring.com/. This web site offers up to date information on
Refactoring, including more refactorings and links to tools that automate the process.
c) Chapter 24 of Code Complete. This offers a concise introduction to Refactoring. If you
don’t read Martin Fowler’s book, I urge you to at least read this section.
d) http://www.martinfowler.com/. This web site offers more information on Refactoring
as well as patterns, agile development techniques etc.
8.3.3 Tools
Many of the refactorings outlined in the texts above can be performed automatically using
Resharper. See the Resharper Refactoring Help Index for a complete list of the refactorings
offered by this tool.
Visual Studio.Net 2005 also offers automated Refactoring.
c) See Test-Driven Development by David Astels (Vero Systems & Projects Library) for a
full discussion on unit testing and Chapter 7 for an example of using Mock Objects.
Also see http://www.mockobjects.com/FrontPage.html for information on the web.
/// <summary>
/// Returns a risk ratio based on supplied risk factors
/// </summary>
/// <param name="age">
/// Valid Insured age. Must be between 14 and 65
/// </param>
/// <param name="gender">
/// Gender to calculate ratio for
/// </param>
/// <param name="isSmoker">
/// The smoker status
/// </param>
/// <returns>
/// Returns the Risk ratio expressed as a decimal between 0 and 1
/// </returns>
// Do method work
8.6.4 Exceptions
Standard exception handling practices are documented in the design standards documents.
See http://vsp/trac/val/wiki/ApplicationDesignStandards for the most current document
addressing design standards.
B.2 Formatting
a) Are there any tab characters in the code?
b) Has the Resharper Reformat been applied?
c) Have regions been applied appropriately?
B.5 Variables
a) Do variable names convey intent? I.e. does the name make the variable’s purpose
obvious?
b) Are all declared variables being used?
c) Are all declared variables being used for a single purpose?
d) Are variables declared close to first use?
e) Are there any “magic” variables (Section 8.1)?
f) Does Resharper display any warnings relating to variables?
B.6 Methods
a) Do method names convey intent? I.e. does the name make the method’s purpose
obvious?
b) Is the method name repeating parameter information? Eg GetPolicyByPolicyID(int
policyID) instead of GetPolicy(int policyID).
c) Is the method consistent with the class’s level of abstraction (section 8.5)?
d) Does the method perform a single task? How large is it? Should it be broken up?
e) Is the method assuming anything? If so are there any Asserts being used? See section
8.6.
f) Are all private methods being used (Resharper will warn on this)?
B.7 Classes
a) Is the class focusing on a single responsibility; or at least a very small number?
b) Is the class’s public interface presenting a consistent abstraction?
c) Are there any publicly visible fields (excluding constant classes)?
d) Do all public methods need to be public?
B.8 Expressions
a) Have complex Boolean expressions been extracted to either a variable or a method?
B.9 Exceptions
a) Is System.Exception being caught anywhere other than the thread level event
handler?
B.10 Comments
a) Do comments accurately reflect the code? Eg has code changed to make a comment
incorrect or irrelevant?
b) Are any comments repeating what the code does?
c) Do comments explaining performance gain quote the test results?
d) Are there any blocks of commented code?
e) Are there any maintenance note comments?
f) Are all XML comments present and accurate? See section 7.3. The compiler will warn
of these. Only exceptions are generated classes such as web service proxies or Crystal
Report generated classes.
g) Are there any outstanding “TODO” comments that should have been implemented?
B.11 General
a) Are there any compiler warnings?
b) Do event handlers have any logic unrelated to the event – eg business logic?
c) Have event handler arguments been converted to appropriate objects before use?
C Change History
Version Date Change Description Author
0.1 29/06/2005 Original draft Christian Maslen