Dotnet Commons Standards and Guidelines

1 Introduction

1.1 Summary

This document is intended for developers who are working on the Dotnet Commons project. The document itself will provide developers with a consistent standard framework for which developers will adhere to.

The document tries not to be too rigid on the standards to be used as not all developers are the same. By placing too many restrictions within the standards framework can be detrimental to a project in terms of both money and time.

The contents within this document will not be static in nature and therefore may change over time as the developers become more familiar with the project environment and structure.

This document requires or recommends certain practices developing programs in the C# language. The
objective of this coding standard is to have a positive effect on

1.2 Source of References

Many of the rules and recommendations were taken from the MSDN C# Usage Guidelines. The naming guidelines in that document are identical to those found in Appendix C of the ECMA C# Language Specification. Naming standards and other style issues are more or less arbitrary, so it seems prudent to follow an existing convention. The naming standard in this document differs from that in the given references only in some miniscule details that will hardly ever occur in practice.

1.3 References

Ref. doc. number Author Title

1 XJS-154-1215 Bart van Tongeren PMS-MR C++ Coding Standard
2 ECMA-334 TC39/TG2 C# Language Specification, ed. Dec 20012
3 msdn, unnumbered Design Guidelines for .NET Class Library Developers

2 General Rules

2.1 Rules and Recommendations

Rule 1. Every time a recommendation is not followed, this must have a good reason
Good reasons do not include personal preferences of style.

Rule 2. Do not mix code from different sources in 1 source file
In general, third party code will not comply with the coding standard, so do not put such code in the same file as proprietary code modifying to the third party code to conform to the coding standards and naming convention.

3 Naming Standards

3.1 Naming Conventions

Naming conventions to be most closely follow those naming standards put out by Microsoft. This standards can be found at the following this link: Naming Guidelines.

3.2 Capitalization Styles

The following section describes different ways of capitalizing identifiers.

Pascal casing
This convention capitalizes the first character of each word. For example:
Color BitConverter

Camel casing
This convention capitalizes the first character of each word except the first word. For example:
backgroundColor totalValueCount

All uppercase
Only use all uppercase letters for an identifier if it contains an abbreviation. For example:
System.IO
System.WinForms.UI

Exception to the Naming Convention

3.3 Capitalization Summary

TypeStandardExamples
Namespaces Pascal case, no underscores. Use Dotnet.Commons as root. Note that any acronyms of 3 characters or more should be Pascal case (System.Xml instead of System.XML) instead of all caps. Acronyms under 3 characters should be all caps (System.IO).Dotnet.Commons.DataAdapters, Dotnet.Commons.Lang
Assemblies If the assembly contains a single name space, or has an entire self-contained root namespace, name the assembly the same name as the namespace. Dotnet.Commons.Collections.dll, Dotnet.Commons.Lang.dll
Classes and Structs Pascal Case, no underscores or leading "C" or "cls". Classes may begin with an "I" only if the letter following the I is not capitalised, otherwise it looks like an Interface. Classes should not have the same name as the namespace in which they reside. Any acronyms of three or more letters should be pascal case, not all caps. Try to avoid abbreviations, and try to always use nouns. Classes / Struts must differ by more than case to be usable from case-insensitive languages like Visual Basic .Net. Widget, InstanceManager, XmlDocument
Collection Classes Follow class naming conventions, but add Collection to the end of the name WidgetCollection
Delegate Classes Follow class naming conventions, but add Delegate to the end of the name WidgetCallbackDelegate
Exception Classes Follow class naming conventions, but add Exception to the end of the name InvalidTransactionException
Attribute Classes Follow class naming conventions, but add Attribute to the end of the name WebServiceAttribute
Interfaces Follow class naming conventions, but start the name with "I" and capitalize the letter following the I IWidget
Enumerations Follow class naming conventions. Do not add "Enum" to the end of the enumeration name. If the enumeration represents a set of bitwise flags, end the name with a plural. SearchOptions
Public and Protected Methods Pascal Case, no underscores except in the event handlers. Try to avoid abbreviations. Methods must differ by more than case to be usable from case-insensitive languages like Visual Basic .Net public void DoSomething(...)
Private Methods Camel Case, no underscores except in the event handlers. Try to avoid abbreviations. Methods must differ by more than case to be usable from case-insensitive languages like Visual Basic .Net public void doSomethingPrivately(...)
Properties Pascal Case, no underscores. Try to avoid abbreviations. Properties must differ by more than case to be usable from case-insensitive languages like Visual Basic .Net. public int RecordID
Parameters Camel Case. Try to avoid abbreviations. Parameters must differ by more than case to be usable from case-insensitive languages like Visual Basic .Net. ref int recordID
Method-Level Variables Camel Case, NO Hungarian Notation recorded, iCustomer, bIsValid
Class-Level Private and Protected variables (Fields) Camel Case with Leading Underscore. private int _recordID;
Controls on Forms Modified 3 to 4 letter Hungarian Notation (where possible) prefixes using .Net Class Names txtUserID, lblHeader, lstChoices, btnSubmit
Constants ALL upper case, words separated with the under score character. Note: Public static readonly fields WILL BE treated as constant as thus the name of such a field MUST be in CAPITALS. private const string CONFIG_FILE = “conf.xml”; private const int MAX_VALUE = 10; public static readonly string SOME_READONLY_FIELD = “someConstant”.ToString();
Objects Camel Cases, object type suffix where possible. IDictionary productDict = new Hashtable()customerDict,accountList,configXmlDoc

