Quantcast
Channel: Scott Bamford » .NET Framework
Viewing all articles
Browse latest Browse all 7

C# Code Guidelines

$
0
0

Coding Guidelines

Every development team or software development team need guidelines to follow to help them write consistent code that keeps maintenance costs low, and development productivity and code reuse high.

I recently updated the ones I use with my team, and though I’d share them to save others having to create their own.  Feel free to reuse in part or full for yourself or your team, and leave a comment with any general suggestions.  Style can be a very personal thing, so don’t be afraid to adapt them to meet your teams own preferences, the key is that all the team follow the same convention, and wherever possible that convention matches the underlying framework you are using.

Naming Conventions

Casing

Use PascalCasing for namespaces, types, and member names.

Use camalCasing for local variables, parameters, and user interface fields.

Use camalCasing with an “m_” prefix for private non-user interface fields.

In 3rd Party Templates or code that uses a “_” prefix within a class rather than a “m_” prefix then be consistant within the class and either rename all to “m_” or continue with the “_” prefix.

Type Notations in Variable Names

Hugarian Notion must not be used – When the type is an important part of the variable’s purpose include it in the name by prefixing or postfixing it to the name without abbreviation.

Do not use abbreviations – If an acronym is widely accepted and used in the framework or toolkit being referenced then it acronym may be used despite the rule to avoid abbreviations.

.NET Word Conventions

Following .NET conventions for the words:

  1. Indexes (not Indices)
  2. UserName (not Username)

Use the following symmetric words when defining pairs of functionality:

  1. Add / Remove
  2. Insert / Delete
  3. Create / Destroy
  4. Initialize / Finalize
  5. Get / Set
  6. LogOn / LogOff
  7. Begin / End
  8. Register / Unregister

Use the following American words rather than the British words for member names:

  1. Color
  2. Initialize

Use of Plural and Singular Words

Name all classes with a singular word or phrase.

Name all collections or with plural words or phrases.

Name all namespaces as plural words or phrases unless the namespace has a special meaning in the MVC framework.

Compatibility with COM and other CLR Languages

Do not name two public or protected members with names that are the same excluding character case.  This would prevent reuse of the classes in languages such as VB.NET.

When an argument for a class is passed in to a method or constructor with the purpose of setting the public member, then use of the same name in camelCase rather than PascalCase is recommend over prefixes or suffixes.

Singletons

Name all static singletons that initialise themselves “Default” unless there is a specific reason to use another name.

Name all static singletons that do not self-initialise “Current” unless there is a specific reason to use another name.

Simple Names

The following simple names are allowed for the uses specified:

  1. obj – to store a generic object who’s type is unimportant.
  2. i, j, k – for control of loops.
  3. s – to store a string value of a variable already in scope in a different type.
  4. e, ea, ee – for subclasses of EventArgs.
  5. e, ex – for subclasses of Exception.
  6. item, it – for the control variable in LINQ query expressions.

Use of Types in Variable Declarations

Use the most specific type available in a variable declaration that is not initialised in-line.

Use var for types that are initialised in-line.

Do not use var for types that are initialised in-line to values of a standard type (e.g. int, string, decimal etc.).

Use var for variables that are initialised as the result of method calls that return collections.

Use var for variables that are storing anonymous types.

Use var when the exact type of a variables is unimportant to the method as more than a return value from an invocation.

Use object for types that are initialised as the result of method calls where the return type is going to be worked with only via reflection.

Use interfaces for variable types if the work being done is dependent only on the interface.

Use dynamic as a variable type only if the type could not be known at compile time, and the code is not going to reflect on the type.

Constructors

Constructor Performance

Avoid use of database connections in constructors.

Avoid use of network calls in constructors.

User Interface Design Time Requirements

Constructors for User Interface classes must be design time compatible.

Member Initialisation

Do not add constructor overloads that perform member initialisation as part of its parameters, these should now be handled by the member initialisation syntax.

Factory and Dependency Injection

Provide a zero parameter constructor unless the class is entirely unusable without a parameter.

Ensure the zero parameter constructor is suitable for use in a class factory or service locator.

Ensure the zero parameter constructor is suitable for use in dependency injection.

Ensure constructors do not over initialise to prevent subclasses from changing implementation details.

Virtual Calls

Avoid calling virtual members from constructors as the behaviour is unpredictable.

Static Constructors

Initialisation

Avoid initialising static members within static constructors.

Wherever possible initialise static members on first use.

Asynchronous Code

Use the await and async keywords when creating asynchronous code.

Prefix “Async” onto all methods that need to be awaited.

Do not prefix “Async” onto any method that cannot be awaited, even if the method contains asynchronous code.

When blocking methods are part of a Portable Class Library and cannot use the await and async keywords, use extension methods with the “Async” prefix to provide asynchronous alternatives for platforms that support it.

When to use Properties, Methods, and Extension Methods

Properties

