Coding guidelines

948 views

Published on

Coding Guidelines

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
948
On SlideShare
0
From Embeds
0
Number of Embeds
13
Actions
Shares
0
Downloads
23
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Coding guidelines

  1. 1. Microsoft .NET Coding Guidelines and Best PracticesConfidential e-Zest Solutions Ltd. Page 1 of 54
  2. 2. Version and HistoryVersion Date Author Reviewed By Comments1.0 23-May-2012 Lalit Kale DraftConfidential e-Zest Solutions Ltd. Page 2 of 54
  3. 3. Table of Contents1 Overview ................................................................................................................................. 52 Principles and Themes .............................................................................................................. 53 How to follow the standards across the team ........................................................................... 64 General Coding Standards ........................................................................................................ 7 4.1 Clarity and Consistency ...............................................................................................................................7 4.2 Formatting and Style...................................................................................................................................8 4.3 Using Libraries.............................................................................................................................................9 4.4 Variable Declarations and Initalizations .....................................................................................................9 4.5 Function Declarations and Calls ................................................................................................................11 4.6 Enums........................................................................................................................................................12 4.7 Comments .................................................................................................................................................14 4.7.1 Inline Code Comments 165 .NET Coding Standards ........................................................................................................... 19 5.1 Design Guidelines for Developing Class Libraries .....................................................................................19 5.2 Files and Structure ....................................................................................................................................19 5.3 Assembly Properties .................................................................................................................................19 5.4 Naming Convensions.................................................................................................................................19 5.4.1 General Naming Conventions 19 5.4.2 Capitalization Naming Rules for Identifiers 19 5.4.3 Hungarian Notation 21 5.4.4 UI Control NamingConventions 21 5.5 Constants ..................................................................................................................................................22 5.6 Strings .......................................................................................................................................................22 5.7 Arrays and Collections ..............................................................................................................................24 5.8 Structures ..................................................................................................................................................26 5.8.1 Structures vs. Classes 27 5.9 Classes .......................................................................................................................................................27 5.9.1 Fields 27 5.9.2 Properties 27 5.9.3 Constructors 28 5.9.4 Methods 28 5.9.5 Events 28 5.9.6 Member Overloading 29 5.9.7 Interface Members 30 5.9.8 Virtual Members 30 5.9.9 Static Classes 30Confidential e-Zest Solutions Ltd. Page 3 of 54
  4. 4. 5.9.10 Abstract Classes 30 5.10 Namespaces ..............................................................................................................................................31 5.11 Errors and Exceptions ...............................................................................................................................31 5.11.1 Exception Throwing 31 5.11.2 Exception Handling 32 5.12 Resource Cleanup .....................................................................................................................................35 5.12.1 Try-finally Block 35 5.12.2 Basic Dispose Pattern 37 5.12.3 Finalizable Types 45 5.12.4 Overriding Dispose 52Confidential e-Zest Solutions Ltd. Page 4 of 54
  5. 5. 1 OverviewThis document defines .NETcoding guidelines for the e-Zest project teams. This standard derives fromthe experience of project and product development efforts and is continuously evolving. If you discovera new best practice or a topic that is not covered, please bring that to the attention of the ArchitectGroup and have the conclusion added to this document.No set of guidelines will satisfy everyone. The goal of a standard is to create efficiencies across all of thedevelopers. Applying a set of well-defined coding standards will result in code with fewer bugs, andbetter maintainability.Adopting an unfamiliar standard may be awkward initially, but the pain fadesquickly and the benefits are quickly realized, especially when you inherit ownership of others code.2 Principles and ThemesHigh-quality code exhibits the following characteristics: 1. Understandable.Code must be clearly readable and straightforward. Code must showcase the key things it isdesigned and implemented for. The relevant parts of entire project/Solution code should be easy to reuse. Projects/Solution should not contain unnecessary code. Projects/Solutionsmust include appropriate documentation. 2. Correct.Projects/Solutions must demonstrateproperly how to perform the key things they are designed to do. Projects/Solutions must compile cleanly, run correctly as documented, and be tested. 3. Consistent.Projects/Solutions should follow consistent coding style and layout to make the code easier to read. Likewise, Projects/Solutions should be consistent with each other to make them easier to use together. Consistency shows craftsmanship and attention to detail. 4. Safe. Projects/Solutions must comply with legal, privacy, and policy standards. They must not demonstrate hacks or poor programming practices. 5. Secure.Projects/Solutions should demonstrate how to use secure programming practices such as least privilege, secure versions of runtime library functions, and SDL-recommended project settings. 6. Reliable 7. Maintainable 8. EfficientThe proper use of programming practices, design, and language features determines how wellProjects/Solutions can achieve these. This code standard is designed to help you createProjects/Solutions that serve as “best practices” for customers to emulate.Confidential e-Zest Solutions Ltd. Page 5 of 54
  6. 6. 3 How to follow the standards across the teamIf you have a team of different skills and tastes, you are going to have a tough time convincing everyoneto follow the same standards. The best approach is to have a team meeting and developing your ownstandards document. You may use this document as a template to prepare your own document.Distribute a copy of this document (or your project’s tailored coding guidelines document) well ahead ofthe coding standards meeting. All members should come to the meeting prepared to discuss pros andcons of the various points in the document. Make sure you have a technical manager present in themeeting to resolve conflicts.Discuss all points in the document. Everyone may have a different opinion about each point, but at theend of the discussion, all members must agree upon the standard you are going to follow. Prepare anew standards/guidelines document with appropriate changes based on the suggestions from all of theteam members. Print copies of it and post it in all workstations.After you start the development, you must schedule code review meetings to ensure that everyone isfollowing the rules.3 types of code reviews are recommended:1.Peer review – another team member review the code to ensure that the code follows the codingstandards and meets requirements. This level of review can include some unit testing also. Every file inthe project must go through this process.2.Architect review – the architect of the team must review the core modules of the project to ensurethat they adhere to the design and there are no “big” mistakes that can affect the project in the longrun.3.Group review – randomly select one or more files and conduct a group review once in a week.Distribute a printed copy of the files to all team members 30 minutes before the meeting. Let them readand come up with points for discussion. In the group review meeting, use a projector to display the filecontent in the screen. Go through every sections of the code and let every member give theirsuggestions on how could that piece of code can be written in a better way. (Don’t forget to appreciatethe developer for the good work and also make sure he does not get offended by the “group attack”!)Confidential e-Zest Solutions Ltd. Page 6 of 54
  7. 7. 4 General Coding StandardsThese general coding standards can be applied to all languages - they provide high-level guidance to thestyle, formatting and structure of your source code.4.1 Clarity and ConsistencyDo ensure that clarity, readability and transparency are paramount. These coding standards strive toensure that the resultant code is easy to understand and maintain, but nothing beats fundamentallyclear, concise, self-documenting code.Do ensure that when applying these coding standards that theyare applied consistently. 1. File name should match with class name. For example, for the class HelloWorld, the file name should be helloworld.cs (or, helloworld.vb) 2. Use Pascal Case for file names. 3. Do not hardcode numbers. Use constants instead. Declare constant in the top of the file and use it in your code.However, for application level variables, using constants are also not recommended. You should use the constants in the config file or database so that you can change it later. Declare them as constants only if you are sure this value will never need to be changed. 4. Do not hardcode strings. Use resource files. 5. Never assume that your code will run from drive "C:". You may never know, some users may run it from network or from a "Z:”. 6. Do not have more than one class in a single file. 7. Avoid having very large files. If a single file has more than 1000 lines of code, it is a good candidate for refactoring. Split them logically into two or more classes. 8. Avoid passing too many parameters to a method. If you have more than 4~5 parameters, it is a good candidate to define a class or structure. 9. Use the AssemblyInfo file to fill information like version number, description, company name, copyright notice etc. 10. Logically organize all your files within appropriate folders. Use 2 level folder hierarchies. You can have up to 10 folders in the root folder and each folder can have up to 5 sub folders. If you have too many folders than cannot be accommodated with the above mentioned 2 level hierarchy, you may need re factoring into multiple assemblies. 11. Make sure you have a good logging class which can be configured to log errors, warning or traces. If you configure to log errors, it should only log errors. But if you configure to log traces, it should record all (errors, warnings and trace). Your log class should be written such a way thatConfidential e-Zest Solutions Ltd. Page 7 of 54
  8. 8. in future you can change it easily to log to Windows Event Log, SQL Server, or Email to administrator or to a File etc without any change in any other part of the application. Use the log class extensively throughout the code to record errors, warning and even trace messages that can help you trouble shoot a problem. 12. If you are opening database connections, sockets, file stream etc, always close them in the finally block. This will ensure that even if an exception occurs after opening the connection, it will be safely closed in the finally block. 13. Declare variables as close as possible to where it is first used. Use one variable declaration per line. 14. Use StringBuilder class instead of String when you have to manipulate string objects in a loop. The String object works in weird way in .NET. Each time you append a string, it is actually discarding the old string object and recreating a new object, which is a relatively expensive operations.4.2 Formatting and StyleDo not use tabs. Its generally accepted across Microsoft that tabs shouldnt be used in source files -different text editors use different spacing to render tabs, and this causes formatting confusion. All codeshould be written using four spaces for indentation.Visual Studio text editor can be configured to insert spaces for tabs.Confidential e-Zest Solutions Ltd. Page 8 of 54
  9. 9. You should limit the length of lines of code. Having overly long lines inhibits the readability of code.Break the code line when the line length is greater than column 78 for readability. If column 78 lookstoo narrow, use column 86 or 90.Douse a fixed-width font, typically Courier New, in your code editor.4.3 Using LibrariesDo notreference unnecessary libraries, include unnecessary header files, or reference unnecessaryassemblies. Paying attention to small things like this can improve build times, minimize chances formistakes, and give readers a good impression.4.4 Variable Declarations and InitalizationsDodeclare local variables in the minimum scope block that can contain them, typically just before useif the language allows; otherwise, at the top of that scope block.Doinitialize variables when they are declared.Dodeclare and initialize/assign local variables on a single line where the language allows it. Thisreduces vertical space and makes sure that a variable does not exist in an un-initialized state or in a statethat will immediately change.Do not use Hungarian notation to name variables.Use Meaningful, descriptive words to name variables. Do not use abbreviations.Confidential e-Zest Solutions Ltd. Page 9 of 54
  10. 10. Good: string address int salaryNot Good: string nam string addr int salDo not use single character variable names like i, n, s etc. Use names like index, tempOne exception in this case would be variables used for iterations in loops: for ( int i = 0; i < count; i++ ) { ... }If the variable is used only as a counter for iteration and is not used anywhere else in the loop, manypeople still like to use a single char variable (i) instead of inventing a different suitable name.Do not use underscores (_) for local variable names.All member variables must be prefixed with underscore (_) so that they can be identified from otherlocal variables.Do not use variable names that resemble keywords.Prefixbooleanvariables, properties and methods with “is” or similar prefixes. Ex: private bool _isFinished // C# sample: string name = myObject.Name; int val = time.Hours; VB.NET sample: Dim name AsString = myObject.Name Dim val AsInteger = time.HoursConfidential e-Zest Solutions Ltd. Page 10 of 54
  11. 11. 4.5 Function Declarations and CallsThe function/method name, return value and parameter list can take several forms. Ideally this can allfit on a single line. If there are many arguments that dont fit on a line those can be wrapped, many perline or one per line. Put the return type on the same line as the function/method name.For example,Single Line Format: // C# function call sample: hr = DoSomeFunctionCall(param1, param2, param3); VB.NETfunction call sample: hr = DoSomeFunctionCall(param1, param2, param3)Multiple Line Formats: // C# function call sample: hr = DoSomeFunctionCall(param1, param2,param3, param4, param5); VB.NETfunction call sample: hr = DoSomeFunctionCall(param1, param2,param3, _ param4, param5)Do order parameters, grouping the in parameters first, the out parameters appear last. Within thegroup, order the parameters based onwhat will help programmers supply the right values. For example,if a function takes arguments named “left” and “right”, put “left” before “right” so that their placematch their names. When designing a series of functions which take the same arguments, use aconsistent order across the functions. For example, if one function takes an input handle as the firstparameter, all of the related functions should also take the same input handle as the first parameter.Do not writing very long methods. A method should typically have 1~25 lines of code. If a method hasmore than 25 lines of code, you must consider refactoring into separate methods.Do not use mis-leading names. Method name should tell what it does.A method should do only one job. Do not combine more than one job in a single method, even ifthose jobs are very small.Good: // Save the address. SaveAddress ( address ); // Send an email to the supervisor to inform that the address is updated. SendEmail ( address, email ); void SaveAddress ( string address ) { // Save the address. // ... }Confidential e-Zest Solutions Ltd. Page 11 of 54
  12. 12. void SendEmail ( string address, string email ) { // Send an email to inform the supervisor that the address is changed. // ... }Not Good: // Save address and send an email to the supervisor to inform that // the address is updated. SaveAddress ( address, email ); void SaveAddress ( string address, string email ) { // Job 1. // Save the address. // ... // Job 2. // Send an email to inform the supervisor that the address is changed. // ... }4.6 EnumsDouse an enum to strongly type parameters, properties, and return values that represent sets ofvalues.Dofavor using an enum over static constants or “#define” values .An enum is a structure with a set ofstatic constants. The reason to follow this guideline is because you will get some additional compiler andreflection support if you define an enum versus manually defining a structure with static constants.Good: // C# sample: publicenumColor { Red, Green, Blue } VB.NET sample: PublicEnum Color Red GreenConfidential e-Zest Solutions Ltd. Page 12 of 54
  13. 13. Blue EndEnumBad: // C# sample: publicstaticclassColor { publicconst int Red = 0; publicconst int Green = 1; publicconst int Blue = 2; } VB.NET sample: PublicClass Color PublicConst Red AsInteger = 0 PublicConst Green AsInteger = 1 PublicConst Blue AsInteger = 2 EndClassDo not use an enum for open sets (such as the operating system version, names of your friends, etc.).Doprovide a value of zero on simple enums.Consider calling the value something like “None.” If suchvalue is not appropriate for this particular enum, the most common default value for the enum shouldbe assigned the underlying value of zero. // C# sample: publicenumCompression { None = 0, GZip, Deflate } VB.NET sample: PublicEnum Compression None = 0Confidential e-Zest Solutions Ltd. Page 13 of 54
  14. 14. GZip Deflate EndEnumDo not use Enum.IsDefined for enum range checks in .NET.There are really two problems withEnum.IsDefined. First it loads reflection and a bunch of cold type metadata, making it a surprisinglyexpensive call. Second, there is a versioning issue here. Good: // C# sample: if (c >Color.Black || c <Color.White) { thrownewArgumentOutOfRangeException(...); } VB.NET sample: If (c > Color.Black Or c < Color.White) Then ThrowNew ArgumentOutOfRangeException(...); EndIf Bad: // C# sample: if (!Enum.IsDefined(typeof(Color), c)) { thrownew InvalidEnumArgumentException(...); } VB.NET sample: IfNot [Enum].IsDefined(GetType(Color), c) Then ThrowNew ArgumentOutOfRangeException(...); EndIf4.7 CommentsYou should use comments that summarize what a piece of code is designed to do and why. Do notuse comments to repeat the code. Good:Confidential e-Zest Solutions Ltd. Page 14 of 54
  15. 15. // Determine whether system is running Windows Vista or later operating // systems (major version >= 6) because they support linked tokens, but // previous versions (major version < 6) do not. Bad: // The following code sets the variable i to the starting value of the // array. Then it loops through each item in the array.You shoulduse ‘//’ comments instead of ‘/* */’ for comments for C# code comments.The single-linesyntax (// …) is preferred even when a comment spans multiple lines. // Determine whether system is running Windows Vista or later operating // systems (major version >= 6) because they support linked tokens, but // previous versions (major version < 6) do not. if (Environment.OSVersion.Version.Major >= 6) { } Get and display the process elevation information (IsProcessElevated) and integrity level (GetProcessIntegrityLevel). The information is not available on operating systems prior to Windows Vista. If (Environment.OSVersion.Version.Major >= 6) Then EndIfYou should indent comments at the same level as the code they describe.You should use full sentences with initial caps, a terminating period and proper punctuation andspelling in comments. Good: // Intialize the components on the Windows Form. InitializeComponent(); Intialize the components on the Windows Form. InitializeComponent() Bad:Confidential e-Zest Solutions Ltd. Page 15 of 54
  16. 16. //intialize the components on the Windows Form. InitializeComponent(); intialize the components on the Windows Form InitializeComponent()4.7.1 Inline CodeCommentsInline comments should be included on their own line and should be indented at the same level as thecode they are commenting on, with a blank line before, but none after. Comments describing a block ofcode should appear on a line by themselves, indented as the code they describe, with one blank linebefore it and one blank line after it. For example: if (MAXVAL >= exampleLength) { // Reprort the error. ReportError(GetLastError()); // The value is out of range, we cannot continue. return E_INVALIDARG; }Inline comments are permissible on the same line as the actual code only when giving a brief descriptionof a structure member, class member variable, parameter, or a short statement. In this case it is a goodidea to align the comments for all variables. For example: class Example { public: ... void TestFunction { ... do { ...Confidential e-Zest Solutions Ltd. Page 16 of 54
  17. 17. } while (!fFinished); // Continue if not finished. } private: int m_length; // The length of the example float m_accuracy; // The accuracy of the example };You should not drown your code in comments. Commenting every line with obvious descriptions ofwhat the code does actually hinders readability and comprehension. Single-line comments should beused when the code is doing something that might not be immediately obvious.The following example contains many unnecessary comments: Bad: // Loop through each item in the wrinkles array for (int i = 0; i <= lastWrinkle; i++) { Wrinkle wrinkle = apWrinkles[i]; // Get the next wrinkle if (wrinkle.IsNew() &&// Process if it’s a new wrinkle nMaxImpact <wrinkle.GetImpact()) // And it has the biggest impact { nMaxImpact = wrinkle.GetImpact(); // Save its impact for comparison pBestWrinkle = wrinkle; // Remember this wrinkle as well } }A better implementation would be: Good: // Loop through each item in the wrinkles array, find the Wrinkle with // the largest impact that is new, and store it in ‘pBestWrinkle’. for (int i = 0; i <= lastWrinkle; i++) { Wrinkle wrinkle = apWrinkles[i];Confidential e-Zest Solutions Ltd. Page 17 of 54
  18. 18. if (wrinkle.IsNew() && nMaxImpact <wrinkle.GetImpact()) { nMaxImpact = wrinkle->GetImpact(); pBestWrinkle = wrinkle; } }You should add comments to call out non-intuitive or behavior that is not obvious from reading thecode.Confidential e-Zest Solutions Ltd. Page 18 of 54
  19. 19. 5 .NET Coding StandardsThese coding standards can be applied to C# and VB.NET.5.1 Design Guidelines for Developing Class LibrariesThe Design Guidelines for Developing Class Libraries document on MSDN is a fairly thorough discussionof how to write managed code.5.2 Files and StructureDo nothave more than one public type in a source file, unless they differ only in the number of genericparameters or one is nested in the other. Multiple internal types in one file are allowed.Do name the source file with the name of the public type it contains. For example, MainForm classshould be in MainForm.cs file and List<T> class should be in List.cs file.5.3 Assembly PropertiesThe assembly should contain the appropriate property values describing its name, copyright, and so on. Standard Example Set Copyright to Copyright © Microsoft Corporation [assembly: AssemblyCopyright("Copyright © 2010 Microsoft Corporation 2010")] Set AssemblyCompany to Microsoft Corporation [assembly: AssemblyCompany("Microsoft Corporation")] Set both AssemblyTitle and AssemblyProduct to the [assembly: AssemblyTitle("CSNamedPipeClient")] current sample name [assembly: AssemblyProduct("CSNamedPipeClient")]5.4 Naming Convensions5.4.1 General Naming ConventionsDo use meaning names for various types, functions, variables, constructs and types.You should not use of shortenings or contractions as parts of identifier names. For example, use“GetWindow” rather than “GetWin”. For functions of common types, thread procs, window procedures,dialog procedures use the common suffixes for these “ThreadProc”, “DialogProc”, “WndProc”.Do not useunderscores, hyphens, or any other non-alphanumeric characters.5.4.2 Capitalization Naming Rules for IdentifiersThe following table describes the capitalization and naming rules for different types of identifiers. Identifier Casing Naming Structure Example Class, Structure PascalCasing Noun public class ComplexNumber {...} public struct ComplextStruct{...} Namespace PascalCasing Noun namespaceConfidential e-Zest Solutions Ltd. Page 19 of 54
  20. 20. Do not use the same name for a namespace and Microsoft.Sample.Windows7 a type in that namespace. Enumeration PascalCasing Noun [Flags] Doname flag enums with plural nouns or noun publicenumConsoleModifiers phrases and simple enums with singular nouns or {Alt, Control} noun phrases. Method PascalCasing Verb or Verbphrase public void Print() {...} public void ProcessItem() {...} Public Property PascalCasing Noun or Adjective publicstring CustomerName Doname collection proprieties with a plural public ItemCollection Items phrase describing the items in the collection, as public boolCanRead opposed to a singular phrase followed by “List” or “Collection”. Doname Boolean proprieties with an affirmative phrase (CanSeek instead of CantSeek). Optionally, you can also prefix Boolean properties with “Is,” “Can,” or “Has” but only where it adds value. Non-public Field camelCasing or Noun or Adjective. privatestring name; _camelCasing Do be consistent in a code sample when you use privatestring_name; the _ prefix. Event PascalCasing Verb or Verb phrase // A close event that is Dogive events names with a concept of before raised after the window is and after, using the present and past tense. closed. Do not use “Before” or “After” prefixes or publicevent WindowClosed postfixes to indicate pre and post events. // A close event that is raised before a window is closed. publicevent WindowClosing Delegate PascalCasing Do add the suffix ‘EventHandler’ to names of publicdelegate delegates that are used in events. WindowClosedEventHandler Do add the suffix ‘Callback’ to names of delegates other than those used as event handlers. Do not add the suffix “Delegate” to a delegate. Interface PascalCasing Noun publicinterfaceIDictionary ‘I’ prefix Constant PascalCasing for Noun publicconststring publicly visible; MessageText = "A"; camelCasing for privateconststring internally visible; messageText = "B"; All capital only for publicconst double PI= abbreviation of one 3.14159...; or two chars long. Parameter, camelCasing Noun int customerID; Variable Generic Type PascalCasing Noun T, TItem, TPolicy Parameter ‘T’ prefix Doname generic type parameters with descriptive names, unless a single-letter name is completely self-explanatory and a descriptive name would not add value. Doprefix descriptive type parameter names with T. You shouldusing T as the type parameter name for types with one single-letter type parameter. Resource PascalCasing Noun ArgumentExceptionInvalidName Do provide descriptive rather than short identifiers.Keep them concise where possible, butConfidential e-Zest Solutions Ltd. Page 20 of 54
  21. 21. do not sacrifice readability for space. Do use only alphanumeric characters and underscores in naming resources.5.4.3 Hungarian NotationDo not use Hungarian notation (i.e., do not encode the type of a variable in its name) in .NET.5.4.4 UI Control NamingConventionsUI controls would use the following prefixes. The primary purpose was to make code more readable. Control Type Prefix Button btn CheckBox chk CheckedListBox lst ComboBox cmb ContextMenu mnu DataGrid dg DateTimePicker dtp Form suffix: XXXForm GroupBox grp ImageList iml Label lb ListBox lst ListView lvw Menu mnu MenuItem mnu NotificationIcon nfy Panel pnl PictureBox pct ProgressBar prg RadioButton rad Splitter spl StatusBar sts TabControl tab TabPage tab TextBox tb Timer tmr TreeView tvwFor example, for the “File | Save” menu option, the “Save” MenuItem would be called “mnuFileSave”.Confidential e-Zest Solutions Ltd. Page 21 of 54
  22. 22. 5.5 ConstantsDouse constant fields for constants that will never change.The compiler burns the values of constfields directly into calling code. Therefore const values can never be changed without the risk ofbreaking compatibility. publicclassInt32 { publicconstint MaxValue = 0x7fffffff; publicconstint MinValue = unchecked((int)0x80000000); } PublicClass Int32 PublicConst MaxValue AsInteger = &H7FFFFFFF PublicConst MinValue AsInteger = &H80000000 EndClassDouse public static (shared) readonly fields for predefined object instances. If there are predefinedinstances of the type, declare them as public readonly static fields of the type itself. For example, publicclassShellFolder { publicstaticreadonlyShellFolder ProgramData = newShellFolder("ProgramData"); publicstaticreadonlyShellFolder ProgramFiles = newShellFolder("ProgramData"); ... } PublicClass ShellFolder PublicSharedReadOnly ProgramData AsNew ShellFolder("ProgramData") PublicSharedReadOnly ProgramFiles AsNew ShellFolder("ProgramFiles") ... EndClass5.6 StringsDo not use the ‘+’ operator (or ‘&’ in VB.NET) to concatenate many strings. Instead, you should useStringBuilder for concatenation. However, do use the ‘+’ operator (or ‘&’ in VB.NET) to concatenatesmall numbers of strings.Confidential e-Zest Solutions Ltd. Page 22 of 54
  23. 23. Good: StringBuilder sb = newStringBuilder(); for (int i = 0; i < 10; i++) { sb.Append(i.ToString()); } Bad: string str = string.Empty; for (int i = 0; i < 10; i++) { str += i.ToString(); }Do use overloads that explicitly specify the string comparison rules for string operations. Typically, thisinvolves calling a method overload that has a parameter of type StringComparison.Do use StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase for comparisons as yoursafe default for culture-agnostic string matching, and for better performance.Do use string operations that are based on StringComparison.CurrentCulture when you display outputto the user.Do use the non-linguistic StringComparison.Ordinal or StringComparison.OrdinalIgnoreCasevaluesinstead of string operations based on CultureInfo.InvariantCulture when the comparison is linguisticallyirrelevant (symbolic, for example).Do not use string operations based onStringComparison.InvariantCulture in most cases. One of the few exceptions is when you are persistinglinguistically meaningful but culturally agnostic data.Do use an overload of the String.Equals method to test whether two strings are equal. For example, totest if two strings are equal ignoring the case, if (str1.Equals(str2, StringComparison.OrdinalIgnoreCase)) If (str1.Equals(str2, StringComparison.OrdinalIgnoreCase)) ThenDo not use an overload of the String.Compare or CompareTo method and test for a return value ofzero to determine whether two strings are equal. They are used to sort strings, not to check for equality.Confidential e-Zest Solutions Ltd. Page 23 of 54
  24. 24. Do use the String.ToUpperInvariant method instead of the String.ToLowerInvariant method when younormalize strings for comparison.5.7 Arrays and CollectionsYou shoulduse arrays in low-level functions to minimize memory consumption and maximizeperformance. In public interfaces, do prefer collections over arrays.Collections provide more control over contents, can evolve over time, and are more usable. In addition,using arrays for read-only scenarios is discouraged as the cost of cloning the array is prohibitive.However, if you are targeting more skilled developers and usability is less of a concern, it might bebetter to use arrays for read-write scenarios. Arrays have a smaller memory footprint, which helpsreduce the working set, and access to elements in an array is faster as it is optimized by the runtime.Do not use read-only array fields. The field itself is read-only and can’t be changed, but elements inthe array can be changed.This example demonstrates the pitfalls of using read-only array fields: Bad: publicstaticreadonlychar[] InvalidPathChars = { ", <, >, |};This allows callers to change the values in the array as follows: InvalidPathChars[0] = A;Instead, you can use either a read-only collection (only if the items are immutable) or clone the arraybefore returning it. However, the cost of cloning the array may be prohibitive. publicstatic ReadOnlyCollection<char> GetInvalidPathChars() { return Array.AsReadOnly(badChars); } publicstaticchar[] GetInvalidPathChars() { return (char[])badChars.Clone(); }You shoulduse jagged arrays instead of multidimensional arrays.A jagged array is an array withelements that are also arrays. The arrays that make up the elements can be of different sizes, leading toless wasted space for some sets of data (e.g., sparse matrix), as compared to multidimensional arrays.Confidential e-Zest Solutions Ltd. Page 24 of 54
  25. 25. Furthermore, the CLR optimizes index operations on jagged arrays, so they might exhibit better runtimeperformance in some scenarios. // Jagged arrays int[][] jaggedArray = { newint[] {1,2,3,4}, newint[] {5,6,7}, newint[] {8}, newint[] {9} }; Dim jaggedArray AsInteger()() = NewInteger()() _ { _ NewInteger() {1, 2, 3, 4}, _ NewInteger() {5, 6, 7}, _ NewInteger() {8}, _ NewInteger() {9} _ } // Multidimensional arrays int [,] multiDimArray = { {1,2,3,4}, {5,6,7,0}, {8,0,0,0}, {9,0,0,0} }; Dim multiDimArray(,) AsInteger = _ { _Confidential e-Zest Solutions Ltd. Page 25 of 54
  26. 26. {1, 2, 3, 4}, _ {5, 6, 7, 0}, _ {8, 0, 0, 0}, _ {9, 0, 0, 0} _ }Douse Collection<T> or a subclass of Collection<T> for properties or return values representingread/write collections, and use ReadOnlyCollection<T> or a subclass of ReadOnlyCollection<T> forproperties or return values representing read-only collections.You should reconsider the use of ArrayList because any objects added into the ArrayList are added asSystem.Object and when retrieving values back from the arraylist, these objects are to be unboxed toreturn the actual valuetype. So it is recommended to use the custom typed collections instead ofArrayList. For example, .NET provides a strongly typed collection class for String inSystem.Collection.Specialized, namely StringCollection.You should reconsider the use of Hashtable. Instead, try other dictionary such as StringDictionary,NameValueCollection, HybridCollection.Hashtable can be used if less number of values is stored.When you are creating a collection type, you should implement IEnumerable so that the collectioncan be used with LINQ to Objects.Do notimplement both IEnumerator<T> and IEnumerable<T> on the same type. The same applies tothe nongeneric interfaces IEnumerator and IEnumerable. In other words, a type should be either acollection or an enumerator, but not both.Do not return a null reference for Arrayor Collection. Null can be difficult to understand in thiscontext. For example, a user might assume that the following code will work.Return an empty array orcollection instead of a null reference. int[] arr = SomeOtherFunc(); foreach (int v in arr) { ... }5.8 StructuresDoensure that a state where all instance data is set to zero, false, or null (as appropriate) is valid.Thisprevents accidental creation of invalid instances when an array of the structs is created.Confidential e-Zest Solutions Ltd. Page 26 of 54
  27. 27. Doimplement IEquatable<T> on value types.The Object.Equals method on value types causes boxingand its default implementation is not very efficient, as it uses reflection. IEquatable<T>.Equals can havemuch better performance and can be implemented such that it will not cause boxing.5.8.1 Structures vs. ClassesDo not define a struct unless the type has all of the following characteristics: • It logically represents a single value, similar to primitive types (int, double, etc.). • It has an instance size fewer than 16 bytes. • It is immutable. • It will not have to be boxed frequently.In all other cases, you should define your types as classes instead of structs.5.9 ClassesDouse inheritance to express “is a” relationships such as “cat is an animal”.Douse interfaces such as IDisposable to express “can do” relationships such as using “objects of thisclass can be disposed”.5.9.1 FieldsDo not provide instance fields that are public or protected.Public and protected fields do not versionwell and are not protected by code access security demands. Instead of using publicly visible fields, useprivate fields and expose them through properties.Douse public static read-only fields for predefined object instances.Douse constant fields for constants that will never change.Do not assign instances of mutable types to read-only fields.5.9.2 PropertiesDocreate read-only properties if the caller should not be able to change the value of the property.Do not provide set-only properties.If the property getter cannot be provided, use a method toimplement the functionality instead. The method name should begin with Set followed by what wouldhave been the property name.Doprovide sensible default values for all properties, ensuring that the defaults do not result in asecurity hole or an extremely inefficient design.Confidential e-Zest Solutions Ltd. Page 27 of 54
  28. 28. You should not throw exceptions from property getters.Property getters should be simple operationswithout any preconditions. If a getter might throw an exception, consider redesigning the property to bea method.This recommendation does not apply to indexers. Indexers can throw exceptions because ofinvalid arguments.It is valid and acceptable to throw exceptions from a property setter.5.9.3 ConstructorsDominimal work in the constructor.Constructors should not do much work other than to capture theconstructor parameters and set main properties. The cost of any other processing should be delayeduntil required.Dothrow exceptions from instance constructors if appropriate.Doexplicitly declare the public default constructor in classes, if such a constructor is required.Eventhough some compilers automatically add a default constructor to your class, adding it explicitly makescode maintenance easier. It also ensures the default constructor remains defined even if the compilerstops emitting it because you add a constructor that takes parameters.Do not call virtual members on an object inside its constructors.Calling a virtual member causes themost-derived override to be called regardless of whether the constructor for the type that defines themost-derived override has been called.5.9.4 MethodsDoplace all out parameters after all of the pass-by-value and ref parameters (excluding parameterarrays), even if this results in an inconsistency in parameter ordering between overloads.Dovalidate arguments passed to public, protected, or explicitly implemented members. ThrowSystem.ArgumentException, or one of its subclasses, if the validation fails: If a null argument is passedand the member does not support null arguments, throw ArgumentNullException. If the value of anargument is outside the allowable range of values as defined by the invoked method, throwArgumentOutOfRangeException.5.9.5 EventsDobe prepared for arbitrary code executing in the event-handling method.Consider placing the codewhere the event is raised in a try-catch block to prevent program termination due to unhandledexceptions thrown from the event handlers.Do not use events in performance sensitive APIs. While events are easier for many developers tounderstand and use, they are less desirable than Virtual Members from a performance and memoryconsumption perspective.Confidential e-Zest Solutions Ltd. Page 28 of 54
  29. 29. 5.9.6 Member OverloadingDouse member overloading rather than defining members with default arguments. Default argumentsare not CLS-compliant and cannot be used from some languages.There is also a versioning issue inmembers with default arguments.Imagine version 1 of a method that sets an optional parameter to 123.When compiling code that calls this method without specifying the optional parameter, the compiler willembed the default value (123) into the code at the call site. Now, if version 2 of the method changes theoptional parameter to 863, then, if the calling code is not recompiled, it will call version 2 of the methodpassing in 123 (version 1’s default, not version 2’s default). Good: PublicOverloadsSub Rotate(ByVal data As Matrix) Rotate(data, 180) EndSub PublicOverloadsSub Rotate(ByVal data As Matrix, ByVal degrees AsInteger) Do rotation here EndSub Bad: PublicSub Rotate(ByVal data As Matrix, OptionalByVal degrees AsInteger = 180) Do rotation here EndSubDo not arbitrarily vary parameter names in overloads. If a parameter in one overload represents thesame input as a parameter in another overload, the parameters should have the same name.Parameterswith the same name should appear in the same position in all overloads.Domake only the longest overload virtual (if extensibility is required). Shorter overloads should simplycall through to a longer overload.Confidential e-Zest Solutions Ltd. Page 29 of 54
  30. 30. 5.9.7 Interface MembersYou should not implement interface members explicitly without having a strong reason to do so.Explicitly implemented members can be confusing to developers because they don’t appear in the list ofpublic members and they can also cause unnecessary boxing of value types.You should implement interface members explicitly, if the members are intended to be called onlythrough the interface.5.9.8 Virtual MembersVirtual members perform better than callbacks and events, but do not perform better than non-virtualmethods.Do not make members virtual unless you have a good reason to do so and you are aware of all thecosts related to designing, testing, and maintaining virtual members.You shouldprefer protected accessibility over public accessibility for virtual members. Public membersshould provide extensibility (if required) by calling into a protected virtual member.5.9.9 Static ClassesDouse static classes sparingly.Static classes should be used only as supporting classes for the object-oriented core of the framework.5.9.10 Abstract ClassesDo not define public or protected-internal constructors in abstract types.Dodefine a protected or an internal constructor on abstract classes.A protected constructor is more common and simply allows the base class to do its own initializationwhen subtypes are created. publicabstractclassClaim { protected Claim() { ... } }An internal constructor can be used to limit concrete implementations of the abstract class to theassembly defining the class.Confidential e-Zest Solutions Ltd. Page 30 of 54
  31. 31. publicabstractclassClaim { internal Claim() { ... } }5.10 NamespacesNamespace names should follow the standard pattern<company name>.<product name>.<top level module/Folder>.<bottom level module/Folder>5.11 Errors and Exceptions5.11.1 Exception ThrowingDo report execution failures by throwing exceptions.Exceptions are the primary means of reportingerrors in frameworks. If a member cannot successfully do what it is designed to do, it should beconsidered an execution failure and an exception should be thrown.Do not return error codes.Dothrow the most specific (the most derived) exception that makes sense.For example, throwArgumentNullException and not its base type ArgumentException if a null argument is passed. ThrowingSystem.Exception as well as catching System.Exception are nearly always the wrong thing to do.Do not use exceptions for the normal flow of control, if possible.Except for system failures andoperations with potential race conditions, you should write code that does not throw exceptions. Forexample, you can check preconditions before calling a method that may fail and throw exceptions. Forexample, // C# sample: if (collection != null && !collection.IsReadOnly) { collection.Add(additionalNumber); } VB.NET sample: If ((Not collection IsNothing) And (Not collection.IsReadOnly)) Then collection.Add(additionalNumber)Confidential e-Zest Solutions Ltd. Page 31 of 54
  32. 32. EndIfDo not throw exceptions from exception filter blocks. When an exception filter raises an exception,the exception is caught by the CLR, and the filter returns false. This behavior is indistinguishable fromthe filter executing and returning false explicitly and is therefore very difficult to debug. VB.NET sample This is bad design. The exception filter (When clause) may throw an exception when the InnerException property returns null Try ... Catch e As ArgumentException _ When e.InnerException.Message.StartsWith("File") ... EndTryDo not explicitly throw exceptions from finally blocks. Implicitly thrown exceptions resulting fromcalling methods that throw are acceptable.5.11.2 Exception HandlingYou should notswallow errors by catching nonspecific exceptions, such as System.Exception,System.SystemException, and so on in .NET code.Do catch only specific errors that the code knows howto handle. You should catch a more specific exception, or re-throw the general exception as the laststatement in the catch block. There are cases when swallowing errors in applications is acceptable, butsuch cases are rare.Good: // C# sample: try { ... } catch(System.NullReferenceException exc) { ...Confidential e-Zest Solutions Ltd. Page 32 of 54
  33. 33. } catch(System.ArgumentOutOfRangeException exc) { ... } catch(System.InvalidCastException exc) { ... } VB.NET sample: Try ... Catch exc As System.NullReferenceException ... Catch exc As System.ArgumentOutOfRangeException ... Catch exc As System.InvalidCastException ... EndTryBad: // C# sample: try { ... } catch (Exception ex) { ... }Confidential e-Zest Solutions Ltd. Page 33 of 54
  34. 34. VB.NET sample: Try ... Catch ex As Exception ... EndTryDoprefer using an empty throw when catching and re-throwing an exception. This is the best way topreserve the exception call stack.Good: // C# sample: try { ... // Do some reading with the file } catch { file.Position = position; // Unwind on failure throw; // Rethrow } VB.NET sample: Try ... Do some reading with the file Catch ex As Exception file.Position = position Unwind on failure Throw Rethrow EndTryBad:Confidential e-Zest Solutions Ltd. Page 34 of 54
  35. 35. // C# sample: try { ... // Do some reading with the file } catch (Exception ex) { file.Position = position; // Unwind on failure throw ex; // Rethrow } VB.NET sample: Try ... Do some reading with the file Catch ex As Exception file.Position = position Unwind on failure Throw ex Rethrow EndTry5.12 Resource CleanupDo not force garbage collections with GC.Collect.5.12.1 Try-finally BlockDouse try-finally blocks for cleanup code andtry-catch blocks for error recovery code. Do not usecatch blocks for cleanup code.Usually, the cleanup logic rolls back resource (particularly, nativeresource) allocations. For example, // C# sample: FileStream stream = null; try { stream = newFileStream(...); ...Confidential e-Zest Solutions Ltd. Page 35 of 54
  36. 36. } finally { if (stream != null) { stream.Close(); } } VB.NET sample: Dim stream As FileStream = Nothing Try stream = New FileStream(...) ... Catch ex As Exception If (stream IsNotNothing) Then stream.Close() EndIf EndTryC# and VB.NET provide the using statement that can be used instead of plain try-finally to clean upobjects implementing the IDisposable interface. // C# sample: using(FileStream stream = newFileStream(...)) { ... } VB.NET sample: Using stream AsNew FileStream(...) ... EndUsingConfidential e-Zest Solutions Ltd. Page 36 of 54
  37. 37. Many language constructs emit try-finally blocks automatically for you. Examples are C#/VB’s usingstatement, C#’s lock statement, VB’s SyncLock statement, C#’s foreach statement, and VB’s For Eachstatement.5.12.2 Basic Dispose PatternThe basic implementation of the pattern involves implementing the System.IDisposable interface anddeclaring the Dispose(bool) method that implements all resource cleanup logic to be shared betweenthe Dispose method and the optional finalizer. Please note that this section does not discuss providing afinalizer. Finalizable types are extensions to this basic pattern and are discussed in the next section. Thefollowing example shows a simple implementation of the basic pattern: // C# sample: publicclassDisposableResourceHolder : IDisposable { private bool disposed = false; privateSafeHandle resource; // Handle to a resource public DisposableResourceHolder() { this.resource = ... // Allocates the native resource } publicvoid DoSomething() { if (disposed) { thrownewObjectDisposedException(...); } // Now call some native methods using the resource ... }Confidential e-Zest Solutions Ltd. Page 37 of 54
  38. 38. publicvoid Dispose() { Dispose(true); GC.SuppressFinalize(this); } protectedvirtualvoid Dispose(bool disposing) { // Protect from being called multiple times. if (disposed) { return; } if (disposing) { // Clean up all managed resources. if (resource != null) { resource.Dispose(); } } disposed = true; } } VB.NET sample: PublicClass DisposableResourceHolder Implements IDisposableConfidential e-Zest Solutions Ltd. Page 38 of 54
  39. 39. Private disposed AsBoolean = False Private resource As SafeHandle Handle to a resource PublicSubNew() resource = ... Allocates the native resource EndSub PublicSub DoSomething() If (disposed) Then ThrowNew ObjectDisposedException(...) EndIf Now call some native methods using the resource ... EndSub PublicSub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) EndSub ProtectedOverridableSub Dispose(ByVal disposing AsBoolean) Protect from being called multiple times. If disposed Then Return EndIf If disposing Then Clean up all managed resources.Confidential e-Zest Solutions Ltd. Page 39 of 54
  40. 40. If (resource IsNotNothing) Then resource.Dispose() EndIf EndIf disposed = True EndSub EndClassDoimplement the Basic Dispose Pattern on types containing instances of disposable types.Doextend the Basic Dispose Pattern to provide a finalizer on types holding resources that need to befreed explicitly and that do not have finalizers.For example, the pattern should be implemented on typesstoring unmanaged memory buffers.You should implement the Basic Dispose Pattern on classes that themselves don’t hold unmanagedresources or disposable objects but are likely to have subtypes that do.A great example of this is theSystem.IO.Stream class. Although it is an abstract base class that doesn’t hold any resources, most of itssubclasses do and because of this, it implements this pattern.Do declare a protected virtual void Dispose(bool disposing) method to centralize all logic related toreleasing unmanaged resources.All resource cleanup should occur in this method. The method is calledfrom both the finalizer and the IDisposable.Dispose method.The parameter will be false if being invokedfrom inside a finalizer. It should be used to ensure any code running during finalization is not accessingother finalizable objects.Details of implementing finalizers are described in the next section. // C# sample: protectedvirtualvoid Dispose(bool disposing) { // Protect from being called multiple times. if (disposed) { return; } if (disposing)Confidential e-Zest Solutions Ltd. Page 40 of 54
  41. 41. { // Clean up all managed resources. if (resource != null) { resource.Dispose(); } } disposed = true; } VB.NET sample: ProtectedOverridableSub Dispose(ByVal disposing AsBoolean) Protect from being called multiple times. If disposed Then Return EndIf If disposing Then Clean up all managed resources. If (resource IsNotNothing) Then resource.Dispose() EndIf EndIf disposed = True EndSubDo implement the IDisposable interface by simply calling Dispose(true) followed byGC.SuppressFinalize(this).The call to SuppressFinalize should only occur if Dispose(true) executessuccessfully.Confidential e-Zest Solutions Ltd. Page 41 of 54
  42. 42. // C# sample: publicvoid Dispose() { Dispose(true); GC.SuppressFinalize(this); } VB.NET sample: PublicSub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) EndSubDo not make the parameterless Dispose method virtual.The Dispose(bool) method is the one thatshould be overridden by subclasses.You should not throw an exception from within Dispose(bool) except under critical situations wherethe containing process has been corrupted (leaks, inconsistent shared state, etc.).Users expect that acall to Dispose would not raise an exception.For example, consider the manual try-finally in this C#snippet: TextReader tr = newStreamReader(File.OpenRead("foo.txt")); try { // Do some stuff } finally { tr.Dispose(); // More stuff }If Dispose could raise an exception, further finally block cleanup logic will not execute. To work aroundthis, the user would need to wrap every call to Dispose (within their finally block!) in a try block, whichConfidential e-Zest Solutions Ltd. Page 42 of 54
  43. 43. leads to very complex cleanup handlers. If executing a Dispose(bool disposing) method, never throw anexception if disposing is false. Doing so will terminate the process if executing inside a finalizer context.Dothrow an ObjectDisposedException from any member that cannot be used after the object hasbeen disposed. // C# sample: publicclassDisposableResourceHolder : IDisposable { private bool disposed = false; private SafeHandle resource; // Handle to a resource publicvoid DoSomething() { if (disposed) { thrownewObjectDisposedException(...); } // Now call some native methods using the resource ... } protectedvirtualvoid Dispose(bool disposing) { if (disposed) { return; } // Cleanup ...Confidential e-Zest Solutions Ltd. Page 43 of 54
  44. 44. disposed = true; } } VB.NET sample: PublicClass DisposableResourceHolder Implements IDisposable Private disposed AsBoolean = False Private resource As SafeHandle Handle to a resource PublicSub DoSomething() If (disposed) Then ThrowNew ObjectDisposedException(...) EndIf Now call some native methods using the resource ... EndSub ProtectedOverridableSub Dispose(ByVal disposing AsBoolean) Protect from being called multiple times. If disposed Then Return EndIf Cleanup ... disposed = TrueConfidential e-Zest Solutions Ltd. Page 44 of 54
  45. 45. EndSub EndClass5.12.3 Finalizable TypesFinalizable types are types that extend the Basic Dispose Pattern by overriding the finalizer andproviding finalization code path in the Dispose(bool) method.The following code shows an example of afinalizable type: // C# sample: publicclassComplexResourceHolder : IDisposable { bool disposed = false; privateIntPtr buffer; // Unmanaged memory buffer privateSafeHandle resource; // Disposable handle to a resource public ComplexResourceHolder() { this.buffer = ... // Allocates memory this.resource = ... // Allocates the resource } publicvoid DoSomething() { if (disposed) { thrownewObjectDisposedException(...); } // Now call some native methods using the resource ... }Confidential e-Zest Solutions Ltd. Page 45 of 54
  46. 46. ~ComplexResourceHolder() { Dispose(false); } publicvoid Dispose() { Dispose(true); GC.SuppressFinalize(this); } protectedvirtualvoid Dispose(bool disposing) { // Protect from being called multiple times. if (disposed) { return; } if (disposing) { // Clean up all managed resources. if (resource != null) { resource.Dispose(); } } // Clean up all native resources.Confidential e-Zest Solutions Ltd. Page 46 of 54
  47. 47. ReleaseBuffer(buffer); disposed = true; } } VB.NET sample: PublicClass DisposableResourceHolder Implements IDisposable Private disposed AsBoolean = False Private buffer As IntPtr Unmanaged memory buffer Private resource As SafeHandle Handle to a resource PublicSubNew() buffer = ... Allocates memory resource = ... Allocates the native resource EndSub PublicSub DoSomething() If (disposed) Then ThrowNew ObjectDisposedException(...) EndIf Now call some native methods using the resource ... EndSub ProtectedOverridesSub Finalize() Dispose(False) MyBase.Finalize()Confidential e-Zest Solutions Ltd. Page 47 of 54
  48. 48. EndSub PublicSub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) EndSub ProtectedOverridableSub Dispose(ByVal disposing AsBoolean) Protect from being called multiple times. If disposed Then Return EndIf If disposing Then Clean up all managed resources. If (resource IsNotNothing) Then resource.Dispose() EndIf EndIf Clean up all native resources. ReleaseBuffer(Buffer) disposed = True EndSub EndClassConfidential e-Zest Solutions Ltd. Page 48 of 54
  49. 49. Domake a type finalizable, if the type is responsible for releasing an unmanaged resource that doesnot have its own finalizer.When implementing the finalizer, simply call Dispose(false) and place allresource cleanup logic inside the Dispose(bool disposing) method. // C# sample: publicclassComplexResourceHolder : IDisposable { ... ~ComplexResourceHolder() { Dispose(false); } protectedvirtualvoid Dispose(bool disposing) { ... } } VB.NET sample: PublicClass DisposableResourceHolder Implements IDisposable ... ProtectedOverridesSub Finalize() Dispose(False) MyBase.Finalize() EndSub ProtectedOverridableSub Dispose(ByVal disposing AsBoolean)Confidential e-Zest Solutions Ltd. Page 49 of 54
  50. 50. ... EndSub EndClassDobe very careful to make type finalizable.Carefully consider any case in which you think a finalizer isneeded. There is a real cost associated with instances with finalizers, from both a performance and codecomplexity standpoint.Doimplement the Basic Dispose Pattern on every finalizable type. See the previous section for detailson the basic pattern.This gives users of the type a means to explicitly perform deterministic cleanup ofthose same resources for which the finalizer is responsible.You shouldcreate and use a critical finalizable object (a type with a type hierarchy that containsCriticalFinalizerObject) for situations in which a finalizer absolutely must execute even in the face offorced application domain unloads and thread aborts.Doprefer resource wrappers based on SafeHandle or SafeHandleZeroOrMinusOneIsInvalid (for Win32resource handle whose value of either 0 or -1 indicates an invalid handle) to writing finalizer by yourselfto encapsulate unmanaged resources where possible, in which case a finalizer becomes unnecessarybecause the wrapper is responsible for its own resource cleanup.Safe handles implement theIDisposable interface, and inherit from CriticalFinalizerObject so the finalizer logic will absolutelyexecute even in the face of forced application domain unloads and thread aborts. ///<summary> /// Represents a wrapper class for a pipe handle. ///</summary> [SecurityCritical(SecurityCriticalScope.Everything), HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true), SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] internalsealedclassSafePipeHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafePipeHandle() : base(true) { }Confidential e-Zest Solutions Ltd. Page 50 of 54
  51. 51. public SafePipeHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { base.SetHandle(preexistingHandle); } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] privatestaticexternbool CloseHandle(IntPtr handle); protectedoverridebool ReleaseHandle() { return CloseHandle(base.handle); } } ///<summary> /// Represents a wrapper class for a local memory pointer. ///</summary> [SuppressUnmanagedCodeSecurity, HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)] internalsealedclassSafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid { public SafeLocalMemHandle() : base(true) { }Confidential e-Zest Solutions Ltd. Page 51 of 54
  52. 52. public SafeLocalMemHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { base.SetHandle(preexistingHandle); } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] privatestaticexternIntPtr LocalFree(IntPtr hMem); protectedoverridebool ReleaseHandle() { return (LocalFree(base.handle) == IntPtr.Zero); } }Do not access any finalizable objects in the finalizer code path, as there is significant risk that they willhave already been finalized. For example, a finalizable object A that has a reference to anotherfinalizable object B cannot reliably use B in A’s finalizer, or vice versa. Finalizers are called in a randomorder (short of a weak ordering guarantee for critical finalization).It is OK to touch unboxed value type fields.Also, be aware that objects stored in static variables will get collected at certain points during anapplication domain unload or while exiting the process. Accessing a static variable that refers to afinalizable object (or calling a static method that might use values stored in static variables) might not besafe if Environment.HasShutdownStarted returns true.Do not let exceptions escape from the finalizer logic, except for system-critical failures.If an exceptionis thrown from a finalizer, the CLR may shut down the entire process preventing other finalizers fromexecuting and resources from being released in a controlled manner.5.12.4 Overriding DisposeIf youre inheriting from a base class that implements IDisposable, you mustimplement IDisposable also.Always call your base classs Dispose(bool) so itcleans up.Confidential e-Zest Solutions Ltd. Page 52 of 54
  53. 53. publicclassDisposableBase : IDisposable { ~DisposableBase() { Dispose(false); } publicvoid Dispose() { Dispose(true); GC.SuppressFinalize(this); } protectedvirtualvoid Dispose(bool disposing) { // ... } } publicclassDisposableSubclass : DisposableBase { protectedoverridevoid Dispose(bool disposing) { try { if (disposing) { // Clean up managed resources. }Confidential e-Zest Solutions Ltd. Page 53 of 54
  54. 54. // Clean up native resources. } finally { base.Dispose(disposing); } } }Confidential e-Zest Solutions Ltd. Page 54 of 54

×