Word choice
System Collections Forms UI
Namespaces
The general rule for namespace naming is: CompanyName.TechnologyName.
Classes
public class FileStream { … }
public class Button { … }
public class String { … }
Interfaces
public interface IComponent { … }
public class Component : IComponent { … }
public interface IServiceProvider{ … }
public interface IFormatable { … }
Enums
public enum FileMode{
    Create,
    CreateNew,
    Open,
    OpenOrCreate,
    Truncate
}
[Flags]
public enum Bindings {
    CreateInstance,
    DefaultBinding,
    ExcatBinding,
    GetField,
    GetProperty,
    IgnoreCase,
    InvokeMethod,
    NonPublic,
    OABinding,
    SetField
    SetProperty,
    Static
}
Static fields Parameters Type GetType (string typeName)
string Format (string format, object [] args)
Methods RemoveAll(), GetCharArray(), Invoke()
Properties
public enum Color {...}
public class Control {
    public Color Color { get {...} set {...} }
}

but this is not
public enum Color {...}
public class Control {
    public int Color { get {...} set {...} }
}

In the latter case, it will not be possible to refer to the members of the Color enum because Color.Xxx will be interpreted as being a member access that first gets the value of the Color property (of type int) and then accesses a member of that value (which would have to be an instance member of System.Int32).
Events public delegate void MouseEventHandler(object sender, MouseEvent e); public delegate void MouseEventHandler(object sender, MouseEvent e);
public class MouseEventArgs : EventArgs {
    int x;
    int y;
    public MouseEventArgs(int x, int y) 
       { this.x = x; this.y = y; }
    public int X { get { return x; } } 
    public int Y { get { return y; } } 
}
public event ControlEventHandler ControlAdded {
//..
} Case sensitivity Examples of what not to do: namespace ee.cummings;
namespace Ee.Cummings; void F(string a, string A) System.WinForms.Point p;
System.WinForms.POINT pp;
int F {get, set};
int F {get, set}
void f();
void F();
Avoiding type name confusion
Different languages use different names to identify the fundamental managed types, so in a multi-language environment, designers must take care to avoid language-specific terminology. This section describes a set of rules that help avoid type name confusion.

For example, a class that supports writing a variety of data types into a stream might have:
void Write(double value);
void Write(float value);
void Write(long value);
void Write(int value);
void Write(short value);

