Featured

Monday 25 June 2018

C# Programming Guide

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 of dynamic.  
  • Use implicit typing var to determine the type of the loop variable in for and foreach 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 or static 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 with public, protected, or internal access modifiers.
  • Only use long for variables potentially containing values too large for an int.
  • Try to use double for fractional numbers to ensure decimal precision in calculations.
  • Only use float for fractional numbers that will not fit double or decimal.
  • Avoid using float unless you fully understand the implications upon any calculations.
  • Avoid boxing and unboxing value types.
  • Prefer String.Format() or StringBuilder 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 using String.Length == 0.

Exception Handling

  • Do not use exceptions for flow control.
  • Use throw; not throw 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 a catch block.
  • Only use the finally block to release resources from a try statement.
  • Derive from Exception not ApplicationException.

Naming Conventions

General Guidelines

  • Always use Camel Case or Pascal Case names.
  • Never prefix with Get or Set properties.
  • Use a maximum of 7 parameters in methods.
  • Always check for null before invoking Events.
  • Avoid evaluating Boolean conditions against true or false.
  • 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:
  • Use camelCasing for method arguments and local variables.
  • Do not use Hungarian notation.
  • use implicit type var for local variable declarations. Exception: primitive types (int, string, double, etc) use predefined names.
  • Declare all member variables at the top of a class, with static variables at the very top.
Private Field _camelCase The following rules outline the naming guidelines for private field:
  • Use camelCasing prefix with underscore for private variables.
  • Do not use Hungarian notation.
Public Field PascalCase The following rules outline the naming guidelines for public field:
  • Use PascalCasing for public variables.
  • Do not use Hungarian notation.
  • Declare all member variables at the top of a class, with static variables at the very top.
Protected Field PascalCase The following rules outline the naming guidelines for protected field:
  • Use PascalCasing for protected variables.
  • Do not use Hungarian notation.
Internal Field PascalCase The following rules outline the naming guidelines for internal field:
  • Use PascalCasing for internal variables.
  • Do not use Hungarian notation.
Constants UpperCase The following rules outline the naming guidelines for constants:
  • Use Screaming Caps for constants or readonly variables.
Property PascalCase The following rules outline the naming guidelines for properties:
  • Use a noun or noun phrase to name properties.
  • Use Pascal case.
  • Do not use Hungarian notation.
  • Consider creating a property with the same name as its underlying type. For example, if you declare a property named Color, the type of the property should likewise be Color.
Method PascalCase The following rules outline the naming guidelines for methods:
  • Use verbs or verb phrases to name methods.
  • Use Pascal case.
Classes and Structs PascalCase The following rules outline the naming guidelines for classes:
  • Use a noun or noun phrase to name a class.
  • Use Pascal case.
  • Use abbreviations sparingly.
  • Do not use the underscore character (_) or leading "C" or "cls".
  • Classes may begin with an "I" only if the letter following the "I" is not capitalized; otherwise it looks like an Interface.
  • Classes should not have same name as the namespace in which they reside.
  • Use abbreviations sparingly.
  • Where appropriate, use a compound word to name a derived class. The second part of the derived class's name should be the name of the base class. For example, ApplicationException is an appropriate name for a class derived from a class named Exception, because ApplicationException is a kind of Exception.
Interface IPascalCase The following rules outline the naming guidelines for interfaces:
  • Name interfaces with nouns or noun phrases, or adjectives that describe behavior. For example, the interface name IComponent uses a descriptive noun.
  • Use Pascal case.
  • Use abbreviations sparingly.
  • Prefix interface names with the letter I, to indicate that the type is an interface.
  • Do not use the underscore character (_).
Parameter camelCase The following rules outline the naming guidelines for parameters:
  • Use camel case for parameter names.
  • Use descriptive parameter names. Parameter names should be descriptive enough that the name of the parameter and its type can be used to determine its meaning in most scenarios.
  • Do not use reserved parameters.
  • Do not prefix parameter names with Hungarian type notation.
Namespaces PascalCase The following rules outline the naming guidelines for namespaces:
  • Use Pascal Case.
  • Do not use underscore and separate logical components with periods.
  • Use CompanyName.TechnologyName as root. If there are no company, use domain name.
  • Do not use same name for a namespace and a class.

More links to refer

No comments:

Post a Comment