Use a property if:

  1. The functionality behaves like a field.
  2. Is a logical attribute of the type.
  3. Is unlikely to throw exceptions.
  4. The contained code has minimum value when debugging.
  5. Does not have a dependency on the order being set.

Never use a property if:

  1. A get implementation is not provided.

Methods

Use a method if:

  1. The operation is a conversion.
  2. There is an observable side-effect from the call.
  3. The order of execution is important.
  4. The method may not return.
  5. The method may run code asynchronously.
  6. The result should be cached for reuse within the calling method for performance.

Do not use a method if:

  1. The return value is a collection that remains linked to the instance.

Extension Methods

Use an extension method if:

  1. The operation needs extend a sealed type.
  2. The operation needs to apply to anonymous types.
  3. The operation needs to apply to general IEnumerable types.
  4. Base functionality is provided for an Interface.

Do not use extension methods if:

  1. The behaviour may want to be specialised by a base class.

Place extension methods that form part of a classes or interfaces core API, or platform specific extensions to the core API, in the same namespace as the class, even if it is provided by another assembly.

Always place extension methods that extend core .NET types outside of the System.Collections namespace in a namespace ending in “.Extensions” to avoid littering the namespace of these core objects.

Method Arguments

Name method arguments with names that inform the caller of the intended purpose, not of its internal use.

When a Boolean argument is used as a flag to change fundamental functionality of a method, always call it using the “name: true” style.

Use Boolean arguments called with the “name: true” instead of two member enumerators for all methods, unless the method extends an API where an existing enumerator is better suited.

Exceptions

Catching Exceptions

Only catch exceptions of specific types if the error message being returned will be specialised for the type.

Catch the generic Exception type to isolate calls from the calling code.

A user must be informed of an exception with an error or warning message.

An error or warning message can be omitted if an exception is caught and ignored to avoid a known framework or platform issue and the issue is commented within the catch block.

Do not catch the general Exception type and hide its value from the user.

Throwing Exceptions

Use the existing Exception types to throw your own exceptions.

Only create Exception subclasses when they are to be used multiple times within a library.

LINQ, for, and foreach.

Use LINQ for queries to external data sources.

Use LINQ for queries over in memory data that is designed for use as a dictionary or database.

Use foreach () for iterating over any IEnumerable.

Use var as the item type for the foreach() loop whenever the IEnumerable implements IEnumerable<T>.

Use for() when the iteration is controlled by a numeric block.

Use for() to walk hierarchies.

Use for() or while() when the iteration is controlled by a non-numeric exit condition.

Use do { } while () only where it reduces code compared to a for() or while().

Documentation

Member Comments

Every public member or class must be commented with an XML comment.

Every protected method and property must be commented.

The comment must be written to explain why somebody would want to invoke the code.

The comment must not be a substitute for a bad member name.

The comment should not attempt to list all exceptions that could be thrown but should exceptions of special Exception subclasses thrown directly by the code.

Do not comment private or internal methods that have obvious use.

Do not comment event handlers unless their implementation is non-obvious.

Ensure member comments are suitable for extraction into API documentation.

Do not repeat the XML comment for overridden methods if the comment has nothing new to add to the base type comment.

Do not repeat the XML comment for the implementation of a member for an interface if the comment has nothing new to add to the interface member comment.

Code Block Comments

Comment code with headers within blocks that perform multiple tasks discrete as part of its implementation.

Comment code blocks that cannot be understood by the code alone.

Comment code wherever a special or magic value is used.

Comment code when a condition in a control block could be misunderstood.

Comment Styles

Use /// Comments when commenting members or classes.

Use // Comments when commenting code blocks or statements

Use /* */ comments only if the comment has to be placed in the middle of a line of code or within a Razor syntax document.

Special Developer Comments

Always mark comments that are reminders of code to fix with “TODO” in upper case followed by a message.  This allows all TODO items to be found and completed or before the release of any solution.

If the last statement of a non-void method is not a return statement, place the lint style comment “/* NOTREACHED */ at the bottom of the method so developers know to maintain this when editing the code.

Braces and Brackets

Brace Positioning

Place opening braces for classes, namespaces, and members on new lines.

Place opening braces for code blocks such as if, for, foreach, while, do, and switch on the same line as the code control statement.

Place all closing braces on new lines.

Place both the opening and closing braces for automatic properties on the same line as the property name e.g. public int MyProperty { get; set; }

Place both the opening and closing braces for anonymous types used as property bags on the same line e.g. Html.Link(“Test”, new { this = “that” })

Place else and else if statements on the same line as the closing brace and keep the next opening brace on the same line too.

Bracket Positioning

Place a space between keywords such as if, for, foreach, and while, and the opening bracket.

Do not place a space between a method name and its opening bracket.

Keep the closing bracket on the same line as the opening bracket in the argument list is small.

If the argument list for a method call is long: keep the opening bracket on the same line as the method name, place each argument on a separate line ending with a comma, and place the closing bracket on a new line.



Viewing all articles
Browse latest Browse all 7

Latest Images

Trending Articles





Latest Images