rather than a language-specific alternative such as:
void Write(double doubleValue);
void Write(float floatValue);
void Write(long longValue);
void Write(int intValue);
void Write(short shortValue);
double ReadDouble();
float ReadSingle();
long ReadIn64();
int ReadInt32();
short ReadInt16();

rather than a language-specific alternative such as:
double ReadDouble();
float ReadFloat();
long ReadLong();
int ReadInt();
short ReadShort();

Folder and Filename Conventions

Folder Structure Conventions

All projects should be contained under the “Dotnet.Commons\” folder.
Under this main default project folder structure, a folder should be created for every namespace. This makes it easier to map namespaces to the folder layout.
Therefore if you have a class in the namespace Dotnet.Commons.Collections, you would see the class under the folder structure as follows:
\Dotnet.Commons\Dotnet.Commons.Collections

Filename Conventions

Each Class within a project is to be place in its own physical file with the same filename as the class name. Therefore if you have two classes called “MyClass” and “YourClass” then “MyClass” should be stored physically in the file MyClass.cs and “YourClass” should be physically stored in the file YourClass.cs. You should never have multiple classes in the same physical file.

Custom Exceptions

Custom Exceptions should be inherited from a System.Exception class (not ApplicationException).

4 Coding Standards

General Coding Standards

4.1 Comments

Comments used within the project will be compliant with the “MSDN C# Programmer's Reference - Recommended Tags for Documentation Comments” Document (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vclrftagsfordocumentationcomments.asp) and will be extracted via the open source application - NDoc Code Documentation Generator for .NET (http://ndoc.sourceforge.net).
The /doc compiler option should be turned on for all projects, as this forces comments to be added to all public classes, methods and properties. The /doc option also produces an XML representation of the comments which can be used to produce a technical specification document using NDoc.
To turn on the /doc compiler option within the Visual Studio .Net environment, you must enter a “XML Document File” name as shown below:

While not absolutely necessary, it is best to name the XML documentation file with the same base name as the name of your assembly (but with the xml extension).
4.1.1.1 Class Level
All classes should contain a summary and remarks comment tags and must provide the following minimum information
/// <summary>[DESCRIPTION]</summary>

Example of usage is as follows:
/// <summary>Holds details relating to Car.</summary>
public class Car
{
	. . . 
}

4.1.1.2 Method Level
All public methods should contain a summary comment tag.
/// <summary>[DESCRIPTION]</summary>

The following methods also require the following: /// <param name="[PARAM NAME]">[DESCRIPTION]</param>

Example:
/// <summary>This method does what I want it to</summary>
/// <param name="Int1">Used to indicate status.</param>
public static void MyMethod(int Int1)
{
}

/// <returns>[DESCRIPTION]</returns>
Example:
/// <summary>This method gets a zero</summary>
/// <returns>Returns zero.</returns>
public int GetZero()
{
    return 0;
}

/// <overloads>[OVERLOAD DESCRIPTION]overloads>
Example:
/// <summary>This overload just says hello.</summary>
/// <overloads>This method has two overloads.</overloads>
public void SayHello()
{
}

/// <summary>This one says hello to someone.</summary>
public void SayHello(string toSomeone)
{
}

/// <exception cref="[EXCEPTION]">[THROW TYPE/REASON]</exception>
Example:
/// <summary>This method services the some.</summary>
/// <exception cref="System.Exception">Thrown when...</exception>
public void SomeMethod()
{
…
}

4.1.1.3 Property Level
All public properties should contain a summary and value comment tags.

/// <summary>DESCRIPTION</summary>
/// <value>VALUE DESCRIPTION</value>

Example:
/// <summary>MyProperty is a property in the Car class.</summary>
/// <value>A string containing the text "MyProperty String".</value>
public string MyProperty
{
get
      {
      	return "MyProperty String";
      }
}

4.1.2 Inline Comments

Include inline comments throughout your code as is per normal programming practices.
For the following comments, please follow this structure:

Format:
// CHANGE – [AUTHOR INITIALS] – [DATE] – [DESCRIPTION]

Example:
// CHANGE – JB – 27/10/2004 – Changed increment value from 1 to 4

Note: Please update class history (as shown in class level comments) for summary description of the changes carried out.

Note: The word CHANGE must be in UPPER CASE
Format:
// TODO – [INITIALS OF AUDIENCE] - [AUTHOR INITIALS] – [DATE] - [DESCRIPTION]

Examples:
// TODO – DB – JL – 27/10/2004 - Change code to add 10

This is asking DB to do the changes
// TODO –– JL – Change Steering method for stick to wheel

This TODO is not directed to any particular developer

Note: The word TODO must be in UPPER CASE.

4.2 Regions

Regions should be used throughout the project to break up code into related groups.

Your classes should have the at least some of the following region types (if applicable):
Where classes are complex and large, it is recommended to have regions based on accessibility levels (Public, Private Protected, Internal, and Protected Internal) as shown in the following:
An example of regions can be seen in the usage of the following Method grouping:

Simple Classes:
        #region Methods
        // All Methods Here
        #endregion  // End Methods Region


	Large / Complex Classes:

        #region Public Methods 
        // Public Methods Here
        #endregion  // End Public Methods Region

        #region Private Methods
        // Public Methods Here
        #endregion  // End Private Methods Region


5 Object Oriented Programming Standards

5.1 OOP Rules and Recommendations

Rule 3. Declare all fields (data members) private.
Exceptions to this rule are static readonly fields, which may have any accessibility deemed appropriate.


Rule 4. Provide a default private constructor if there are only static methods and properties on a class.
Instantiating such a class would be useless.

Rule 5. Explicitly define a protected constructor on an abstract base class.
Of course an abstract class cannot be instantiated, so a public constructor should be harmless. However, 3
states:
Many compilers will insert a public or protected constructor if you do not. Therefore,
for better documentation and readability of your source code, you should explicitly define a
protected constructor on all abstract classes.
Dubious reasoning, but harmless. This recommendation is provisional.

Rule 6. Selection statements (if-else and switch) should be used when the control flow depends on an object’s value; dynamic binding should be used when the control flow depends on the object’s type.
This is a general OO principle. Please note that it is usually a design error to write a selection statement that queries the type of an object (keywords typeof, is).

Exception:
Using a selection statement to determine if some object implements one or more optional interfaces is a valid construct though.

Rule 7. All variants of an overloaded method shall be used for the same purpose and have similar behavior.
Doing otherwise is against the Principle of Least Surprise.

Rule 8. If you must provide the ability to override a method, make only the most complete overload virtual and define the other operations in terms of it.
Using the pattern illustrated below requires a derived class to only override the virtual method. Since all the other methods are implemented by calling the most complete overload, they will automatically use the new implementation provided by the derived class.

An even better approach, not required by this coding standard, is to refrain from making virtual methods
public, but to give them protected5 accessibility, changing the sample above into:

Rule 9. Specify methods using preconditions, postconditions, exceptions; specify classes using invariants.
You can use Debug.Assert to ensure that pre- and post-conditions are only checked in debug builds. In release builds, this method does not result in any code.
Compilable preconditions etc. are testable.
The exact form (e.g. assertions, special DbC functions such as require and ensure) is not discussed here.
However, a non-testable (text only) precondition is better than a missing one.
In this context the ‘modifying’ operators are those that have a corresponding assignment operator, i.e. the nonunary versions of +, -, *, /, %, &, |, ^, << and >>.
There is very little literature regarding operator overloading in C#. Therefore it is wise to approach this feature with some caution.

Overloading operators on a struct type is good practice, since it is a value type. The class is a reference type and users will probably expect reference semantics, which are not provided by most operators.

Consider a class Foo with an overloaded operator(int), and thus an impicitly overloaded operator=(int). If we define the function AddTwenty as follows:
public static void AddTwenty (Foo f)
{
f += 20;
}


