Coding Standards for .Net

Blossom Programming | Coding Standards for .Net

 C# Coding Standards


The purpose of creating this set of rules is an attempt to set standards for C# coding that would be convenient and practical at the same time. Not all of these rules have definitive ground. We simply accepted some of them as standards. After all, it does not matter what you choose, but rather how strictly you follow the selected rules.

 

Basic Principles

This document cannot cover all the cases you may face. If you have doubts, rely on the basic principles, applicable in any situation. Some of these principles are:

  • The Principle of Least Surprise (POLA). Always favor the most obvious solution, to make your code understandable and not to confuse other developers
  • Keep It Simple Stupid (KISS). Choose the simplest solution for your tasks
  • You Ain’t Gonna Need It (YAGNI). Work on the task at hand, do not create code only because you think you are going to need it in the future
  • Don't Repeat Yourself (DRY). Abstain from duplicating code within one component, repository and keep in mind the rule of three.
  • The four principles of object-oriented programming: encapsulation, abstraction, inheritance, and polymorphism.
  • Generally, you do not have to make the entire code base compliant with these guidelines. Nevertheless, it should comply as much as possible.

 

Purpose of coding standards and best practices

To develop reliable and maintainable applications, you must follow coding standards and best practices.

 

The naming conventions, coding standards and best practices described in this document are compiled from our own experience and by referring to various Microsoft and non-Microsoft guidelines.

 

There are several standards exists in the programming industry. None of them are wrong or bad and you may follow any of them. What is more important is, selecting one standard approach and ensuring that everyone is following it.

 

Acknowledgement

This document is based on the coding style that is prevalent in Microsoft Developer Network

(MSDN) example code, and should already be familiar to most developers. The guidelines presented here were not created in a vacuum. In the process of creating this document, the authors have scanned many existing .NET code conventions and guideline documents including

MSDN Best Practice Guidelines


How to follow the standards across the team

 

If you have a team of different skills and tastes, you are going to have a tough time convincing everyone to follow the same standards. The best approach is to have a team meeting and discuss the standards mentioned in this document or develop your own standards document. You may use this document as a template to prepare your own document.

 

Distribute a copy of this document (or your own coding standard document) well ahead of the coding standards meeting. All members should come to the meeting prepared to discuss pros and cons of the various points in the document.

 

Discuss all points in the document. Everyone may have a different opinion about each point, but at the end of the discussion, all members must agree upon the standard you are going to follow. Draft a new version of this document with appropriate changes based on the suggestions from all of the team members.

 

 

 Naming Conventions

Naming conventions make programs more understandable by making them easier to read and ensuring consistency.

Choosing identifiers that conform to these guidelines improves the reusability of your code.

 

 

Note :

The terms Pascal Casing and Camel Casing are used throughout this document.

Pascal Casing - First character of all words are Upper Case and other characters are lower case.

Example: BackColor

Camel Casing - First character of all words, except the first word are Upper Case and other characters are lower case.

Example: backColor

 

 

Below are our C# coding standards, naming conventions, and best practices. Use these in your own projects and/or adjust these to your own needs.

General Naming Conventions

 

Choose easily readable identifier names, and favor readability over brevity. The property name

CanScrollHorizontally is better than ScrollableX (an obscure reference to the X-axis).

 

Choose semantically meaningful names rather than language-specific keywords for type names.

(GetLength is more meaningful than GetInt.)

 

Avoid using underscores, hyphens, or any other non-alphanumeric characters. When an identifier consists of multiple words, do not use separators, such as underscores ("_") or hyphens ("-"), between words. Instead, use casing to indicate the beginning of each word.

 

Avoid abbreviations or contractions (e.g. use OnButtonClick rather than OnBtnClick)

 

Do not use any acronyms that are not widely accepted, and then only when necessary.

 

Avoid using identifiers that conflict with keywords of widely used programming languages.

Though most keywords can be made to work as regular identifiers, doing so is confusing to read.

 

Names of Assemblies and DLLs

