Академический Документы
Профессиональный Документы
Культура Документы
0 Coding Guidelines
Guidelines for .NET development
www.avivasolutions.nl blog.avivasolutions.nl
Contents
1 General ........................................................................................................................................... 1
1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 Introduction ............................................................................................................................................. 1 Goals ...................................................................................................................................................... 1 Visual Studio Code Analysis and Source Analysis ................................................................................. 1 Guidelines, not a standard ...................................................................................................................... 1 What about design patterns? .................................................................................................................. 2 Feedback and disclaimer ........................................................................................................................ 2 Contributions .......................................................................................................................................... 2 History .................................................................................................................................................... 2
2 3 4 5 6 7 8 9
Design Guidelines ......................................................................................................................... 3 Maintainability Guidelines ........................................................................................................... 8 Naming Guidelines ..................................................................................................................... 15 Performance Guidelines ............................................................................................................ 19 Usage Guidelines ........................................................................................................................ 20 Documentation Guidelines ........................................................................................................ 22 Layout Guidelines ....................................................................................................................... 24 Resources .................................................................................................................................... 26
[ II ]
www.avivasolutions.nl blog.avivasolutions.nl
1
1.1
General
Introduction
This document attempts to provide useful and pragmatic guidelines for programming in C# 3.0 which we at Aviva Solutions already use in our day-to-day work. This idea started in 2002 when Vic Hartog (Philips Medical Systems) and I were assigned the task of writing up a coding standard for C# 1.0. Since then, I've tried to publish a similar document for C# 2.0, but because of a change of employer, I never officially published it other than through blog posts. In the last couple of months Ive received several requests from the community for an updated version of this document, preferably covering C# 3.0 as well. Moreover, I have become particularly fond of the power that Visual Studio's Code Analysis (FxCop) provides.
1.2
Goals
The coding guidelines have been written up for several reasons that should help writing high quality code that is easy to understand code and easy to maintain by (future) team members. Aviva Solutions applies code reviews to validate code quality, so it is important that all members of a project use the same style of coding. Style in this sense means using common constructs, writing proper documentation and code comments, and organizing code using a common layout.
Although complying with coding guidelines may seem to appear as undesired overhead or may limit creativity, this approach has already proven its value for many years. Moreover, not all coding guidelines have a clear rationale. Many of them are simply choices we made at Aviva Solutions. Additional goals include:
1.3
Preventing common mistakes and pitfalls. Preventing language constructs that are less comprehensive. Promoting object-oriented development.
Another more recent effort is Source Analysis, a.k.a. StyleCop. But even though we really like it, its current ruleset does not allow sufficient flexibility to be pragmatic. For instance, we do want all public members to have proper documentation, but for many private members we don't need one. The current version of StyleCop does not allow you to choose this as an option yet.
1.4
[1]
www.avivasolutions.nl blog.avivasolutions.nl
1.6
It is allowed to copy, adapt, and redistribute this document and its companion quick reference guide for noncommercial purposes or internal usage. However, you may not republish this document, or publish or distribute any adaptation of this document for commercial use without first obtaining express written approval from Aviva Solutions.
1.7
Contributions
The following (prior) colleagues and members from the .NET community have contributed to this document both directly and indirectly (through web sites, articles and on-line discussions): Erwin Derksen (Ordina), Leendert Versluijs (Ordina), Matthijs den Haan (Ordina), John Dekkers (Ordina), Juwal Lovy (IDesign), Peter Ritchie (Independent MVP), Vic Hartog (Philips Medical Systems), William van Strien (Ordina), Martin Opdam (Aviva Solutions), Stephan Bookholt (Aviva Solutions), Jo-Wen Mei (Oosterkamp Training)
1.8
History
Jan 2006 Jan 2009 Initial version based on the Philips C# 1.0 Standard Major overhaul. Introduced recommended use of Code Analysis / FxCop and removed overlapping guidelines. Added C# 3.0 / LINQ coding guidelines. Mar 2009 First publication on the internet Dennis Doomen Dennis Doomen Dennis Doomen
[2]
www.avivasolutions.nl blog.avivasolutions.nl
2
AV1001
Design Guidelines
Do use a public static readonly field to define predefined object instances For example, consider a Color struct that stores a color internally as red, green, and blue components and this class has a constructor taking a numeric representation, then this class may expose several predefined colors like this. public struct Color { public static readonly Color Red = new Color(0xFF0000); public static readonly Color Black = new Color(0x000000); public static readonly Color White = new Color(0xFFFFFF); public Color(int redGreenBlue) { // implementation } }
AV1002
Do mark classes that only contain static members as static The advantage of using a static class is that the compiler can make sure that no instance members are accidentally defined. The compiler will guarantee that instances of this class cannot be created and hence, relieves you of creating a private constructor such as was required in C# 1.0. Use a static class to contain methods that are not associated with a particular instance. For example: public static class EuroConversion { public static Decimal FromUSD(Decimal inUsd) { ... } public static Decimal ToUSD(Decimal inEuro) { ... } }
AV1003
Do seal a class unless it has been designed for inheritance Defining a class sealed ensures that other classes cannot derive from it. Unless you have thought through the consequences of deriving from your class and have provided appropriate measurements (e.g. defined protected default constructors, defined virtual methods and properties, etc), define the class sealed. For example: public sealed class Book { public Book() { } }
AV1010
Dont hide inherited members with the new keyword Not only does the new keyword break Polymorphism, one of the most essential object-orientation principles, it also makes subclasses more difficult to understand. Consider the following two classes: public class Book { public virtual void Print() { Console.WriteLine("Printing Book"); } } public class PocketBook : Book {
[3]
www.avivasolutions.nl blog.avivasolutions.nl
It should not make a difference whether you call Print through the base class or the derived class. AV1011 It should be possible to treat a derived object as if it were a base class object In other words, it shall be possible to use a reference to an object of a derived class wherever a reference to its base class object is used without knowing the specific derived class. This rule is also known as the Liskov Substitution Principle (LSP). Please note that an interface is also regarded as a base class in this context. AV1015 Do allow properties to be set in any order Properties should be stateless with respect to other properties, i.e. there should not be a difference between first setting property DataSource and then DataMember, and vice versa. AV1016 Do use a method, rather than a property, in the following situations
The operation is orders of magnitude slower than a field set would be. If you are even considering providing an asynchronous version of an operation to avoid blocking the thread, it is very likely that the operation is too expensive to be a property. In particular, operations that access the network or the file system (other than once for initialization) should most likely be methods, not properties.
The operation is a conversion, such as the Object.ToString method. The operation returns a different result each time it is called, even if the parameters didnt change. For example, the NewGuid method returns a different value each time it is called. The operation has a significant and observable side effect. Note that populating an internal cache is not generally considered an observable side effect. The operation returns a copy of an internal state (this does not include copies of value type objects returned on the stack).
AV1020
Dont 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. A private constructor is exempt from this rule.
AV1025
Dont return an array This allows calling code to change the items in the array. Even though callers cannot replace the array itself with another array, they can still replace an item within the array with another item. This may cause unexpected effects within the class that owns the array. Instead, return an IEnumerable<T>, or, if the number of items is important for the caller, an ICollection<T>.
[4]
www.avivasolutions.nl blog.avivasolutions.nl
[5]
www.avivasolutions.nl blog.avivasolutions.nl
Important Derived classes that override the protected virtual method are not required to call the base class implementation. The base class must continue to work correctly even if its implementation is not called. AV1053 Consider providing property-changed events Consider providing events that are raised when certain properties are changed. Such an event should be named PropertyChanged, where Property should be replaced with the name of the property with which this event is associated.
Note If your class has many properties that require corresponding events, consider implementing the INotifyPropertyChanged interface instead. AV1054 Dont pass null as the sender parameter when raising an event Often, an event handler is used to handle similar events from multiple senders. The sender argument is then used to get to the source of the event. Always pass a reference to the source (typically this) when raising the event. Furthermore dont pass null as the event data parameter when raising an event. If there is no event data, pass EventArgs.Empty instead of null.
Exception On static events, the sender parameter should be null. AV1060 Do only implement casts that operate on the complete object In other words, dont cast one type to another using a member of the source type. For example, a Button class has a string property Name. It is valid to cast the Button to the Control (since Button is a Control), but it is not valid to cast the Button to a string by returning the value of the Name property. AV1061 Dont generate a semantically different value with a cast For example, it is appropriate to convert a Time or TimeSpan into an Int32. The Int32 still represents the time or duration. It does not, however, make sense to convert a file name string such as c:\mybitmap.gif into a Bitmap object using a cast operation.
[6]
www.avivasolutions.nl blog.avivasolutions.nl
[7]
www.avivasolutions.nl blog.avivasolutions.nl
3
AV1501
Maintainability Guidelines
Avoid using names that can be mistaken with other names. Although technically allowed, the following statement is quite confusing. bool b001 = (lo == l0) ? (I1 == 11) : (lOl != 101);
AV1505
Do name assemblies after their contained namespace To allow storing assemblies in the Global Assembly Cache (GAC) the filename of an assembly must be unique. Therefore, use the namespace name as a prefix of the name of the assembly. As an example, consider a group of classes organized under the namespace AvivaSolutions.Web.Binding exposed by a certain assembly. According to this guideline, that assembly should be called AvivaSolutions.Web.Binding.dll. All DLLs should be named according to the pattern <Company>.<Component>.dll where <Company> refers to your companys name and <Component> contains one or more dot-separated clauses. For example AvivaSolutions.Web.Controls.dll.
Exception If you decide to combine classes from multiple unrelated namespaces into one assembly, consider post fixing the assembly with Core, but do not use that suffix in the namespaces. For instance, AvivaSolutions.Consulting.Core.dll. AV1506 Do name a source file to the class it contains Also, use Pascal casing for naming the file and dont use underscores. AV1507 Do limit the contents of a source code file to one class Exception It is allowed to place small helper classes such as the ones that provide event data (subclasses of EventArgs) in the same file as the corresponding main class. However, place them after the main class. AV1508 Do name a source file to the logical function of the partial type When using partial types and allocating a part per file, name each file after the logical part that part plays. For example: // In MyClass.cs public partial class MyClass {...} // In MyClass.Designer.cs public partial class MyClass {...} AV1510 Do use using instead of fully qualified type names Limit usage of fully qualified type names to prevent name clashing. For example: Dont: var list = new System.Collections.Generic.List<string>(); Do: using System.Collections.Generic; var list = new List<string>();
[8]
www.avivasolutions.nl blog.avivasolutions.nl
If you do need to prevent name clashing, use a using directive to assign an alias: using Label = System.Web.UI.WebControls.Label; AV1515 Dont use "magic numbers" Dont use literal values, either numeric or strings, in your code other than to define symbolic constants. For example: public class Whatever { public static readonly Color PapayaWhip = new Color(0xFFEFD5); public const int MaxNumberOfWheels = 18; } Strings intended for logging or tracing are exempt from this rule. Literals are allowed when their meaning is clear from the context, and not subject to future changes, For example: mean = (a + b) / 2; WaitMilliseconds(waitTimeInSeconds * 1000); // okay // clear enough
If the value of one constant depends on the value of another, do attempt to make this explicit in the code. For example, dont public class SomeSpecialContainer { public const int MaxItems = 32; public const int HighWaterMark = 24; } but do public class SomeSpecialContainer { public const int MaxItems = 32; public const int HighWaterMark = 3 * MaxItems / 4; } Note An enumeration can often be used for certain types of symbolic constants. AV1520 Do use var only when the type is very obvious Only use var as the result of a LINQ query, or if the type is very obvious from the same statement and using it would improve readability.
// at 75%
// at 75%
Don't var i = 3; // var imyfoo = MyFactoryMethod.Create("arg"); // // // // what type? int? uint? float? Not obvious what base-class or interface to expect. Also difficult to refactor if you can't search for the class
Do:
[9]
www.avivasolutions.nl blog.avivasolutions.nl
[ 10 ]
www.avivasolutions.nl blog.avivasolutions.nl
[ 11 ]
www.avivasolutions.nl blog.avivasolutions.nl
Exception In some cases, such as when preconditions are checked and that condition is not met, it may be good practice to exit a method immediately. AV1545 Dont use selection statements instead of a simple assignment or initialization Express your intentions directly. For example, rather than bool pos; if (val > 0) { pos = true; } else
[ 12 ]
www.avivasolutions.nl blog.avivasolutions.nl
write return someString ?? Unavailable; AV1550 Do explicitly define the scope of a type or member Even though types and members have a default scope, always explicitly define whether the scope is public, private or internal. For example: class Cat {} // Better: same visibility as Cat but more explicit internal class Dog { int length; // Better: same scope as length, but more explicit private int height; } AV1551 Do implement the most complete overload of a method or constructor and call it from the other overloaded
methods or constructors This guideline only applies to overloads that are intended for providing optional arguments. Consider for example the following code snippet: public class MyString { private string someText; public MyString(string s) { this.someText = s; } public int IndexOf(string s) {
[ 13 ]
www.avivasolutions.nl blog.avivasolutions.nl
Important If you also want to allow derived classes to override these methods, define the most complete overload as a protected virtual method that is called by all overloads. public class MyString { // same as above public int IndexOf(string s, int startIndex, int count) { return InternalIndexOf(s, startIndex, count); } protected virtual int InternalIndexOf(string s, int startIndex, int count) { return someText.IndexOf(s, startIndex, count); } } AV1560 Do be consistent in the ordering of parameters in overloaded members Parameters with the same name should appear in the same position in all overloads. AV1561 Avoid methods with more than 5 arguments If you end up with a method with more than five arguments, use a structure or class for passing multiple arguments. Moreover, a method with that many arguments may imply that the responsibilities have not been evenly distributed over the classes in a component. AV1562 Dont use ref or out parameters Ref and out parameters make code less understandable and therefore may introduce bugs. Prefer returning compound objects instead. AV1570 Do 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 much later stage if the object did not implement that interface.
[ 14 ]
www.avivasolutions.nl blog.avivasolutions.nl
4
AV1701
Naming Guidelines
Do use proper US-English All identifiers should be named using words from the English language.
Choose easily readable identifier names. For example, HorizontalAlignment is more readable than AlignmentHorizontal. Favor readability over brevity. The property name CanScrollHorizontally is better than ScrollableX (an obscure reference to the X-axis). Avoid using identifiers that conflict with keywords of widely used programming languages.
Exception In some languages it may appear counterintuitive to translate domain-specific non-English terms into its English counterparts. In those cases, it may be wise to keep the original term from the native language. For instance, GetZaak for getting a legal case. However, Code Analysis also performs a spelling check, so you may need to add those terms to a Custom Code Analysis Dictionary. AV1705 Dont prefix member fields Dont use a prefix for field names. For example, Dont use g_ or s_ to distinguish static versus non-static fields. In general, a method in which it is difficult to distinguish local variables from member fields, is too big. Examples of incorrect identifier names are: _currentUser, mUserName, m_loginTime. AV1706 Do use abbreviations with care Dont use abbreviations or acronyms as parts of identifier names. For example, use OnButtonClick rather than OnBtnClick. Avoid single character variable names, such as i or t. Use index or temp instead.
Exceptions Use well-known abbreviations that are widely accepted such as UI instead of UserInterface. AV1707 Do name an identifier according its meaning and not its type
Do use semantically interesting names rather than language-specific keywords for type names. For example, GetLength is a better name than GetInt. Dont use terms like Enum, Class or Struct in a name. Do use a generic Common Type System (CTS) type name, rather than a language-specific name in the rare cases when an identifier has no semantic meaning beyond its type. For example, a method that converts data to Int16 should be named ToInt16, not ToShort because Short is the language-specific type name for Int16.
AV1708
Do name classes, interfaces and value types with nouns, noun phrases or adjective phrases Do name classes, interfaces, and value types with nouns, noun phrases, or occasional adjective phrases, and dont give class names a prefix (such as the letter C).
Bad examples: SearchExamination: in this case it was a page for searching for examinations Common: does not end with a noun,and does not explain what its purpose is
[ 15 ]
www.avivasolutions.nl blog.avivasolutions.nl
AV1709
Do name generic type parameters with descriptive names The following guidelines cover selecting the correct names for generic type parameters.
Do name generic type parameters with descriptive names, unless a single-letter name is completely self explanatory and a descriptive name would not add value. For example: IDictionary is an example of an interface that follows this guideline.
Use the letter T as the type parameter name for types with one single-letter type parameter. Do prefix descriptive type parameter names with the letter T. Consider indicating constraints placed on a type parameter in the name of parameter. For example, a parameter constrained to ISession may be called TSession.
AV1710
Dont repeat the name of a class or enumeration in its members class Employee { // Wrong! static GetEmployee() {} DeleteEmployee() {} // Right static Get() {...} Delete() {...} // Also correct. AddNewJob() {...} RegisterForMeeting() {...} }
AV1711
Do name members similarly to members of .NET Framework classes Stay close to the naming philosophy of the .NET Framework. Developers are already accustomed to the naming patterns .NET Framework classes use, so following this same pattern helps them find their way in your classes as well. For instance, if you define a class that behaves like a collection, provide members like Add, Remove and Count instead of AddItem, Delete or NumberOfItems.
AV1715
Do name properties with nouns, noun phrases, or occasionally adjective phrases. Do name boolean properties with an affirmative phrase. E.g. CanSeek instead of CantSeek. Consider prefixing Boolean properties with Is, Has, Can, Allows, or Supports. Consider giving a property the same name as its type. When you have a property that is strongly typed to an enumeration, the name of the property can be the same as the name of the enumeration. For example, if you have an enumeration named CacheLevel, a property that returns one of its values can also be named CacheLevel.
[ 16 ]
www.avivasolutions.nl blog.avivasolutions.nl
// Wrong: What does first mean? How many? // Better // Best: self-describing // Although not using verb-object pair; type name is clear enough
Do name namespaces according a well-defined pattern All namespaces should be named according to the pattern <Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>] For instance: Microsoft.WindowsMobile.DirectX. Note Dont use the same name for a namespace and a type in that namespace. For example, dont use Debug for a namespace name and also provide a class named Debug in the same namespace.
AV1730
Do add the suffix Callback to delegates related to callback methods Delegates that are used to refer to a callback method (so not an event) must be suffixed with Callback. For example: public delegate void AsyncIOFinishedCallback(IpcClient client, string message);
AV1735
Do use a verb or verb phrase to name an event Do name events with a verb or a verb phrase. For example: Click, Deleted, Closing, Minimizing, and Arriving. For example, the declaration of the Search event may look like this: public event SearchEventHandler Search;
AV1736 AV1737
Dont add an Event suffix to the name of an event Do use -ing and -ed to express pre-events and post-events Do give event names a concept of before and after, using the present and past tense. For example, a close event that is raised before a window is closed would be called Closing and one that is raised after the window is closed would be called Closed. Dont use Before or After prefixes or suffixes to indicate pre and post events. Suppose you want to define events related to the deletion process of an object. Avoid defining the Deleting and Deleted events as BeginDelete and EndDelete.
Deleting: Occurs just before the object is getting deleted Delete: Occurs when the object needs to be deleted by the event handler. Deleted: Occurs when the object is already deleted.
[ 17 ]
www.avivasolutions.nl blog.avivasolutions.nl
Exception In some situations you might be faced with multiple classes exposing the same event name. To allow separate event handlers use a more intuitive name for the event handler, as long as it is prefixed with On. AV1745 Group extension methods in a class suffixed with Extensions If the name of an extension method conflicts with another member or extension method, you must prefix the call with the class name. Having them in a dedicated class with the Extensions suffix improves readability.
[ 18 ]
www.avivasolutions.nl blog.avivasolutions.nl
5
AV1800
Performance Guidelines
Clearly document if calling a member has a performance impact If calling a member causes a performance impact such as involvement of unmanaged code, copies that are being made, expensive calculations that are being performed, or network interaction, then clearly document that. This allows to caller to explicitly cache the result of calling the member and prevent a potential performance issue.
[ 19 ]
www.avivasolutions.nl blog.avivasolutions.nl
6
AV2201
Usage Guidelines
Do use C# types instead of the types from the System namespace For example: use object instead of Object, string instead of String, and int instead of Int32.
AV2205
Do properly name and use resources The guidelines in this topic apply to localizable resources such as error messages and menu text. Do use Pascal casing in resource keys. Do provide descriptive rather than short identifiers. Keep them concise where possible, but dont sacrifice readability. Do use only alphanumeric characters in naming resources.
AV2206
Dont hardcode strings that are presented to end-users Use resources instead.
AV2207
Dont hardcode strings that change based on the deployment Examples include connection strings, server addresses, etc. Use Resources, the ConnectionStrings property of the ConfigurationManager class, or the Settings class generated by Visual Studio.
AV2210
Do build with the highest warning level Configure the development environment to use Warning Level 4 for the C# compiler, and enable the option Treat warnings as errors. This allows the compiler to enforce the highest possible code quality.
AV2211 AV2215
Avoid suppressing specific compiler warnings Do properly fill the attributes of the AssemblyInfo.cs file Ensure that the attributes for the company name, description, copyright statement, version, etc. are filled. One way to ensure that version and other fields that are common to all assemblies have the same values, is to move the corresponding attributes out of the AssemblyInfo.cs into a SolutionInfo.cs file that is shared by all projects within the solution.
AV2216
Do always sign assemblies with a private key Signing an assembly with a private key will give the assembly a strong name which enables the following benefits.
AV2220
Malicious attempts to replace the assembly with another equally named assembly will fail. Signed assemblies properly integrate with .NET security. They can be deployed in the Global Assembly Cache. Classes exposed in the assembly can be exposed to COM.
Avoid LINQ for simple expressions Rather than var q = from item in items where item.Length > 0; prefer using the extension methods from the System.Linq namespace. var q = items.Where(i => i.Length > 0);
[ 20 ]
www.avivasolutions.nl blog.avivasolutions.nl
Since LINQ queries should be written out over multiple lines for readability, the second example is a bit more readable. AV2221 Do use Lambda expressions instead of delegates Lambda expressions have been introduced in C# 3.0 and provide a much more elegant alternative for anonymous delegates. So instead of Customer c = Array.Find(customers, delegate(Customer c) { return c.Name == Tom; }); use an Lambda expression: Customer c = Array.Find(customers, c => c.Name == Tom); Or even better var customer = customers.Where(c => c.Name == Tom);
[ 21 ]
www.avivasolutions.nl blog.avivasolutions.nl
7
AV2301 AV2305
Documentation Guidelines
Do write comments and documentation in US English Do use XML tags for documenting types and members Document all public types and member of types using the built-in XML comment functionality of Visual Studio. Documenting your code allows Visual Studio to pop-up the documentation when your class is used somewhere else. Furthermore, by properly documenting your classes, tools can generate professionally looking class documentation.
The XML elements in the following table are available for documenting a class or class member.
Description Short description of maximum two or three lines. This element is used to generate an overview page of the members of a class. Provides additional details, including preconditions, special behaviour, the relation to other members or classes. Describes the meaning of a method or constructor argument. Describes the return value of a method. Describes a type parameter for a generic type or method declaration to describe. Add a tag for each type parameter of the generic type or method. Describes the type of the data a property accepts or returns.
These elements can also be used on classes and their members but are used to enrich the documentation.
Description Marks a block of text as code. Specifies an example of how to use a method or other library member. This commonly involves using the <code> tag.
Adds an entry to the See Also section at the bottom of a documentation page. Provides a summary for multiple overloads of a method. Without this, the overview page of a class will take the summary of the first overload. Indicates which events under which conditions will be raised by a method or property. Specifies which exceptions can be thrown that a caller may catch. Ensures that a member does not appear in generated documentation. Specifies to comments in another file that describe the types and members in your source code. This is an alternative to placing documentation comments directly in your source code file.
Documents the access of a member. Indicates that the documentation is preliminary and may change in the near future. Describes how a class behaves in a multi-threaded environment.
Inline elements can be used within the contents of the elements from the preceding table.
[ 22 ]
www.avivasolutions.nl blog.avivasolutions.nl
Do write XML documentation with the caller in mind Write the documentation of your class with the class user in mind. Assume the user will not have access to the source code and try to explain how to get the most out of the functionality of your class.
AV2307
Do write MSDN-style documentation Following the MSDN on-line help style and word choice helps the developer to find its way through your documentation more easily. Tip The tool GhostDoc can generate a starting point for documenting code with a shortcut key.
AV2308
Do document preconditions Properly document the preconditions for using a class or its members. Examples include:
AV2309
Argument requirements: non-null, minimum length of an array, element type of an array, etc. State/order related: what other members must be called first. External dependencies: is a certain resource (network, file, etc) required?
Do document post conditions Document clearly whether a member returns null, an empty string, an empty array or something alike. To prevent surprises for the developer, try to stay close to the .NET Framework philosophy.
AV2310
Do document the exceptions that a member can throw Document the exceptions a member can throw (using the <exception> tag) and explain under which situations it may throw this exception. Consider the .NET Framework online help as a good example of how to properly document this.
AV2315 AV2316
Do use // for comments Do write comments that explain the purpose of a code block Try to focus comments on the why and what of a code block and not the how. Avoid explaining the statements in words, but instead, help the reader understand why you chose a certain solution or algorithm and what you are trying to achieve. If applicable, also mention that you chose an alternative solution because you ran into a problem with the obvious solution.
Tip You can also define your own tags like <comment>. They will not be used yet, but can be helpful to add additional comments.
[ 23 ]
www.avivasolutions.nl blog.avivasolutions.nl
8
AV2401 AV2402
Layout Guidelines
Dont put a using statement in a namespace Do order and group namespaces according the company // Microsoft namespaces are first using System; using System.Collections; using System.XML; // Then any other namespaces in alphabetic order using AvivaSolutions.Business; using AvivaSolutions.Standard; using Telerik.WebControls; using Telerik.Ajax;
AV2403
Dont define multiple namespaces in one file A single file should contribute types to only a single namespace.
AV2405
Do place modifiers in a well-defined order When multiple modifier keywords are needed in a type or member declaration, the modifiers should be placed in the following order of appearance: public, protected, internal, private, partial, new, abstract, virtual, override, sealed, static, readonly, extern, volatile, const.
AV2406
Order class members in a well-defined pattern. Maintaining a common order allows other team members to find their way in your code more easily. In order of appearance:
1. Private fields (in a region) 2. Public read-only static fields 3. Constructors and the Finalizer 4. Events 5. Properties 6. Other members grouped in a functional manner. Common groups include: a. Control event handlers b. Page lifecycle handlers c.
Interface implementations (in a #region)
7. Private properties
Private methods should be placed behind the public member in calling order. This prevents readers from having to browse up and down through the code file. AV2407 Be reluctant with #regions Regions can be helpful, but can also hide to main purpose of a class. Therefore, use #regions only for:
Private fields (preferably in a Private Definitions region). Control event handlers Page lifecycle handlers
[ 24 ]
www.avivasolutions.nl blog.avivasolutions.nl
Nested classes Helper classes (in the same file) Interface implementations (only if the class contains other members)
Although not required, give the #endregion statement the same name as the #region to improve readability. AV2410 Use empty lines wherever considered appropriate See an empty line as a paragraph break in a text document. So statements or declarations that logically belong to each other should be hold together. And remember, a text document with a paragraph break after each one or two sentences is difficult to follow, so dont overdo. Good candidates for an empty line include:
AV2411 AV2412 AV2413
Between members After the closing parentheses Between unrelated code blocks Around the #region keyword Between the using statements of the same company.
Dont exceed a line length of 130 characters Do insert space after if, switch, while, for, foreach, catch, lock and using Do put parentheses on a new line Always put { and } on new lines at the same level of indentation as the keyword they belong to. if (someCondition) { Foo(); } Exception To help distinct simple from more complex code, property getters and setters that only consist of a single statement may be written in a more compact form. For example: public string Name { get { return name; } set { if ((name != null) && (name.Length > 0)) { name = value; } } }
[ 25 ]
www.avivasolutions.nl blog.avivasolutions.nl
Resources
1. LINQ Design Guidelines, Mircea Trofin
http://blogs.msdn.com/mirceat/archive/2008/03/13/linq-framework-design-guidelines.aspx
5. CodeBetter.com
http://codebetter.com/
[ 26 ]
www.avivasolutions.nl blog.avivasolutions.nl
10
The table below lists the Visual Studio Code Analysis / FxCop rules that we at Aviva Solutions recommend for any serious software development. Since generic and framework code requires a higher quality than for instance line-of-business applications, we made a distinction between the two using the LOB and Fx (framework) columns.
Design Rules CA1000 DoNotDeclareStaticMembersOnGenericTypes CA1001 TypesThatOwnDisposableFieldsShouldBeDisposable CA1002 DoNotExposeGenericLists CA1003 UseGenericEventHandlerInstances CA1004 GenericMethodsShouldProvideTypeParameter CA1005 AvoidExcessiveParametersOnGenericTypes CA1006 DoNotNestGenericTypesInMemberSignatures CA1007 UseGenericsWhereAppropriate CA1008 EnumsShouldHaveZeroValue CA1009 DeclareEventHandlersCorrectly CA1010 CollectionsShouldImplementGenericInterface CA1011 ConsiderPassingBaseTypesAsParameters CA1012 CA1013 CA1014 CA1016 CA1017 CA1018 CA1019 CA1020 CA1021 CA1023 CA1024 CA1025 CA1026 CA1027 CA1028 CA1030 CA1031 CA1032 CA1033 CA1034 CA1035 CA1036 CA1038 CA1039 CA1040 CA1041 CA1043 CA1044 CA1045 CA1046 CA1047 CA1048 CA1049 CA1050 CA1051 CA1052 CA1053 CA1054 CA1055 CA1056 CA1057 CA1058 CA1059 CA1060 CA1061 CA1062 CA1063 CA1064 AbstractTypesShouldNotHaveConstructors OverloadOperatorEqualsOnOverloadingAddAndSubtract MarkAssembliesWithClsCompliant MarkAssembliesWithAssemblyVersion MarkAssembliesWithComVisible MarkAttributesWithAttributeUsage DefineAccessorsForAttributeArguments AvoidNamespacesWithFewTypes AvoidOutParameters IndexersShouldNotBeMultidimensional UsePropertiesWhereAppropriate ReplaceRepetitiveArgumentsWithParamsArray DefaultParametersShouldNotBeUsed MarkEnumsWithFlags EnumStorageShouldBeInt32 UseEventsWhereAppropriate DoNotCatchGeneralExceptionTypes ImplementStandardExceptionConstructors InterfaceMethodsShouldBeCallableByChildTypes NestedTypesShouldNotBeVisible ICollectionImplementationsHaveStronglyTypedMembers OverrideMethodsOnComparableTypes EnumeratorsShouldBeStronglyTyped ListsAreStronglyTyped AvoidEmptyInterfaces ProvideObsoleteAttributeMessage UseIntegralOrStringArgumentForIndexers PropertiesShouldNotBeWriteOnly DoNotPassTypesByReference DoNotOverloadOperatorEqualsOnReferenceTypes DoNotDeclareProtectedMembersInSealedTypes DoNotDeclareVirtualMembersInSealedTypes TypesThatOwnNativeResourcesShouldBeDisposable DeclareTypesInNamespaces DoNotDeclareVisibleInstanceFields StaticHolderTypesShouldBeSealed StaticHolderTypesShouldNotHaveConstructors UriParametersShouldNotBeStrings UriReturnValuesShouldNotBeStrings UriPropertiesShouldNotBeStrings StringUriOverloadsCallSystemUriOverloads TypesShouldNotExtendCertainBaseTypes MembersShouldNotExposeCertainConcreteTypes MovePInvokesToNativeMethodsClass DoNotHideBaseClassMethods ValidateArgumentsOfPublicMethods ImplementIDisposableCorrectly ExceptionsShouldBePublic LOB x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x Fx x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x Notes
[ 27 ]
www.avivasolutions.nl blog.avivasolutions.nl
o x x
o x x
o x x
o x x
o o o o o o o o o o o o o o o o o
o o o o o o o o o o o o o o o o o
Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke Only if you use P/Invoke
o o
o o
x o
x o
x x x x x x x x x x x x x x x X X X X X X X X X X X
x x x x x x x x x x x x x x x x x x x x x x x x x x
[ 28 ]
www.avivasolutions.nl blog.avivasolutions.nl
X X X X X X X X X X X X X X X X X X X X X X
x x x x x x x x Far fetched x x x x x x x x x x x x x x
X X X X
x x x x x x x x x o x x o x x x x x x x x x x x x x
X X O
X X
x x x x x x x x x x x x x
x x x x x x x x x x x x x
[ 29 ]
www.avivasolutions.nl blog.avivasolutions.nl
Maintainability Rules CA1500 VariableNamesShouldNotMatchFieldNames CA1501 AvoidExcessiveInheritance CA1502 AvoidExcessiveComplexity CA1504 ReviewMisleadingFieldNames CA1505 AvoidUnmaintainableCode CA1506 AvoidExcessiveClassCoupling Reliability Rules CA2000 DisposeObjectsBeforeLosingScope CA2001 AvoidCallingProblematicMethods CA2002 DoNotLockOnObjectsWithWeakIdentity CA2003 DoNotTreatFibersAsThreads CA2004 RemoveCallsToGCKeepAlive CA2006 UseSafeHandleToEncapsulateNativeResources
x x x x x x
x x x x x x
x x x x x x
x x x x x x
[ 30 ]
www.avivasolutions.nl blog.avivasolutions.nl