Then this function has no net effect:
{
	Foo bar = new Foo(5);
	AddTwenty (bar);
	// note that ‘bar’ is unchanged
	// the Foo object with value 25 is on its way to the GC...
}

The exception to this recommendation is a class type that has complete value semantics, like
System.String.


Rule 12. Do not modify the value of any of the operands in the implementation of an overloaded operator.
This rule can be found in a non-normative clause of 2, section 17.9.1. Breaking this rule gives counterintuitive results.

Rule 13. If you implement one of operator==(), the Equals method or GetHashCode(), implement all three.
Also override this trio when you implement the IComparable interface.

Do consider implementing all relational operators (!=, <, <=, >, >=) if you implement any.

If your Equals method can throw, this may cause problems if objects of that type are put into a container. Do consider to return false for a null argument.

The MSDN guidelines 3 recommend to return false rather than throwing an exception when two incomparable objects, say the proverbial apples and oranges, are compared. Since this approach sacrifices the last remnants of type-safety, this recommendation has been weakened.

Rule 14. Use a struct when value semantics are desired.
More precisely, a struct should be considered for types that meet any of the following criteria: Remember that a struct cannot be derived from.

Rule 15. Allow properties to be set in any order.
Properties should be stateless with respect to other properties, i.e. there should not be an observable difference between first setting property A and then B and its reverse.

Rule 16. Use the property accessors rather than accessing private member fields directly.
Instead of doing the following:
Public class MyClass
{
	private string _myfield;
	public void foobar()
	{
		this._myfield = “Hello”;
		Console.Writeln(“My field is {0}”, this._myField);
	}
}

One should do the following instead:
Public class MyClass
{
	private string _myfield;

	public string MyField
	{
		get { return this._myfield; }
		set { this._myfield = value; }
	}

	public void foobar()
	{
		this.Myfield = “Hello”;
		Console.Writeln(“My field is {0}”, this.MyField);
	}
}

The reason being that it is possible to have additional statements inside the property get and set method doing something before returning or setting the field value. Consider the following example:
Public class MyClass
{
	private string _myfield;

	public string MyField
	{
		get { return this._myfield.ToLower(); }
		set { this._myfield = value + “ world”; }
	}

	public void foobar()
	{
		this.Myfield = “Hello”;
		Console.Writeln(“My field is {0}”, this.MyField);
	}
}


Rule 17. Use a property rather than a method when the member is a logical data member.

Rule 18. Use a method rather than a property when this is more appropriate.
In some cases a method is better than a property:
Rule 19. Do not create a constructor that does not yield a fully initialized object.
Only create constructors that construct objects that are fully initialized. There shall be no need to set additional properties.

Rule 20. Always check the result of an as operation.
If you use as to obtain a certain interface reference from an object, always ensure that this operation does not return null. Failure to do so may cause a NullReferenceException at a later stage if the object did not implement that interface.

Rule 21. Use explicit interface implementation only to prevent name-clashing or to support optional interfaces.
When you use explicit interface implementation, then the methods implemented by the class involved will not be visible through the class interface. To access those methods, you must first cast the class object to the requested interface.
It is recommended to use explicit interface implementation only: Consider the following example.

public interface IFoo1
{
		void Foo()
}

public interface IFoo2
{
	void Foo()
}

public class FooClass : IFoo1, IFoo2
{
	// This Foo is only accessible by explictly casting to IFoo1

	void IFoo1.Foo() { … }

	// This Foo is only accessible by explictly casting to IFoo2
	void IFoo2.Foo() { … )
}

6 Building and Releasing Standards

6.1 Checking for .Net Compliance

FxCop (http://www.gotdotnet.com/team/fxcop) is a code analysis tool that checks .NET managed code assemblies for conformance to the Microsoft .NET Framework Design Guidelines.

The tool checks for more than 200 defects in the following areas:
This tool should be run against any .net code before its release.