NET Coding Standards
NET Coding Standards
June 2006
Jigar Acharya
Version: 0.4
Document Control
Amendment History
Distribution List
are [indicative/preliminary drafts] only and [are accordingly subject to amendment and verification/must be modified as appropriate for
the relevant piece of work being undertaken][; and may contain bugs or inaccuracies that are latent or otherwise not discovered until
application of the relevant documentation or model in the required environment]. Accordingly: no warranties express or implied are
made as to their accuracy or suitability nor does Skyward accept any liability in respect of their use by any party for any purpose; and
the appropriate tests must be undertaken prior to their use.
must not be used without full understanding and proper consideration by or consultation with suitably qualified personnel;
are the confidential information and copyright of Skyward, must accordingly be kept confidential and may only be used by employees of
Skyward for the internal purposes of Skyward and to be amended for the purposes of its business; they may not otherwise be copied or
disclosed in whole or in part save without the express written consent of Skyward.
1.2 Purpose
The purpose of this document is to provide a Set of Coding Standards / Guidelines to the .NET Technical
team which will support development of new .NET Applications or re-factoring of existing .NET Applications
in the .NET Programme wherever applicable.
1.3 Scope
This coding standards document covers only essential areas as currently required for the .NET Technical
team. Although most of the specifications or guidelines given in this document are derived from Microsoft’s
specifications, amendments have been made where found necessary.
This document covers standards / guidelines for the following:
1. General Naming and Declaration guidelines.
2. Formatting of C# Code.
3. Naming, Declaration and Usage Guidelines for various known programming constructs in C#. E.g.
classes, interfaces, methods, properties etc.
4. Code Comments, Documentation comments and other miscellaneous guidelines.
It does not cover:
1. Coding standards for other .NET compliant languages (e.g. VB.NET in particular), even though
some guidelines may apply to these programming languages.
2. Standard Practices for specific type of solutions e.g. “Securing Web Services using WSE”. However
you may find references to such topics. A separate document for “Standard Practices” could be
launched in future.
3. Architecture or Design details of any .NET Application.
4. Recommendations for any SDLC processes.
Since the document is still evolving there are changes expected in terms of addition of new sections,
amendments to the existing sections and in some cases even deletion of existing sections.
• Initialisation: if possible assign default values to the variable as they are declared.
o E.g.: int index = 0;
3.2.1.1 Don’ts
• Don’t insert space between method name and its opening parenthesis
o int Method() is right
o int Method () is wrong.
3.2.2.1 Don’ts
• Don’t insert space between method name and its opening parenthesis
o Console.WriteLine("Step 1") is right
o Console.WriteLine ("Step 1") is wrong.
3.2.3.1 Don’ts
• Don’t insert space within empty square brackets
o string [] args is right
o string [ ] args is wrong
• Don’t insert space before open square bracket (except for declarations)
o itemArray[0] is right
o itemArray [0] is wrong
3.2.3.2 Do’s
• Insert space before open square bracket during declarations
o string [] args is right
o string[] args is wrong
3.2.4.1 Don’ts
• Don’t insert space before or after dot
o return new System.Collections.ArrayList() is right
o return new System. Collections .ArrayList() is wrong
• Don’t insert space before colon for base or interface in type declaration
o class ProductService: IService is right
o class ProductService :IService is wrong
3.2.4.2 Do’s
• Insert space after colon for base or interface in type declaration
o class ProductService: IService is right
o class ProductService:IService is wrong
3.2.5.1 Don’ts
• Don’t insert spaces between a unary operator and its operand
o counter++ is right
o counter ++ is wrong
3.2.5.2 Do’s
• Insert spaces before and after the binary operators
o int result = 1 + 2 * 3 is right
o int result = 1+ 2*3 is wrong
3.2.6.1 Don’ts
• Don’t insert space within parenthesis of expressions
o return a * (b - a) is right
o return a * ( b - a ) is wrong
3.2.6.2 Do’s
• Insert space after keywords in control flow statements
o if (a > b) is right
o if(a > b) is wrong
• After a class/struct/interface name and before the opening bracket of the class/struct/interface body
public interface IRenderer
{
//interface members...
}
• After a Method/Property name and before the opening bracket of the Method/Property body. Applies
to the Set and Get blocks within a property.
public static string GetConnectionString()
{
//Method body
}
• As discussed in the section “Common Code Structures / Control of Flow statements” later in the
document.
1
denotes new Line break
The first is preferred, since the break occurs outside the parenthesized expression (higher level rule). Note
that you indent with tabs to the indentation level and then with spaces to the breaking position in our
example this would be:
> var = a * b / (c - g + f) +
> ......4 * z;
Where '>' are tab chars and '.' are spaces. (the spaces after the tab char are the indent with of the tab). A
good coding practice is to make the tab and space chars visible in the editor which is used.
if (<condition>)
{
//Do this
}
else
{
//Do that
}
if (<condition1>)
{
//Do this
}
else if (<condition2>)
{
//Do that
}
else
{
//Do something else
}
• If these blocks contain considerable number of lines, group them into regions or create sub routines/
methods and call them.
In the above example there’s only one line of code to be executed if the specified condition is met.
• If the body of the loop is deliberately kept empty, please add a comment specifying so. E.g.
for (int i = 0; i < errors.Count; errorMessage.Append(errors[i]), i++)
{
// Empty loop. Just preparing an error message
}
OR
// Empty loop. Just preparing an error message
for (int i = 0; i < errors.Count; errorMessage.Append(errors[i]), i++) ;
• As discussed in the earlier sections, a while loop or a do-while loop, if kept empty should be
accompanied by relevant comments / explanations.
case <B>:
//block B
break;
default:
//block default
break;
}
• Always provide the default block.
OR…
try
{
//guarded block
}
catch (Exception exp)
{
//Handle the exception
}
finally
{
//do the inevitable
}
Note: Explicitly specify the kind of exception object in case predictable. e.g. SQLException. For details on
exception handling refer to the later section in this document.
5.2 Namespaces
5.2.1 Naming guidelines
• A namespace should form a logical package for the types contained in it and hence its name must
indicate the same.
• Use Pascal casing
• Skyward.TimesheetManager
• Skyward.TimesheetManager.Business
• Skyward.TimesheetManager.Business.Workflow
• In case of ambiguities in class names across namespaces use the namespace alias in the
using statement and then use this alias to qualify the class.
E.g.: using SysConf = System.Configuration;
using BPAConf = Skyward.TSM.Utilities.Configuration;
• For details please refer to the section “Exception Handling” later in this document.
/// <summary>
/// Path to the Mailer Section
/// </summary>
public const string MAILER = "/Mailer";
#endregion
}
• If specific private data member is exposed through a Property make sure that their names are same
except for the fact that the Property name will use Pascal casing.
Public or Internal data members
This applies to any data member declared as public or internal in the class. Although this is discouraged
there might be rare occasions when one may need to declare public data members. Name of a Public
data member…
• Must be Noun of a Noun Phrase
• Should not use a plural form unless the variable represents an array or a collection.
• Must use Pascal Casing
• In case the event happens to come in a pair of “Pre” and “Post” forms, use the Present (“… ing”) and
Past tense (“... [e]d”) forms of the verb respectively. E.g.…
o public event EventHandler FormValidating
o public event EventHandler FormValidated
Non-public events:
• Same as the Public Events. Note that this is a rare situation.
5.8 Methods
5.8.1 Naming guidelines
A Method name…
• Must be a Verb or a Verb phrase
• Must use Pascal casing
• Should avoid using short forms or abbreviations unless really required.
• Should indicate the type of work done. E.g. if a method returns a value consider starting its name
with “Get” or “Retrieve”. If it returns a Boolean consider starting its name with “Is”.
E.g.: InsertTimesheet, SendNotification, GetTotalLeaves
• Use the right access specifiers. Do not expose the members unnecessarily.
/// <summary>
/// Searches for a query in the collection by the specified name
/// </summary>
/// <param name="key">The name of the Query</param>
/// <returns>Query reference if found ...</returns>
public Query this[string key];
/// <summary>
/// Returns a query in the collection at a specified position
/// </summary>
/// <param name="index">The index within the collection</param>
/// <returns>Query reference if found at ...</returns>
public Query this[int index];
#endregion
}
/// <summary>
/// Provides access to the config data in the "dataAcecss" section
/// </summary>
public static class DataAccessSection
{
public static string GetConnectionString();
public static string GetQueryConfigPath(HttpServerUtility server);
}
/// <summary>
/// Provides access to the config data in the "regionalOptions" section
/// </summary>
public static class RegionalOptionsSection;
{
public static DateTimeFormatInfo GetRegionalDateTimeFormatInfo();
public static string GetDefaultCurrencySymbol();
}
#endregion
}
• Static Methods: Follow the Naming guidelines as given earlier for non-static Methods.
• Static Properties: Follow the Naming guidelines as given earlier for non-static Properties.
5.14 Interfaces
5.14.1 Naming guidelines
An interface name…
• Must be a Noun, Noun phrase or Adjective describing a specific behaviour
• Should use “I” as the prefix to indicate that it’s an interface
}//end IServiceController
}//end namespace ServiceBroker
5.16 Enumerations
5.16.1 Naming guidelines
An Enum name…
• Should be a Noun or a Noun phrase.
• Should use Pascal casing.
• Should avoid using a plural form in the name even if the Enum represents a group of values.
o E.g. consider “ViewMode” instead of “ViewModes”.
An Enum Value name…
• Should be a Noun or a Noun Phrase unless the value itself represents otherwise as per business
rules.
• Should use Pascal casing. Do not use any prefix or a postfix.
• Do not repeat any part of the Enum name in the Value name. E.g. “ViewMode.Read” is better than
“ViewMode.ReadMode”. (All values in ViewMode are basically Modes)
/// <summary>
/// Indicates Read & Write permissions
/// </summary>
ReadWrite,
/// <summary>
/// Indicates No Access
/// </summary>
None
}
Delegate declaration:
public delegate void NotificationEventHandler(object sender,
NotificationEventArgs e);
Event declaration:
public event NotificationEventHandler Notify;
• In .NET2.0 the EventHandler delegate is templated to work with any “EventArgs” based class.
Hence there is no special need to create a custom delegate as given above. The same can be
implemented as follows.
Event declaration:
public event EventHandler<NotificationEventArgs> Notify;
• Declare the appSettings and the connectionStrings sections right at the bottom of the
configuration file.
• Declare all the custom sections in between. Have a starting and ending XML comment block for
each section describing what’s held in it.
6 Comments
Terms revisited:
• Comment: A comment can be referred to a useful note added along with the code to provide some
useful information which is ignored by the source code compiler. (Although some special comments
are treated differently by some compilers. E.g. C# documentation comments)
• Commented Code: This can refer to any part of the source code which is commented out so that it
will not be used by the source code compiler.
Note: Ideally a fully matured code should not have any “commented code” but only “comments”.
o This will set off the block visually from code for the (human) reader. Surrounding such
comment blocks within regions is quite useful.
• Alternatively one might use the old fashioned C style for single line comments, even though it is not
recommended. In case you use this style, a line break should follow the comment, as it is hard to
see code preceded by comments in the same line.
if (condition1) /* && <condition2>)*/
{
//do something...
}
o This type of comment should be used only for temporary purposes and for code only. E.g.
while conducting unit test to test specific piece of code.
Since CVS will be used for Source Code Control, we’ll use facilities of one of its client i.e. WinCVS by which
it can update any text/ASCII based file with the latest information of it as shown above.
• WinCVS provides a feature of WinCVS variables like Source, Date and Author which supply the
respective information during a commit operation.
• While committing a Text/ASCII file into CVS using WinCVS, WinCVS retrieves the current value of
the used variable and replaces all its occurrences in the file with this value.
• E.g. if a text file has following block defined somewhere in it…
//$Source: $
//$Date: $
//$Author: $
• During the next commit operation the block will be modified as follows…
• Please also note that creating such a header is one time activity and required only when a file is
committed for the first time. Subsequent CVS commits will automatically update the variable values.
• Every Source file hence will always have a header as shown in sections below (right before anything
else in the file). This might differ slightly based on the type of file used.
• For a C# source file
• For static content & script files (HTML, JS, CSS etc)
o Unfortunately we cannot use the same feature for these files are they are served “as-is” to
the web clients by the Web server. We would not want confidential information about the
document to be sent over to the web client that way.
The compiler creates/updates the specified xml file with all the Xml Documentation comments inserted the
source files of the project. Warnings are displayed if there are no comments available for the members
visible from type library (metadata). Tools like NDoc can be used for creating standard class library help files
in various known styles (JavaDoc, MSDN or Custom).
• Class declaration
/// <summary>
/// The exception thrown when an error occurs in Download.
/// </summary>
public class DownloadException: ApplicationException
{
private FileInfo fileInfo;
public DownloadException(FileInfo fileInfo, string errorMessage)...
}
• Method declaration
/// <summary>
/// Initiates a File Download for the given file
/// </summary>
/// <param name="filePath">Physical path of the file on the web server</param>
/// <param name="response">Reference to the HttpResponse object</param>
/// <exception cref="DownloadException">This exception is thrown if the
specified file not found on the web server</exception>
/// <remarks>The method clears the current Response before initiating a
download</remarks>
public static void InitiateFileDownload(string filePath, HttpResponse response)
{
//method implementation goes here...
}
• Please note that the comment must be start with two forward slashes followed by the word TODO,
the colon as shown above. Visual Studio identifies this as a token.
If the Author of this source file has the custom token “REVIEWER” setup in his/her IDE, the task list will show
it up as a task as follows.
• Use short but meaningful names for the aspx pages as the end user will use see these.
• Use Pascal naming convention as their code-behind classes will also use the same name
• E.g. CreateUser.aspx, Login.aspx, Order.aspx.
•
7.1.1.2 Web User controls (ASCX)
7.1.1.2.1 Views
• Postfix the word “View” to indicate its role. One should be able to relate to its parent ASPX page by
name.
• Use Pascal naming convention
• E.g. CreateUserView, CreateUserErrorView, CreateUserSuccessView.
•
7.1.1.2.2 Controllers
Label lbl
Literal lit
CheckBox, HtmlInputCheckBox cb
CheckBoxList cbl
RadioButton, HtmlRadioButton rb
RadioButtonList rbl
ImageButton ibtn
LinkButton lbtn
HyperLink, HtmlAnchor hl
ImageMap imap
Calendar cal
AdRotator adr
TableRow, HtmlTableRow tr
TableCell, HtmlTableCell td
Panel pnl
Div div
View vw
MultiView mvw
PlaceHolder ph
Validation Controls
RequiredFieldValidator rfv
RegularExpressionValidator rev
RangeValidator rv
CompareValidator cmpv
CustomValidator cstv
ValidationSummary vs
Data Controls/Variables
DataGrid dg
DataList dl
GridView gv
Repeater rptr
FormView fvw
DetailsView dvw
Xml xml
DataSet ds
DataRelation drel
DataTable dtbl
DataView dvw
DataRow drw
SqlDataAdapter, OleDbDataAdapter da
Navigation Controls
SiteMapPath smp
Menu mnu
TreeView tvw
• Avoid putting code in ASPX files of ASP.NET. All code should be in the code-behind class.
• Code in code behind class of ASP.NET should call other components rather than contain direct
business logic.
• In both ASP.NET pages and web services, wrap session variables in local properties such that only
these properties will access the session variable and the rest of the code will use these properties
only.
• Avoid setting the Auto-Postback property to “true” for server controls in ASP.NET.
• In transactional pages or web services, it is recommended to store session in Database.
• Turn on Smart Navigation for ASP.NET pages.
• Strive to provide interfaces for web services
• Always provide namespace and service description for web services.
• Always provide a description for web methods.
• When adding a web service reference, provide a meaningful name for the location.(use host IP
Addresses such that change in Deployment becomes easier)
• Always modify client-side web service wrapper class to support cookies.
• The “InitializeComponent” method (ASP.NET1.1): The InitializeComponent method which is
created by default for ASPX and ASCX code-behind classes, contains lines which initialise event
handlers for many events like page loads, button clicks etc. Due to a bug in Visual Studio.NET 2003,
many a times when the developer switches to Design mode, these lines are removed. We can use
the following solution …