An assembly contains all or part of a reusable library and is contained in a single dynamic-link library (DLL). Assemblies and DLLs are the physical organization of a library (namespaces are a logical organization and should be factored independent of the assembly's organization).

 

Choose names for your assembly DLLs that suggest large chunks of functionality such as System.Data. Assembly and DLL names do not have to correspond to namespace names but it is reasonable to follow the namespace name when naming assemblies.

 

Name DLLs according to the pattern:

<Product Name>.<Functionality>[.<Component>].dll

 

For example: SampleProject.Configuration.DataAccess.dll

 

 

Additional levels may be added to <Functionality> or <Component> to subdivide large collections of functionality.

 

Names of Namespaces

The name chosen for a namespace should indicate the functionality made available by types in the namespace.

 

Use a stable, version-independent product name at the second level of a namespace name.

 

Use Pascal casing, and separate namespace components with periods.

 

Do not use generic type names such as Element, Node, Log, or Message, or names in the functionality or component namespaces. There is a very high probability these will cause type name conflicts in common scenarios.

 

doorganize namespaces with a clearly defined structure

1.       // Examples

2.      namespace Company.Product.Module.SubModule

3.       namespace Product.Module.Component

4.      namespace Product.Layer.Module.Group

 

 

Names Of Class Names#

Do use PascalCasing for class names.

1.       public class ClientActivity

2.      {

3.           public void ClearStatistics()

4.          {

5.              //...

6.          }

7.           public void CalculateStatistics()

8.          {

9.              //...

10.       }

11.   }

Noun Class Names#

 

douse noun or noun phrases to name a class.

1.       public class Employee

2.      {

3.       }

4.      public class BusinessLocation

5.      {

6.      }

7.       public class DocumentCollection

8.      {

9.      }

 

 

Names Of Interfaces

Do prefix interfaces with the letter I.  Interface names are noun (phrases) or adjectives.

1.       public interface IShape

2.      {

3.       }

4.      public interface IShapeCollection

5.      {

6.      }

7.       public interface IGroupable

8.      {

9.      }

 

 

Names Of Variable Names#

 

douse camelCasing for local variables and method arguments.

1.       public class UserLog

2.      {

3.           public void Add(LogEvent logEvent)

4.          {

5.              int itemCount = logEvent.Items.Count;

6.              // ...

7.           }

8.      }

Names Of Identifiers#

 

do notuse Hungarian notation or any other type identification in identifiers

1.       // Correct

2.      int counter;

3.       string name;

4.       

5.      // Avoid

6.      int iCounter;

7.       string strName;

Names Of Constants#

 

do notuse Screaming Caps for constants or readonly variables

1.       // Correct

2.      public static const string ShippingType = "DropShip";

3.        

4.      // Avoid

5.      public static const string SHIPPINGTYPE = "DropShip";

Names Of Abbreviations#

 

avoidusing Abbreviations.
Exceptions: abbreviations commonly used as names, such as Id, Xml, Ftp, Uri

1.       // Correct

2.      UserGroup userGroup;

3.       Assignment employeeAssignment;

4.       

5.      // Avoid

6.      UserGroup usrGrp;

7.       Assignment empAssignment;

8.       

9.      // Exceptions

10.   CustomerId customerId;

11.   XmlDocument xmlDocument;

12.   FtpHelper ftpHelper;

13.   UriPart uriPart;

Abbreviation Casing

 

douse PascalCasing for abbreviations 3 characters or more (2 chars are both uppercase)

1.       HtmlHelper htmlHelper;

2.      FtpTransfer ftpTransfer;

3.       UIControl uiControl;

Names Of Type Names#

 

douse predefined type names instead of system type names like Int16, Single, UInt64, etc

1.       // Correct

2.      string firstName;

3.       int lastIndex;

4.      bool isSaved;

5.       

6.      // Avoid

7.       String firstName;

8.      Int32 lastIndex;

9.      Boolean isSaved;

Implicit Types

 

douse implicit type var for local variable declarations.
Exception: primitive types (int, string, double, etc) use predefined names.

1.       var stream = File.Create(path);

2.      var customers = new Dictionary<int?, customer="" style="box-sizing: border-box;">();

3.       <int?, customer="" style="box-sizing: border-box;">

4.      <int?, customer="" style="box-sizing: border-box;">// Exceptions

5.      <int?, customer="" style="box-sizing: border-box;">int index = 100;

6.      <int?, customer="" style="box-sizing: border-box;">string timeSheet;

7.       <int?, customer="" style="box-sizing: border-box;">bool isCompleted;

Names Of File Names#

 

doname source files according to their main classes.

Exception: file names with partial classes reflect their source or purpose, e.g. designer, generated, etc.

 

1.       // Located in Task.cs

2.      public partial class Task

3.       {

4.          //...

5.      }

1.       // Located in Task.generated.cs

2.      public partial class Task

3.       {

4.          //...

5.      }

Names Of Member Variables#

 

dodeclare all member variables at the top of a class, with static variables at the very top.

1.       // Correct

2.      public class Account

3.       {

4.          public static string BankName;

5.          public static decimal Reserves;

6.       

7.           public string Number {get; set;}

8.          public DateTime DateOpened {get; set;}

9.          public DateTime DateClosed {get; set;}

10.       public decimal Balance {get; set;}

11.    

12.       // Constructor

13.       public Account()

14.       {

15.           // ...

16.      }

17.   }

Names Of Enums#

 

douse singular names for enums.

Exception: bit field enums.

1.       // Correct

2.      public enum Color

3.       {

4.          Red,

5.          Green,

6.          Blue,

7.           Yellow,

8.          Magenta,

9.          Cyan

10.   }

11.    

12.   // Exception

13.   [Flags]

14.   public enum Dockings

15.   {

16.      None = 0,

17.       Top = 1,

18.       Right = 2,

19.      Bottom = 4,

20.      Left = 8

21.   }

Enum Types#

 

do notexplicitly specify a type of an enum or values of enums (except bit fields)

1.       // Don't

2.      public enum Direction : long

3.       {

4.          North = 1,

5.          East = 2,

6.          South = 3,

7.           West = 4

8.      }

9.       

10.   // Correct

11.   public enum Direction

12.   {

13.       North,

14.       East,

15.       South,

16.      West

17.   }

Enum Suffix#

 

do notsuffix enum names with Enum

1.       // Don't

2.      public enum CoinEnum

3.       {

4.          Penny,

5.          Nickel,

6.          Dime,

7.           Quarter,

8.          Dollar

9.      }

10.    

11.   // Correct

12.   public enum Coin

13.   {

14.       Penny,

15.       Nickel,

16.      Dime,

17.       Quarter,

18.       Dollar

19.  }

Others

No Underscores#

 

do notuse Underscores in identifiers.
Exception: you can prefix private static variables with an underscore.

 

1.       // Correct

2.      public DateTime clientAppointment;

3.       public TimeSpan timeLeft;

4.       

5.      // Avoid

6.      public DateTime client_Appointment;

7.       public TimeSpan time_Left;

8.       

9.      // Exception

10.   private DateTime _registrationDate;

Curly Brackets#

 

Doverti

cally align curly brackets.

1.       // Correct

2.      class Program

3.       {

4.          static void Main(string[] args)

5.          {

6.          }

7.       }

 

Unit Test Cases

Test naming is important for teams on long term project as any other code style conventions. By applying code convention in tests you proclaim that each test name will be readable, understandable and will have a well-known naming pattern for everyone on the project.

 

There are few recommendations regarding test naming:

·        Test name should express a specific requirement

·        Test name could include the expected input or state and the expected result for that input or state

·        Test name should be presented as a statement or fact of life that expresses workflows and outputs

·        Test name could include the name of the tested method or class

MethodName_ExpectedBehavior_StateUnderTest

For Example:

Get_ShouldReturnListOfCustomers_WhenQueryParametersAreValid()

Get_ShouldReturnBadRequest_WhenRequestIsInvalid()

Post_ShouldInsertNewCustomer_WhenDataIsValid()

Post_ShouldThrowException_WhenCustomerTypeIsInvalid()

 

 Commenting and Documentations

 

Both General Comments and XML Documentation Comments are encouraged in VA code. General comments are comments which are delimited by /* and */, or //. XML Documentation Comments are delimited with ///.

 

General Comments

General comments are meant to aid developers in further understanding code and implementation decisions. General comments should contain only information that is relevant to reading and understanding the program. Discussion of nontrivial or unobvious design decisions is appropriate, but avoid duplicating information that is present in (and clear from) the code.

In general, avoid any comments that are likely to get out of date as the code evolves.

Temporary comments that are expected to be changed, or removed later, should be marked with special tokens so that they can easily be found.

Ideally, all temporary comments shall be removed by the time a program is ready to be moved to production.

Comments should not be enclosed in large boxes drawn with asterisks or other characters and should not include special characters such as form-feed and backspace.

 

Single-Line Comments

Short comments can appear on a single line indented to the level of the code that follows. If a comment can't be written in a single line, it should follow the block comment format. A single-line comment should be preceded by a blank line.

 

Here's an example of a single-line comment in .NET

 

1.  if (bar > 1) {

2.  bar--;

3.  //Do a triple-flip

4.  }

 

The // comment delimiter should not be used on consecutive full lines for text comments. However, it can be used in consecutive multiple lines for commenting out sections of code.

1.  //if (bar > 1) {

2.  // bar--;

3.  //

4.  // // Do a triple-flip.

5.  // ...

6.  //}

 

 

Trailing Comments

Trailing comments are very short comments that appear on the same line as the code they describe. Trailing comments should be shifted far enough to the right in order to separate them from the statements. Multiple trailing comments contained in a section of code should be indented to the same tab setting.

The // comment delimiter can comment out a complete line or only a partial line.

 

1.  if (foo > 1) {

2.  foo--;

3.  // Do a double-flip.

4.  ...

5.  }

6.  else {

7.  return false; // foo <=1, no double-flip

8.  }

 

Block Comments

Block comments are used to provide descriptions of files, methods, data structures and algorithms. Block comments may be used at the beginning of a file and/or before a method or class. They can also be used in other places, such as within methods. Block comments inside a function or method should be indented to the same level as the code they describe.

A block comment should be preceded by a blank line. This sets it apart from the rest of the code.

For example:

 

/*

* Here is a block comment.

* It extends over several lines,

* and uses the proper formatting.

*/

 

Special Tokens in Comments

In addition to general comments, Microsoft Visual Studio allows developers to place special tokens in comments to indicate areas where there is additional work to be completed or a known issue needs to be corrected.

These types of comments indicate that the code is not complete, or is not implemented in an optimal manner.

 

1.  if (foo > 1) {

2.  // Do a double-flip.

3.  ...

4.  }

5.  else {

6.  // HACK: Would be better if bar() would accept foo value

7.  return false;

8.  }

9.     // TODO: Implement triple-flip

 

These special token comments can be viewed in the Task List in the IDE. The default special tokens are TODO, HACK, and UNDONE, but custom tokens may be added

Released source code shall not contain special token comments showing incomplete work.

 

XML Documentation Comments

In Visual C#, you can create documentation for your code by including XML elements in special comment fields (indicated by triple slashes) in the source code directly before the code block to which the comments refer, for example:

 

/// <summary>

/// This class performs an important function.

/// </summary>

public class MyClass{}

 

When you compile with the /doc option, the compiler will search for all XML tags in the source code and create an XML documentation file. To create the final documentation based on the compiler-generated file, you can create a custom tool or use a tool such as Sandcastle.

XML documentation comments can also provide valuable pop-up tips to those using libraries where methods and classes are appropriately documented.

For usage information, see How to: Use the XML Documentation Features in the Microsoft Developer Network C# Programming Guide.

 


 

After you start the development, you must schedule code review meetings to ensure that everyone is following the rules. 3 types of code reviews are recommended:

 

  • Peer review – Another team member review the code to ensure that the code follows the coding standards and meets requirements. This level of review can include some unit testing also. Every file in the project must go through this process.
  • Architect review – The architect of the team must review the core modules of the project to ensure that they adhere to the design and there is no “big” mistakes that can affect the project in the long run.
  • Group review – Randomly select one or more files and conduct a group review once in a week. Share the file link to all team members before the meeting. Let them read and come up with points for discussion. Go through every sections of the code and let every member give their suggestions on how could that piece of code can be written in a better way. (Don’t forget to appreciate the developer for the good work and also make sure he does not get offended by the “group attack”!)
  • Live Share - Live Share is a feature of Visual Studio that enables real-time collaboration between developers. It gives users the ability to share a session with someone else, allowing them to edit code as well as share a server and debugging session. You can make use of this to review the code.

You can download the word documents here

Comments

Popular Posts

How to position controls using Canvas control in WPF using MVVM

Change font and size in visual studio

JWTs in ASP.NET Core 2.0