net framework design guidelines - search...

269
.NET Framework Design Guidelines Microsoft Confidential .NET Framework Design Guidelines Desiging Class Libraries for the .NET Framework Public version of the document can be found at http://www.gotdotnet.com/team/libraries/ . Overview Moving to a managed execution environment offers an opportunity to improve the programming model. The goal of this document is to encourage consistency and predictability in the publicly exposed APIs while enabling integration with multiple languages and application models. Document Info Owner KCwalina Last Saved 8/15/2005 File document.doc Primary Reviewers urtlib; External reviewers netprof; lapilead UE GlennHa Contributors The following people substantially contributed to the document: Brad Abrams, Chris Anderson, Erik Christensen, Jason Clark, Krzysztof Cwalina, Patrick Dussud, Anders Hejlsberg, Jim Miller, Michael Murray, Lance Olson, Chi-Yan Tong, Eric Gunnerson, Dare Obasanjo, Ahmed Abou-Taleb, Steve Starck. Table of Contents 1 Introduction..........................................................7 1.1 Goals................................................................8 1.2 How to Read the Document.............................................9 1.2.1 Document Styles.................................................9 1.2.2 FxCop Rules Coverage...........................................10 2 Library Design Fundamentals..........................................10 2.1 Targeting the Breadth of Developers.................................10 2.1.1 Architecture...................................................11 1

Upload: vuongdien

Post on 22-Apr-2018

222 views

Category:

Documents


1 download

TRANSCRIPT

.NET Framework Design Guidelines Microsoft Confidential

.NET Framework Design Guidelines

Desiging Class Libraries for the .NET Framework

Public version of the document can be found at http://www.gotdotnet.com/team/libraries/.

OverviewMoving to a managed execution environment offers an opportunity to improve the programming model. The goal of this document is to encourage consistency and predictability in the publicly exposed APIs while enabling integration with multiple languages and application models.

Document InfoOwner KCwalinaLast Saved 8/16/2005File document.docPrimary Reviewers urtlib;External reviewers netprof; lapileadUE GlennHa

ContributorsThe following people substantially contributed to the document: Brad Abrams, Chris Anderson, Erik Christensen, Jason Clark, Krzysztof Cwalina, Patrick Dussud, Anders Hejlsberg, Jim Miller, Michael Murray, Lance Olson, Chi-Yan Tong, Eric Gunnerson, Dare Obasanjo, Ahmed Abou-Taleb, Steve Starck.

Table of Contents 1 Introduction............................................................................................7

1.1 Goals...........................................................................................................................81.2 How to Read the Document........................................................................................9

1.2.1 Document Styles................................................................................................91.2.2 FxCop Rules Coverage......................................................................................10

2 Library Design Fundamentals.................................................................102.1 Targeting the Breadth of Developers........................................................................10

2.1.1 Architecture......................................................................................................112.2 Exposing Functionality to COM [TO be removed when new section added]..............13

3 Naming Guidelines.................................................................................13

1

.NET Framework Design Guidelines Microsoft Confidential3.1 Capitalization Conventions........................................................................................14

3.1.1 Capitalization Rules for Identifiers....................................................................143.1.2 Capitalizing Acronyms......................................................................................163.1.3 Capitalizing Compound Words and Common Terms.........................................183.1.4 Case Sensitivity................................................................................................19

3.2 General Naming Conventions....................................................................................203.2.1 Word Choice.....................................................................................................203.2.2 Using Abbreviations and Acronyms..................................................................223.2.3 Avoiding Language-specific Names..................................................................22

3.3 Names of Assemblies and DLLs.................................................................................243.4 Names of Namespaces..............................................................................................25

3.4.1 Standard Sub-Namespace Names....................................................................263.4.2 Namespaces and Type Name Conflicts.............................................................283.4.3 WinFx Namespace Plan (MS Internal)...............................................................29

3.5 Names of Classes, Value Types, and Interfaces........................................................333.5.1 Names of Generic Type Parameters.................................................................353.5.2 Names of Common Types.................................................................................363.5.3 Naming Enumerations......................................................................................38

3.6 Names of Type Members..........................................................................................393.6.1 Names of Methods............................................................................................393.6.2 Names of Properties.........................................................................................393.6.3 Names of Events..............................................................................................413.6.4 Naming Fields...................................................................................................43

3.7 Naming Parameters..................................................................................................433.8 Naming Resources....................................................................................................45

4 Type Design Guidelines..........................................................................464.1 Types and Namespaces............................................................................................474.2 Choosing Between Class and Struct..........................................................................484.3 Choosing Between Class and Interface.....................................................................49

4.3.1 Abstract Classes...............................................................................................534.3.2 Static Classes...................................................................................................54

4.4 Interface Design........................................................................................................544.5 Struct Design............................................................................................................564.6 Enum Design.............................................................................................................57

2

.NET Framework Design Guidelines Microsoft Confidential4.6.1 Flags Enum Design...........................................................................................614.6.2 Adding Values to Enums...................................................................................63

4.7 Nested Types............................................................................................................645 Member Design......................................................................................65

5.1.1 Property Design................................................................................................655.1.2 Properties vs. Methods.....................................................................................705.1.3 Read-Only and Write-Only Properties...............................................................725.1.4 Indexed Property (Indexer) Design...................................................................725.1.5 Event Design....................................................................................................735.1.6 Method Design.................................................................................................755.1.7 Method Overloading.........................................................................................765.1.8 Variable Number of Arguments........................................................................785.1.9 Operator Overload Design................................................................................815.1.10 Implementing Equals and Operator==...........................................................835.1.11 Conversion Operators.....................................................................................855.1.12 Constructor Design.........................................................................................855.1.13 Type Constructor Guidelines..........................................................................895.1.14 Field Design....................................................................................................905.1.15 Explicit Member Implementation....................................................................93

5.2 Parameter Design.....................................................................................................955.2.1 Argument Checking..........................................................................................955.2.2 Parameter Passing............................................................................................985.2.3 Pointer Arguments............................................................................................995.2.4 Enums vs Boolean Arguments........................................................................100

6 Common Contract Implementations......................................................1036.1 Collections..............................................................................................................103

6.1.1 Naming...........................................................................................................1036.1.2 Implementation..............................................................................................1036.1.3 Collection Usage.............................................................................................1046.1.4 Generic Collections Usage..............................................................................1056.1.5 Implementing IEnumerable............................................................................1066.1.6 Arrays vs. Collections.....................................................................................1076.1.7 Collection.......................................................................................................1076.1.8 Indexed Properties in Collections...................................................................109

3

.NET Framework Design Guidelines Microsoft Confidential6.1.9 Array Valued Properties..................................................................................1106.1.10 Returning Empty Arrays...............................................................................110

6.2 IDisposable Pattern.................................................................................................1106.2.1 General...........................................................................................................1116.2.2 SafeHandle.....................................................................................................1126.2.3 Finalize...........................................................................................................1136.2.4 Dispose..........................................................................................................1166.2.5 Other Instance Methods.................................................................................1176.2.6 Dispose Pattern..............................................................................................1176.2.6.1 Simple Pattern..........................................................................................1186.2.6.2 Complex Pattern......................................................................................1196.2.7 Example.........................................................................................................1206.2.7.1 Simple Pattern Example.....................................................................1206.2.7.2 Complex Pattern Example........................................................................1226.2.8 Recreatable....................................................................................................125

6.3 IComparable...........................................................................................................1266.4 ICloneable...............................................................................................................1266.5 Delegates................................................................................................................1276.6 Attributes................................................................................................................1276.7 Exception................................................................................................................1296.8 Equals.....................................................................................................................1296.9 Finalize....................................................................................................................1336.10 ToString................................................................................................................1336.11 Serializable [Draft]................................................................................................1336.12 COM Visibility [Draft].............................................................................................135

7 Common Design Patterns.....................................................................1367.1 Asynchronous Pattern.............................................................................................136

7.1.1 Introduction to Asynchronous Programming...................................................1367.1.2 Asynchronous API Design...............................................................................1377.1.3 Summary of Asynchronous Pattern................................................................140

7.2 Optional Features....................................................................................................1417.3 Searcher.................................................................................................................1457.4 Resource Proxy.......................................................................................................1457.5 Builder....................................................................................................................145

4

.NET Framework Design Guidelines Microsoft Confidential7.6 Cannonical Type.....................................................................................................1457.7 Static Method Holder..............................................................................................1457.8 Immutable Types....................................................................................................1457.9 Static Methods and Singleton Design......................................................................145

7.9.1 Singleton Pattern............................................................................................1457.9.2 Static Classes.................................................................................................146

7.10 Callbacks...............................................................................................................1477.11 Factories...............................................................................................................1487.12 Timeouts...............................................................................................................1517.13 Default Instance (Empty) Pattern [Draft]..............................................................1537.14 Obscuring Low Level Funcationality......................................................................154

8 Error Reporting and Handling...............................................................1548.1 Benefits of Exception Handling...............................................................................1548.2 Working with Exceptions.........................................................................................156

8.2.1 Exception Handling Examples from the Framework.......................................1618.3 Exception Usage Guidelines....................................................................................164

8.3.1 Throwing Exceptions......................................................................................1648.3.2 Exception Error Messages..............................................................................1688.3.3 Handling Exceptions.......................................................................................169

8.4 Standard Exception Types......................................................................................172 ArgumentException Usage................................................................................174

8.5 Wrapping Exceptions..............................................................................................1759 Usability..............................................................................................175

9.1 Problem Definition..................................................................................................1759.2 Core Principles of Progressive API Design...............................................................178

9.2.1 Principle of Scenario-Driven Design................................................................1789.2.2 Principle of Customizable Defaults.................................................................1809.2.3 Principle of the Aggregate Component...........................................................1829.2.4 Principle of Self Documenting Object Models.................................................185

9.3 Summary of Usability Guidelines............................................................................1899.3.1 General Usability Guidelines...........................................................................1899.3.2 Scenario Development Guidelines..................................................................1899.3.3 Usable Object Model Design Guidelines.........................................................1909.3.4 Aggregate Component Guidelines..................................................................191

5

.NET Framework Design Guidelines Microsoft Confidential10 Evolving Managed APIs........................................................................192

10.1.1 Consider Existing Consumers.......................................................................19210.1.2 Naming.........................................................................................................193

11 Generics..............................................................................................19511.1 Generics Related Terminology..............................................................................19711.2 General Generics Usage Guidelines......................................................................198

11.2.1 Generics and Usability..................................................................................19911.2.2 Generics and Performance...........................................................................20211.2.3 Common Patterns.........................................................................................206

11.3 Naming Guidelines................................................................................................20911.4 Usage Guidelines..................................................................................................209

11.4.1 General Usage..............................................................................................20911.4.2 Generic Collections.......................................................................................21011.4.3 Nullable<T>.................................................................................................21211.4.4 EventHandler<T>........................................................................................21311.4.5 Comparer<T>..............................................................................................213

11.5 Simulating Covariance..........................................................................................21312 Usage Guidelines.................................................................................214

12.1 System.URI Usage.................................................................................................21412.1.1 System.Uri Implementation Rules................................................................21412.1.2 FxCop Rules..................................................................................................215

12.2 Resources.............................................................................................................21512.3 OptionalValue<T> Usage......................................................................................21712.4 System.Xml Usage................................................................................................218

13 Security...............................................................................................21913.1 Protecting objects with permissions......................................................................21913.2 Fully-trust class library code.................................................................................21913.3 Precautions for highly trusted code.......................................................................22013.4 Performance.........................................................................................................22013.5 General Code Access Security Guidelines.............................................................22113.6 Security Related Coding Conventions...................................................................22213.7 Specific Security Issues.........................................................................................225

13.7.1 Culture Aware String Concerns.....................................................................22513.7.2 Restricting Access (Friends).........................................................................227

6

.NET Framework Design Guidelines Microsoft Confidential13.8 Summary of Security Issues..................................................................................230

14 Misc....................................................................................................23114.1 Interoperating Between Managed and Unmanaged Code.....................................231

14.1.1 Exposing Managed API to Unmanaged Code................................................23114.1.2 Using Unmanaged Code from Managed Code..............................................23314.1.3 Using COM from Managed C++....................................................................23414.1.4 Using ReleaseComObject.............................................................................234

14.2 Platform Support...................................................................................................23514.3 Threading..............................................................................................................236

15 Appendixes..........................................................................................23915.1 Appendix I: The .NET Framework Overview...........................................................239

15.1.1 Generics Overview.......................................................................................23915.2 Appendix II: FxCop................................................................................................23915.3 Appendix III: C# Style Guide.................................................................................239

15.3.1 Exposing Platform Specific.....................................................................23915.3.2 Synchronization and Concurrency........................................................24015.3.3 Remoting...................................................................................................24015.3.4 Internationalization.................................................................................24015.3.5 Deployment..............................................................................................24015.3.6 Component Model....................................................................................24015.3.7 Callback mechanisms..............................................................................24015.3.8 Remoting vs. Messages..........................................................................240

1 Introduction Designing managed, object oriented software is difficult. Designing code to work with other managed libraries outside of your direct control is even more difficult. This problem is exacerbated by the fact that for years most of your functionality has been exposed in an unmanaged way. There is considerable code, design experience, and most importantly, faithful customer's hard learned knowledge invested in the legacy design. Which parts of your libraries should be managed? How do these managed libraries interoperate with COM and other unmanaged applications? How does this fit into the overall Microsoft strategy? What will impress your customers about a managed design?This document does not address all of these issues. Instead it defines a set of guidelines as a way to help class library designers more fully understand the trade-offs between different solutions. Rules are made to be broken, and we understand that there are

7

Krzysztof Cwalina, 12/13/04,
This section needs to be reworked. It needs to stress the importance of consistency, higher-level APIs, wide range of developers as the target, platform, etc.

.NET Framework Design Guidelines Microsoft Confidentialsituations where it is necessary to stray from these guidelines. However, our hope is to force designers to make an explicit decision to violate these guidelines and for these violations to be rare and not far from the spirit of this document.A well-designed managed class library has the following characteristics.

It is consistent: Similar design patterns are implemented across libraries. It is predictable: Functionality is easily discoverable. There is typically only one way

to perform a specified task. It is Web centric: It is designed with cross context, cross process and cross machine

execution in mind. It is flexible: It is callable from semi-trusted code. It is multi-language: Functionality is accessible to many different programming

languages.

1.1 GoalsMoving to a managed execution environment offers an opportunity to improve the programming model. For several reasons, we strongly advise designers to treat these guidelines as if they were prescriptive.We believe that developer productivity can be seriously hampered by inconsistent design.Development tools and add-ins will turn some of these guidelines into de facto prescriptive rules, and reduce the value of non-conforming components. These non-conforming components will function, but not to their full potential.It is very important that you follow the guidelines provided here. However, there are instances where good library design dictates that these guidelines be broken. In such cases, it is important to provide solid justification.

Relationship to the Common Language SpecificationTargeting the common language specification (CLS) is an excellent way to ensure cross language interoperation. The CLS defines a set of programmatically verifiable rules that governs the interoperation of types authored in different programming languages. Although the CLS encourages good library design, it does not enforce it. The CLS is a set of rules to be used by managed class library designers to guarantee that their APIs will be callable across a wide range of programming languages. You should follow two guiding principles when determining which features to include in your class library.Does the feature facilitate the type of API development we want to encourage in the managed space?Although we want the CLS to be rich enough to provide the ability to write any managed library exclusively in the CLS, more is not always better. Providing ten ways to do the same task leads to confusing and bad design/usage discussions. For example, providing both safe and unsafe constructs forces users to decide which one they want to use. The CLS encourages correct behavior by only offering type safe constructs.

8

Krzysztof Cwalina, 12/13/04,
We should probably move the section or rework it.

.NET Framework Design Guidelines Microsoft ConfidentialIs it burdensome for a compiler to expose the feature?All languages will require some modification in order to target the runtime and our common type system. However, in order to be CLS compliant, we do not have to create a large amount of additional work. The goal is for the CLS to be as small as possible and still meet the first goal. For example, parameterized types are not included, because it is burdensome for a compiler to expose this feature.For more information, see the Common Type System <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpconwhatiscommonlanguagespecification.asp> specification.

1.2 How to Read the Document

1.2.1 Document StylesThe vast majority of the guidelines in this document apply equally well to the low level power and expressiveness APIs and the high level ease of use APIs. However there are a few guidelines that must be read differently depending on which developers you are primarily targeting. The guidelines found in this document are annotated to make it clear where tradeoffs are required for the different levels of developers. Examples:Typical guideline, applies regardless target developer:

Do use PascalCasing for all public identifiers consisting of compound words. For example, use TextColor rather than Textcolor or Text_color.Specific guideline when targeting the high level developer:

Consider static members for shared resource creation and instance members to manipulate proxies to such shared resources.Tradeoff: For targeting the higher level developers considers limiting the scenarios where static and instance members are used on the same type. Usability studies have shown that static and instance members on the same type confuse some customers (Mort). If it is critical for your API to be tailored for Mort, you may consider not using static and instance members on the same type. Be aware that tools will be able to mitigate the problem a bit. Specific guideline when targeting the low level developer:

Do prefer collections over arrays. Collections are more usable and institutive in many cases. Collections provide more control over the contents of the container and are more versionable. For read-only values use of arrays often requires cloning and it is therefore more efficient to use collections in many read-only scenarios. Tradeoff: For targeting lower level developers it is often better to use arrays for read-write scenarios. Arrays have a lower memory footprint which helps reduce working set and access to elements in an array can be inlined by the JIT. However usability studies have shown that some customers (Mort) have problems dealing with arrays. The problem lays in the conceptual overhead of understanding the techniques to declare arrays in VB. Collections provide them a simple and consistent model. Array usage for

9

Brad Abraqms, 12/13/04,
Needs to get added to the mainline doc

.NET Framework Design Guidelines Microsoft Confidentialread only scenarios is discouraged even in low level APIs as the cost of cloning the array is prohibitive.

1.2.2 FxCop Rules CoverageFxCop is a code analysis tool that checks CLR assemblies for conformance to some of the guidelines described in this document. The tool checks assemblies against a set of rules that cover the guidelines, and displays violations to these rules. Each guideline in this document is annotated by the coverage that FxCop gives, and the rules that cover it:Fully covered by FxCop rules:

Do … Do not …

Partially covered by FxCop rules. Do … Do not …

Not covered by FxCop rules. Do …

Do not …

2 Library Design Fundamentals

2.1 Targeting the Breadth of DevelopersThis document describes how to design APIs that are both powerful and usable for the breadth of developers. This design paradigm delivers on one of the core value propositions of the framework; which is to offer a unified programming model regardless of programming language choice. By following these guidelines you can create a framework that offers a single, consistently available, set of functionality that is applicable regardless of the application type (client, server, or service) or programming language. It is true that all developers are not solving the same kind of problems. Different types of developers require different levels abstraction and different amounts of control and power. These different types of developers want different things out of the libraries they use. One class of developers, who typically use C++ or C# value power and expressiveness in APIs they use. We refer to these power APIs as low level APIs because they offer a low level of abstraction. On the other hand, some developers that typically use C# or VB.NET value productivity and simplicity. We refer to these more abstract APIs as high level because they offer a higher level of abstraction. By using a layered API design it is possible to build a single API set that meets these diverse needs

2.1.1 Architecture 10

Brad Abrams, 12/13/04,
Somewhere we should talk about what the green and red dots mean

.NET Framework Design Guidelines Microsoft ConfidentialThe general guideline for accomplishing the goal of building a single API set that targets the breadth of developers is to factor your API set into low-level classes that expose all the power and expressiveness and a higher level library that wraps the low level classes with convenience functionality. Figure 1 is a simple illustration of this concept.

Figure 1: Factoring of functionality between high level and low level developers.

An application of this pattern is the APIs exposed in ASP.NET (in the System.Web namespace). For the power an expressiveness crowd ASP.NET offers a low level HTTP Runtime layer that allows developers to code against the raw requests coming into the web server with very little abstraction provided. However ASP.NET also offers a rich set of Web Controls such as a ListBox or Calendar control that allows developers to code against properties and methods on a class without worrying about the request\response patterns needed to implement the behavior. In this way ASP.NET offers a single API set that is consistently available but has layers that target different developer audiences. Notice it is totally possible that based on customer scenarios one layer or another may not be needed. That is some functionality may only expose a low level API.

Also note that care should be taken when implementing high level classes in terms of the lower level classes, the high level developer should not be forced to understand the low level classes to perform common operations. In particular, error messages in exceptions thrown by lower level classes need to be handled appropriately by the higher level classes (for example, by rewording appropriate messages so that they only refer to concepts exposed by the higher level classes). There are a couple of different ways to accomplish this factoring. 1. Expose layers in sub-namespacesUnder this plan you put the high level and low level classes in different, but related namespaces. This has the advantage of hiding the low level classes out of the mainstream scenarios without putting them too far out of reach when customers need to roll over to them for more complex scenarios

11

Low level Power and ExpressivenessTarget: Einstein and Elvis

High level Simplicity and Ease of useTarget: Mort and Elvis

.NET Framework Design Guidelines Microsoft ConfidentialThis strategy works best when there is a logical factoring of the functionality. That is we discourage the use of subnamespaces called “Advanced” and instead use subnamespaces that describe the functionality clearly. Such as System.Net.Sockets.ASP.NET’s functionality is factored according to this pattern. The low level HttpRuntime and application services (such as Caching) are in separate namespaces from the page framework and Web controls in the System.Web.UI namespace. Everything is built on top of the HttpRuntime (which provides core IHttpHandler and IHttpModule functionality). The Page Framework is built on top of this (the Page class implements IHttpHanlder) and this provides the programming model we expect 99% of customers to use.We expect the majority of library developers to follow this pattern. 2. Expose layers in the same namespaceUnder this plan you put the high level and low level classes in the same namespace. This has the advantage of providing seamless roll over to the more complex functionality when it is needed. The down side is that the very fact of having the complex classes in the namespace makes some scenarios more difficult even if those types are not used. Intellisense, docs, etc show the full list of types which can cause users to be misled to using the more complex types.This strategy works best for more basic, shallow levels of functionality. For example the System.Net namespace includes both low level types such as Dns as well as the higher level WebClient class. It should be noted that the System.Net namespace also uses namespace factoring to put the even lower level sockets classes out of the main line scenario.

Note, as with building any feature, good API design is scenario based. Be sure to understand the core scenarios you are enabling and other namespaces are needed accomplish these scenarios. Even functionality in those namespaces should be exposed in a way that meets the needs of the developers you are targeting.

2.2 Exposing Functionality to COM [TO be removed when new section added]

The common language runtime provides rich support for interoperating with COM components. A COM component can be used from within a managed type and a managed instance can be used by a COM component. This support is the key to moving unmanaged code to managed code one piece at a time; however it does present some issues for class library designers. In order to fully expose a managed type to COM clients, the type must expose functionality in a way that is supported by COM and abides by the COM versioning contract.Managed class libraries should be marked with the ComVisible() attribute to indicate whether COM clients can use the library directly or whether they must use a wrapper that shapes the functionality so that they can use it.

12

.NET Framework Design Guidelines Microsoft Confidential Do mark managed class libraries with the ComVisible() attribute1. The vast majority of

library code should be marked as ComVisible(false). Types and Interfaces that must be used directly by COM clients (such as to host in an unmanaged container) should be marked with the ComVisible(true) attribute. The transitive closure of all types referenced by exposed types should all be explicitly marked as ComVisible(true) if not they will be exposed as IUnknown.Note   Members of a type can also be marked as ComVisible(false); this allows a reduced exposure to COM and therefore less restrictions on what a managed type can use.

Types marked with the ComVisible(true) attribute must adhere to the following guidelines.

Do not expose functionality exclusively in a way that is not usable from COM. Specifically, COM does not support the following:

Static methods2

Parameterized constructors3

Do test the type's functionality from classic COM clients. Do understand the Registry impact for making all types cocreateable.

3 Naming GuidelinesFollowing a consistent set of naming conventions in the development of a reusable library is a major contributor to the library’s usability. It allows the library to be used by many developers on widely separated projects. Beyond consistency of form, names for library elements must be easily understood and must convey the function of each element. The goal of the guidelines in this chapter is to provide a consistent set of naming conventions that result in names that make immediate sense to developers. Many of the naming guidelines are simply conventions that have no technical rationale other than their internal consistency. However, following these naming guidelines will ensure that the names in reusable libraries are understandable and consistent. Although adopting these naming conventions as general code development guidelines would result in more consistent naming throughout your code, they are only indented to cover APIs that are publicly exposed (public or protected types and members, and explicitly implemented interfaces).

Annotation (Krzysztof Cwalina):The team that develops the .NET Framework Base Class Library spends an enormous amount of time on naming, and considers it to be a crucial part of library development.

1 Fully covered by FxCop rule: DesignRules/AssembliesShouldBeComVisibleAttributed.2 Fully covered by FxCop rule: ComRules/AvoidStaticMembersForComVisibility3 Fully covered by FxCop rule: ComRules/ComCreatableTypesShouldHavePublicDefaultConstructor

13

.NET Framework Design Guidelines Microsoft ConfidentialThis chapter describes general naming guidelines, involving how to use capitalization, mechanics, and certain specific terms. It also provides specific naming guidelines for naming namespaces, types, members, parameters, assemblies, and resources.

3.1 Capitalization ConventionsBecause the CLR supports many languages, which may or may not be case sensitive, case alone cannot be used to differentiate names. However, the importance of case in enhancing the readability of names cannot be overemphasized. The guidelines in this chapter lay out a simple, consistent scheme for using case that, when applied consistently, make identifiers for types, members, and parameters easy to read.

3.1.1 Capitalization Rules for IdentifiersTo differentiate words in an identifier, capitalize the first letter of each word in the identifier. You should not use underscores to differentiate words, or, for that matter, anywhere in identifiers. There are two appropriate ways to capitalize identifiers, depending on the use of the identifier:

Pascal Casing Camel Casing

Annotation (Brad Abrams): In the initial design of the Framework we had hundreds of hours of debate about naming style. To facilitate these debates we coined a number of terms. With Anders Hejlsberg, the original designer of Turbo Pascal, and a key member of the design team, it is no wonder that we chose the term Pascal Casing for the casing style popularized by the Pascal programming language. We were somewhat cute in using the term camelCasing for the casing style that looks something like the hump on a camel. We used the term SCREAMING CAPS to indicate an all upper case style. Luckily this style (and name) did not survive in the final guideline.

Pascal Casing convention capitalizes the first character of each word (including acronyms over two letters in length) as in the following examples.

PropertyDescriptorHtmlTag

A special case is made for two-letter acronyms, and both letters are capitalized, as in the following identifier:

IOStream

Camel Casing convention capitalizes the first character of each word except the first word, as in the following examples. As in the example, two-letter acronyms that begin a camel Cased identifier are both lower case.

propertyDescriptorioStreamhtmlTag

Annotation: (Brad Abrams)

14

.NET Framework Design Guidelines Microsoft ConfidentialIt may seem odd to make a special case of two-letter acronyms, when acronyms with three or more letters are treated as words following either the PascalCasing or camelCasing rules.  We had many heated debates about this guideline when we were building version 1 of the Framework.  The first proposal was that acronyms would be all upper case, but this was rejected because of readability—for example the ASP.NET team felt strongly that HtmlButton is more readable than HTMLButton.  On the other hand, when considering making all acronyms PascalCased we thought it would be odd to see acronyms such as IO PascalCased.  As an example, the BCL team felt it was clear that System.IO is more natural than System.Io. We compromised on treating acronyms of three or more letters as words, and following the guidelines for capitalizing words.

Always use Pascal Casing for all public member, type, and namespace names consisting of multiple words4. For example, use TextColor rather than Textcolor or Text_color. Single words, such as Button, simply have initial capitals. Compound words that are always written as a single word, like ‘endpoint’, are treated as single words and have initial capitals only. More information on compound words is in section 3.1.3 of this chapter.

Always use Camel Casing for parameter names5.Table 3-1 describes the capitalization rules for different types of identifiers.Table 3-1. Capitalization Rules for Different Types of Identifiers

Identifier Casing ExampleNamespace Pascal Casing namespace System.Security { … }  

Type Pascal Casing public class StreamReader { … }

Interface Pascal Casing public interface IEnumerable { … }

Method Pascal Casing public class Object { public virtual string ToString();   }

Property Pascal Casing public class String { public int Length { get; }}    

Event Pascal Casing public class Process { public event EventHandler Exited; }

Fields Pascal Casing public MessageQueue { public static readonly TimeSpan InfiniteTimeout;}   

Enum value Pascal Casing FileMode { Append, …

4 Fully covered by FxCop rules: NamingRules/MemberNamesArePascalCased, NamingRules/NamespaceNamesArePascalCased, NamingRules/TypeNamesArePascalCased5 Fully covered by FxCop rule: NamingRules/ParameterNamesArePascalCased

15

.NET Framework Design Guidelines Microsoft Confidential

}   

Parameter Camel Casing public class Convert { public static int ToInt32(string value);}   

Annotation (Brad Abrams): An early version of this table included a convention for instance field names. We later adopted a guideline that you should almost never use publicly exposed instance fields, but use properties instead. As such the guideline for publicly exposed instance fields was no longer needed. For the record, the convention was camelCasing.

3.1.2 Capitalizing AcronymsIn general, it is important to avoid using acronyms in identifier names unless they are in common usage and are immediately understandable to anyone who might use the library. For example, HTML, XML, and IO are all well understood, but any company specific acronym should definitely be avoided.

Annotation (Krzysztof Cwalina):Acronyms are distinct from abbreviations, which should never be used in identifiers. An acronym is a word made from the initial letters of a phrase, while an abbreviation simply shortens a word.

By definition, an acronym must be at least two characters. Acronyms of three or more characters follow the guidelines of any other word. Only the first letter is capitalized, unless it is the first word in a camel-cased parameter name, in which case it is all lower case. Two-character acronyms (such as IO) are treated differently. Both characters should be capitalized unless it is the first word in a camel-cased parameter name, in which case both characters are lower case. The following examples illustrate all of these cases:

public void StartIO(Stream ioStream, bool closeIOStream);public void ProcessHtmlTag(string htmlTag)

Always capitalize both characters of two character acronyms except the first word of a camel-cased identifier.

System.IOpublic void StartIO(Stream ioStream)

Always capitalize only the first character of acronyms with three or more characters except the first word of a camel-cased identifier.

System.Xmlpublic void ProcessHtmlTag(string htmlTag)

D o not capitalize any of the characters of any acronyms, whatever their length, at the beginning of a camel-cased identifier.

Annotation (Brad Abrams):

16

Krzysztof Cwalina, 12/13/04,
It would be nice to have an annotation on why two letter acronyms are different.

.NET Framework Design Guidelines Microsoft ConfidentialIn my time working on the .NET Framework and WinFX I have heard every possible excuse to violate these naming guidelines. Many teams feel that they have some special reason to want to use case differently in their identifiers than in the rest of the Framework. These excuses include consistency with an older platform (MFC, HTML, etc), avoiding geo-political issues (casing of some country names), honoring the dead (abbreviations names that came up with some crypto algorithm), and the list goes on and on. For the most part the places we have diverged from these guidelines (for even the best excuse) have been seen by our customers as warts in the Framework. The only time I think it really makes sense to violate these guidelines is when using a trademark as an identifier. In most of these cases I suggest not using trademarks as they tend to change faster than APIs. We have the class below in the Framework today. It successfully follows the guidelines for casing and uses “Argb” rather than “ARGB”. But we have actually gotten bug reports along the lines “How do you convert a color from an ARGB value--all I see is methods to convert “from argument b”.

public struct Color {... public static Color FromArgb(int alpha, Color baseColor); public static Color FromArgb(int alpha, int red, int green, int blue); public static Color FromArgb(int argb); public static Color FromArgb(int red, int green, int blue);...}

In retrospect, should this have been a place where we violated the guidelines and used FromARGB? I do not think so. It turns out this is a case of over-abbreviation. RGB is a well recognized abbreviation for Red-Green-Blue values. An ARGB value is a relatively uncommon abbreviation that includes the alpha channel. It would have been clearer to name these AlphaRgb and would have been more consistent with the rest of the framework.

public struct Color {... public static Color FromAlphaRgb(int alpha, Color baseColor); public static Color FromAlphaRgb(int alpha, int red, int green, int blue); public static Color FromAlphaRgb(int argb); public static Color FromAlphaRgb(int red, int green, int blue);...}

3.1.3 Capitalizing Compound Words and Common TermsMost compound terms are treated as single words.Do not capitalize each word in closed-form compound words. These are compound words written as a single word, such as ‘endpoint’. For the purpose of casing guidelines, treat a closed-form compound word as a single word. Use a current US-English dictionary to determine if a compound word is written in closed form.

Table 3-2 shows capitalization for some of the most commonly used compound words and common terms.

Pascal Camel NOT BitFlag bitFlag BitflagCanceled canceled Cancelled

17

Krzysztof Cwalina, 12/13/04,
The table needs to be sorted.
brada, 12/13/04,
I wonder if we should suggest a particular one.

.NET Framework Design Guidelines Microsoft Confidential

Callback callback CallBackDoNot doNot DontEndpoint endpoint EndPointFileName fileName FilenameGridline gridline GridLineHashtable hashtable HashTableId id IDIndexes indexes IndicesLogOff logOff LogOutLogOn logOn LogInMultiview multiview MultiViewMultipanel multipanel MultiPanel Namespace namespace NameSpaceOk ok OKPlaceholder placeholder PlaceHolderSignIn signIn SignOnSignOut signOut SignOffUserName userName UsernameWhiteSpace whiteSpace WhitespaceWritable writable WriteableMetadata metadata MetaData,

metaDataEmail email EMailPi pi PI

Two other terms that are in common usage are in a category by themselves, because they are common slang abbreviations. The two words Ok and Id (and they should be cased as shown) are the exceptions to the guideline that no abbreviations should be used in names.

Annotation (Brad Abrams):The table above is driven from specific examples found in the development of the .NET Framework. You may find it useful to create your own appendix to this table for compound words commonly used in your domain.

Annotation (Brad Abrams):

18

.NET Framework Design Guidelines Microsoft ConfidentialOne abbreviation commonly used in COM interface names was Ex (for interfaces that were expanded versions of previously existing interfaces). This abbreviation should be avoided in reusable libraries. A meaningful name the describes the new functionality should be used instead.

3.1.4 Case SensitivityLanguages that can run on the Common Language Runtime are not required to support case-sensitivity, although some do. Even if your language supports it, other languages that may access your libraries or components do not. Any code that is externally accessible, therefore, cannot rely on case alone to distinguish between two names in the same context.

Annotation (Paul Vick):When it came to the question of case sensitivity, there was no question in the minds of the Visual Basic team that the CLR had to support case insensitivity as well as case sensitivity. Visual Basic has been case insensitive for a very long time, and the shock of trying to move VB developers (including myself, I might add) into a case sensitive world would have many any of the other challenges we faced pale in comparison. Add to that the fact that COM is case insensitive, and the matter seemed pretty clear. The CLR would have to take case insensitivity into account. That was primarily done by adopting these naming guidelines for

Annotation (Jeffrey Richter):To be clear, CLR is actually case-sensitive. Some programming languages, like Visual Basic, are case insensitive. When the VB compiler is trying to resolve a method call to a type defined in a case sensitive language, like C#, the compiler (not the CLR) figures out the actual case method’s name and embeds it in metadata. The CLR knows nothing about this. Now, if you are using reflection to bind to a method, the reflection APIs do offer the ability to do case-insensitive lookups. This is the extent to which the CLR doesn’t support case-insensitivity.

Do not assume that all programming languages are case sensitive. They are not. Names cannot differ by case alone.

3.2 General Naming ConventionsThis section describes some general naming conventions that relate to word choice, guidelines on using abbreviations and acronyms, and how to avoid using language-specific names.

3.2.1 Word ChoiceIt is important that names within managed components and libraries make sense on first reading. Identifier names should clearly state what each method does and what each type and parameter represents. To this end, it is more important that the name be clear than that it be short. Names should correspond to scenarios, logical or physical parts of the system, and well-known concepts rather than names that refer to technologies or architecture.

Always choose easily readable identifier names. For example, a property named HorizontalAlignment is more English-readable than AlignmentHorizontal.

19

.NET Framework Design Guidelines Microsoft Confidential Do favor readability over brevity. The property name CanScrollHorizontally is better

than ScrollableX (an obscure reference to the X-axis). Do not use underscores, hyphens, or any other non-alphanumeric characters6. Do not use Hungarian notation7.

Annotation: (Krzysztof Cwalina)As with most naming conventions, there have always been both positive and negative effects of using the Hungarian naming convention (and they still exist today). Positives include better readability (if used correctly). Negatives include cost of maintenance, confusion if maintenance was not done properly, and finally, Hungarian makes the API more cryptic (less approachable) to some developers. In the world of procedural languages (like C) and the separation of the System APIs for advanced developers from framework libraries for a much wider developer group, the positives seemed to be greater than the negatives. In today’s landscape with System API designed to be approachable to a broader range of developers, and with Object-Oriented languages, the tradeoff seem to be pulling in the other direction. OO encapsulation brings variable declaration and usage points closer together, OO style favors short well factored methods, and finally abstractions often make the exact type less important or even meaningless (lots of types are simply objects).

Annotation (Jeffrey Richter):I’ll admit it; I miss Hungarian notation. While in many editors, like Visual Studio, you can hover the mouse over a variable and the editor pops up the type, this does not work when reading source code in a book chapter or magazine article. Fortunately, in OOP, variables tend have a short scope making it so that you only need to scan a few lines to find the definition of a variable. However, this is not true for a type’s static and instance fields. Personally, I make all my fields private and I now prefix my instance fields with “m_” and my static field with “s_” so that I can easily spot fields in my methods. This helps me a lot but I still can’t tell what type a variable represents. I rely on my editor’s tool tips for this.

Avoid using identifiers that conflict with keywords of widely used programming languages. Annotation (BradA): According to Rule 4 of the Common Language Specification, all compliant languages must provide a mechanism that allows access to named items that use a keyword of that language as an identifier. C#, for example, uses the “@” sign as an escape mechanism in this case. However it is still a good idea to avoid common keywords as it is much more difficult to use a method with the escape sequence than not.

Annotation (Jeffrey Richter):

6 Partially covered by FxCop rules: NamingRules/MemberNamesDoNotHaveUnderscores, NamingRules/NamespaceNamesDoNotHaveUnderscores, NamingRules/TypeNamesDoNotHaveUnderscores, NamingRules/ParameterNamesDoNotHaveUnderscores, Only covers underscores. Currently no coverage for hyphens and other non-alphanumeric characters. Coming soon, FxCopBug 10107 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly, This rule only covers spelling, not necessarily all prefixes. Full coverage coming soon, FxCopBug 999

20

.NET Framework Design Guidelines Microsoft ConfidentialWhen I was porting my Applied Microsoft .NET Framework Programming book from C# to Visual Basic, I ran into this situation a lot. For example, the class Library has Delegate. Module, and Assembly classes and Visual Basic uses these same terms for keywords. This problem is exacerbated by the fact that VB is a case-insensitive language. Visual Basic, like C#, has a way to escape the keywords to disambiguate the situation to the compiler (using square brackets) but I was surprised that the VB team selected keywords that conflict with so many class library names.

Annotation: (Steven Clarke)Be careful about using keywords inside identifiers also. In a usability study we ran on the Monad APIs, participants were very confused by a parameter named PipelineInputType. They needed to set this parameter to some value inside an attribute in order for their cmdlet to be able to accept input that was ‘piped’ in from some other cmdlet. The parameter specifies the way in which input from other commands will be mapped on to the structure of a cmdlet and can take the values PipelineInput.AsIs or PipelineInput.ByMatchingProperty. However, due to the presence of the word Type in the parameter name, all participants thought that they needed to supply the CLR type that they were piping in to their cmdlet as input. Instead of setting the parameter to PipelineInput.AsIs, participants tried to pass an instance of System.Type.

3.2.2 Using Abbreviations and AcronymsIn general, do not use abbreviations or acronyms in identifiers. As stated earlier, it is more important for names to be readable than that they are brief. It is equally important not to use abbreviations and acronyms that are not generally understood—that is, that the large majority of people who are not experts in a given field know immediately what they mean.Do not use abbreviations or contractions as parts of identifier names8. For example, use GetWindow rather than GetWin.

Do not use any acronyms that are not widely accepted9, and then, only when necessary. For example, UI is used for User Interface and HTML is used for Hyper-Text Markup Language. While many developers feel that some recent acronym will soon be widely accepted, it is bad practice to put them in reusable library names.For acronym capitalization rules, see section 3.1.2.

Annotation (Brad Abrams): We continually debate about whether a given acronym is “well-known” or not. A good divining rod is the Google test. Simply search for the acronym in Google. If the first few results returned are indeed the meaning you intend your acronym qualifies as “well-known” otherwise, think harder about the name. Don’t just spell out the acronym but consider being descriptive.

8 Fully covered by FxCop rules: MSInternalRules/MemberNameShouldBeSpelledCorrectly, MSInternalRules/NamespacesNameShouldBeSpelledCorrectly, MSInternalRules/TypeNameShouldBeSpelledCorrectly, NamingRules/ParameterNamesShouldHaveCompleteWords9 Partially covered by FxCop rules: MSInternalRules/MemberNameShouldBeSpelledCorrectly, MSInternalRules/NamespacesNameShouldBeSpelledCorrectly, MSInternalRules/TypeNameShouldBeSpelledCorrectly, Currently no coverage for parameters. Coming soon, FxCopBug 1041

21

.NET Framework Design Guidelines Microsoft Confidential3.2.3 Avoiding Language-specific Names

Programming languages that target the CLR often have their own names (aliases) for the CLR primitive types. For example, int is the C#’s alias for System.Int32 while Visual Basics alias for System.Int32 is Integer. To ensure that your library can take full advantage of the cross-language interoperation that is one of the core features of the CLR, it is important to avoid the use of these language specific type names in identifiers. This section lists the guidelines that will allow you to avoid type name confusion.

Annotation (Jeffrey Richter):Personally, I take this a step farther and I never use the language’s alias names. I find that the alias adds nothing of value and introduces enormous confusion. For example, I’m frequently asked what is the difference between ‘String’ and ‘string’ in C#. I’ve even heard people say that strings (lowercase S) are allocated on the stack while Strings (uppercase S) are allocated on the heap. In my Applied Microsoft .NET Framework Programming book, I give several reason in addition to this one for avoiding the alias names. Another example of a class library/language mismatch is the NullReferenceException class which can be thrown by VB code. But, VB uses Nothing; not null.

Always use semantically interesting names rather than language-specific keywords for type names10. For example, GetLength is a better name than GetInt.

Use a generic CLR type name, rather than a language specific name, in the rare cases when an identified has no semantic meaning beyond its type 11. For example, a method converting to System.Int64 should be named ToInt64, not ToLong (because System.Int64 is a CLR name for the C# specific keyword ‘long’). Table 3-3 lists the CLR type names (as well as corresponding type names for C#, Visual Basic, and C++) for the basic value types.

Table 3-3. CLR Type Names for Language-specific Type Names

C# Visual Basic C++ CLR sbyte SByte char SBytebyte Byte unsigned char Byteshort Short short Int16ushort UInt16 unsigned short UInt16int Integer int Int32uint UInt32 unsigned int UInt32long Long __int64 Int64

10 Partially covered by FxCop rules: NamingRules/NamespaceNamesDoNotMatchKeywordsNamingRules/ParameterNamesDoNotMatchKeywordsNamingRules/TypeNamesDoNotMatchKeywordsNo coverage for members because there are cases where they conflict with keywords or types. (eg. Thread.Start, Thread.Stop)11 Coming soon. FxCopBug 1114

22

.NET Framework Design Guidelines Microsoft Confidential

ulong UInt64 unsigned __int64 UInt64float Single float Singledouble Double double Doublebool Boolean bool Booleanchar Char wchar_t Charstring String String Stringobject Object Object Object

Use a common name, such as value or item, rather than repeating the type name, in the rare cases when an identifier has no semantic meaning and the type of the parameter is not important. The following is a good example of methods of a class that supports writing a variety of data types into a stream:

void Write(double value); void Write(float value);void Write(short value);

3.3 Names of Assemblies and DLLsAn assembly is the unit of deployment and identity for managed code programs. Although assemblies can span one or more files, typically an assembly containing reusable library maps one to one with a DLL. Because of that, this section will describe only DLL naming conventions, which then can be mapped to assembly naming conventions.

Annotation (Jeffrey Richter):Multi-file assemblies are rarely used and Visual Studio has no built-in support for them.

Keep in mind that namespaces are distinct from DLL names. Namespaces represent logical groupings for developers whereas DLLs and assemblies represent packaging and deployment boundaries. DLLs can contain multiple namespaces for product factoring and other reasons. Since the constraints around namespace factoring are different than the constraints around DLL factoring, you should design them independently. For example, if you decide to name your DLL MyCompany.MyTechnology.dll, it does not mean that the DLL must contain only the namespace named MyCompany.MyTechnology.

Annotation (Jeffrey Richter):Programmers are frequently confused by the fact that .NET does not enforce a relationship between namespaces and assembly file names. For example, System.IO.FileStream is in MSCorLib.dll and System.IO.FileSystemWatcher is in System.dll. As you can see, types in a single namespace can span multiple files. Also notice that the .NET Framework doesn’t ship with a System.IO.dll file at all.

Always choose names for your DLLs that suggest large chunks of functionality such as System.Data.dll.

Consider naming DLLs according to the following pattern.<Company>.<Component>.dll

Where <Component> contains one or more dot-separated clauses. For example,

23

.NET Framework Design Guidelines Microsoft ConfidentialMicrosoft.VisualBasic.dllMicrosoft.VisualBasic.Vsa.dllFabrikam.Security.dllLitware.Controls.dll

MICROSOFT INTERNALDo follow the prescribed namespace naming pattern for the <Company> part of your DLL name: Use either System or Microsoft as the <Company> part of the pattern for all Microsoft managed DLLs. Your DLL names should be of the form System.<Component>.DLL or Microsoft.<Component>.DLL12.

3.4 Names of NamespacesThe following template specifies the general rule for naming namespaces.<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]as in the following examples:

Microsoft.VisualStudioMicrosoft.VisualStudio.DesignMicrosoft.CollaborationPowerSoft.PowerBuilder.Math

Do prefix namespace names with a company name to prevent namespaces from different companies from having the same name, prefix. For example, the Office Automation Classes provided by Microsoft are in the namespace Microsoft.Office.

Annotations (BradA): It is important to use the official name of your company or organization when choosing the first part of your namespace name to avoid possible conflicts. For example is Microsoft had chosen to use “MS” as its root namespace it might have been confusing to developers at other companies such as Morgan Stanley.

Do use a stable, version-independent product or technology name at the second level of a namespace name for general purpose libraries.

Do not use organizational hierarchies as the basis for names in namespace hierarchies, since group names within corporations tend to be short-lived.

Annotation: (Brad Abrams)Late in the ship cycle for V1.0 of the .NET Framework we added a set of controls to ASP.NET that rendered for mobile devices. Because these controls came from a team in a different division our immediately reaction was to put them in a different namespace (System.Web.MobileControls). A couple of re-orgs (and .NET Framework versions) later we realized a better engineering trade off was to fold that functionality into the existing controls in System.Web.Controls. In retrospect we let internal the organizational differences affect the public exposure of the APIs and we came to regret that later. Avoid this type of mistake in your designs.

Use Pascal Casing, and separate namespace components with periods (For example, Microsoft.Office.PowerPoint)13. If your brand employs non-traditional casing, you should

12 FxCop rule coming: Bug# 174213 Partially covered by FxCop rules: NamingRules/NamespaceNamesArePascalCasedOnly covers namespace PascalCasing.

24

.NET Framework Design Guidelines Microsoft Confidentialfollow the casing defined by your brand, even if it deviates from normal namespace casing (For example, NeXT.WebObjects).

Consider using plural namespace names because they are plural by nature as they contain multiple types. For example, use System.Collections instead of System.Collection. Brand names and acronyms are exceptions to this rule, however. For example, use System.IO instead of System.IOs.

Do not use the same name for a namespace and a type in that namespace. For example, do not use Debug for a namespace name and also provide a class named Debug in the same namespace. Several compilers require such types to be fully qualified.

3.4.1 Standard Sub-Namespace NamesTypes that are rarely used should be placed in sub-namespaces to avoid cluttering the main namespaces. We have identified several groups of types that should be separated from their main namespaces.

The .Design sub-namespaceDesign-time only types should reside in a sub-namespace named .Design. For example, System.Windows.Forms.Design contains Designers and related classes used to do design of applications based on System.Windows.Forms.

System.Windows.Forms.Design System.Messaging.DesignSystem.Diagnostics.Design

Use a namespace with the .Design suffix to contain types that provide design-time functionality for a base namespace.

The .Permissions sub-namespacePermission types should reside in a sub-namespace named .Permissions

Use a namespace with the .Permissions suffix to contain types that provide custom permissions for a base namespace.

Annotation (Krzysztof Cwalina): In the initial design of the .NET Framework namespaces, all types related to a given feature area were in the same namespace. Prior to the first release, we moved design-related types to sub-namespaces with the .Design suffix. Unfortunately, we did not have time to do it for the Permission types. This is a problem in several parts of the Framework. For example, a large portion of the types in the System.Diagnostics namespace are types needed for the security infrastructure and very rarely used by the end users of the API.

The .Interop sub-namespaceOne of the most important features of any library is interoperability with legacy components. Due diligence should be used in designing interoperability from the ground up. However, the nature the problem often requires that the shape and style of such APIs is often quite different from good managed code design. Thus, it makes sense to put functionality related to interoperation with legacy components in a subnamespace.

25

Krzysztof Cwalina, 12/13/04,
The following is not strictly naming. Do we want to move it to another section?
Krzysztof Cwalina, 12/13/04,
Maybe this whole section should go to namespace design (not naming)

.NET Framework Design Guidelines Microsoft ConfidentialYou should not put types that completely abstract some unmanaged concepts and expose them as managed into the Interop sub-namespace. Types that definitely should be in the Interop namespace are types that expose methods that directly call functions in the underlying operating system, using, for example, Platform Invoke. Such methods should not be publicly exposed and should follow guidelines described in Section Xxx.For example, many of the classes in System.Windows.Desktop implement the ICOMDataSourceHandler interface for interoperability with COM (The Microsoft Component Object Model). To follow this guideline the ICOMDataSourceHandler interface should be moved to the System.Windows.Desktop.Interop namespace.In addition, if types in the core namespace contain members that are related to interoperability, you should consider moving these members onto types in the Interop subnamespace. For example, instead of a class such as:namespace System.Windows.Explorer { public class Item: IComparable, IDisposable, IEnumerable { public Item (IntPtr idList); public Item (SpecialFolder s); public Item (string path);

//other methods } }}

It would be better to define two classes:namespace System.Windows.Explorer {

public class Item: IComparable, IDisposable, IEnumerable {public Item (SpecialFolder s);

public Item (string path);//other methods}

}namespace System.Windows.Explorer.Interop {

public class InteropHelpers { public static Item GetItemForNativeIdList (IntPtr idList);

//other methods}

}

It is often the case that managed APIs are implemented by calling out to unmanaged code. For example the System.IO.FileStream class calls out to Win32 CreateFile. This is perfectly acceptable and does not imply that the FileStream class needs to be in System.IO.Interop namespace as FileStream completely abstracts the Win32 concepts and publicly exposes a nice managed abstraction.

Always use a namespace with the .Interop suffix to contain types which provide interop functionality for a base namespace.

Always use a namespace with the .Interop suffix for all code in a PIA (Primary Interop Assembly). See section X.Y for more info on PIAs.

3.4.2 Namespaces and Type Name Conflicts

26

Krzysztof Cwalina, 12/13/04,
I am not sure we have any section here.
Krzysztof Cwalina, 12/13/04,
What is the section?

.NET Framework Design Guidelines Microsoft ConfidentialNamespaces are used to organize APIs into a logical and easy to explore hierarchy. They are also indispensable in resolving type name ambiguities that may arise when importing multiple namespaces. However, that should not be used as an excuse to introduce known ambiguities between types in different namespaces that are commonly used together. Developers should not be required to qualify type names in common scenarios.

Do not introduce generic type names such as Element, Node, Log, Message, etc. There is a very high probability it would lead to type name conflicts in common scenarios. You should qualify the generic type names, for example, FormElement, XmlNode, EventLog, and SoapMessage.

There are specific guidelines for avoiding type name conflicts for different categories of namespaces. Namespaces can be divided into the following categories:

Application model namespaces Infrastructure namespaces Core Namespaces Technology namespace groups

Application Model NamespacesNamespaces belonging to a single application model are very often used together but they are almost never used with namespaces of other application models. For example, the System.Windows.Forms namespace is very rarely used together with the System.Web.UI namespace. The following is a list of well known application model namespace groups:System.Windows*System.Web.UI*

Do not give the same name to types in namespaces within a single application model. For example, do not add a type named Page to the System.Web.UI.Adapters namespace, because the System.Web.UI namespace already contains a type named Page.

Infrastructure NamespacesThis group contains namespaces that are rarely imported during development of common applications. For example, .Design namespaces are mainly used when developing programming tools. Avoiding conflicts with types in these namespaces is not critical. System.Windows.Forms.Design*.Design*.Permissions

Core NamespacesCore namespaces include all System namespaces, excluding namespaces of the application models and the Infrastructure namespaces. For example, Core namespaces include System, System.IO, System.Xml, and System.Net.

Do not give types names that would conflict with any type in the Core namespaces. For example, never use Stream as a type name. It would conflict with System.IO.Stream, a very commonly used type.

27

brada, 12/13/04,
KC: you need to describe what a Core Namespace is…
Krzysztof Cwalina, 12/13/04,
B&K: can this list be expanded?
Krzysztof Cwalina, 12/13/04,
[B&K—we need either to expand this list, or rewrite the above paragraph.

.NET Framework Design Guidelines Microsoft ConfidentialBy the same token, do not add a type named EventLog to the System.Diagnostics.Events namespace, because the System.Diagnostics namespace already contains a type named EventLog.

Technology Namespace GroupsThis category includes all namespaces with the same first two namespace nodes (<Company>.<Technology>*), such as Microsoft.Build.Utilities and Microsoft.Build.Tasks. It is important that types belonging to a single technology do not conflict with each other.

Do not assign type names that would conflict with other types within a single technology.

Do not introduce type name conflicts between types in technology namespaces and an application model namespace (unless the technology is not intended to be used with the application model). For example, do not add a type named Binding to the Microsoft.VisualBasic namespace as the System.Windows.Forms namespace already contains that type name.

3.4.3 WinFx Namespace Plan (MS Internal)Goals of WinFx Namespaces

Provide a logical view of the platform Group related functionality together It is not about versioning, deployment, packaging, etc.Root Namespaces (MS Internal)

There are two high level choices for root namespaces we considered using for the new APIs in Longhorn

Microsoft.*

Pros: Promotes our most important brand Follows the pattern we have set out for other companies Clearly distinguishes the Longhorn client technologies from server, legacy, and

other stuff

Cons: Creates an artificial "break" in the platform between the platform pieces of the

Framework and the new Longhorn namespaces. There is no meaningful distinction between the two root namespaces Having the same namespace helps in unifying the platform Hard to rationalize the common namespaces that span client and server (for

example System.Data is required for both)

28

.NET Framework Design Guidelines Microsoft ConfidentialSystem.*

Pros: Unifies the platform for Windows Consistent with the V1 of the Framework. This provides a better message and long

term path for existing customers One place for developers to find all client, server, and common stuff

Cons: Does not promote the MS brand Could be considered to mean cross platform Can not use namespaces differentiate functionality common to both client and

server (eg. system.data may have differences between client and server Can not use namespaces to distinguish what features run on down level platforms

and what is Longhorn only. Can not use namespaces to specifically identify the LHAPI platform from other

stuff (such as Windows.Forms)

In the end, it seems clear there is no compelling reason to split the platform so keeping with the System.* standard we have today is the right approach. In response to the Cons above for System: It seems un-necessary and possible counter productive to push the Microsoft

brand in every source file developers write. System does not mean cross platform today, see Q&A below Namespaces are not the best way to differentiate functionality between client and

sever. Our predictive powers as to what is a client technology and what is a server technology are not good (see Trident, System.Drawing, etc). It is better to use other, less durable mechanism.

The current version of our platform already has some stuff in System that doesn't run down level. ASP.NET, Process component, etc. Also, this strategy clearly breaks down as we go to the next platform.

Namespaces are not the next way to differentiate functionality that is in LAPI and that which is not. The System namespace already contains some types that are part of LAPI (System.Object) and some that may not be System.Windows.Forms.

Implementation Plan (MS Internal)

INTERNAL:

For the most part, Microsoft follows the general guidance above for naming its technologies exposed to the managed world. We would expect to see namespaces such as Microsoft.Word, Microsoft.Exchange, and Microsoft.BizTalk in the next couple of years.

The company has an obligation to identify certain technologies as being fundamental building blocks of the platform. These technologies are part of the Microsoft platform.

Annotation (AndersH):

29

.NET Framework Design Guidelines Microsoft ConfidentialQuestion: We want to ship our new XQuery implementation that is still not a W3C recommendation.  In the meantime, it will be shipped in SQL Server 2005 over XML Datatype.  We will ship the client implementation in Whidbey over in memory documents.  The current plan of record is to ship it as a separate dll but in the System.Xml.XQuery namespace.  I want to get some guidance from you.

Answer:I agree with your plan to ship it as a separate .dll, but I would strongly recommend you put it in a non-System namespace, for example Microsoft.Xml.XQuery or just Microsoft.XQuery. Furthermore, you should make it clear in documentation that this API is likely to change in the future. Only once the API is absolutely stable should you put it in System.Xml. Anything in the System namespace is considered a core platform API, like the Win32 APIs. We need to be very conservative about what we put in there, because we can't change it and we'll have to live with it for a good, long time.

System.*

System is the root namespace for the set of functionality that is part of the managed code platform. The definition of what’s in a platform is by necessity subjective. Certainly a judgment call needs to be made on what is part of the platform and what is not. However, we have outlined the following guidelines for functionality in the System namespace.

Be part of the operating system – Have concrete plans to ship as part of the next operating system release. Essentiality if you are part of the Longhorn API you are should be in System. Otherwise you should not.

Expose a generic set of functionality - The functionality must be infrastructure pieces upon which we expect our customers to build. This restriction helps ensure that System is kept integral; That is, it cannot be diluted by just any functionality Microsoft builds. For example, the Office object model should NOT be in system because the functionality it exposes is not generic: It is specific to the Office implementation. And the base IO functionality should be in System as it is fundamental to the platform.

Be Rationalized with Similar Technology – We don’t want to expose more than one way to accomplish the same goal in the base system classes. Therefore what we do expose needs to be rationalized with similar functionality. All teams shipping similar features should agree that your feature should ship in System. For example, we cannot ship a messaging story in System that we already know will be completely replaced in V2. We can, however, ship the building blocks or a small part of the messaging story in System. We can, of course version what we have already shipped in System or in some cases even Obsolete technology. But there needs to be a clear road map so developers understand what is the “right” technology to use.

Does not Re-Introduce Existing Functionality – If we already ship a way to solve a problem, do not add a new way in System. Again, we may need to version functionality in System.

Is logically part of the Redistributable – It is clear that we will not ship a single redistributable for this platform. Different configurations on different platforms will included different subsets of functionality, but all will include some subset of System.*. If a set of classes is not in any redistributable, they should not be in the System.

Be Free – That is, be an indirect source of income for Microsoft. Anything in the System namespace must be shipped under a similar terms as the runtime. We will not charge for development or redistribution of anything in System. System classes may provide

30

.NET Framework Design Guidelines Microsoft Confidentialaccess to for-profit functionality (such as SqlServer or the OS), but the System classes them selves must be free.

Follow the Design Guidelines - Follow the Design Guidelines as spelled out in this document

Depend only on System.* – To keep the set logically consistent, stuff in System can only publicly depend on other stuff in System.

Naming in System - When choosing names for the System namespace consider: Names should be durable, concise, and objectively reflect semantics. Don’t use product names in a namespace if the purpose behind this is solely

branding. Avoid having the same namespaces in System.* and Microsoft.*. That is don’t

have System.IO and Microsoft.IO – it is confusing to developers as it bifurcates platform

Avoid using product specific names in System.* -- use generic names such as “Web” instead of “ASP.NET”.

Microsoft.*

This set of functionality represents the value added on top of the core operating system. It is typically more domain specific (i.e. word processing, financial) and our customers find it valuable enough to pay for.

The Microsoft name is the product namespace, while System is for general purpose. For example we don't have a "Microsoft.Web" product, so that doesn't make sense, it should be Microsoft.Gxa.

Although we certainly expect the majority of functionality in the Microsoft.* namespace to have most of the attributes listed above, they are not required. We do expect all code that Microsoft ships to follow the Design Guidelines spelled out in this document.

Common Q&A

Q: Does being in the System namespace have any ramifications on being considered middleware?

A: No. Legal (Hossein Nowbar (LCA)) has reviewed the issue and sees no correlation between namespaces and middleware

Q: Does being in System mean we 3rd parties can port to other OSs?

A: No. Namespaces have nothing to do with porting to other OSs.

31

.NET Framework Design Guidelines Microsoft ConfidentialQ: Does being in System mean we can’t charge for the OS that contains these APIs

A: No. Our goal here is to add value to the operating system.

Q: Does being in System affect the CLI’s plans?A: No. The CLI will be able to work with whatever we do in the System namespaces

Q: Should we split client specific namespaces out from Server specific namespace?A: Turns out it is very difficult to predict what will be important on the client or server. We are better served to keep our options open.

Q. does being in system mean that we need to carry everything in system today forward?A.  No.  We can obsolete functionality using the ObsoleteAttribute.

3.5 Names of Classes, Value Types, and InterfacesIn general, type names should be noun phrases. Types should represent entities of the system, so noun phrases as names are appropriate, such as, XmlWriter, MessageQueue, or Button. A good rule of thumb is that if you are not able to come up with a noun phrase name for a type, you probably should rethink the general design of the type as it is likely not cohesive or well defined enough. Another important consideration is that the most easily recognizable names should be used for most commonly used types, even if the name fits some other less used type better in the purely technical sense. For example, a type used in mainline scenarios to submit print jobs to print queues should be named Printer, rather than PrintQueue. Even though technically the type represents a print queue and not the physical device (printer), from the scenario point of view, Printer is the ideal name as most people are interested in submitting print jobs and not in other operations related to the physical printer device (such as configuring the printer). If you need to provide another type that corresponds, for example, to the physical printer to be used in configuration scenarios, the type could be called PrinterConfiguration or PrinterManager.

Annotation (Krzysztof Cwalina): I know this goes against the technical precision that is one of the core character traits of most software engineers, but we really do think it’s more important to have better names from the point of view of the most common scenario, even if it results in slightly inconsistent or even wrong type names from purely technical point of view. Advanced users will be able to tolerate slightly inconsistent naming. Most users are usually not concerned with technicalities and will not even notice the inconsistency, but will appreciate the names guiding them to the most important and commonly used APIs.

Similarly, names of most commonly used types should reflect usage scenarios, not inheritance hierarchy. Most users use the leaves of an inheritance hierarchy almost exclusively, and are rarely concerned with the structure of the hierarchy. Yet, API designers often see the inheritance hierarchy as the most important criterion for type

32

.NET Framework Design Guidelines Microsoft Confidentialname selection. For example, Stream, StreamReader, TextReader, StringReader, FileStream, all describe the place of each of the types in the inheritance hierarchy quite well, but at the same time they obscure the most important information for the majority of users: the type that they need to instantiate to read text from a file.

Annotation (Krzysztof Cwalina):Usage scenarios are of interest to 100% of customers. Inheritance hierarchy is of interest to 20% of customers.

It is important to give classes and value types names that are clearly understandable. The following naming guidelines apply to general type naming.

Always name classes, interfaces, and value types with nouns, noun phrases, or, occasionally, adjective phrases, using Pascal Casing14. This distinguishes type names from methods, which are named with verb phrases. Do not give class names a prefix (such as C)15.

Annotation: (Krzysztof Cwalina)The only prefix used is I for interfaces (as in ICollection), but that is for historical reasons. In retrospect, I think it would have been better to use CollectionInterface as the name—it is clearer and follows the guidelines.

Annotation (Brad Abrams): On the other hand, the “I” prefix on interfaces is a clear recognition of the influence of COM (and Java) on the .NET Framework. COM popularized, even institutionalized the notation that interfaces begin with “I” Although we discussed diverging from this historic pattern we decided to carry forward the pattern as so many of our users were already familiar with COM.

Annotation (Jeffrey Richter):Personally, I like the ‘I’ prefix and I wish we had more stuff like this. Little one character prefixes go a long way toward keep code terse and yet descriptive. As I said earlier, I use prefixes for my private type fields because I find this very useful. Also, when I define generic type parameters, I use descriptive names and I prefix them with an uppercase ‘T’. I purposely violate the generic guideline (mentioned later in this section) because I think what I do is much more useful and maintainable.

Consider ending the name of derived classes with the name of the base class. This is very readable and explains the relationship clearly. Some examples of this in code are: ArgumentOutOfRanageException, which is a kind of Exception, and SerializableAttribute, which is a kind of Attribute. However, it is important to use reasonable judgment in applying this; for example, Button is a fine name even though it is a kind of Control. The following are examples of correctly named classes.public class FileStream : Stream {…}public class Button : Control {…}

Always prefix interface names with the letter I, to indicate that the type is an interface16. Interface naming rules are simple and generally well understood.

14 Fully covered by FxCop rule: NamingRules/TypeNamesArePascalCased15 Fully covered by FxCop rule: NamingRules/TypeNamesDoNotHaveCPrefix16 Fully covered by FxCop rule: NamingRules/InterfaceNamesHaveIPrefix

33

Krzysztof Cwalina, 12/13/04,
Examples would be great here.

.NET Framework Design Guidelines Microsoft ConfidentialFor example, IComponent (descriptive noun), ICustomAttributeProvider (noun phrase), and IPersistable (adjective) are appropriate interface names. As with other type names, avoid abbreviations.

Annotation (Jeffrey Richter):There is one interface I’m aware of that doesn’t follow this guideline: System._AppDomain. It is very disconcerting to me when I see this type used without the uppercase I.

Always ensure that when defining a class/interface pair where the class is a standard implementation of the interface, the names differ only by the letter I prefix on the interface name.17

The following example illustrates this guideline for the interface IComponent and its standard implementation, the class Component.public interface IComponent { … }public class Component : IComponent { … }

3.5.1 Names of Generic Type ParametersGenerics are a major new feature of the CLR. A general overview and other guidelines related to Generics can be found in Chapter 7.

      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.

public interface ISessionChannel<TSession> { … }public delegate TOutput Converter<TInput,TOutput>(TInput from);public class List<T> { … }

      Consider using T as the type parameter name for types with one single letter type parameter.

public int IComparer<T> { … }public delegate bool Predicate<T>(T item);public struct Nullable<T> where T:struct { … }  

      Do prefix descriptive type parameter names with “T”.public interface ISessionChannel<TSession> where TSession : ISession {   TSession Session { get; }}

      Consider indicating constraints placed on a type parameter in the name of parameter. For example, a parameter constrained to ISession may be called TSession.  

3.5.2 Names of Common Types Always follow the guidelines described in Table 3-4 when naming types derived

from or implementing specified types18.

17 Partially covered by FxCop rule: NamingRules/InterfaceNamesHaveIPrefixThe rule only checks that interfaces have ‘I’ prefix, not the rest of the name. Full coverage coming soon, FxCopBug 1113

34

Brad Abrams, 12/13/04,
See note on this in the inheritance guideline… I think this may not be a good pattern

.NET Framework Design Guidelines Microsoft ConfidentialTable 3-4. Name Rules for Types Derived from or Implementing Certain Core Types

Type Derived/Implementing Type Guideline

System.Attribute Always add the suffix Attribute to custom attribute classes, as in this example:public class ObsoleteAttribute : Attribute { … }

System.Delegate Always add the suffix EventHandler to names of types that are used in events (such as return types of a C# event).

Always add the suffix Callback in the name of a member that takes a delegate but is not an event.

Do not add the suffix Delegate to a delegate.

System.EventArgs Always add the suffix EventArgs System.Enum Do not derive from this class; use the

keyword supported by your language instead. e.g. In C#, use the enum keyword

Do not add the suffix Enum or Flag

System.Collections.IEnumeratorSystem.Collections.Generic.IEnumer

Always add the suffix Enumerator

18 Fully covered by FxCop rules: NamingRules/AttributeNamesHaveAttributeSuffix, NamingRules/CollectionNamesHaveCollectionSuffix, NamingRules/ConditionNamesHaveConditionSuffix, NamingRules/DelegateNamesDoNotHaveDelegateSuffix, NamingRules/DictionaryNamesHaveDictionarySuffix, NamingRules/EventHandlerNamesHaveEventHandlerSuffix, NamingRules/EnumerationNamesDoNotHaveEnumSuffix, NamingRules/EventArgsNamesHaveEventArgsSuffix, NamingRules/ExceptionNamesHaveExceptionSuffix, NamingRules/PermissionNamesHavePermissionSuffix, NamingRules/StreamNamesHaveStreamSuffix, NamingRules/OnlyAttributeNamesHaveAttributeSuffix, NamingRules/OnlyCollectionNamesHaveCollectionSuffix, NamingRules/OnlyConditionNamesHaveConditionSuffix, NamingRules/OnlyEventHandlerNamesHaveEventHandlerSuffix, NamingRules/OnlyEventArgsNamesHaveEventArgsSuffix, NamingRules/OnlyExceptionNamesHaveExceptionSuffix, NamingRules/OnlyPermissionNamesHavePermissionSuffix, NamingRules/OnlyStreamNamesHaveStreamSuffix

35

.NET Framework Design Guidelines Microsoft Confidential

ator<T>System.Exception Always add the suffix Exception System.Collections.IDictionarySystem.Collections.Generic.IDictionary<K,V>

Always add the suffix Dictionary. Note that IDictionary is a specific type of collection, but this guideline takes precedence over the more general collections guideline below.

System.Collections.IEnumerableSystem.Collections.ICollectionSystem.Collections.IListSystem.Collections.Generic.IEnumerable<T>System.Collections.Generic.ICollection<T>System.Collections.Generic.IList<T>

Always add the suffix Collection

System.IO.Stream Always add the suffix Stream System.Security.CodeAccessPermissionSystem.Security.IPermission

Always add the suffix Permission

For example, ClickedEventArgs is a type derived from System.EventArgs, and System.ObsoleteAttribute is a type derived from System.Attribute.These suffixing guidelines apply to the whole hierarchy of the specified base type. For example, it is not just types derived directly from System.Exception that need the suffixes, but those derived from Exception subclasses as well. These suffixes should be reserved for the specifically listed types. Types derived from or implementing other types should not use these suffixes. For example, the following represent incorrect naming://Incorrect namingpublic class ElementStream : Object {} public class WindowsAttribute : Control {}

3.5.3 Naming EnumerationsEnumeration type names follow the general naming rules (Pascal Casing, etc.) but are not distinguished by a prefix or suffix.

Do not use a prefix on enumeration names (For example, ad for ADO enums, rtf for rich text enums, etc.)19.public enum PhotoshopMode {

19 coming soon, FxCopBug 99936

Krzysztof Cwalina, 12/13/04,
This statement should be turned into a guideline.
brada, 12/13/04,
Does the flow here make sense
brada, 12/13/04,
We should have an example for each one of these in this table

.NET Framework Design Guidelines Microsoft Confidential PhotoshopModeBitmap = 0, PhotoshopModeGrayscale = 1, PhotoshopModeIndexed = 2, PhotoshopModeRgb = 3,}

The following naming scheme would be better:public enum PhotoshopMode { Bitmap = 0, Grayscale = 1, Indexed = 2, Rgb = 3,}

Annotation (Brad Abrams): Notice that this guideline is the exact opposite of common usage in C++ programming. In C++ it is important to fully qualify each enum member as they can be accessed outside of the scope of the enum name. However in the managed world enum members are only accessed through the scope of the enum name.

Do not use an Enum suffix on enum types20.Do not use a Flags suffix on enum types.

Always use a singular name for an enumeration, unless its values are bit fields21. Always use a plural name for enumerations with bit fields as values22, also called flag

enums.

3.6 Names of Type MembersTypes contain members such constructors, properties, methods, events, and fields. The following sections describe guidelines for naming those members of types.

3.6.1 Names of Methods Because methods are the means of taking action, they are commonly given names that are verbs or verb phrases. This also serves to distinguish them from property and type names, which are noun or adjective phrases.

Give methods names that are verbs or verb phrases23.

Annotation (Steven Clarke):

20 Fully covered by FxCop rule: NamingRules/EnumerationNamesDoNotHaveEnumSuffix21 Coming soon, FxCopBug 103122 Fully covered by FxCop rule: NamingRules/FlagEnumerationsShouldHavePluralNames23 Coming soon. FxCopBug 1014

37

Krzysztof Cwalina, 12/13/04,
This is silly.

.NET Framework Design Guidelines Microsoft ConfidentialDo your best to name methods according to the task that they enable, not according to some implementation detail. In a usability study on the System.Xml APIs, participants were asked to write code that would perform a query over an instance of an XPathDocument. In order to do this, participants needed to call the CreateXPathNavigator method from XPathDocument. This returns an instance of an XPathNavigator that is used to iterate over the document data returned by a query. However, not one participant expected or realized that they would have to do this. Instead, they expected to be able to call some method named Query or Select on the document itself. Such a method could just as easily return an instance of XPathNavigator in the same way that CreateXPathNavigator does. By tying the name of the method more directly to the task it enables, rather than to the implementation details, it is more likely that developers using your API will be able to find the correct method to accomplish a task.

3.6.2 Names of PropertiesUnlike other members, properties should be given noun phrase or adjective names. That is because a property refers to data, and the name of the property reflects that. Pascal casing is always used for property names.

Always name properties using a noun, a noun phrase, or an adjective24.Do not have properties that match the name of Get methods as in the following example25.public string TextWriter { get {...} set {...} }public string GetTextWriter(int value){

...}

This pattern typically indicates the property should really be a method; see section 5.1 for information on that.

Always name 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. For example, CanRead is more understandable than Readable. However Created is actually more readable than IsCreated. Having the prefix is often too verbose and unnecessary particularly in the face of intellisense in the code editors. It is just as clear to type “MyObject.Enabled =” and have an intellisense drop down pop up true and false as it is to have “MyObject.IsEnabled =”, and the second one is more verbose.

Consider giving a property the same name as its type, if there is no other meaningful name for the property. For example, the following property correctly gets and sets an enum value named Color, so the property is named Color:public enum Color {...}public class Control { public Color Color { get {...} set {...} }}

24 Coming soon. FxCopBug 101325 Fully covered by FxCop rule: NamingRules/PropertyNamesShouldNotMatchGetMethodNames

38

.NET Framework Design Guidelines Microsoft ConfidentialDo not name properties using the following patternpublic enum Color {...}public class Control { public Color TheColor { get {...} set {...} }}

(MS Internal) Always name dynamic properties according to the following guideline26.

public static readonly DynamicProperty <PropertyName>Property = DependencyProperty.Register ("<PropertyName>", 0, typeof(<PropertyType>), ...);

public static <PropertyType> Get<PropertyName> (DependencyObject e) {

return e.GetValue(<PropertyName>);

}

public static void Set<PropertyName>( DependencyObject e, <PropertyType> value){

e.SetValue(<PropertyName>, value);

}

So for example the boolean IsSelected property would be:

public static readonly DynamicProperty IsSelectedProperty = PropertyManager.RegisterProperty("IsSelected", 0, typeof(bool), ...);

public static bool GetIsSelected(DependencyObject e){

return e.GetValue(IsSelectedProperty);

}

public static void SetIsSelected(DependencyObject e, bool value){

e.SetValue(IsSelectedProperty, value);

}

3.6.3 Names of Events Always name events with a verb or a verb phrase. For examples, Clicked, Painting,

DroppedDown, etc27.

26 Coming soon. FxCopBug xxxx27 Partially covered by FxCop rule: DesignRules/EventsShouldBeUsed. This rule only catches those cases that have AddOn, RemoveOn, Raise, and Fire in the method name and suggests the above guideline.

39

Krzysztof Cwalina, 12/13/04,
The intro should describe the concept of pre and post events.

.NET Framework Design Guidelines Microsoft Confidential Always give events names with a concept of before and after using the present and

past tense (do not use the BeforeXxx\AfterXxx pattern)28. 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.

Always give events names that use verb tense to indicate before and after. For example, an event that is raised before a Form closes should be named Closing. An event raised after a Form is closed should be named Closed.Do not use the Before or After prefixes to indicate pre and post events29.

Always name event handlers (types inheriting used as types of events) with the EventHandler suffix as in the following example30.public delegate void ClickedEventHandler(object sender, ClickedEventArgs e);

Always use two parameters named sender and e31 in event handlers.The sender parameter represents the object that raised the event. The sender parameter is typically of type object, even if it is possible to employ a more specific type. The pattern is used consistently across the Framework.public delegate void <EventName>EventHandler(object sender, <EventName>EventArgs e);

Typically it is best to use the most specific types possible. However, there are occasionally advantages to using a more generic sender object and event argument:

Flexibility: It allows flexibility in sharing event handlers – For example, a CancelEventHandler can be used for lots of things that take a cancel event, such as Buttons, DataGrids, Network Connections, etc. Because we’re passing a reference to the object that generated the event, if there is more than one source for the event the handler can easily determine which source is responsible. This technique is also useful within an inheritance hierarchy. For example, the Windows Forms Button class would end up with a click event where the sender is of type Control, since that's where the event is actually declared. If the user wanted to manipulate Button members through the sender argument, a cast would still be required, so in inheritance cases there is no improvement over sender as type object.Inheritance and Events: When an event is inherited from a base class, the sender parameter is now of a base class type and not of the most derived class type expected by the user. In a lot of cases, this will lead to "ragged" event signatures.

28 Fully covered by FxCop rule: NamingRules/EventsDoNotHaveBeforeOrAfterPrefix29 Fully covered by FxCop rule: NamingRules/EventsDoNotHaveBeforeOrAfterPrefix30 Fully covered by FxCop rule: NamingRules/EventHandlerNamesHaveEventHandlerSuffix31 Fully covered by FxCop rule: NamingRules/EventFirstParametersHaveNameSender, NamingRules/EventSecondParametersHaveNameE, NamingRules/EventFirstParametersAreTypeObject, DesignRules/EventsHaveTwoParameters

40

Krzysztof Cwalina, 12/13/04,
The following three seem to overlap.

.NET Framework Design Guidelines Microsoft Confidential Always name event argument classes with the EventArgs suffix as in the following

example32. public class ClickedEventArgs : EventArgs { private int x; private int y; public ClickedEventArgs (int x, int y) { this.x = x; this.y = y; } public int X { get { return x; } } public int Y { get { return y; } } }

From a versioning perspective, using an EventArgs class to encapsulate a set of arguments is more flexible than having a number of individual arguments. With an EventArgs class, you can add another argument to this class at any time, without having to change the signature of the event handlers and event related methods that take the arguments as parameters.This does not work well with individual parameters. Adding a new argument means you will have to go through all event handlers and event related methods and change their signatures to reflect the addition.

3.6.4 Naming FieldsThe field naming guidelines apply to only static public and protected fields. Internal and private fields are not covered by guidelines and public or protected instance fields are not allowed except in very limited circumstances.

Always name fields with nouns or noun phrases, and use Pascal casing.33. Do not abbreviate field names34.

Spell out all the words used in a field name. Use abbreviations if developers generally understand them. Do not use uppercase letters for field names. For example:

public class Foo { public static string Url; public static string DestinationUrl;}

Do not use a prefix for field names35. For example do not use or 's_' for static36.

32 Fully covered by FxCop rule: NamingRules/EventArgsNamesHaveEventArgsSuffix33 Coming soon, FxCopBug 101334 Fully covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly.35 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly. This rule only covers spelling, not necessarily all prefixes. Full coverage coming soon: FxCopBug 999.36 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly. This rule only covers spelling, not necessarily prefixes. Full coverage coming soon: FxCopBug 999.

41

Krzysztof Cwalina, 12/13/04,
We need to finalize and add the guidelines for public fields.

.NET Framework Design Guidelines Microsoft Confidential3.7 Naming Parameters

Beyond the obvious reason of readability, it is important to follow the guidelines for parameter names because parameters are displayed in documentation and the designer when visual design tools provide IntelliSense, and class browsing functionality.

Annotation (Steven Clarke): Do your best to name methods according to the task that they enable, not according to some implementation detail. In a usability study on the System.Xml APIs, participants were asked to write code that would perform a query over an instance of an XPathDocument. In order to do this, participants needed to call the CreateXPathNavigator method from XPathDocument. This returns an instance of an XPathNavigator that is used to iterate over the document data returned by a query. However, not one participant expected or realized that they would have to do this. Instead, they expected to be able to call some method named Query or Select on the document itself. Such a method could just as easily return an instance of XPathNavigator in the same way that CreateXPathNavigator does. By tying the name of the method more directly to the task it enables, rather than to the implementation details, it is more likely that developers using your API will be able to find the correct method to accomplish a task.

Always use descriptive parameter names37. Parameter names should be descriptive enough that in most scenarios the name of the parameter and its type can be used to determine its meaning.

Use Camel Casing in parameter names38. Consider using names based on a parameter's meaning rather than names based on

the parameter's type39. Development tools must provide useful information about the type, so the parameter name can be put to better use describing semantics rather than the type. Occasional use of type-based parameter names is entirely appropriate—but it is not ever appropriate under these guidelines to revert to the Hungarian naming convention.

Be consistent in naming parameters when overloading, overriding and implementing interfaces. This discipline increases the developer perception of connection and interrelation between the methods. Implementing Interfaces:

public class IComparable{ int CompareTo(object x, object y);}public class FooComparable : IComparable { // Correct public int CompareTo(object x, object y){…} // Incorrect public int CompareTo(object value1, object value2){ … }

37 Partially covered by FxCop rule: NamingRules/ParameterNamesShouldHaveCompleteWords. No coverage for “descriptiveness.”38 Fully covered by FxCop rule: NamingRules/ParameterNamesAreCamelCased39 Partially covered by FxCop rule: NamingRules/ParameterNamesShouldHaveCompleteWords. No coverage for “descriptiveness.”

42

.NET Framework Design Guidelines Microsoft Confidential}

Overriding Members:public class Object { public virtual bool Equals(object obj) { … } }}public class MyClass { // Correct public overide bool Equals(object obj) { … } //Incorrect public overide bool Equals(object value) { … }}

Overloading:public class String { // Correct public int IndexOf (string value) {} public int IndexOf (string value, int startIndex) {} public int IndexOf (string value, int startIndex, int endIndex) {} //Incorrect public int IndexOf (string value) {} public int IndexOf (string str, int startIndex) {} public int IndexOf (string value, int beginIndex, int endIndex) {}}

3.8 Naming ResourcesBecause resources can be referenced via certain objects as if they were properties, the naming guidelines for resources are similar to property guidelines.

Always use PascalCasing for resource identifiers40. Always provide descriptive rather than short identifiers41. Keep them concise where

possible, but do not sacrifice readability for space. Do not use language-specific keywords such as int, class, etc.

Use only alpha-numeric characters and underscores in naming resources. Always use the dot separator to nest identifiers with a clear hierarchy. For example,

if you design menu system resources, consider naming them like the following: Menus.FileMenu.Close.Text Menus.FileMenu.Close.Color Menus.FileMenu.SaveAs.Text Menus.HelpMenu.About.Text

40 Coming soon. FxCopBug xxxx41 Partially covered by FxCop rule: MSInternalRules/ResourceStringsShouldBeSpelledCorrectly. No coverage for “descriptiveness.”

43

Krzysztof Cwalina, 12/13/04,
Why do we allow underscores?

.NET Framework Design Guidelines Microsoft Confidential Always use the following naming convention for exception message resources. The

resource identifier should be the exception type name plus a short identifier of the exception separated by a dot: ArgumentException.IllegalCharacters ArgumentException.InvalidName ArgumentException.FileNameIsMalformedType Design Guidelines

From the CLR perspective, there are only two categories of types: Reference Types and Value Types, but for the purpose of library design discussion we divide types into several more logical groups, each with its own specific design rules. Figure 4-1 shows these logical groups.

Figure 4-1. The logical grouping of types

Classes are the general case of Reference Types. They make up the bulk of types in the majority of reusable libraries. Classes owe their popularity to the rich set of object-oriented features they support and to their general applicability. Interfaces are types that can be implemented by both reference and Value Types and thus serve as roots of polymorphic hierarchies or reference and Value Types. In addition, they can be used to simulate multiple inheritance, which is not natively supported by the CLR.Structs are the general case of Value Types and should be reserved for small, simple types, similar to language primitives.

44

.NET Framework Design Guidelines Microsoft ConfidentialEnums are a special case of Value Types used to define short sets of values, such days of week, console colors, etc. Guidelines for the design of enums are discussed later in this chapter.Static Classes are types intended as placeholders for static members. They are commonly used to provide shortcuts to other operations.Delegates, exceptions, attributes, arrays, and collections, are all special cases of Reference Types intended for specific uses, and guidelines for their design and usage are discussed elsewhere in this book.

Ensure that each type is a well-defined set of related members, and not just a random collection of unrelated functionality. It’s that you can say in one sentence what goes on in the type. A good definition should also rule out functionality that is only tangentially related.

Annotation (Brad Abrams):Like most of us, types don’t generally do well when they don’t have a crisp set of responsibilities. I have noticed that types without a firm and focused scope tend to be magnets for more random functionality, which, over time, make a small problem a lot worst. It becomes more difficult to justify why the next member with even more random functionality does not belong in the type. As the focus of the members in a type blurs, the developer’s ability to predict where to find a given functionality is impaired, and so is productivity.

3.9 Types and NamespacesBefore designing a large reusable library, you should decide how to factor your functionality into a set of functional areas represented by namespaces. Such top-down architectural design is important to ensure a coherent set of namespaces containing types that are well integrated, don’t collide, and are not repetitive. Of course the namespace design process is iterative and it should be expected that the design will have to be tweaked as types are added to the namespaces. This leads to the following guidelines.

Use namespaces to organize types into a hierarchy of related feature areas. The hierarchy should be optimized for users browsing the library for desired APIs.

Annotation (Krzysztof Cwalina):This is an important guideline. Contrary to a popular belief, the main purpose of namespaces is not to help in resolving naming conflicts between types with the same name that happen to reside in different namespaces. As the guideline states, the main purpose of namespaces is to organize types in a coherent, easy to navigate, and easy to use hierarchy. I consider type name conflicts in a single library to indicate sloppy design. Types with identical names should either be merged to allow for better integration between parts of the library or should be renamed to improve code readability and searchability.

Avoid very deep namespace hierarchies. Such hierarchies are difficult to browse as the user has to backtrack often.

Avoid too having too many namespaces. Users of a library should not have to import many namespaces in most common scenarios. Types that are used together in common scenarios should reside in a single namespace if at all possible.

45

Krzysztof Cwalina, 12/13/04,
Some guidelines from the naming section need to be moved here. [KC: I will follow up after merging with chapter 3]

.NET Framework Design Guidelines Microsoft Confidential Avoid having types designed for advanced scenarios in the same namespace as types

intended for common programming tasks. This makes it the easier to understand the basics of the library and to use the library in the most common scenarios.

Do not define types without specifying their namespaces. This organizes related types in a hierarchy, and can help to resolve potential type name collisions42. Please note that the fact that namespaces can help to resolve name collisions does not mean that such collisions should be introduced. See section 3.4.2 for details.

Annotation (Brad Abrams):It is important to realize that namespaces can not actually prevent naming collisions but they can significantly reduce them. I could define a class called MyNamespace.MyType in an assembly called MyAssembly, and define a class with precisely the same name in another assembly. I could then build an application that uses both of these assemblies and types. The CLR would not get confused. The reason is that the type identity in the CLR is based on so called strong name (which includes fully qualified assembly name) rather than just the namespace and type name.  This can be seen by looking at the C# and ILASM of code creating an instance of MyType.  C#: new MyType();

IL: IL_0000: newobj instance void [MyAssembly]MyNamespace.MyType::.ctor()

Notice that the C# compiler adds an ‘[MyAssembly]’ which is a reference to the assembly that defines the type, so the runtime always has a disambiguated, fully qualified name to work with.   

3.10 Choosing Between Class and Struct One of the basic design decisions every library designer has to make is to choose between class and struct. Good understanding of the differences in the behavior of Reference Types and Value Types is crucial in making the choice. Here is the list of the main differences and their implications most relevant to type design. Reference Types are allocated on the heap, and garbage-collected, while Value

Types are allocated on the stack and deallocated when the stack unwinds. Therefore, allocations and deallocations of Value Types are much cheaper than allocations and deallocations of Reference Types.

Arrays of Reference Types are allocated out of line, meaning the array elements are just references to separate instances of the Reference Type residing on the heap. Value Type arrays are allocated in line, meaning the array elements are instances of the Value Type. Therefore, allocations and deallocations of Value Type arrays are much cheaper than allocations and deallocations of Reference Type arrays. In addition, Value Type arrays exhibit much better locality of reference.

Value Types get boxed when cast to object or one of the interfaces they implement. They get unboxed when cast back to the Value Type. Since boxes are objects that are allocated on the heap and are garbage collected, too much boxing and unboxing can have a negative impact on the heap, the garbage collector, and ultimately the performance of the application.

42 Fully covered by FxCop rule: DesignRules/TypesBelongToNamespaces.46

.NET Framework Design Guidelines Microsoft Confidential Reference Type assignments copy the reference, while Value Type assignments copy

the entire value. Therefore assignments of large Reference Types are cheaper than assignments of large Value Types.

Finally, Reference Types are passed by reference, while Value Types are passed by value. Changes to an instance of a Reference Type affect all references pointing to the instance. Value Type instances are copied when they are passed by value. When an instance of a Value Type is changed, it of course does not affect any of its copies. Because the copies are not created explicitly by the user, but rather implicitly when arguments are passed or return values are returned, Value Types that can be changed can be confusing to many users. Therefore Value Types should be immutable.

As a rule of thumb, majority of types in a reusable library should be classes. There are however some situations where the characteristics of a Value Type make it more appropriate to use structs.

Consider defining a struct instead of a class if instances of the type are small and short lived.

Do not define a struct, unless the type has all of the following characteristics: It logically represents a single value, similar to primitive types. It has an instance size under 16 bytes. It is immutable. It will not have to be boxed too frequently.

3.11 Choosing Between Class and InterfaceNote: This introduction is a draft. The guidelines are official.

In general, classes are the preferred construct for exposing managed APIs. The main drawback of interfaces is that they are much less flexible than classes when it comes to allowing for evolution of APIs. Once you ship an interface, the set of its members is fixed forever. Any additions to the interface would break existing types implementing the interface. A class offers much more flexibility. You can add members to classes that have already shipped. As long as the method is not abstract (that is, as long as you provide a default implementation of the method), any existing derived classes continue to function unchanged. Let’s illustrate the concept with a real example from the .NET Framework. The System.IO.Stream abstract class shipped in the Version 1.0 of the framework without any support for timing out pending I/O operations. In the Version 2.0, several members were added to Stream to allow subclasses to support timeout related operations, even when accessed through their base class APIs.public abstract class Stream { public virtual bool CanTimeout { get { return false; } } public virtual int ReadTimeout{

47

Krzysztof Cwalina, 12/13/04,
Readers may not know what’s immutable. [KC: Susan, what’s the best way to resolve this? I can write a section on immutable types, but it will be long (1 page at least)]

.NET Framework Design Guidelines Microsoft Confidential get{ throw new NotSupportedException(…); { set { throw new NotSupportedException(…); } }}

public class FileStream : Stream { public override bool CanTimeout { get { return true; } } public override int ReadTimeout{ get{ … { set { … } }}

The only way to evolve interface-based APIs is to add a new interface with the additional members. This may seem like a good option, but it suffers from several problems. Let’s illustrate this on a hypothetical IStream interface. Let’s assume we had shipped the following APIs in the Version 1.0 of the Framework.public interface IStream { …}

public class FileStream : IStream { …}

If we wanted to add support for timeouts to streams in Version 2.0, we would have to do something like the following.public interface ITimeoutEnabledStream : IStream { int ReadTimeout{ get; set; }}

public class FileStream : ICancellableStream { public int ReadTimeout{ get{ … { set { … } }}

But now we would have a problem with all the existing APIs that consume and return IStream. For example StreamReader has several constructor overloads and a property typed as Stream.public calss StreamReader {

public StreamReader(IStream stream){ … }public IStream BaseStream { get { … } }

48

.NET Framework Design Guidelines Microsoft Confidential}

How would we add support for ITimeoutEnabledStream to StreamReader? We would have several options, each with substantial development cost and usability issues: 1. Leave the StreamReader as is and ask users who want to access the timeout related

APIs on the instance returned from BaseStream property to use a dynamic cast and ‘query’ for ITimeoutEnabledStream interface.StreamReader reader = GetSomeReader();ITimeoutEnabledStream stream = reader.BaseStream as ITimeoutEnabledStream;if(stream != null){ stream.ReadTimout = 100;}

This option unfortunately does not perform well in usability studies. The fact that some streams may now support the new operations is not immediately visible to the users of StreamReader APIs. Also, some developers have difficulties understanding and using dynamic casts.

2. Add a new property to StreamReader that would return ITimeoutEnabledStream if one was passed to the constructor or null if IStream was passed.StreamReader reader = GetSomeReader();ITimeoutEnabledStream stream = reader.TimoutEnabledBaseStream;if(stream!= null){ stream.ReadTimout = 100;}

Such APIs are only marginally better in terms of usability. It’s really not obvious to the user that the TimoutEnabledBaseStream property getter may return null, which results in confusing and often unexpected NullReferenceExceptions.

3. Add a new type called TimeoutEnabledStreamReader that would take ITimeoutEnabledStream parameters to the constructor overloads and return ITimeoutEnabledStream from the BaseStream property. The problem with the approach is that every additional type in the library adds complexity for the users of the library. But what’s worse, the solution usually creates more problems like the one it is trying to solve. StreamReader itself is used in other APIs. These other APIs will now need new versions that can operate on the new TimeoutEnabledStreamReader.

One the other hand working with the .NET Framework 2.0 Stream APIs is straightforward, discoverable, and the additions had little impact on other parts of the library.

StreamReader reader = GetSomeReader();if(reader.BaseStream.CanTimeout){ reader.BaseStream.ReadTimeout = 100;}

One of the most commonly brought arguments in favor of interfaces is that they allow separating contract from the implementation. But the argument incorrectly assumes that you cannot separate contracts from implementation using classes. Abstract classes residing in a separate assembly from their concrete implementations are a great way to achieve such separation. For example, the contract of IList<T> says that when an item is added to a collection, the Count property is incremented by one. Such simple contract can be expressed and what’s more important locked for all subtypes, using the following abstract class.

49

.NET Framework Design Guidelines Microsoft Confidentialpublic abstract class CollectionContract<T> : IList<T> {

public void Add(T item){AddCore(item);this.count++;

}public int Count {

get { return this.count; }}protected abstract void AddCore(T item);

private int count;}

Annotation (Krzysztof Cwalina): I often hear people saying that interfaces specify contracts. I believe this is a dangerous myth. Interfaces, by themselves, do not specify much beyond the syntax required to use an object. The interface-as-contract myth causes people to do the wrong thing when trying to separate contracts from implementation, which is a great engineering practice. Interfaces separate syntax from implementation, which is not that useful, and the myth provides a false sense of doing the right engineering. In reality, the contract is semantics, and these can actually be nicely expressed with some implementation.

COM exposed APIs exclusively through interfaces, but you should not assume that COM did this because interfaces were superior. COM did it because COM is an interface standard that was intended to be supported on my execution environments. CLR is an execution standard and it provide a great benefit for libraries which can now relay on portable implementation.

Strongly favor defining classes over interfaces. Class-based APIs can be evolved with much greater ease than interface-based APIs because it is possible to add members to a class without breaking existing code.

Annotation (Krzysztof Cwalina): I have talked about this guideline with quite a few developers who work on the .NET Framework libraries. Many of them, including those who initially disagreed with the guideline, have said that they regret having shipped some API as an interface. I have not heard even one case where somebody regretted that they shipped a class.

Use abstract classes instead of interfaces to decouple the contract from implementations. Abstract classes, if designed correctly, allow for the same degree of decoupling between contract and implementation.

Do define an interface if you need to provide a polymorphic hierarchy of Value Types. Value Types cannot inherit from other types, but they can implement interfaces. For example, IComparable, IFormattable, IConvertible are all interfaces so Value Types such as Int32, Int64, and other primitives can all be comparable, formatable, and convertible.public struct Int32 : IComparable, IFormattable, IConvertible { …}public struct Int64 : IComparable, IFormattable, IConvertible { …}

Consider defining interfaces to achieve a similar effect to that of multiple inheritance. For example, System.IDisposable and System.ICloneable are both interface

50

.NET Framework Design Guidelines Microsoft Confidentialso types, like System.Drawing.Image, can be both disposable, cloneable, and still inherit from System.MarshalByRefObject class. public class Image : MarshalByRefObject, IDisposable, ICloneable {

…}

3.11.1 Abstract Classes Do not define public or protected internal constructors in abstract types43. Public and

protected internal constructors create instances of a type, and because you cannot create instances of an abstract type, an abstract type with a public constructor is incorrectly designed.

public abstract class Claim { // Incorrect Design public Claim () { }}

Always define a protected or an internal constructor on abstract classes.Protected constructor is more common and simply allows subtypes to call the base constructor.

public abstract class Claim { // Correct Design protected Claim() { … }}

An internal constructor can be used to limit concrete implementations of the abstract class to the assembly defining the class.

public abstract class Claim { // Correct Design internal Claim() { … }}

Note: Many languages (such as C#) will insert a protected constructor if you do not. It is a good practice to define the constructor explicitly in the source so that it can be more easily documented and maintained over time.

Do provide at least one concrete type that inherits from each abstract class that you ship. This helps to validate the design of the abstract class. For example, System.IO.FileStream is an implementation of the System.IO.Stream abstract class.

3.11.2 Static ClassesStatic class is defined as a class that contains only static members (of course besides the instance members inherited from System.Object and a private constructor). Some

43 Fully covered by FxCop rule: DesignRules/AbstractTypesShouldNotHaveConstructors.51

Krzysztof Cwalina, 12/13/04,
Annotation: Add annotation on HasShutdownStarted. We can grab the text from the BCL book as a starter? [KC: Susann, could you do this?]

.NET Framework Design Guidelines Microsoft Confidentiallanguages provide built-in support for static classes. In C#, when a class is declared to be static, it is sealed, abstract, has a private default constructor, and no instance members can be overridden or declared.public static class File { …}

If your language does not have a built-in support for static classes, you can declare such class manually as follows.Public NotInheritable Class File { Private Sub New() End Sub …End Class

Static classes are a compromise between pure object-oriented design and simplicity. They are commonly used to provide shortcuts to other operations (such as System.IO.File), or functionality for which a full OO wrapper is unwarranted (such as System.Environment).

Use static classes sparingly. Such classes should be used only as supporting classes for the Object-Oriented core of the library.

Do not treat static classes as a miscellaneous bucket. There should be a clear charter for the class.

Do not declare or override instance members in static classes. Do declare static classes as sealed, abstract, and add a private instance constructor,

if your programming language does not have a built-in support for static classes.

3.12 Interface DesignWhile most APIs are best modeled using classes and structs, there are cases where interfaces are more appropriate or are the only option.The CLR does not support multiple inheritance (i.e. CLR classes cannot inherit from more than one base class), but it allows types to implement one or more than interfaces in addition to inheriting from a base class. Therefore interfaces are often used to achieve the effect of multiple inheritance. For example, IDisposable is an interface so that types can support disposability independent of any other inheritance hierarchy they want to participate in.public class Component : MarshalByRefObject, IDisposable, IComponent {…}

The other situation in which defining an interface is appropriate is in creating a common interface that can be supported by Value Types. Value Types cannot inherit from other types, but they can implement interfaces, so using an interface is the only option. For example, IComparable is an interface, so that Value Types can be comparable.public struct Boolean : IComparable {…}

52

.NET Framework Design Guidelines Microsoft Confidentialpublic struct Int32 : IComparable {…}

Do define an interface if you need some common API to be supported by both Reference and Value Types.

Consider defining an interface if you need to support its functionality on types that already inherit from some other type.

Avoid using marker interfaces (interfaces with no members)44. If you need to mark a class as having a specific characteristic (marker), use a custom attribute rather than an interface. // Avoidpublic interface IImmutable {} // empty interface

public class String : IImmutable { …}

//Do[Immutable]public class Key { …}

Methods can be implemented to reject parameters that are not marked with a specific attribute as follows:public void Add(Key key, object value){ if(!key.GetType().IsDefined(typeof(ImmutableAttribute), false)){ throw new ArgumentException(“The parameter must be immutable”,“key”); } …}

The problem with this approach is that the check for the custom attribute can occur only at runtime. Sometimes, it is very important that the check for the marker be done at compile-time. For example, a method that can serialize objects of any type might be more concerned with verifying the presence of the marker than with type verification at compile-time. Using marker interfaces may be acceptable in such situations. The following example illustrates this design approach.public interface ITextSerializable {} // empty interfacepublic void Serialize(ITextSerializable item){ // use reflection to serialize all public properties …}

Do provide at least one type that is an implementation of an interface45. This helps to validate the design of the interface. For example, System.Collections.ArrayList is an implementation of the System.Collections.IList interface.

44 Fully covered by FxCop rule: DesignRules/InterfacesShouldNotBeEmpty.45 Coming soon: FxCopBug 1011.

53

brada, 12/13/04,
Annotation: This is a great place for an annotation on where we have seen people screw up on this. [KC: I sent mail to Brad]

.NET Framework Design Guidelines Microsoft Confidential Do provide at least one API consuming each interface you define (a method taking the

interface as a parameter or a property typed as the interface). This helps to validate the interface design. For example, List<T>.Sort consumes IComparer<T> interface.

Do not add members to an interface that has previously shipped. Doing so would break implementations of the interface. You should create a new interface to avoid versioning problems.

3.13 Struct DesignThe general purpose Value Type is most often referred to by its C# keyword struct. This section provides some guidelines for the design of these. The next section presents guidelines for the design of a special case of Value Type, the enum.Some important guidelines related to the design of structs are located in section Choosing Between Class and Struct .

Do not provide a default constructor for a struct46. This allows arrays of structs to be created without having to run the constructor of each instance. Notice the C# does not allow structs to have default constructors.

Ensure that a state where all instance data is set to zero, false, or null (as appropriate) is valid. This prevents accidental creation of invalid instances when an array of the structs is created. For example, the following struct is incorrectly designed. The parameterized constructor is meant to ensure valid state, but the constructor is not executed when an array of the struct is created.

public struct PositiveInteger { int value; public PositiveInteger(int value) { if (value <= 0) throw new ArgumentException(…); this.value = value; } public override string ToString() { return value.ToString(); }}

Do not explicitly extend System.ValueType. In fact, most languages prevent this.

3.14 Enum DesignEnums are a special kind of Value Type used for two purposes: Simple enums, which represent small closed sets of choices. A common example of the

simple enum is a small set of colors. For example,public enum Color {    Red,    Green,    Blue,    …}

46 Coming soon: FxCopBug 1116.54

.NET Framework Design Guidelines Microsoft Confidential Flag enums, which are designed to support bitwise operations on the enum values. A

common example of the flags enum is list of options. For example,[Flags]public enum AttributeTargets {    Assembly = 1,    Module = 2, Cass = 4, Struct = 8,    …}

Annotation (Brad Abrams):We had some debates about what to call enums that are designed to be bitwise OR’ed together. We considered bitfields, bitflags even bitmasks but ultimately decided to use ‘flags enums’ as it was clear, simple and approachable.

Annotation (Steven Clarke):I’m sure that less experienced developers will be able to understand bitwise operations on flags. The real question, though, is whether they would expect to have to do this. Most of the APIs that I have run through the labs don’t require them to perform such operations so I have a feeling that they would have the same experience that we observed during a recent study—it’s just not something that they are used to doing so they may not even think about it. Where it could get worse, I think, is that if less advanced developers don’t realize they are working with a set of flags that can be combined with one another, they may just look at the list available and think that is all the functionality they can access. As we’ve seen in other studies, if an API makes it look to them as though a specific scenario or requirement isn’t immediately possible, it’s likely that they will change the requirement and do what does appear to be possible, rather than being motivated to spend time investigating what they need to do to achieve the original goal.

Historically, many reusable libraries, Win32 APIs for example, represented sets of values using integer constants. Enums make such sets more strongly typed, thus improve compile time error checking, usability, and readability. For example, it allows development tools to know the possible values for a property or a parameter.

Convert.ChangeType(object value, TypeCode typeCode);public enum TypeCode{    Boolean,    Byte,    Char,    DateTime,    …}

Use an enum to strongly type parameters, properties, and return values that represent sets of values.

Favor using an enum over static constants. // Avoid the followingpublic static class Color {    public static int Red = 0;

55

.NET Framework Design Guidelines Microsoft Confidential    public static int Green = 1;    public static int Blue = 2;    …}

// Favor the followingpublic enum Color {    Red,    Green,    Blue,    …}

Do not use an enum for open sets (such as the operating system version). Do not provide reserved enum values that are intended for future use. You can always

simply add values to the existing enum at a later stage. See section Adding Values to Enums for more details. Reserved values just pollute the set of real values and can be error prone for users.public enum DeskType {   Circular,   Oblong,   Rectangular, // the following two values should not be here ReservedForFutureUse1,    ReservedForFutureUse2,} 

Avoid publicly expose enums with one value only. A common practice for ensuring future extensibility of C APIs is to add reserved parameters to method signatures. Such reserved parameters can be expressed as enums with a single default value. This should not be done in managed APIs. Method overloading allows adding parameters in future releases.

// Bad Designpublic enum SomeOption {   DefaultOption   // we will add more options in the future}

// The option parameter is not needed. It can always be added in the future // to an overload of SomeMethod()public void SomeMethod(SomeOption option) {

… }

Do not include ‘sentinel’ values in enums. While they are sometimes helpful to library developers, they are confusing to users of the library. Sentinel values are values used to track the state of the enum, rather than being one of the values from the set represented by the enum. The following example shows an enum with an additional sentinel value used to identify the last value of the enum, and intended to be used in range checks. This is bad practice in library design.public enum DeskType {   Circular = 1,

56

.NET Framework Design Guidelines Microsoft Confidential   Oblong = 2,   Rectangular = 3,

   LastValue = 3 // this sentinel value should not be here}

public void OrderDesk(DeskType deskType){ if((desk > DeskType.LastValue){ throw new ArgumentOutOfRangeException(…); } …}

Rather than relying on sentinel values, library developers should perform the check using one of the real enum values.public void OrderDesk(DeskType deskType){ if(desk > DeskType.Rectangular || desk < DeskType.Circular){ throw new ArgumentOutOfRangeException(…); } …}

Do provide a value of zero on simple enums. Consider calling the value something like “None”. If such value is not appropriate for this particular enum, the most common default value for the enum should be assigned the underlying value of zero. public enum Compression { None = 0, GZip, Deflate,}public enum EventType { Error = 0, Warning, Information, …}

Always use Int32 (the default in most programming languages) as the underlying type of an enum unless any of the following is true[3]:1. The enum is a flags enum and you have more or expect to have more than 32 flags

in the future.

Annotation (Brad Abrams):  This may not be as uncommon a concern as you might first expect.  We are only in V2.0 of the .NET Framework and we are already running out of values in the CodeDom GeneratorSupport enum.  In retrospect, we should have used a different mechanism for communicating support of a larger underlying type.

2. The underlying type needs to be different than Int32 for easier interoperability with code expecting different size enums.

3. A smaller underlying type would result in substantial savings in space. If you expect to the enum to be used mainly as an argument for flow of control the size makes little differences. The size savings may be significant if:

[

57

.NET Framework Design Guidelines Microsoft Confidentiala. You expect to the enum to be used as a field in a very frequently instantiated

structure or class. b. You expect users to create large arrays or collections of the enum instances. c. You expect a large number of instances of the enum to be serialized.

Annotation (BradA): Note that for in-memory usage you should be aware that managed objects are always DWORD aligned so you effectively need multiple enums or other small structures in an instance to pack a smaller enum with to make a difference as the total instance size is always going to be rounded up to a DWORD.

Annotation (Brad Abrams): Keep in mind that it is a binary breaking change to change the size of the enum type once you have shipped, so choose wisely, with an eye on the future.  Our experience is that Int32 is usually the right choice and thus we made it the default.  

Do not use the “Enum” suffix in enum type names. For example, the following enum is badly named.// Bad namingpublic enum ColorEnum { …}

Do not use the “Flag” or “Flags” suffixes in enum type names. For example, the following enum is badly named.// Bad naming[Flags]public enum ColorFlags { …}

Flags enums should be named with plural nouns or noun phrases and simple enums should be named with single form nouns or noun phrases. See the naming section 3.5.3 for details.

Do not extend System.Enum. System.Enum is a special type used by the CLR to create user-defined enumerations. Most programming languages provide a programming element that gives you access to this functionality. For example, in C# the enum keyword is used to define an enumeration.

3.14.1 Flags Enum Design Apply the System.FlagsAttribute to flags enums. Do not apply this attribute to simple

enums.[Flags]public enum AttributeTargets {    …}

Use powers of two for the flags enum values so they can be freely combined using the bitwise OR operation.

[Flags]public enum WatcherChangeTypes {

58

.NET Framework Design Guidelines Microsoft Confidential    Created = 1,    Deleted = 2,    Changed = 4,    Renamed = 8,}

Consider providing special enum values for commonly used combinations of flags. Bitwise operations are an advanced concept and should not be required for simple tasks. FileAccess.ReadWrite is an example of such special value.

[Flags]public enum FileAccess {    Read = 1,    Write = 2,    ReadWrite = Read | Write}

Avoid creating flags enums where certain combinations of values are invalid.The System.Reflection.BindingFlags enum is an example of such incorrect design. The enum tries to represent many different concepts, such as visibility, static-ness, member kind, etc.

[Flags]public enum BindingFlags { Instance, Static, NonPublic, Public, CreateInstance, GetField, SetField, GetProperty, SetProperty, InvokeMethod, …}

Certain combinations of the values are not valid. For example Type.GetMembers method accepts this enum as a parameter but the documentation for the method warns users that “You must specify either BindingFlags.Instance or BindingFlags.Static in order to get a return.” Similar warnings apply to several other values of the enum.

If you have an enum with the problem described above, you should separate the values of the enum into two or more enums or other types. For example, the Reflection APIs could have been designed as follows.

[Flags]public enum Visibilities { Public, NonPublic}

[Flags]public enum MemberScopes { Instance, Static}

59

.NET Framework Design Guidelines Microsoft Confidential

[Flags]public enum MemberKinds { Constructor, Field, PropertyGetter, PropertySetter, Method, }

public class Type { public MemberInfo[] GetMembers(MemberKinds members, Visibilities visibility, MemberScopes scope);}

Avoid using flag enum values of zero, unless the value represents ‘all flags are cleared’ and is names appropriately as prescribed by the guideline below. The following example shows a common implementation of a check that programmers use to determine if a flag is set (see the if statement). The check works as expected for all flag enum values except the value of zero, where the Boolean expression always evaluates to true.[Flags]public enum SomeFlag {

ValueA = 0,  // this may be confusing to usersValueB = 1,ValueC = 2,ValueBAndC = ValueB | ValueC,

}

SomeFlag flags = GetValue();if ((flags & SomeFlag.ValueA) === SomeFlag.ValueA) { …}

Annotation (AndersH): Note that in C# the literal constant 0 implicitly converts to any enum type, so you could just write:

if (Foo.SomeFlag == 0)…

We support this special conversion to provide programmers with a consistent way of writing the default value of an enum type, which by CLR decree is "all bits zero" for any Value Type.

Name the zero-value of flags enums “None”. For a flags enum, the value must always mean ‘all flags are cleared’.

[Flags]public enum BorderStyle { Fixed3D           = 0x1,  FixedSingle       = 0x2, None              = 0x0}if (foo.BorderStyle == BorderStyle.None)....

Annotation (Vance Morrison):

60

.NET Framework Design Guidelines Microsoft ConfidentialThe rational for avoiding zero in a flag enumeration for an actual flag (only the special enum member ‘None’ should have zero) is that you can’t OR it in with other flags as expected.However, notice that this rule only applies to Flag enumerations; in the case where enumeration is NOT a flag enumeration, there is a real disadvantage of avoiding zero that we have discovered however.  ALL enumerations begin their life with this value (memory is zeroed by default).  Thus if you avoid zero, every enumeration has an ILLEGAL value in it when it first starts its life in the run time (we can’t even pretty print it properly).  This seems bad.In my own coding, I do one of two things for non-flag enumerations. If there is an obvious default that is highly unlikely to cause grief if programmers forget to set it (program invariants do NOT depend on it), I make this the zero case.    Usually this is the most common value, which makes the code a bit more efficient (it is easier to set memory to 0 than to any other value).  If no such default exists, I make zero my ‘error’ (non-of-the-above) enumeration value.  That way when people forget to set it, some assert will fire later and we will find problem.In either case, however, from the compiler (and runtime), point of view every enumeration has a value for 0 (which means we can pretty print it). 

3.14.2 Adding Values to EnumsIt is very common to discover that you need to add values to an enum after you have shipped a library containing the enum.  There is a potential application compatibility problem when the newly added value is returned from an existing API as poorly written applications may not handle the new value correctly. Documentation, samples and FxCop rules encourage application developers to write robust code that can help applications deal with unexpected values. Therefore, it is generally acceptable to add values to enums, but as with most guidelines there may be exceptions to the rule based on the specifics of the library. 

It is acceptable to add values to enums.If you have real data about application incompatibilities caused by additions to an enum, consider adding a new API which returns the new and old values, and deprecate the old API, which should continue returning just the old values. This will ensure that the existing applications remain compatible.

Annotation (Clemens Szyperski): Adding a value to an enum has a very real possibility of breaking a client. Before the addition of the new enum value, a client who was throwing unconditionally in the default case presumably never actually threw the exception, and the corresponding catch path is likely untested. Now that the new enum value can pop up, the client will throw and likely fold.The biggest concern with adding values to enums, is that you don't know whether clients perform an exhaustive switch over an enum or a progressive case analysis across wider-spread code. Even with the FxCop rules above in place and even when it is assumed that client apps pass FxCop without warnings, we still would not know about code that performs things like  if (myEnum == someValue) ...  in various places.

Clients may instead perform point-wise case analyses across their code, resulting in fragility under enum versioning. It is important to provide specific guidelines to developers of enum client code detailing what they need to do to survive the addition of new elements to enums they use. Developing with the suspected future versioning of an enum in mind is the required attitude.

3.15 Nested Types

61

.NET Framework Design Guidelines Microsoft ConfidentialA nested type member is a type defined within the scope of another type, which is called the enclosing type. Just like other members of a type, a nested type has access to all members of its enclosing type. For example, it has access to private fields defined in the enclosing type and to protected fields defined in all ascendants of the enclosing type.In general, nested types should be used sparingly. There are several reasons for this. Same developers are not fully familiar with the concept. These developers may for example have problems with the syntax of declaring variables of nested types. Nested types are also very tightly coupled with their enclosing types, and as such are not suited for general purpose types. Nested types are best suited for modeling implementation details of their enclosing types. The end user should rarely have to declare variables of a nested type and almost never explicitly instantiate nested types. For example, the enumerator of a collection can be a nested type of that collection. Enumerators are usually instantiated by their enclosing type and since many languages support the foreach statement, enumerator variables have to be rarely declared by the end user.

Use nested types when the relationship between the nested type and its outer type is such that member-accessibility semantics are desirable. For example, the nested type needs to have access to private members of the outer-type. Do not use public nested types as a logical grouping construct; use namespaces for this47.

Avoid publicly exposed nested types48. The only exception to this is if variables of the nested type need to be declared only in rare scenarios such as subclassing or other advanced customization scenarios.

Annotation (Krzysztof Cwalina): The main motivation for this guideline is that many less skilled developers don’t understand why some type names have dots in them and some don’t. As far as they don’t have to type the type name, they don’t care. But the moment you ask them to declare a variable of a nested type, they get lost. Therefore, we in general avoid nested types and only use them in places where developers almost never have to declare variables of the type (for example collection enumerators).

Do not use nested types if the type is likely to be referenced outside of the containing type. For example, an Enum passed to a method defined on a class should NOT be defined as a nested type in the enum. 

Do not use nested types if they need to be instantiated by client code. If a type has a public constructor, it should probably not be nested.  If a type can be instantiated, it seems to indicate that the type has a place in the library on its own (you can create it, work with it, and destroy it, without ever using the outer type), thus should not be nested. Inner types should not be widely reused outside of the outer type without any relationship whatsoever to the outer type.

Do not define a nested type as a member of an interface. Many languages do not support such a construct.

47 Coming soon: FxCopBug 1027.48 Coming soon. FxCopBug 1027.

62

.NET Framework Design Guidelines Microsoft Confidential

4 Member Design

4.1.1 Property Design Do use PascalCasing for Property names49.public class Button { public Color BackColor { }}

Do not use Hungarian notation50. Do see section 4.1.2 on choosing between properties and methods.

Do provide properties as points of customization for objects. Users should be able to change what their code is doing by setting properties (to a limit), not by rewriting the code from scratch.

Do provide sensible defaults for all properties as long as the defaults do not result in a security hole or a horribly inefficient design.

Do favor properties over methods wherever they make sense. Do preserve the previous value if a property setter throws an exception. Do allow properties to be set in any order. Properties should be stateless with

respect to other properties.It is often the case that a particular feature of an object will not take effect until the developer specifies a particular set of properties, or until an object has a particular state. Until the object is in the correct state, the feature is not active. When the object is in the correct state, the feature automatically activates itself without requiring an explicit call. The semantics are the same regardless of the order in which the developer sets the property values or how the developer gets the object into the active state.For example, a TextBox control may have two related properties: DataSource and DataField. DataSource specifies the table name, and DataField specifies the column name. Once both properties are specified, the control can automatically bind data from the table into the Text property of the control. The following code examples illustrates that you can set the properties in any order.TextBox t = new TextBox();t.DataSource = "Publishers";t.DataField = "AuthorID";// The data binding feature is now active.

The previous code is equivalent to the following.TextBox t = new TextBox();t.DataField = "AuthorID";

49 Fully covered by FxCop rule: NamingRules/MemberNamesArePascalCased50 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectlyThis rule only covers spelling, not necessarily all prefixes. Full coverage coming soon. FxCopBug 999

63

.NET Framework Design Guidelines Microsoft Confidentialt.DataSource = "Publishers";// The data binding feature is now active.

In addition, the developer can set a property to null, to indicate that the value is not specified.TextBox t = new TextBox();t.DataField = "AuthorID";t.DataSource = "Publishers";// The data binding feature now active t.DataSource = null;// The data binding feature is now inactive

The following code example illustrates how to implement this by tracking the state of the data binding feature and automatically activating or deactivating it at the appropriate times.public class TextBox { string dataSource; string dataField; boolean active; public string DataSource { get { return dataSource; } set { if (value != dataSource) { // Update active state. SetActive(value!= null && dataSource != null); dataSource = value; } } } public string DataField { get { return dataField; } set { if (value != dataField) { // Update active state. SetActive(value != null && dataField != null); dataField = value; } } } void SetActive(boolean value) { if (value != active) { if (value) { Activate(); Text = dataBase.Value(dataField); } else { Deactivate(); Text = ""; } active = value; // set active only if success } } void Activate() { // open database }

64

.NET Framework Design Guidelines Microsoft Confidential void Deactivate() { // close database }}

In the previous example, the following expression determines whether the object is in a state in which the data binding feature can activate itself.value != null && dataField != null

It might make sense to make this into a method that determines whether the object can be activated given its current state, and then activates it as necessary.void UpdateActive(string dataSource, string dataField){ SetActive(dataSource != null && dataField != null);}

The expression that appears in this method indicates the parts of the object model that need to be examined in order to enforce these state transitions. In this case, the DataSource and DataField properties are affected.

It is recommended components raise <Property>Changed events.If there is a good scenario for a user wanting to know when a property of a component is changing, the component should raise a <Property>Changed event for the property. For example, Control might raise a TextChanged event when the control's text is changed. The <Property>Changed event is raised after the property value has changed. There is a protected helper routine On<Property>Changed, which is used to raise this event. However, it is unlikely to be worth the overhead to raise a <Property>Changed event for a Hashtable item addition.class Control : Component{ string text; public string Text{ get{ return text; } set{ if (!text.Equals(value)){ text = value; OnTextChanged(...); } } }}

Data binding uses this pattern to allow two-way binding of the property. If these events do not exist, then data binding works in one direction (if the database changes, the property is updated). Each property that raises the <Property>Changed event should provide metadata to indicate that the property supports data binding.

It is recommended that you raise change events when the value of a property changes via external forces. If a property value changes via some external force (in a way other than by calling methods on the object), then raise events indicate to the developer that the value is changing and has changed. A good example is the Text property of a text box control. When the user types text in the text box, the property value automatically changes.

65

Krzysztof Cwalina, 12/13/04,
How?

.NET Framework Design Guidelines Microsoft ConfidentialAn event should be raised before the value of the property has changed. It does not pass the old or new value, but can be canceled by the developer by throwing an exception. The name of the event is the name of the property followed by the suffix “ing” (for example TextChanging). The following code illustrates a changing event.public class TextBox {

public event TextChangingEventHandler TextChanging;

public string Text { get { return text; } set { if (text != value) { OnTextChanging(Event.Empty); text = value; } } }}

An event is also raised after the value of the property has changed but it cannot be canceled at that point. The name of the event is the name of the property followed by the suffix Changed. The generic <Property>Changed event should also be raised (see the previous section on <Property>Changed events). class TextBox { public event TextChangedEventHandler TextChanged; public event TextChangingEventHandler TextChanging;

public string Text { get { return text; } set { if (text != value) { OnTextChanging(Event.Empty); text = value; OnTextChanged(…); } } }

protected virtual void OnTextChanged(…){ TextChanged(this,…); } protected virtual void OnTextChanging(…){ TextChanging(this,…); } }

There are cases when the underlying property value is not stored as a field and therefore it is more difficult to track changes to its value. When raising the changing event, find all of the places that the property value can change and provide the ability to cancel. For example, the previous control example is not actually accurate in the concrete case of System.Windows.Forms.TextBox because the Text value is actually stored in the HWND. In order to raise the TextChanging event, you must examine Windows messages to determine when the text may change, and allow for an exception thrown in OnTextChanging to cancel. If it is too difficult to provide a changing event, it is reasonable to support only the Changed event.

66

.NET Framework Design Guidelines Microsoft Confidential Avoid throwing exceptions from property getters. Property getters should be simple

operations and should not have any preconditions. If a getter may throw an exception, it should probably be redesigned to be a method.   Notice this rule does not apply to indexers where we do expect exception as a result of validating the index. Annotation (Patrick Dussud): Notice this guideline only applies to property getters. It is OK, to throw exception in property setter. It is very much like setting an array element, which can throw as well (and not just when checking the index bound but the possibility of type mismatch between the value and the array element type)

4.1.2 Properties vs. MethodsLibrary designers sometimes face a decision between a property and a method. In general, methods represent actions and properties represent data.Use the following guidelines to help you choose between these options.

Do use a property in the following situation. The member has a logical backing store as in the following example.

string Type.Name // Should be a property, string Name because // the name is a logical attribute of a class

Guid Guid.GetNext() // Should not be a property, because Guids // do not naturally have a "next" Guid.

Do use a method in the following situations.It is not necessary or even desirable to name such a method with a “Get” prefix. Often a more meaningful name can be found such as GenerateNext() rather than GetNext().

The operation is a conversion (such as Object.ToString()) The operation is expensive (orders of magnitude slower than a field set would be).If you are planning to provide an async version of this operation because of concerns for not blocking the UI thread, then it is likely that the operation is too expensive use a property.

The Visual Studio debugger will call a properties getter many times a second if you have it expanded in a locals or autos pane. It will never call an objects methods.

The operator is not local Obtaining a property value using the Get accessor has an observable side effect. Calling the member twice in succession results in different results. The order of execution is important as in the following example.

public class Connection { // It is good for these three to be properties // because they can be set in any order. public String DNSName { get{}; set{}; } public String UserName { get{}; set{}; } public String Password { get{}; set{}; }

// It would be bad for this to be a property

67

Brad Abrams, 12/13/04,
Roll in some data from: http://blogs.gotdotnet.com/brada/commentview.aspx/9b86339f-06e7-4223-9014-f33ae198d387

.NET Framework Design Guidelines Microsoft Confidential // because it has to be done in a particular order. // In this case, after the others have been set. // Therefore, use a method here. public bool Execute();}

The member is static but it returns a mutable value. The member shows up easily in the debugger. Properties appear by default when

the developer is examining objects in the debugger. For example, if FooClass has a Bar property, then when the developer examines FooClass, they will see the value of Bar; however, if, instead, FooClass had a GetBar method, the developer would have to explicitly open the immediate (or watch) window and type in the call to the method to return the value.

The member returns an array51.Properties that return arrays can be very misleading. Usually it is necessary to return a copy of the internal array so that the user cannot change internal state. This, coupled with the fact that a user could easily assume it is an indexed property, leads to inefficient code. In the following example, each call to the Method’s property creates a copy of the array. That would be 2n+1 copies for this loop.Type type = //get a type somehowfor (int i = 0; i < type.Methods.Length; i++) {if (type.Methods[i].Name.Equals ("foo")) { ... }}

This problem can be addressed by either:1. Change the property to be a method which has the effect of making the code

above look obviously wrong. for (int i = 0; i < type.Methods.Length; i++) {if (type.GetMethods()[i].Name.Equals ("foo")) { ... }}

2. Change the property to return a collection that wraps the underlying array and provides readonly access. You can use the ArrayList.ReadOnly() method to get a readonly IList wrapper from an array (or other collection.

When deciding to implement a type with properties and methods, there are two general designs:

Have fewer properties, and have “complex” methods with a large number of parameters to maintain atomicy of the actions.

public class PersonFinder {public string FindPersonsName (int height, weight,

string hairColor, string eyeColor,int shoeSize, int whichDatabase){

51 Fully covered by FxCop rule: NamingRules/ConsiderReplacingMethodsWithProperties68

.NET Framework Design Guidelines Microsoft Confidential// perform operation using the parameters...

)}

Have more properties to set the “configuration” of the type, and have “simple” methods with a small number of parameters.

public class PersonFinder{

public int Height { get {...} set {...} }public int Weight { get {...} set {...} }public string HairColor { get {...} set {...} }public string EyeColor { get {...} set {...} }public int ShoeSize { get {...} set {...} }

public string FindPersonsName (int whichDatabase){

// use the properties already set to perform operation...

}}

The first design is generally not preferable because methods with many parameters are difficult to use and makes the type less customizable. Types should hold state, and each state should be able to be set individually. Therefore, the second method is preferred over the first. More properties allow the user to set the “configuration” of the type, before using the methods to perform the required actions.

4.1.3 Read-Only and Write-Only Properties Do use read-only properties when the user cannot change the logical backing data

field. Do not use set-only properties. If the property getter cannot be provided, implement the

functionality as a method instead. It’s perfectly fine to have get-only properties52.

4.1.4 Indexed Property (Indexer) Design Do use indexed properties when the logical backing store is an array.

public char this[int index] {get;}

Do use only System.Int32, System.Int64, System.String, and System.Object for the indexer53. If the design requires other types for the indexer, strongly re-evaluate if it really represents a logical backing store. If not use a method.

Consider using only one index54. If the design requires multiple indices reconsider if it really represents a logical baking store. If not use a method.

52 Fully covered by FxCop rule DesignRules/PropertiesShouldNotBeWriteOnly53 Fully covered by FxCop rule: DesignRules/OnlyIntegralValuesOrStringsShouldBeUsedForIndexers54 Coming soon. FxCopBug 1047

69

Krzysztof Cwalina, 12/13/04,
What about Int16? If it does not save space, we should add it to justification.

.NET Framework Design Guidelines Microsoft Confidential Do use only one indexed property per class and make it the default indexed property

for that class55. This is enforced by C# indexer support. Do not use non-default indexed properties56. This is not allowed in C#.

Do use the name Item for indexed properties unless there is an obviously better name (for example a Chars property on String). In C#, Indexers are by default named Item. The IndexerNameAttribute can be used to customize this name.

Do not provide both indexed properties and methods that are semantically equivalent to two or more overloaded methods. In the example below, the property should be changed to GetMethod(string) method. Notice this is not allowed in C#.MethodInfo Type.Method[string name]MethodInfo Type.GetMethod (string name, boolean ignoreCase)

4.1.5 Event Design Do name events using PascalCasing57. Do not use Hungarian notation58.

Do use the "raise" terminology for events rather than "fire" or "trigger" terminology. When referring to events in documentation, use the phrase "an event was raised" instead of "an event was fired" or "an event was triggered."

Consider naming events with a verb. Examples: Clicked, Painting, DroppedDown, etc59. Do name event names that have a concept of pre and post using the present and past

tense (do not use the BeforeXxx\AfterXxx pattern)60. For example, a close event that can be canceled would have a Closing and Closed event.

Do use a return type of void for event handlers for easy combinability61. For example:public delegate void ClickedEventHandler(object sender, ClickedEventArgs e);

Do use strongly typed event data classes when the event conveys some meaningful bit of data (such as the coordinates of a mouse click)

55 Coming soon. FxCopBug xxxx56 Coming soon. FxCopBug xxxx57 Fully covered by FxCop rule: NamingRules/MemberNamesArePascalCased58 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly. This rule only covers spelling, not necessarily all prefixes. Full coverage coming soon. FxCopBug 99959 Partially covered by FxCop rule: DesignRules/EventsShouldBeUsed. This rule only catches those cases that have AddOn, RemoveOn, Raise, and Fire in the method name and suggests the above guideline.60 Fully covered by FxCop rule: NamingRules/EventsDoNotHaveBeforeOrAfterPrefix61 Fully covered by FxCop rule: DesignRules/EventHandlersReturnVoid

70

.NET Framework Design Guidelines Microsoft Confidential Do make event data classes extend the class System.EventArgs as in the following

example62.public class ClickedEventArgs : EventArgs { }

Do not create a special event handler when not using a strongly typed EventArgs subclass. There is no need to define a delegate with the signature: Object, EventArgs. If that is all that is needed simply use the EventHandler class.

Do use a protected (family) virtual method to raise each event63. For each event on a class, include a corresponding protected (family) virtual method that raises the event. This is not appropriate for sealed classes, because classes cannot be derived from them. The purpose of the method is to provide a way for a derived class to handle the event using an override. This is more natural than using delegates in the case where the developer is creating a derived class. The name of the method is OnEventName where EventName is the name of the event being raised. For example: public class Button { ClickedHandler onClickedHandler; protected virtual void OnClicked(ClickedEventArgs e) { if (onClickedHandler != null) { onClickedHandler(this, e); } }}

The derived class can choose not to call the base during the processing of OnEventName. Be prepared for this by not including any processing in the OnEventName method that is required for the base class to work correctly.

Do assume that anything can go in an event handler.Classes are ready for the handler of the event to do almost anything, and in all cases the object is left in a good state after the event has been raised. Consider using a try/finally block at the point where the event is raised. Since the developer can call back on the object to perform other actions, do not assume anything about the object state when control returns to the point at which the event was raised. For example:public class Button { ClickedHandler onClickedHandler; protected void DoClick() { PaintDown(); // paint button in depressed state try { OnClicked(args); // call event handler } finally { // window may be deleted in event handler if (windowHandle != null) { PaintUp(); // paint button in normal state

62 Fully covered by FxCop rule: NamingRules/EventArgsNamesHaveEventArgsSuffix, NamingRules/OnlyEventArgsNamesHaveEventArgsSuffix63 Coming soon. FxCopBug 1044

71

Brad Abrams, 12/13/04,
Add something about when you use the generic EventArgs class
Brad Abrams, 12/13/04,
We need to update this section for generics.

.NET Framework Design Guidelines Microsoft Confidential } } } protected virtual void OnClicked(ClickedEventArgs e) { if (onClickedHandler != null) onClickedHandler(this, e); }}

Do raise cancelable events to allow the developer to cancel events. Use or extend System.ComponentModel.CancelEventArgs to allow the developer to control events of an object.For example, the TreeView control raises a LabelEditing when the user is about to edit a node label. The following example illustrates how a developer can use this event to prevent a node from being edited.public class MainForm : Form { TreeView tree = new TreeView(); void LabelEditing(object source, NodeLabelEditEventArgs e) { e.Cancel = true; }}

Note that in this case, no error is generated to the user. The label is read only.The cancel events are not appropriate in cases where the developer would to cancel the operation and return an exception. In these cases, you should raise an exception inside of the event handler in order to cancel. For example, the user may want to write validation logic in an edit control.public class MainForm : Form { EditBox edit = new EditBox(); void TextChanging(object source, EventArgs e) { throw new InvalidOperationException("Edit not allowed in this mode"); }}

4.1.6 Method Design Do name methods with PascalCasing64. Do not use Hungarian notation65.

Do default to having non-virtual methods. Do see the Inheritance section of this topic for more information. Avoid methods that cannot be called on an object instantiated with a simple constructor

because the method requires further initialization of the object. If this is unavoidable,

64 Fully covered by FxCop rule: NamingRules/MemberNamesArePascalCased65 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly. The rule only covers spelling, not necessarily all prefixes. Full coverage coming soon: FxCopBug 999

72

Krzysztof Cwalina, 12/13/04,
This is a fake example. It needs fixing.

.NET Framework Design Guidelines Microsoft Confidentialthrow an exception clearly stating in the message what needs to be initialized. Usually an InvalidOperationException should be thrown in such cases.

4.1.7 Method OverloadingMethod Overloading occurs when there are two methods accessible from the same class with the same name but different signatures.

Do use method overloading when you provide different methods that do semantically the same thing.

Do favor method overloading to default arguments66. Default arguments do not version well and therefore are not allowed in the common language specification (CLS) and are not supported in the C# programming language.int String.IndexOf (String name);int String.IndexOf (String name, int startIndex);

Annotation (Brad Abrams): The issue with default arguments and versioning is that once you define a default argument you can never change its value. Consider the following method (in VB as C# does not support default arguments; the basic issue exists in C++ as well). Public Shared Function ComputeTotal(ByVal subtotal As Double, Optional ByVal salesTaxPrecent As Double = 8.8) As Double ComputeTotal = subtotal + subtotal * salesTaxPrecent / 100 End Function

Call site:Foo.ComputeTotal(100)

Looking at the IL disassembly for this call is instructive in showing what is going on: IL_0001: ldc.r8 100. IL_000a: ldc.r8 8.8000000000000007 IL_0013: call float64 ConsoleApplication5.Foo::ComputeTotal(float64, float64)

Notice in line 000a the VB compiler generated the IL instruction to load the literal 8.8. This is burned into the call site. If we change the definitions of the default value for salesTaxPrecent to 7.8% and do not recompile the calling code (as is common when working with large frameworks) 8.8 will continue to be passed as the default value. This can be a very nasty bug to track down!Using method overloading encapsulates the default value so that it can be changed in a predictable way.

Public Shared Function ComputeTotal(ByVal subtotal As Double, ByVal salesTaxPrecent As Double) As Double ComputeTotal = subtotal + subtotal * salesTaxPrecent / 100 End Function

Public Shared Function ComputeTotal(ByVal subtotal As Double) As Double ComputeTotal = ComputeTotal(subtotal, 8.8) End Function

Do use default values correctly67.In a family of overloaded methods the complex method should use parameter names that indicate a change from the default state assumed in the simple method. This is mostly applicable to Boolean parameters. For example, in the code below, the first method assumes the look-up will be case sensitive. In method two we use the name

66 Coming soon : FxCopBug 104567 Coming soon.

73

Brad Abrams, 12/13/04,
They also version better

.NET Framework Design Guidelines Microsoft ConfidentialignoreCase rather than caseSensitive because the former indicates how we are changing the default behavior. 1: MethodInfo Type.GetMethod(String name); //ignoreCase = false2: MethodInfo Type.GetMethod (String name, boolean ignoreCase);

It is very common to use a zero'ed state for the default value (such as: 0, 0.0, false, "", etc).

Avoid method families with the simplest overload having more than 3 simple parameters. Do not have constructor with the simplest overload having more than 5 parameters.

Do place out parameters after all value and ref parameters (excluding parameter arrays); even if it results in non-compliance with the next guideline (see below)68. The out parameters can be seen as extra return values and grouping them together makes the method signature easier to understand. For example:TryParse(string s, DateTimeStyles style, out DateTime result);TryParse(string s, out DateTime result);

Note: In general out and ref parameters should be avoided. See Parameter Passing section for more details.

Do be consistent in the ordering and naming of method parameters.It is common to have a set of overloaded methods with an increasing number of parameters to allow the developer to specify a desired level of information. The more parameters specified, the more detail that is specified. All the related methods have a consistent parameter order and naming pattern. Each of the method variations has the same semantics for their shared set of parameters.public class Foo{ readonly string defaultForA = "default value for a"; readonly int defaultForB = 42; readonly double defaultForC = 68.90; public void Bar(){ Bar(defaultForA, defaultForB, defaultForC); } public void Bar(string a){ Bar(a, defaultForB, defaultForC); } public void Bar(string a, int b){ Bar(a, b, defaultForC); } public void Bar(string a, int b, double c){ // core implementation here } }

The only method in such a group that should be virtual is the one that has the most parameters and only when extensibility is needed.

68 Coming soon: FxCopBug 1710.74

Krzysztof Cwalina, 12/13/04,
should we just call it T.default? (or whatever the terminology is)

.NET Framework Design Guidelines Microsoft Confidential Do make only the most complete overload virtual (if extensibility is needed) and

define the other operations in terms of it. public int IndexOf (string s) { return IndexOf (s, 0);}public int IndexOf (string s, int startIndex) { return IndexOf (s, startIndex, s.Length);}public virtual int IndexOf (string s, int startIndex, int count) { //do real work}

Consider using a static factory method (see section 6.11) instead of a constructor if the semantics of the desired operation do not map directly to the construction of a new instance, or if following the above guidelines feel unnatural.

4.1.8 Variable Number of Arguments69

Methods that can take an unlimited number of parameters are expressed by providing an overload that takes an array. For example, String.Format could provide the following overload:

string String.Format(string format, object[] args)

A user can then write:    String.Format("{0} {1} {2} {3}", new object[] {1, 2, 3, 4});

Adding the params keyword to the last parameter:    string String.Format(string format, params object[] args)

provides a shortcut to creating the temporary array, and allows the user to write:    String.Format("{0} {1} {2} {3}", 1, 2, 3, 4);

Users expect to use the short form, and it's therefore important to use "params" where appropriate.

Do not use params if the user would not expect to use the short form. Consider:

    public void Write(byte[] value);

In this case, the user would not expect to be able to specify individual bytes, so params would not be appropriate.

Do use params if all overloads are performing the identical operation. For example:

    public void Combine(Delegate delegate1, Delegate delegate2);

69 Substantial contribution from Eric Gunnerson75

.NET Framework Design Guidelines Microsoft Confidential   public void Combine(Delegate[] delegates);

Adding params to the second overload allows the use the same idiom in their code regardless of the number of arguments.

Consider using Params if a simple overload could use params but a more complex one could not, ask yourself "would users value the utility of having params on one overload even if it wasn't on all overloads". Consider the following overloaded methods:        ExecuteAssembly(String,Evidence,String[])        ExecuteAssembly(String,Evidence,String[],Byte[],AssemblyHashAlgorithm)

Even if the parameters could be re-ordered in the second overload to place an array as the last parameter, because there are two arrays, it's not a good candidate to use params. But it could be used on the first overload. If the first overload is often used, users will appreciate the simplification of using params. The correct params usage in this case is:public int ExecuteAssembly(string assemblyFile, Evidence assemblySecurity, params string[] args);public int ExecuteAssembly(string assemblyFile, Evidence assemblySecurity, string[] args, byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm);

A simpler example is the following:        FillPolygon(Brush,PointF[])        FillPolygon(Brush,PointF[],FillMode)The user will want "params" on the first version, event though they can't use it on the second version. The correct params usage in this case is:

       public void FillPolygon(Brush brush, params PointF[] points)       public void FillPolygon(Brush brush,PointF[] points,FillMode fillmode)

Do order parameters so that it's possible to apply "params" to the methods. Consider the following:

        Find(IComparer)        Find(String[],IComparer)        Find(String[])

Because of the ordering of parameters on the second overload, the opportunity to use "params" has been lost. If this had been written as:

        Find(IComparer)        Find(IComparer, String[])        Find(String[])

"params" could have been used for both overloads.

76

.NET Framework Design Guidelines Microsoft Confidential Do use the params construct instead of several overloaded methods for repeated

arguments70.

Do add the params keyword to a parameter that meets these guidelines even if you have already shipped it once undecorated. Adding params is NOT a breaking change. Existing client code will continue to work as expected and new code can start to take advantage of params.

Do not use the params when the array can is modified by the method. Because the array is a temporary any modifications to the array will be lost.

Do be aware that null could be passed in for a paramarray. You should validate that that paramarray is not null before processing (see section X.y on parameter passing). Failing to validate this could lead to unexpected exceptions for developers and may expose a security issues in your code.

static void Main() { Sum(1, 2, 3, 4, 5); //result == 15 Sum(null); //throws null reference exception } static int Sum(params int[] values) { int sum = 0; foreach (int i in values) { sum += i; } return sum; }

Do not use the VarArgs calling convention, otherwise known as the ellipsis (…), exclusively because the Common Language Specification does not support it71. For extremely performance sensitive code, you might want to provide special code paths for a small number of elements. You should only do this if you are going to special case the entire code path (not just create an array and call the more general method). In such cases, we recommend the following pattern as a balance between performance and the cost of specially cased code.void Format (string formatString, object arg1)void Format (string formatString, object arg1, object arg2)…void Format (string formatString, params object [] args)

4.1.9 Operator Overload Design

70 Fully covered by FxCop rule: DesignRules/ConsiderReplacingRepetitiveArgsWithParameterArray71 Coming soon : FxCopBug 1115.

77

.NET Framework Design Guidelines Microsoft Confidential Do define operators on Value types that are logically a built-in language type (such

as System.Decimal) Do provide operator-overloading methods only involving the class in which the

methods are defined. This C# compiler enforces this guideline. Do use the names and signature conventions described in the Common Language

Specification <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconwhatiscommonlanguagespecification.asp>.

Do not be cute. Operator overloading is useful in cases where it is immediately obvious what the result of the operation will be. For example, it makes sense to be able to subtract one Time value from another Time value and get a TimeSpan. However, it is not appropriate to use an or operator to union two database queries, or to use shift to write to a stream.

Do overload operators in a symmetric fashion72. For example, if you overload the Equal operator (==), you should also overload not equals (!=) operator.

Do provide alternate signatures73.Most languages do not support operator overloading. For this reason, it is a CLS requirement that all types that overload operators include a secondary method with an appropriate domain-specific name that provides equivalent functionality. The following example illustrates the point.public struct DateTime { public static TimeSpan operator -(DateTime t1, DateTime t2) { } public static TimeSpan Subtract (DateTime t1, DateTime t2) { }}

The following table contains a list of operators and their alternative methods

C++ Operator Symbol

Name of the alternative method

Name of operator in metadata

Not defined ToXxx or FromXxx op_ImplicitNot defined ToXxx or FromXxxx op_explicit+ (binary) Add op_Addition- (binary) Subtract op_Subtraction* (binary) Multiply op_Multiply/ Divde op_Division% Mod op_Modulus^ Xor op_ExclusiveOr& (binary) BitwiseAnd op_BitwiseAnd| BitwiseOr op_BitwiseOr

72 Fully covered by FxCop rule: UsageRules/OperatorsHaveSymmetricalOverloads.73 Fully covered by FxCop rule: UsageRules/OperatorOverloadsHaveNamedAlternativeMethods.

78

Brad Abrams, 12/13/04,
The full spec is not at this link...

.NET Framework Design Guidelines Microsoft Confidential

&& And op_LogicalAnd|| Or op_LogicalOr= Assign op_Assign<< LeftShift op_LeftShift>> RightShift op_RightShiftNot defined LeftShift op_SignedRightShiftNot defined RightShift op_UnsignedRightShift== Equals op_Equality!= Equals op_Inequality> CompareTo op_GreaterThan< CompareTo op_LessThan>= CompareTo op_GreaterThanOrEqual<= CompareTo op_LessThanOrEqual*= Multiply op_MultiplicationAssignmen

t-= Subtract op_SubtractionAssignment^= Xor op_ExclusiveOrAssignment<<= LeftShift op_LeftShiftAssignment%= Mod op_ModulusAssignment+= Add op_AdditionAssignment&= BitwiseAnd op_BitwiseAndAssignment|= BitwiseOr op_BitwiseOrAssignment, op_Comma/= Divide op_DivisionAssignment-- Decrement op_Decrement++ Increment op_Increment- (unary) Negate op_UnaryNegation+ (unary) Plus op_UnaryPlus~ OnesComplement op_OnesComplement

4.1.10 Implementing Equals and Operator== Do see the section on implementing the Equals method in section 8.3.

79

Brad Abrams, 12/13/04,
Make this a link

.NET Framework Design Guidelines Microsoft Confidential Do implement GetHashCode() whenever you implement Equals()74. This keeps Equals()

and GetHashCode() synchronized. Do override Equals whenever you implement operator== and make them do the same

thing75. This allows infrastructure code such as Hashtable and ArrayList which use Equals() to behave the same way as user code written using operator==. Note the reverse is not always true, you do not need to implement operator == anytime you override the Equals() method.

Do override Equals anytime you implement IComparable76. Consider overloading operators ==, !=, <, >, <=, >= when you implement IComparable

on an immutable type that has value semantics77. Do not throw exceptions from Equals(), GetHashCode(), or operator== methods.

Implementing operator== on Value Types Do overload operator== if equality is meaningful78. In most programming languages

there is no default implementation of operator== for value types. Consider implementing Equals() on ValueTypes because the default implementation on

System.ValueType will not perform as well as your custom implementation79. Do implement operator== anytime you override Equals() on an immutable type that has

value semantics80. Do provide a strongly typed Equals() method any type you override the Equals().

Rational: Calling the strongly typed version avoids boxing. public struct MyStruct {

public override bool Equals(object obj){

if (obj is MyStruct)

74 Fully covered by FxCop rule: UsageRules/EqualsOverridesRequireGetHashCodeOverride.75 Fully covered by FxCop rule: UsageRules/OperatorEqualsOverridesRequireEqualsOverride.76 Fully covered by FxCop rule: DesignRules/IcomparableImplementationsOverrideEquals.77 Fully covered by FxCop rule: DesignRules/IcomparableImplementationsOverrideOperators.78 Fully covered by FxCop rule: UsageRules/ValueTypesEqualsOverridesRequireOperatorEqualsOverride.79 Fully covered by FxCop rule: PerformanceRules/ConsiderOverridingEqualsAndOperatorEqualsOnValueTypes.80 Fully covered by FxCop rule: UsageRules/OperatorEqualsOverridesRequireEqualsOverride.

80

Brad Abrams, 12/13/04,
We should show a default implementation calling through to the CompareTo() method.

.NET Framework Design Guidelines Microsoft Confidential{

return Equals ((MyStruct) obj );}return false;

}public bool Equals (MyStruct value) {

//do implementation}//other methods

} Do not implement Operator== in terms of Equals( object ) to avoid unnecessary boxing

Implementing operator== on Reference Types Do not define operator== on a mutable reference type. 

Rational: Most languages already have a built in meaning for operator== on reference types to be reference equality (equivalent to Object.ReferenceEquals()) and therefore developers have come to expect that behavior.  This problem is mitigated for immutable reference types because without the aliasing problem associated with mutable types developers do not notice the difference between reference equality and logical equality provided by implementing operator==.Note: Mutable reference types that need to provide logical equality should do so by overriding the .Equals() method but NOT overriding operator==.

Do not define operator== on a reference type if the implementation is significantly slower than that of reference equality.

4.1.11 Conversion Operators Do not define cast operators in publicly exposed APIs. The exception to this rule is for

creating “primitive” types such as Int32, Double, or DateTime. Do not define casting operators outside of a types domain – for example Int32, Double,

and Decimal are all numeric types – while DateTime is not. Therefore there should be no cast operator to go from a Double to a DateTime. A constructor is preferred in this case.

Do not use cast operators in a surprising way. That is only provide them where there is a strong expectation that they would be there and ideally some prior art that justifies them.

Do not lose precision in implicit casts.For example, there should not be an implicit cast from Double to Int32, but there may be one from Int32 to Int64.

81

.NET Framework Design Guidelines Microsoft Confidential Do not throw exceptions from implicit casts because it is very difficult for the developer

to understand what is happening. Do provide casts that operate on the whole object. The value that is cast represents

the whole value being cast, not one sub part. For example, it is not appropriate for a Button to cast to a string by returning its caption.

Do not generate a semantically different value.For example, it is appropriate to convert a Time or TimeSpan into an Int. The Int still represents the time or duration. It does not make sense to convert a file name string such as, "c:\mybitmap.gif" into a Bitmap object.Do cast values that are in the same domain. Do not cast values from different domains. Casts operate within a particular domain of values. For example, numbers and strings are different domains. So it makes sense that an Int32 can cast to a Double. It does not make sense for an Int to cast to a String, because they are in different domains.

4.1.12 Constructor Design Avoid constructor families with the simplest overload having more than 3 simple

parameters. Do not have constructor with the simplest overload having more than 5 parameters.

Consider providing simple, ideally default, constructors. A simple constructor has a very small number of parameters, and all parameters are primitives or enumerations.

Do have only a default private constructor if there are only static methods and properties on a class81.public sealed class Enviroment{ private Enviroment(); // Prevents the class from being created. //…}

Do make static constructors private82. A static constructor, also called a class or type constructor, is used to initialize a type. The system calls the static constructor before the first instance of the type is created or any static members are referenced. The user has no control over when the static constructor is called. If a static constructor is not private, it can be called by code other than the system. Depending on the operations performed in the constructor, this can cause unexpected behavior.

Do minimal work in the constructor. Constructors should not do much work other than to capture the constructor parameters. The cost of other operations is delayed until the user uses a particular feature of the instance.Do not call virtual members from constructors. Calling virtual methods during construction will cause the most derived override to be called, even though the most derived constructor has not been fully run yet.  FxCop Rule:

81 Fully covered by FxCop rule: DesignRules/TypesHavingOnlyStaticMembersShouldNotHaveConstructors82 Fully covered by FxCop rule: SecurityRules/StaticConstructorsHavePrivateAccessLevel

82

Brad Abrams, 12/13/04,
Should we move this towards the top of this section?

.NET Framework Design Guidelines Microsoft ConfidentialConstructorsShouldNotCallBaseClassVirtualMethods

Consider the example below which prints out “value != 42, what is wrong” when a new instance of Derived is created.  The implementer of the derived class assumes that the value will be set to 42 before anyone can call Method1().  But that is not true because the base class’s constructor is called before the Derived class’s constructor finishes, so any calls it makes to Method1() causes the problem.  

public class Base{    public Base()    {        Method1();    }    public virtual void Method1() {        Console.WriteLine("In Base's Method1()");    }}public class Derived: Base{    private int value;    public Derived()    {        value = 42;    }

    public override void Method1()    {        if (value == 42) Console.WriteLine("value == 42, all is good");        else Console.WriteLine("value != 42, what is wrong?");    }}

When a virtual method is called, the actual type that executes the method is not selected until runtime. When a constructor calls a virtual method there is a chance that the constructor for the instance that invokes the method has not executed.Annotation (CBrumme): In unmanaged C++, the vtable is updated during the construction so that a call to a virtual function during construction only calls to the level of the object hierarchy that has been constructed.It’s been my experience that as many programmers are confused by the C++ behavior as the managed behavior. The fact is that most programmers don’t think about the semantics of virtual calls during construction / destruction – until they have just finished debugging a failure related to this.Either behavior is appropriate for some programs and inappropriate for others. Both behaviors can be logically defended. For the CLR, the decision is ultimately based on our desire to support extremely fast object creation.

Annotation (Tony Williams): Within a "program" a developer can deal with the behavior that is implemented. If there are different policies chosen in different "programs" interop becomes a serious issue. Therefore any API between separate "programs" (apps, add-ins) should not depend on behavior of virtual methods. C++ direct calls are another manifestation of this.

Do throw exceptions from constructors if appropriate. As a matter of fact any constructor can throw several exceptions without explicit throw statements in your code. This includes OutOfMemoryException, ThreadAbortException, and others.Note:   When an exception propagates out of a constructor, the object is created but the operator new does not return the reference. The finalizer of the object will run when the object becomes eligible for collection.

83

Brad Abrams, 12/13/04,
We should add a note about how this is different fom the C++ world

.NET Framework Design Guidelines Microsoft Confidential Do provide a constructor for every type

If the type is not meant to be creatable use a private constructor83.If you don't specify a constructor many languages (such as C#) implicitly add a public default constructor. (Abstract classes automatically get a protected constructor)public class Foo {}

is equivalent topublic class Foo { public Foo () {}}

Adding a non-default constructor removes the implicit constructor which could break client code. Consider a V1 class:public class Foo {}

Code can call the implicit default constructorFoo f = new Foo ();

In V2, if the owner of the Foo class decides to add a non-default constructor the class will no longer need the implicit one and it will not be emitted.public class Foo { public Foo (int value) {}}

This will break the calling code above and is unlikely to be caught in a code review.The best practice is to always explicitly specify the constructor even if it a public default constructor.

Do provide a protected (family) constructor that can be used by types in a derived class.

It is recommended that you not provide a default (paramaterless) constructor for a struct (value types)84. Note that many compilers don't allow structs to have paramaterless constructors for this reason.If no constructor is supplied, the runtime will initialize all of the fields of the struct to zero. This makes array and static field creation faster.

Do use parameters in constructors as shortcuts for setting properties. There should be no difference in semantics between using the empty constructor followed by some property sets, and using a constructor with multiple arguments. The following three code examples are equivalent.

83 Fully covered by FxCop rule: DesignRules/TypesHavingOnlyStaticMembersShouldNotHaveConstructors84 Coming soon. FxCopBug 1116.

84

Brad Abrams, 12/13/04,
Add a note about C#’s defaults here

.NET Framework Design Guidelines Microsoft Confidential//1EventLog applicationLog = new EventLog();applicationLog.MachineName = "BillingServer";applicationLog.Log = "Application";

//2EventLog applicationLog = new EventLog("Application");applicationLog.MachineName = "BillingServer";

//3EventLog applicationLog = new EventLog("Application", "BillingServer");

Do be consistent in the ordering and naming of constructor parameters. A common pattern for constructor parameters is to provide an increasing number of parameters to allow the developer to specify a desired level of information. The more parameters that are specified, the more detail that is specified. For all of the following constructors, there is a consistent order and naming of the parameters.public class EventLog { private const string defaultLog = ""; private const string defaultMachine = "."; private const string defaultSource = ""; public EventLog() : this(defaultLog, defaultMachine, defaultSource) {}

public EventLog(string logName) : this(logName, defaultMachine, defaultSource) {}

public EventLog(string logName, string machineName) : this(logName, machineName, defaultSource) {}

public EventLog(string logName, string machineName, string source){ // the actual single implementation. } }

4.1.13 Type Constructor GuidelinesA static constructor, also called a type constructor or by the name emitted into the metadata (“.cctor”), is used to initialize a type. The runtime calls the static constructor before the first instance of the type is created or any static members are referenced.

Do make static constructors private[1]. The user has no control over when the static constructor is called. If a static constructor is not private, it can be called by code other than the system. Depending on the operations performed in the constructor, this can cause unexpected behavior.

Do favor initializing static state inline rather than explicitly using static constructors as the runtime is able to optimize the performance of types that use in inline mechanism.  FxCop Rule: 3246.

[

85

.NET Framework Design Guidelines Microsoft ConfidentialIncorrect code:

public class Foo{ public static int Value; static Foo() { Value = 63; } public static void PrintValue() { Console.WriteLine(Value); }}

Correct code:

public class Foo{ public static int Value = 63; public static void PrintValue() { Console.WriteLine(Value); }}

Do be aware that initializing static state inline (i.e. tdBeforeFieldInit) has very loose guarantees about when the state will be initialized.  The guarantee is that they will be initialized before the first static data is accessed, but it could potentially be much earlier.  The CLR reserve the right to do the initialization before the program even starts running (using NGEN techniques for example).  Explicit static constructors (i.e. no tdBeforeFieldInit) makes a very precise guarantee.  It will be run before the first static member (code or data) is accessed but no earlier.

Avoid creating dependencies between static constructors.  The runtime will break dependency cycles by exposing partially initialized types in some cases.  FxCop Rule 3246

Avoid creating static constructors on value types as they may not be run in some cases such as allocate an array of value types.  FxCop rule 3246.

4.1.14 Field Design Do not use instance fields that are public or protected (family)85.

Consider providing get and set property accessors for fields instead of making them public.

85 Fully covered by FxCop rule: DesignRules/TypesDoNotHavePublicInstanceFields.86

Brad Abrams, 12/13/04,
Add a note about inliineing, etc

.NET Framework Design Guidelines Microsoft Confidentialpublic struct Point{ private int x; private int y; public Point(int x, int y){ this.x = x; this.y = y; } public int X{ get{ return x; } set{ x = value; } } public int Y{ get{ return y; } set{ y = value; } }}

To expose a field to a derived class, use a protected (family) property that returns the value of the field.public struct Control : Component{ private int handle; protected int Handle{ get{ return handle; } }}

By not exposing fields directly to the developer, the class can be versioned more easily for the following reasons: A field cannot be changed to a property while maintaining binary compatibility. The presence of executable code in get and set property accessors allows later

improvements, such as demand-creation of an object upon usage of the property, or a property change notification.

Do use const (static literal) fields for constants that will NEVER change. The compiler burns the values of const fields directly into calling code. Therefore const values can never be changed.public struct Int32{ public const int MaxValue = 0x7fffffff; public const int MinValue = unchecked((int)0x80000000);}

Do use public static readonly fields for predefined object instances. 87

Brad Abrams, 12/13/04,
Can we get a non-interop examples?

.NET Framework Design Guidelines Microsoft ConfidentialIf there are predefined instances of an object, declare them as public readonly static fields of the object itself. Use Pascal casing because they are public. For example:public struct Color{ public static readonly Color Red = new Color(0x0000FF); public static readonly Color Green = new Color(0x00FF00); public static readonly Color Blue = new Color(0xFF0000); public static readonly Color Black = new Color(0x000000); public static readonly Color White = new Color(0xFFFFFF); public Color(int rgb) { }

public Color(byte r, byte g, byte b) { }

public byte R { get {...} } public byte G { get {...} } public byte B { get {...} }}

Do not return mutable types from readonly fields. A mutable type is a type whose instance data can be modified (notice arrays and most collections are mutable types). The read-only modifier on a reference type field prevents the field from being replaced by a different instance of the reference type but does not prevent the field's instance data from being modified through the reference type.86

The following example shows how it is possible to change the value of a readonly field. using System;

public class F { int i; public void Change () { i++; } public void Print () { Console.WriteLine (i); }}

public class Bar { public static readonly F f = new F ();}public class Foo {

public static void Main () { Bar.f.Change(); Bar.f.Change(); Bar.f.Print(); } }Output:2

Do not abbreviate field names87. Spell out all the words used in a field name. Only use abbreviations if developers generally understand them. Do not use uppercase letters for field names. For example:

86 Covered by FxCop rule: MutableReferenceTypesShouldNotBeReadOnly87 Fully covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly.

88

.NET Framework Design Guidelines Microsoft Confidentialclass Foo { string url; string destinationUrl;}

Do not use Hungarian notation for field names88. Good names describe semantics, not type.

Do not use a prefix for field names89. Do not use a prefix for static field names90. Do not include a prefix on a field name, for example 'g_' or 's_' to distinguish static vs.

non-static fields91.

4.1.15 Explicit Member ImplementationExplicit member implementation allows an interface member to be implemented such that it is only available when cast to the interface type. For example, consider the following definition:

public struct Int32 : IConvertible, IComparable { public override string ToString () {..} int ICovertible.ToInt32 () {..} ...}

This code calls the IConvertable members:

int i = 42;i.ToString(); // worksi.ToInt32(); // does not compile((IConvertible) i).ToInt32(); // works

Do not use explicit members as a security boundary. They can be called by any client who cast an instance to the interface.

Do use explicit members to hide implementation details Do use explicit members to approximate private interface implementations. If you

need to implement an interface for only infrastructure reasons and you NEVER expect developers to directly call methods on that interface from this type then implement the members explicitly to “hide” them from pubic view.

88 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly. This rule only covers spelling, not necessarily all prefixes. Full coverage coming soon: FxCopBug 999.89 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly. This rule only covers spelling, not necessarily all prefixes. Full coverage coming soon: FxCopBug 999.90 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly. This rule only covers spelling, not necessarily all prefixes. Full coverage coming soon: FxCopBug 999.91 Partially covered by FxCop rule: MSInternalRules/MemberNamesShouldBeSpelledCorrectly. This rule only covers spelling, not necessarily prefixes. Full coverage coming soon: FxCopBug 999.

89

.NET Framework Design Guidelines Microsoft ConfidentialFor example, all of the base datatypes must implement IConvertable for infrastructure reasons. IConvertable has 19 conversion methods that would pollute the public interface of these types. So it is appropriate to explicitly implement these members so they are available when cast to IConvertable but do not appear on the public interfaces. This makes the development experience much cleaner.

Do expose an alternative way to access any explicitly implemented members that subclasses are allowed to override.92 Use the same method name unless a conflict would arise.Annotation (AndersH): Programmer in other environments consistently complain about the need for internal methods to be public just so a class can implement some worker interface. EMIs are the correct solution to that problem. Yes, it is true that C# doesn't give you syntax to call the base implementation of an EMI, but I have seen very few actual requests for that feature.

The following example shows a type, ViolatingBase, that violates the rule and a type, FixedBase, that shows a fix for the violation.using System;

namespace DesignLibrary{ public interface ITest { void SomeMethod(); }

public class ViolatingBase : ITest { void ITest.SomeMethod() { // ... } }

public class FixedBase : ITest { void ITest.SomeMethod() { SomeMethod(); }

virtual protected void SomeMethod() { // ... } }

public class Derived : FixedBase, ITest { override protected void SomeMethod()

92 Fully Covered by ExplicitMethodImplementationsInUnsealedClassesHaveVisibleAlternates

90

.NET Framework Design Guidelines Microsoft Confidential { // ... base.SomeMethod();

// This would cause recursion and a stack// overflow.

// ((ITest)this).SomeMethod(); } }}

Do be aware of possible unintended points of specialization introduced by explicit members. See section x.y on unintended points of specialization with interfaces.

4.2 Parameter Design

4.2.1 Argument Checking Do check arguments for validity93.

Perform argument validation for every public or protected (family) method and property set accessor, and throw meaningful exceptions to the developer. The System.ArgumentException exception, or one of its subclasses, is used in these cases.class Foo{ public int Count{ get{ return count; } set{ if (value < 0 || value >= MaxValue) throw new ArgumentOutOfRangeException(Sys.GetString( "InvalidArgument", "value", value.ToString() ));

count = value; } } public void Select(int start, int end){ if (start < 0) throw new ArgumentException(Sys.GetString( "InvalidArgument", "start", start.ToString() )); if (end < start) throw new ArgumentException(Sys.GetString( "InvalidArgument", "end", end.ToString()

93 FxCop rule under investigation.91

.NET Framework Design Guidelines Microsoft Confidential )); }}

Note that the actual checking does not necessarily have to happen in the public/protected (family) method itself. It could happen at a lower level in some private routines. The main point is that the entire surface area that is exposed to developers checks for valid arguments.

Annotation (Cbrumme): [raw] By setting the InitLocals flag, it is possible to get a NULL ByRef value on the stack. This value can then be passed in as a ByRef parameter to other methods. C#/VB does not allow this, it may be possible in C++. Programmers should ''not'' check for NULL in this situation, but should just be aware of the possibility.

Do provide overloads for methods with optional arguments. If a method takes some arguments that are not required provide overloads of the method without the optional arguments. See section X.Y on method overloading. That is if you have this method here geometry is optional, provide an overload without it as well.public void DrawGeometry(Brush brush, Pen pen, Geometry geometry);public void DrawGeometry(Brush brush, Pen pen);

Do allow null to be passed for optional arguments. If a method takes optional arguments that are reference types, allow null to be passed to indicate the default value should be used. This avoids the problem of having to check for null before calling an API as shown below: if (brush == null) DrawGeometry(pen, geometry); else DrawGeometry(brush, pen, geometry);

Annotation (Adam Smith): It sure seems that we're providing a less startling API if we define reasonable, expected behavior when "null" is passed for a param.  If that's really impossible, sure, throw an exception, but to throw when there's a consistent, non-crashing thing we could have done seems unhelpful. 

Do be aware that mutable parameters may have changed after they were validated. If the operation is security sensitive you are encouraged to make a copy, then validate and process the argument.

TODO: Annotation on boxed value types (the fact that they are mutable, the fix for Whidbey etc.

The following sample code demonstrates the issue. The DeleteFiles method does not create a copy of the filenames array before validation as such it is subject to a security issue because of race condition. For simple correctness issues insulation from this threading issues is not necessary as libraries are free threaded (don’t take locks), etc. See the threading section x.y for more information.

/// <summary> /// Deletes all the files passed in if they pass validation, throws otherwise. /// </summary> public void DeleteFiles(string[] filenames) {

92

Brad Abrams, 12/13/04,
Todo: mark with a NOT symbol
Brad Abrams, 12/13/04,
Add a note about why: people thing the framework is buggy if they get a nullrefexception

.NET Framework Design Guidelines Microsoft Confidential if (!ValidateFiles(filenames)) throw new ArgumentException("Files must be local"); Thread.Sleep(1);//force a race to demonstrate the problem foreach (string s in filenames) { Console.WriteLine("Thread1: Deleting file: {0}", s); /*TODO: File.Delete(s); */ } } private bool ValidateFiles(string[] filenames) { foreach (string s in filenames) { if (s.Contains("..")/*TODO: real test */) { return false; } else { Console.WriteLine("Thread1: '{0}' passes validation", s); } } //end for return true; }

Notice we force the race condition with the Thread.Sleep()_call, without the call the problem may still happen depending on other factors on the machine. This is exploited by the calling code forking off a thread to change the values in the array after validation occurs. static void Main(string[] args) { Program p = new Program(); string[] names = { "one.txt", "two.txt" }; //init to a set of valid values Thread hackerThread = new Thread(delegate(object obj) //set up hacker thread { names[1] = @"..\..\boot.ini"; Console.WriteLine("Thread2: changing 1 to '{0}'", names[1]); }); hackerThread.Start(); p.DeleteFiles(names); //call the API being hacked }

The output from this code is:Thread1: 'one.txt' passes validationThread1: 'two.txt' passes validationThread2: changing 1 to '..\..\boot.ini'Thread1: Deleting file: one.txtThread1: Deleting file: ..\..\boot.ini

Notice that Thread1 validates ‘one.txt’ and ‘two.txt’, but ends up deleting ‘one.txt’ and ‘..\..\boot.ini’ because thread2 is able to change one of the values after validation happens.

The fix for this problem is relatively simple, if expensive. Simply use Array.Copy() to create a local copy of the array *before* validating and performing operations on it. Notice

93

.NET Framework Design Guidelines Microsoft ConfidentialArray.Copy() only does a shallow copy, this works for arrays of strings as strings are immutable, but if you are dealing with an array of some mutable type (such as StringBuilder) you’d have use a different mechanism to validate all the data.

/// <summary> /// Deletes all the files passed in if they pass validation, throws otherwise. /// </summary> public void DeleteFiles(string[] filenames) { string [] filenamesCopy = new string[filenames.Length]; Array.Copy(filenames, filenamesCopy,filenames.Length); if (!ValidateFiles(filenamesCopy)) throw new ArgumentException("Files must be local"); Thread.Sleep(1);//force a race foreach (string s in filenamesCopy) { Console.WriteLine("Thread1: Deleting file: {0}", s); /*TODO: File.Delete(s); */ } }

With this change, we throw an exception as expected or delete only the safe values depending on a race.

4.2.2 Parameter PassingThere are three ways of passing parameters into members.By ValueThe member receives a copy of the actual variable passed in. If the variable is a value type, a copy of the value type is put on the stack. If the variable is a reference to a reference type, a copy of the reference is put on the stack. This is the default type of parameter passing for C#, VB.NET, C++, and other popular CLR languages.public void Add (object value) {..}

By ReferenceThe member receives a reference to the actual variable passed in. If the member alters the variable, then the value of the variable is also changed. The ref modifier is used to designate that a parameter is to be passed by reference.public static int Exchange (ref int location, int value) {..}

Out ParametersSimilar to passing by reference with the following differences:The parameter passed into the member is initially considered unassigned. That is, it cannot be read until it is assigned a value.The parameter must be assigned a value upon completion of the member. This means that there has to be an “output” when the member returns to the caller.

94

.NET Framework Design Guidelines Microsoft ConfidentialThe out modifier is used to designate that it is an output parameter.[DllImport("Kernel32.dll")]public static extern bool QueryPerformanceCounter(out long value);

Do not pass reference types by reference94.Pass reference types by value instead. This already references the location of the variable passed in, and gives the desired result for most scenarios.

Avoid using out or ref parameters95. Using out or ref parameters require experience with pointers, understanding how value types and reference types differ, and handling methods with multiple return values. Also, the difference between out and ref parameters is not widely understood. Library architects designing for a general audience should not expect users to master working with out or ref parameters.

Do not have publicly exposed methods that take pointers, arrays of pointers, or multidimensional arrays as parameters96.Pointers and multidimensional arrays are relatively complex concepts, and require more experience from developers to use them. Forcing users to pass in these types of parameters make it difficult for them to call the method. In almost all cases, methods can be redesigned to avoid taking these complex types as parameters.

4.2.3 Pointer ArgumentsIt is very rare but possible to use pointer arguments in a well designed framework. Most of the time pointers should be encapsulated in a managed instance and thereby completely hidden. However in some cases where interop is a key scenario using pointers is appropriate.

Do provide an alternative for any member that takes a pointer argument as pointers are not in allowed in the CLS.

[CLSCompliant(false)]public unsafe int GetBytes(char* chars, int charCount,

byte* bytes, int byteCount);

public int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex, int byteCount)

94 Fully covered by FxCop rule: DesignRules/ReferenceTypesAreNotPassedAsByRefParameters95 Fully covered by FxCop rules: DesignRules/AvoidOutParameters, DesignRules/ValueTypesAreNotPassedAsByRefParameters, DesignRules/ReferenceTypesAreNotPassedAsByRefParameters96 Fully covered by FxCop rule: DesignRules/PointersAndMultiDimensionalArraysAreNotPassedAsParameters.

95

.NET Framework Design Guidelines Microsoft ConfidentialAvoid doing expensive argument checking on methods that take pointer arguments. In general argument checking is well worth the cost but for APIs that are performance critical enough to require using pointers the overhead is often not worth it.

Do use common pointer patterns rather than managed patterns. For example there is no need to pass the start index as simple pointer arithmetic can be used to accomplish the same result. //Bad practicepublic unsafe int GetBytes(char* chars, int charIndex, int charCount,

byte* bytes, int byteIndex, int byteCount)

//Better practicepublic unsafe int GetBytes(char* chars, int charCount,

byte* bytes, int byteCount)

//example callsiteGetBytes(chars + charIndex, charCount, bytes + byteIndex, byteCount);

Annotation (Brad Abrams): For developers working with pointer based APIs it is more natural to think of the world in a pointer-oriented mindset. Although it is common in “safe” managed code, in pointer based code passing an index is uncommon; it is more natural to use pointer arithmetic.

4.2.4 Enums vs Boolean Arguments A framework designer is often faced with the choice of when to use enums and when to use Booleans for method and constructor arguments. In general terms you should favor using enums where it makes the readability of source code more explicit and therefore easier to understand. Anywhere using enums would add unneeded complexity and actually hurt readability of source code Booleans should be preferred.

Do use enums if you two or more arguments that are Booleans. Enums are much more readable (in books, documentation, code reviews, etc). Consider a method call that looks such as:FileStream f = File.Open (“foo.txt”, true, false);

This call gives you no context whatsoever to understand the meaning behind true and false. Now consider if the call where:FileStream f = File.Open (“foo.txt”, CasingOptions.CaseSenstative, FileMode.Open);

Annotation (AMoore): Some have asked why we don’t have a similar guideline for integers, doubles, etc, should we find a way to “name” them as well? There is a big difference between numeric types and Booleans: you almost always use constants and variables to pass numerics around, because it is good programming practice and you don’t want to have “magic numbers”. However, if you take a look at any managed code-base, this is almost never true of Booleans. 80% of the time a Boolean argument is passed in as a constant, and its intention is to turn a piece of behavior on or off. We could alternatively try to establish a coding guideline that you should never pass a primitive “true/false” value to a method or constructor, but we would probably get significant pushback on that. I certainly don’t want to define a constant for each Boolean parameter I’m passing in.

Enums are much easier for developers to work with in Intellisense and in documentation. Often a good parameter name can give you a hint as to when to pass true or false, but parameter names are not generally available when reading code. enums leave little ambiguity by making very clear which value to pass when writing and reading code.

96

.NET Framework Design Guidelines Microsoft ConfidentialAnnotation (Jon Pincus): Methods with two Boolean parameters (like the one in the example above) allow developers to inadvertently switch the arguments, and the compiler and static analysis tools can't help you. Even with just one parameter, I tend to believe it's a somewhat easier to make a mistake with Booleans ... let's see, does true mean "case insensitive" or "case sensitive"?

Do use enums unless you are 100% sure there will never be a need for another option. Enums have the potential to give you more room for future expansion but be aware of versioning issues specific to enums in section x.y. Annotation (BradA): We have seen a couple of places in the framework where we added a Boolean in V1 and in V2 we were forced to add another Boolean option to account for what could have been a foreseeable change. Don’t let this happen to you, if there is even a slight possibility of needing a more options in the future use an enum now.

Avoid using enums for method\constructor arguments for single arguments that are truly two state values. If the member does not take more than one Boolean argument and there are now and forever more only two states.

Annotation (Greg Schechter): There are a number of reasons to avoid introduction of more enums than necessary to meet the spirit of this guideline. Most of the problems manifest themselves when you use properties that return Enums which is not directly covered by this guideline. Examples include:

It is difficult to “interop” what are essentially Boolean values that are expressed as independent enums. For instance, if I want to do something like underline something that is not bold, I want to be able to do the following: myStyle.Underline = !myStyle.Bold;This works because both underline and bold are two-state, and will always be two-state (there are always examples where this is not the case, and in such cases, enums should be used). Note that if I were to use enums, I’d need to write:

if (myStyle.Boldness == BoldStyle.Bold) { myStyle.Underline = UnderlineStyle.NoUnderline; } else { myStyle.Underline = UnderlineStyle.Underline; }

or

myStyle.Underline = (myStile.Boldness == BoldStyle.Bold ? UnderlineStyle.NoUnderline : UnderlineStyle.Underline);

neither of which are particularly appealing.

If the enum is returned from a property, then the consumer of that property doesn’t really know whether or not they need to consider whether or not the enum is going to have additional states in later versions. They don’t know that it’s now and forevermore a two-state value. Therefore, they don’t know what to do in the “default” section of their switch statement that consumes this value. As an example of this, the writer of the code in the point above may not know that BoldStyle is truly and forevermore a two-state value. To protect themselves for versioning’s sake, they won’t even be able to write the above, they’ll need to go even further to:

switch (myStyle.Boldness) { case BoldStyle.Bold: myStyle.Underline = UnderlineStyle.NoUnderline; break;

case BoldStyle.NotBold:

97

.NET Framework Design Guidelines Microsoft Confidential myStyle.Underline = UnderlineStyle.Underline; break;

default: // something else, appropriate for versioning of this code. break; }As an even more extreme, but very real, example of the issue described at top, consider the databinding scenario where one wants to databind two values that would otherwise be Booleans together. For example, binding the “bold-ness” of one instance to the “underline-ness” of another. Here, the problem is exacerbated because writing the code that would do the conversion between enum values is much less simple… that is, there’s typically not a chunk of code to add such a conversion into. What is required is the addition of a data transformer into the data binding evaluation that will do the transformation. Same problem and issue, just a much more elaborate workaround required.

Hence, because of these difficulties in using enums when Booleans sufficiently describe the data, API designers should think hard about whether they really require multiple Boolean parameters to a method. If they can avoid such method signatures, they should be able to avoid introducing a new enum when a Boolean will do.

Annotation (AMoore): An interesting clarification of this guideline for constructor parameters that map onto properties is that if the value is typically set in the constructor an enum value is better otherwise a Boolean value is better. This thinking helped us clarify a recent CodeDom work item to add “IsGlobal” on CodeTypeReference. In this case it should be an enum because it is typically set in the constructor, but the “IsPartial” property on CodeTypeDeclaration should be a Boolean.

Avoid sharing of enum types between different families of methods. Although it may seem like similar concepts unless there represent the exact same concept there will be issues as they diverge in the future.

Annotation (Brad Abrams): Generally speaking, enums don’t cost noticeably more than Booleans. As far as the runtime is considered an enum is treated just like its underlying type which is in most cases Int32 (the same in memory size Booleans take up). Today there is a very small overhead (on the order of 300 bytes for each enum type referenced) but this at the noise range and should not be considered a factor in choosing to use a Boolean over an enum.

It is possible to write bad code with enums that does perform poorly; you should see section x.y on argument validation for a note on avoiding calls to Enum.IsDefined as it loads reflection which is often performance issue.

5 Common Contract Implementations

5.1 CollectionsTypes implementing IEnumerable, ICollection, or IList are called Collections. Types implementing IDictionary are called Dictionaries, even if they also implement IEnumerable, ICollection, or IList. We will use lower case collection to refer to both Collections and Dictionaries.

5.1.1 Naming

98

Krzysztof Cwalina, 13/12/04,
This section needs a major cleanup.

.NET Framework Design Guidelines Microsoft Confidential Do name Collections according the following pattern97. Assuming that the type of the

items in the collection is ItemType, the Collection should be named ItemTypeCollection. For example, a class implementing IList and storing Address objects should be named AddressCollection.

Do name Dictionaries according to the following pattern98. Assuming the Dictionary keys are of KeyType type and values are of ValueType type, the dictionary should be named KeyTypeValueTypeDictionary. For example, a dictionary that maps strings to exceptions should be named StringExceptionDictionary. If the type of the keys and the type of the values are the same, KeyTypeDictionary naming pattern should be used.

Do not postfix your collection names with List, Hashtable or any other word implying particular implementation of the collection99. Do not do it even if you inherit from the ArrayList or the Hashtable. It is ok, in rare circumstances, to postfix some very specialized collections with Queue, Stack, or Set. Those names are not implementation related but rather indicate specific semantics.

5.1.2 Implementation Do implement strongly typed collections100. Any method storing or retrieving items from

a collection should take or return objects of a specific type, not generic Object type (unless it's a collection of objects). If the collection stores reference types, IEnumerator.GetEnumerator does not need to be implemented as a strongly typed member. Value type collections should implement strongly typed enumerators to avoid boxing.

Do use explicit member implementation to implement strongly typed members101. For example:public ExceptionCollection: IList { object IList.this[int item]{ … } public Exception this[int item] { … }}

Do not implement collections storing value types by delegating to a collection of reference types. This would result in significant performance overhead as each item would have to be boxed when passed through a reference type interface. For examplepublic Int32Collection: IList {

// array list is reference type (Object) based collection ArrayList myNaiveImplementation = new ArrayList();

97 Fully covered by FxCop rule: NamingRules/CollectionNamesHaveCollectionSuffix.98 Fully covered by FxCop rule: NamingRules/DictionaryNamesHaveDictionarySuffix.99 Fully covered by FxCop rule: NamingRules/CollectionNamesHaveCollectionSuffix.100 Fully covered by FxCop rule: DesignRules/IcollectionImplementationsHaveStronglyTypedMembers.101 Fully covered by FxCop rule: DesignRules/ICollectionImplementationsHaveStronglyTypedMembers, DesignRules/IListImplementationsHaveStronglyTypedMembers,

DesignRules/IEnumeratorImplementationsHaveStronglyTypedMembers99

Brad Abrams, 12/13/04,
This rule is under debate now

.NET Framework Design Guidelines Microsoft Confidential public void Add(int item){ // Bad! The following line will box the integer! myNaiveImplementation.Add(item); }}

Note:  Do see the collections spec on <http://comrtime/specs/classlibs/Doc/Collections.doc>

5.1.3 Collection Usage Consider using keyed collections if the items stored in the collection have natural

names. Keyed collections are collections that are indexed by a string-typed index and an integer-typed index. System.Collection.KeyedCollection is an example of a keyed collection.Directory dir = new Directory(@“c:\temp”);dir.Files[“myTemp1.txt”].Delete(); // Directory.Files is a keyed collectionfor(int index=0; index<dir.Files.Count; index++){

Console.WriteLine(dir.Files[index].Filename);}

Tradeoff: Keyed collections usually have high memory footprint and performance disadvantages over simple collections. Keyed collections should not be used where the disadvantages outweigh the advantage of having the keys.

5.1.4 Generic Collections Usage Do take the least specialized interface possible as a parameter type. Most methods

operating on collections could take IEnumerable<T> interface.public void PrintCollection<T>(IEnumerable<T> collection){

foreach(T item in collection){Console.WriteLine(item);

}}

Note: If the API is intended to work with non-generic collections, you need to provide an overload that takes IEnumerable (the non-generic interface).

Do consider taking IEnumerable<T> as a parameter and dynamically check if the object implements ICollection<T> to implement a more efficient code. The guideline above applies to both generic and non-generic collection interfaces.

public class List<T> : IList<T> {public List<T>(IEnumerable<T> collection){

// check if it implements ICollectionICollection<T> col = collection as ICollection<T>;

int numberOfNewItems=0;// optimized and slow code pathsif(col!=null){

numberOfNewItems = collection.Count;}else{

IEnumerator<T> enumerator = collection.GetEnumerator();while(enumerator.MoveNext()) numberOfNewItems++;

100

.NET Framework Design Guidelines Microsoft Confidential}

this.Capacity = numberOfNewItems;foreach(T item in collection){

Add(item);}this.TrimToSize();

}

Consider inheriting from generic base collections to create strongly typed custom collections. This allows adding helper methods that are not present on the base collection interfaces. This is especially important for high-level APIs that often if not always need helper methods.public TraceSourceCollection : ListBase<TraceSource> {

// optinal helper methodpublic void FlushAll {

foerach(TraceSource source in this){source.Flush();

}}

// another common RAD helperpublic void AddSource(string sourceName){

Add(new TraceSource(sourceName));}

}

Note: The base collections do not exist in M2 builds. As a temporary workaround, we recommend you create a custom collection by implementing one of the interfaces (IList<T>, IDictionary<T> and delegating to one of the concrete classes (List<T>, Dictionary<T>).

5.1.5 Implementing IEnumerable Almost all collections expose some way to enumerate elements it contains.  The IEnumerable interface encapsulates this notion such that common facilities can be built that work on any kind of collection.   These guidelines apply to any type implementing ICollection, IList or IDictionary as well. 

Do see the generics guidelines in section x.y (tbd) Do see section 11 for more collections guidelines

Do implement IEnumerable on any type that can be enumerated Do name the class ItemTypeCollection for implementations that contain homogenous

types. Such as StringCollection, EmployeeCollection, etc Do explicitly implement IEnumerable.GetEnumerator() Do provide a GetEnumerator() method that returns a nested public struct called

“Enumerator” Rationale: the foreach language construct will prefer calling the method named GetEnumerator (that follows the enumerator pattern) rather than the interface method which means there will be one less GC heap allocation each time the collection is enumerated.  

Do explicitly implement the IEnumertor.Current property on the Enumerator struct

101

.NET Framework Design Guidelines Microsoft Confidential Do provide a strongly typed Current property that returns the item type on the

Enumerator structRationale: If item type is a value type this avoids a boxing operation each time through the loop.  If item type is a reference type there is a small savings for not having to do the cast.

Avoid having members on your collection be virtual unless extensibility is truly requiredRationale: The JIT is not able to inline calls to virtual methods.

Avoid doing any work in the Enumerator’s Current property that would prevent it from being inlined by the JIT. The Current property should simply return the current value.

These guidelines lead to this pattern… public class  ItemTypeCollection: IEnumerable { public struct Enumerator : IEnumerator {    public ItemType Current { get {… } } object IEnumerator.Current { get { return Current; } }      public bool MoveNext() { … }      …   }   public Enumerator GetEnumerator() { … }   IEnumerator IEnumerable.GetEnumerator() { … }   …}Tradeoff: Implementing this pattern involves having an extra public type (the Enumerator) and several extra public methods that are really there just for infrastructure reasons. These types add to the perceived complexity of the API and must be documented, tested, versioned, etc. As such this pattern should only be followed where performance is paramount.

Prefer implementing IEnumerable interface with optimistic concurrency Rationale: There are two legitimate ways to implement the IEnumerable interface. The first is to assume that the collection will not be modified while it is being enumerated. If it is modified throw an InvalidOperationException exception. The 2nd way is to make a snap-shot of the collection in the enumerator thus isolating the enumerator from changes in the underlying collection. For most usages for enumerable. For most general usage scenarios the optimistic concurrency model provides net better performance.

102

.NET Framework Design Guidelines Microsoft Confidential5.1.6 Arrays vs. Collections

Class library designers are sometimes faced with a decision about when to use an array and when to return a collection. These solutions have very similar usage models, but somewhat different performance characteristics.

5.1.7 Collection Do use a collection when Add, Remove or other methods for manipulating the

collection are supported. This scopes all related methods to the collection. Do prefer collections over arrays in common scenario API. Collections provide more

control over the contents of the container, are more version-able, and more usable. Do use zero based indexes if the collection is integral indexed.

Annotation (BradA): In designing the first version of the .NET Framework we went around and around on using zero or one based indexes for collections. There was tons of prior art for both, for example the C derived languages (C, C++, etc) where all zero based and the VB world was one based. Early on we made a call that arrays would be zero based and built that assumption deep into the implementation making collections that are 1 based harder to implement in a performant way. But at this point the most important reason to make sure integral indexed collections are zero based is simply consistency with the rest of the platform.

Do prefer collections over arrays. Collections are more usable and institutive in many cases. Collections provide more control over the contents of the container and are more versionable. For read-only values use of arrays often requires cloning and it is therefore more efficient to use collections in many read-only scenarios. Tradeoff: For targeting lower level developers it is often better to use arrays for read-write scenarios. Arrays have a lower memory footprint which helps reduce working set and access to elements in an array can be inlined by the JIT. However usability studies have shown that some customers (Mort) have problems dealing with arrays. The problem lays in the conceptual overhead of understanding the techniques to declare arrays in VB. Collections provide them a simple and consistent model. Array usage for read only scenarios is discouraged even in low level APIs as the cost of cloning the array is prohibitive.

Do not return internal instances of arrays as they can be changed by calling code. In this example the badChars array can be changed by anyone accessing the property even through it does not have an accessor. public sealed class Path { private Path () {} private static char[] badChars = { '\"', '<', '>'}; public static char[] GetInvalidPathChars () { return badChars; } }

This code prints out the elements of the array as you would expect: "<>foreach (char c in Path.GetInvalidPathChars()) { Console.Write (c); }

This code sets all the values to A

103

Krzysztof Cwalina, 12/13/04,
This section is weak. It never talks about difference between returning a snapshot and a live collection.

.NET Framework Design Guidelines Microsoft Confidential Path.GetInvalidPathChars()[0] = 'A'; Path.GetInvalidPathChars()[1] = 'A'; Path.GetInvalidPathChars()[2] = 'A';

This code prints out the elements of the array again, this time changed: AAA foreach (char c in Path.GetInvalidPathChars()) { Console.WriteLine (c); }

To fix this issue use a readonly collection or clone the array before returning it.public static char[] GetInvalidPathChars () { return (char[]) badChars.Clone();}

Do not use readonly fields of arrays (or other mutable) types.The array itself is readonly and can't be changed, but elements in the array can be changed. Consider this incorrect example: public sealed class Path { private Path () {} public static readonly char[] InvalidPathChars = { '\"', '<', '>', '|'}; }

Callers change the values in the arrayPath.InvalidPathChars[0] = 'A';

Use a property as described previously102. Consider using jagged arrays instead of multi-dimensional arrays103. A jagged array is an

array whose elements are also arrays. The arrays that make up the elements can be of different sizes, leading to less wasted space for some sets of data, as compared to multi-dimensional arrays. Furthermore, the CLR optimizes the access path of jagged arrays. Note that jagged arrays are not CLS compliant, so only follow this guideline when CLS compliancy is not needed (for example, when not exposed to external users).// jagged arrays have better performance in the CLRint[][] jaggedArray ={new int[] {1,2,3,4},new int[] {5,6,7},new int[] {8},new int[] {9}};

102 Fully covered by FxCop rules: DesignRules/ConsiderReplacingMethodsWithProperties, SecurityRules/ArrayFieldsShouldNotBeReadOnly.103 Fully covered by FxCop rules: PerformanceRules/ConsiderJaggedArrayInsteadOfMultiDimensionalArrayInFields, PerformanceRules/ConsiderJaggedArrayInsteadOfMultiDimensionalArrayInMethods, PerformanceRules/ConsiderJaggedArrayInsteadOfMultiDimensionalArrayInProperties.

104

.NET Framework Design Guidelines Microsoft Confidential

// multi-dimensional arrays are CLS compliant int [,] multiDimArray ={{1,2,3,4},{5,6,7,0},{8,0,0,0},{9,0,0,0}};

5.1.8 Indexed Properties in CollectionsUse indexed properties only as the default member of a collection class or interface.

Do not create families of functions like the following in non-collection types. A pattern of methods along the lines of Add, Item, Count, signals that the type should be a collection.int FooCount { get; }SomeType Foo[int index] { set; get; }void ApppendFoo(SomeType foo)

5.1.9 Array Valued Properties It is recommended that you use collections to avoid the inefficiencies in the following

code104.for (int i = 0; i < obj.myObj.Count; i++) { DoSomething(obj.myObj[i]);}

Also see Properties vs. Methods.

5.1.10 Returning Empty ArraysString and Array properties should never return null. The reason for this is that users do not understand null in this context. They always assume that the following code will work.public void DoSomething(…){ string s = SomeOtherFunc(); if (s.Length > 0){ // do something else }}

The general rule is that null, empty string, and empty (0 item) arrays should be treated the same.

Do return an Empty array or String.Empty() instead of a null reference.

104 Fully covered by FxCop rule: PerformanceRules/PropertiesShouldNotReturnArrays.105

Brad Abrams, 12/13/04,
More collections stuff to add: I never saw a response to this – If the collection is mutable, that is clients can add and remove elements, then using a propriety is fine… The only problem with properties is if you clone the underlying data on every call to the property… That has performance issues. ..brad From: Ravi Bikkula Sent: Tuesday, October 21, 2003 11:40 AMTo: Net ProfessorSubject: Property(or)Method for returning collections What is the correct way to return a collection via a method or a property? The collection returned can be modified by the user. Internally the collection is implemented by the generic collection class and is constructed when the object is constructed. Thx, Ravi
Krzysztof Cwalina, 12/13/04,
This is actually applicable to all collections. We should make it clear.
Brad Abrams, 12/13/04,
Make this a link

.NET Framework Design Guidelines Microsoft Confidential5.2 IDisposable Pattern

Types occasionally encapsulate control over resources not managed by the runtime (for example Hwnds, Database connections etc.). The smallest possible class should be used to encapsulate those resources. Ideally this should contain just allocation, basic access and freeing of the resources. Enclosing types can be used to provide a more natural view over the resource. By following this pattern reduce the chances of partially created types leaking out. In most cases, an explicit and an implicit way to free those resources should be provided. Implicit control should always be provided by protecting these resources with a SafeHandle (todo: see interop section on SafeHandles). In addition, if supplementary finalization semantics are required you should implement the protected Finalize() method (using the destructor syntax in C#:~TypeName()). Do be aware that the runtime will free your resource and run supplementary finalization semantics at an undefined point after there are no longer any valid references to that instance.In many cases, it is desirable to provide programmers the ability to explicitly release these external resources before the garbage collector frees the instance. If the external resource is scarce or expensive, better performance can be achieved by having the client program explicitly release resources when it is done using them. If implemented, the explicit control is provided by a Dispose() method from the IDisposable interface. Generally speaking it is considered good design for consumers of an IDisposable instance to call this method when they are done using the instance, however do not assume that Dispose will be called in every circumstance, finalization logic most be encapsulated in a SafeHandle or a finalize method so that the runtime will ensure finalization if the client developer does not. Dispose() can be called even if other references to the object are alive. In such a case it is common for the instance to be zombied-out in such a way that any operation that touches the resources will throw an ObjectDisposedException. Note that even when explicit control is provided, implicit cleanup using SafeHandle and, if needed your own Finalize method you should always be provided to prevent resources from permanently leaking if the programmer fails to call Dispose.

Annotation (KCwalina): TODO: Many people who hear about disposable for the first time complain that GC sucks as it does not collect resources and you have to dispose as you did in unmanaged world. The truth is that the GC was never meant to manage resource. It was designed to manage memory and it is excellent in doing that.

Annotation (Clemens Szyperski): The only problem is that it is the automatic management of memory and thus objects that makes it difficult to ensure that resources held by objects are released deterministically (that is, early). The reliance on the GC can lead programmers to think that they don't need to worry about this anymore, which is not the case. In fact, any object that implements IDisposable should be mentally tagged with a red flag and should not be allowed to fall of the scene without Dispose having been called. The finalization/safe handle safety net is really not good enough to prevent lousy user experiences - such as a file remaining locked for an unexpectedly long time after "save" and "close" of a document window (but with the app still running). Careful use of AppDomains and their forced unloading (which triggers safe handles) is sometimes a way to deal with this rigorously.

106

.NET Framework Design Guidelines Microsoft Confidential5.2.1 General

This section describes two very similar patterns for dealing with external resources. A simple pattern for the common cases that delegates most of the work to the framework and a complex pattern when more control is required.

Do use the simple Dispose pattern wherever possible. There are two twists on the dispose pattern. The simple version for common scenarios simply encapsulates the disposable resources in a SafeHandle and the complex version for scenarios where more customization of the finalization logic. See section x.y below for more detailsOnly use the Complex Dispose pattern when:

1. Inheriting from a class that uses the Complex pattern2. Required to work on .NET Framework V1.0\1.13. You require custom finalization semantics that you are not able to accomplish

in a SafeHandle subclass such as flushing buffered content before closing a stream.

Avoid making calls to GC.Collect and GC.GetTotalMemory(true)105. Use HandleCollector or GC.AddPressure() Calling GC.Collect() interferes with the natural GC collection schedule. This may decrease performance of the application. In general, both methods were designed mainly for testing purposes.

Do not always make your finalize and Dispose method threadsafe. Like other instance methods the cost of making these members threadsafe often outways the benefits.

Annotation (CBrumme):I describe the threading environment for finalization at http://blogs.msdn.com/cbrumme/archive/2004/02/20/77460.aspx.  As you can see there, techniques like resurrection can cause your application threads and the finalizer thread to access your object concurrently.If this is a security risk, you must fix it.  An obvious way to fix it is by adding thread safety to finalization.If this isn’t a security risk, then you can simply declare that your object doesn’t support this sort of use (actually, abuse).StringBuilder is a good example of this.  If you use a StringBuilder from multiple threads, you will get garbage text built up in the buffer.  That’s the caller’s problem.  But earlier implementations of StringBuilder actually exposed a security hole when used in this manner.  It was possible to create mutable strings, where the result of StringBuilder.ToString could be modified.  This was a huge security hole and it was fixed.  But the data integrity hole is not a security hole and it will never be fixed.Consider the same sort of distinction when deciding whether to make your Finalize implementation thread-safe or not.

105[1] Coming Soon: FxCopBug 1514.107

brada, 12/13/04,
Consider moving this to a different section
brada, 12/13/04,
TODO: add section on these from the MSTE slides

.NET Framework Design Guidelines Microsoft Confidential5.2.2 SafeHandle

Using classes derived from SafeHandle allows you to wrap a handle to an unmanaged resource. It provides protection for handle recycling security attacks, critical finalization, and special managed/unmanaged interop marshaling.

Do use SafeHandle for wrapping scarce unmanaged resources such as OS handles

private SafeHandleZeroOrMinusOneIsInvalid handle;

If your resource is very light-weight, such as a small unmanaged buffer, and it is not subject to recycling attacks and your scenario is very performance sensitive, you should consider avoiding SafeHandle. SafeHandle has many advantages, such as reducing the graph promotion due to Finalization, avoid recycling attacks, and guaranteeing no leaks even in the face of rude AppDomain unloading. But it may be too heavy-weight for very light-weight resources.

Do not  represent native handles with IntPtr or Int32, prefer using a SafeHandle subclass instead

private IntPtr handle; //Wrong: perfer using SafeHandle private int handle; //Wrong: perfer using SafeHandle

MS-Only: More information can be found in the spec: http://devdiv/SpecTool/Documents/Whidbey/CLR/CurrentSpecs/Interop%20-%20SafeHandle%20Spec.doc

5.2.3 FinalizeDo be aware that the finalizer may not be run in some circumstances such as a RudeUnload of the appdomain or an improper process exit.

Do not implement Finalize on types if you are able to use SafeHandle to clean up all your unmanaged resources.

Do only implement Finalize on types that need finalization106. There is some cost associated with it.

Annotation (BradA): Instances of types that are finalizable have to be kept around an order of magnitude longer than instances of types that are not finalizable in order to give the runtime an opportunity to execute their finalize method. This uses memory that could otherwise be freedfreed sooner reducing the overall working set of the application and therefore application performance.

If you have to use the complex pattern and explicitly define a Finalize (destructor) method

106[2] Fully covered by FxCop rule: UsageRules/DisposeMethodsRequireFinalizeMethod.108

.NET Framework Design Guidelines Microsoft ConfidentialDo be aware that the finalizers can execute in any order, on any thread or threads and execution can be interleaved between finalizers.

Do not make the Finalize method more visible107. It should be protected, not public. Do free any external resources you own in your Finalize method108.

A Finalize method should only release resources that are held on to by this object, and it should not reference any other objects.

Do not directly call a Finalize method on any object other than your base’s109. This is not legal in C#. However you should be aware when implemenating your finalizer that it is technically possible for your finalizer to be explicit called by user code and\or executed multiple times.

Do not refer to any objects from your Finalizable object (including transitively), except for exactly the object state you need to perform the cleanup. Finalizable objects should be leaf objects in a reachability graph, for performance reasons.

Do call base.Finalize() in your finalizer110. Note: this is done automatically with the C# and the C++ destructor syntax. Notice that this guideline is unnecessary if you are strictly following the pattern described here. The pattern says that Finalize should call the virtual Dispose(Boolean) and the each Dispose(Boolean) should call its base class. FxCop rule 3247.

Annotation (PaulV): You should be aware that finalizers can be invoked explicitly. Although some languages prevent this, other languages like VB allow it.

Do not defined finalizers on value types as they are always ignored. Notice: The C# compiler enforces this rule.Do not throw exceptions from your finalizer or cause exceptions to be thrown. Doing so will stop other finalizers from executing because the process will be shutdown (in V2.0 and above) as with unhandled exception from any method. TODO: FxCop Rule 3229

Do not refer to any objects from your Finalizable object (including transitively), except for exactly the object state you need to perform the cleanup. Finalizable objects should be leaf objects in a reachability graph, for performance reasons.

Do not call virtual members from destructors. Calling virtual members will result in possibly surprising behavior because the most derived implementation of the virtual method

107[3] Fully covered by FxCop rule: UsageRules/FinalizeMethodsHaveProtectedAccessLevel.108[4] Partially covered by FxCop rule: UsageRules/DisposeMethodsRequireFinalizeMethod. Rule for implementing dispose method when type owns external resources coming soon: FxCopBug 1012.109[5] Partially covered by FxCop rule: UsageRules/FinalizeMethodsCallBaseClassFinalize. Only covers calling base.Finalize(). No coverage for not calling other object’s finalize methods.110[6] Fully covered by FxCop rule: UsageRules/FinalizeMethodsCallBaseClassFinalize.

109

.NET Framework Design Guidelines Microsoft Confidentialwill be run.  FxCop Rule:  TBD (3217)

Consider the example below, for an instance of derived a C++ developer would expect Base::DoCleanUp() to run with the base class’s finalizer is run however because the runtime virtualizes the call to the runtime type of the instance is used and Derived::DoCleanUp() is called.  Notice this issue can be worked around my making DoCleanUp() no virtual or requiring overrides to insert a call to the base classes implementation.  

public class Base{    public virtual void DoCleanUp() {        Console.WriteLine("Do Base's Cleanup");    }    ~Base()    {        DoCleanUp();    }}public class Derived: Base{

    public override void DoCleanUp()    {        Console.WriteLine("Do Derived Cleanup");    }    ~Derived()    {        DoCleanUp();    }}

Do ensure that all managed references are valid before accessing them.  Even resources that are allocated in the constructor may not be valid because an exception may have been thrown from the constructor before the reference is assigned.  In this case the finalizer will still run, but there reference will be null.  (FxCop Rule: 3221) For example, in the following code, list maybe null if the constructor throws an exception before list is assigned to.

  public class MyClass{    private ArrayList list;    public MyClass() {        //some work        list = new ArrayList();    }

    ~MyClass() //bug: list could be null    {        foreach (int i in list) {            CloseHandle(i);        }    }}

110

.NET Framework Design Guidelines Microsoft ConfidentialConsider this fix to the finalizer.

    ~MyClass() //fixed     {        if (list != null)        {            foreach (int i in list)            {                CloseHandle(i);            }        }    }

Annotation (CBrumme): You can find more information than you ever wanted to know about how the CLR handles Finalization and why in this blog entry: http://blogs.msdn.com/cbrumme/archive/2004/02/20/77460.aspx

5.2.4 Dispose Do implement the dispose pattern when your type contains resources that explicitly

need to be freed111. This provides a public method for developers to free external resources.

Do implement an IDisposable on any type that has a finalizer. You may implement IDisposable on types without a finalizers.

Do implement the dispose pattern on base types that commonly have subtypes that hold on to resources even if the base type does not (having a method such as “Close” on the base type is an indication of this case)112. In such cases, do not implement a Finalize method on the base type that should be done by derived types that introduce the disposable resources.

Do free any disposable resources your type owns in the Dispose method113. Note, this includes Disposing of any SafeHandles your type has a fields.

Do suppress finalization of your instance once Dispose has been called, unless there is other work to do in Finalize that is not covered by Dispose (which is very unlikely)114.

Do call your base class’s Dispose(bool) method if it implements IDisposable115. Do not assume that Dispose will be called116. Unmanaged resources owned by this type

should also be released in the Finalize method or encapsulated in a SafeHandle just in case Dispose is not called.

Do propagate dispose through containment hierarchies.

111[7] Coming soon: FxCopBug 1012.112[8] Fully covered by FxCop rule: UsageRules/ConsiderCallingDataMembersDisposeMethod.113[9] Coming soon: FxCopBug 1012.114[10] Fully covered by FxCop rule: PerformanceRules/DisposeMethodsCallSuppressFinalize.115[11] Fully covered by FxCop rule: UsageRules/DisposeMethodsCallBaseClassDispose.116[12] Fully covered by FxCop rule: UsageRules/DisposeMethodsRequireFinalizeMethod.

111

.NET Framework Design Guidelines Microsoft ConfidentialDispose() should dispose of all resources held by this object and any object "owned"

by this object (the notion of ownership here depends on the scenario). Say for example you have a TextReader-like object that holds onto a Stream and an Encoding, both of which are created by the TextReader without the user's knowledge. Further say that both the Stream and the Encoding have acquired external resources. When you call Dispose() on the TextReader, it should in turn call Dispose() on the Stream and the Encoding, causing them to release their resources.

Consider not having your object be usable after calling Dispose. Recreating an object that has already been disposed is often a difficult undertaking in most cases having members that need to access disposed resources throw an ObjectDisposedException is the best solution.

Do allow your Dispose method to be called more than once without throwing an exception. The method will do nothing after the first call.

5.2.5 Other Instance MethodsMembers should check whether resources they require have been disposed. If so, they can reacquire the resources or throw an ObjectDisposedException.

Note (raw): this guideline leave it pretty much to the designer to the API to decide what methods should throw ObjectDisposedException, but the usually implementations in the Framework only throw from members that actually want to use the disposed resource. I think it’s a good approach. I think it’s really rare that a method that did not need a resource evolves to something that does need the resource (not that I have a scientific backing for that, but haven’t seen an example). Checking isDisposed in every method just pollutes the code and sometimes may prevent inlining (I think exception throws prevent inlining, but I am not sure). Also, I think that the versioning argument below can be extended to any precondition (let’s say properties need to be initialized) and we don’t want to check every single property of an object in every single method to make sure the properties are initialized in case we will need one of those properties in the future. For example, we don’t want to check whether Customer.Id was initialized in Customer.ToString (which just prints Customer.Name), just in case we will ever need the ID in ToString. That said, if you can think of a reason why some particular method may need the resource in the future, you are free to throw the exception if the resource is disposedNote: If you choose to reacquire resources, ensure that you call the GC.ReRegisterForFinalize.

5.2.6 Dispose Pattern

There are two twists on the dispose pattern. The simple version for common scenarios and the complex version for scenarios where more customization of the finalization logic.

5.2.6.1 Simple Pattern

public class MyResource : IDisposable { private SafeHandle handle; // pointer to a external resource encapsulated in some SafeHandle private Component component; // other resource you use

112

.NET Framework Design Guidelines Microsoft Confidential private bool disposed = false;

public MyResource () { //Create the resource, it will be closed by the SafeHandle handle = … }

// Implements IDisposable public virtual void Dispose() {

if (this.disposed) return; component.Dispose();

handle.Dispose(); this.disposed = true; component = null; }

//No finalizer! the SafeHandle takes care of this!

//Whenever you do something with this class, check to see if //the state is disposed, if so, throw this exception. public void GetWindowHandle() { if (this.disposed) { throw new ObjectDisposedException("TODO: Add Message"); } } }

//Derived class public class MyCustomResource : MyResource { private Component aNewComponent; // resource introduced in this cass

private bool disposed = false;

public MyCustomResource () { }

public override void Dispose() { if (!this.disposed) { //free any disposable resources introduced

aNewComponent.Dispose(); //Do any advanced finalization required by this class base.Dispose ();

this.disposed = true; } } }}

113

.NET Framework Design Guidelines Microsoft Confidential5.2.6.2 Complex Pattern

The complex pattern is needed when a type must customize its finalization logic and therefore can not rely solely on the SafeHandle’s cleanup. Examples including needing to flush any unwritten data in a buffer.

public class Base : IDisposable{ private bool disposed = false;

// Implements IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }

protected virtual void Dispose(bool disposing) { if (disposing) { // free other state (managed objects) // set interesting (large) fields to null

} // free your own state (unmanaged objects)}

// Simply call Dispose(false)

~Base(){ Dispose (false); }}

//Derived classpublic class Derived : Base, IDisposable{

protected override void Dispose(bool disposing) { if (disposing) { // free other state } // free your own state // set interesting fields to null base.Dispose(disposing);

}// No finalizer/destructor needed, handled in the base// No Dispose() method, handled in the base

}

Annotation(BradA): We had a fair amount of debate about the relative ordering of calls in the Dispose() method. public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }

Or public void Dispose() { GC.SuppressFinalize(this); Dispose(true); }

114

.NET Framework Design Guidelines Microsoft Confidential

We opted for the first ordering as it ensures that GC.SuppressFinalize() only gets called if the Dispose operation completes successfully.

5.2.7 ExampleClasses that contain references to unmanaged resources should follow the pattern illustrated by the following example.

5.2.7.1 Simple Pattern Exampleusing System;using System.Runtime.ConstrainedExecution;using System.Security;using System.ComponentModel;using System.Runtime.InteropServices;

public class SimpleWindow : IDisposable{ // pointer to a external resource encapsulated in one of the standard SafeHandles private MySafeHandleSubclass handle; private Component component; // other resource you use private bool disposed = false;

public SimpleWindow() { //Create the resource, it will be closed by the SafeHandle handle = CreateWindow("MyClass", "Test Window", 0, 50, 50, 500, 900, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); component = new Component(); }

// Implements IDisposable public virtual void Dispose() { if (this.disposed) return; component.Dispose();

handle.Dispose(); this.disposed = true; component = null; }

//Whenever you do something with this class, check to see if the //state is disposed, if so, throw this exception. public void ShowWindow() { if (this.disposed) { throw new ObjectDisposedException("TODO: Add Message"); } } [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]

115

.NET Framework Design Guidelines Microsoft Confidential private static extern MySafeHandleSubclass CreateWindow(string lpClassName, string lpWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hwndParent, IntPtr Menu, IntPtr hInstance, IntPtr lpParam);

internal sealed class MySafeHandleSubclass : SafeHandle {

// Called by P/Invoke when returning SafeHandles private MySafeHandleSubclass() : base(IntPtr.Zero, true) { }

// No need to provide a finalizer - SafeHandle's critical finalizer will // call ReleaseHandle for you.

public override bool IsInvalid { get { return handle == IntPtr.Zero; } }

override protected bool ReleaseHandle() { return CloseHandle(handle); }

[DllImport("kernel32"), SuppressUnmanagedCodeSecurity] [ReliabilityContract(Consistency.WillNotCorruptState, CER.Success)] private static extern bool CloseHandle(IntPtr handle);

[DllImport("kernel32")] public static extern MySafeHandleSubclass CreateHandle(int someState);

}

}

//Derived classpublic class MySimpleWindow : SimpleWindow{ private Component myComponent; // other resource you use

public MySimpleWindow() { }

public override void Dispose() { myComponent.Dispose(); myComponent = null; base.Dispose(); }}

116

.NET Framework Design Guidelines Microsoft Confidential

5.2.7.2 Complex Pattern Example

using System;using System.Runtime.ConstrainedExecution;using System.Security;using System.ComponentModel;using System.Runtime.InteropServices;

public class ComplexWindow : IDisposable{ private MySafeHandleSubclass handle; // pointer to a external resource private Component component; // other resource you use private bool disposed = false;

public ComplexWindow() { handle = CreateWindow("MyClass", "Test Window", 0, 50, 50, 500, 900, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); component = new Component(); }

// Implements IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }

protected virtual void Dispose(bool disposing) { if (!this.disposed) { //if this is a dispose call dispose on all state you //hold, and take yourself off the Finalization queue. if (disposing) { handle.Dispose(); component.Dispose(); component = null; } ///free your own state (unmanaged objects) AdditionalCleanup(); this.disposed = true; } }

//Simply call Dispose(false) ~ComplexWindow() {

117

.NET Framework Design Guidelines Microsoft Confidential Dispose(false); }

//Some custom cleanup logic private void AdditionalCleanup() { }

//Whenever you do something with this class, check to see if the //state is disposed, if so, throw this exception. public void ShowWindow() { if (this.disposed) { throw new ObjectDisposedException(""); } //do work }

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)] private static extern MySafeHandleSubclass CreateWindow(string lpClassName, string lpWindowName, int dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hwndParent, IntPtr Menu, IntPtr hInstance, IntPtr lpParam);

internal sealed class MySafeHandleSubclass : SafeHandle {

// Called by P/Invoke when returning SafeHandles private MySafeHandleSubclass() : base(IntPtr.Zero, true) { }

// No need to provide a finalizer - SafeHandle's critical finalizer will // call ReleaseHandle for you. public override bool IsInvalid { get { return handle == IntPtr.Zero; } }

override protected bool ReleaseHandle() { return CloseHandle(handle); }

[DllImport("kernel32"), SuppressUnmanagedCodeSecurity] [ReliabilityContract(Consistency.WillNotCorruptState, CER.Success)] private static extern bool CloseHandle(IntPtr handle);

[DllImport("kernel32")] public static extern MySafeHandleSubclass CreateHandle(int someState); }

118

.NET Framework Design Guidelines Microsoft Confidential}

//Derived classpublic class MyComplexWindow : ComplexWindow{

private Component myComponent; // other resource you use bool disposed = false;

public MyComplexWindow() { myComponent = new Component(); }

protected override void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { //free any disposable resources you own myComponent.Dispose(); this.disposed = true;

} //perform any custom clean-up operations // such as flushing the stream base.Dispose(disposing); } }}

5.2.8 Recreatable It is occasionally interesting to make an encapsulation of a resource recreatable; after it has been disposed, the resource is demand created and reset to the right state. It can be difficult to implement this pattern correctly. Therefore, its use should be well motivated and rare.

// whenever you call a method that access the resources of // this class, check to see if the state is disposed, if // so, reopen this // resource.public void DoStuff(){ if (disposed)

{ ReOpen();}//do the work

}

//Note: The following code does not handle thread-safety

119

.NET Framework Design Guidelines Microsoft Confidential// issues, it is meant to convey the concept only.public void ReOpen(){

this.disposed = false;GC.ReRegisterForFinalization(this);handle = //get new handle otherRes = new OtherResource();

}

5.3 IComparable

5.4 ICloneable The ICloneable interface contains a single Clone method, which is used to create a copy of the current object.public interface ICloneable {

object Clone();}

Do not implement ICloneable117.There are two general ways to implement ICloneable, either as a deep, or non-deep copy. Deep-copy copies the cloned object and all objects referenced by the object, recursively until all objects in the graph are copied. A non-deep copy (referred to as ‘shallow’ if only the top level references are copied) may do none, or part of a deep copy. Because the interface contract does not specify the type of clone performed, different classes have different implementations. A consumer cannot rely on ICloneable to let them know whether an object is deep-cloned or not.Note: If you need a cloning mechanism, define your own Clone, or Copy methodology, and ensure that you document clearly whether it is a deep or shallow copy. An appropriate pattern is: public <type> Copy();

Do not use ICloneable in public APIs118.

5.5 DelegatesDelegates are a powerful tool that allow the managed code object model designer to encapsulate method calls. They are used in two basic areas.

117 FxCop bug coming soon (#1826)118 FxCop bug coming soon (#1827)

120

Krzysztof Cwalina, 12/13/04,
Refer people to Equals implementation. Also, see if there is something in the operator overloading section.

.NET Framework Design Guidelines Microsoft ConfidentialEvent notificationsSee section 3.2 on event usage guidelines.Callbacks Passed to a method so that user code can be called multiple times during execution to provide customization. The classic example of this is passing a Compare callback to a sort routine. These methods should use the Callback conventions

Do use an Event design pattern for events (even if it is not user interface related)119. Do use end callbacks with the suffix Callback120.

Do favor using events over methods that take delegates. Methods that take delegates are a complicated concept that is not easy for the general user to understand. Events are a more familiar idea to developers, and therefore are simpler to use. Furthermore, events have support from IDE designers, such as drop down lists of currently used events and other event-specific information to help the developer use events in their libraries.Methods taking delegates should only be used when the target user fully understands the concept of delegates, and the situation is not event-related. Situations such as notification of an object’s state change should be implemented by events only.

Do prefer using events as the way of customizing behavior of Components. Events integrate better with visual designers and are easier to understand for a wider range of developers. Tradeoff: Events are definitely not appropriate as a general purpose customization mechanism. They have much higher performance overhead and as not as flexible as, for example, inheritance based customization.

5.6 AttributesThe .NET Framework enables developers to invent new kinds of declarative information, to specify declarative information for various program entities, and to retrieve attribute information in a run-time environment. For example, a framework might define a HelpAttribute attribute that can be placed on program elements such as classes and methods to provide a mapping from program elements to their documentation. New kinds of declarative information are defined through the declaration of attribute classes, which may have positional and named parameters.

Do suffix custom attribute classes with Attribute121.

119 Fully covered by FxCop rules: NamingRules/EventFirstParametersHaveNameSender, NamingRules/EventSecondParametersHaveNameE, DesignRules/EventsHaveTwoParameters, DesignRules/EventFirstParametersAreTypeObject, DesignRules/EventSecondParametersAreEventArgsType, DesignRules/EventHandlersReturnVoid.120 Partially covered by FxCop rules: NamingRules/DelegateNamesDoNotHaveDelegateSuffix. Currently no coverage for raising violations on other suffices.121 Fully covered by FxCop rule: NamingRules/AttributesHaveAttributeSuffix.

121

Brad Abrams, 12/13/04,
Make this a link

.NET Framework Design Guidelines Microsoft Confidentialpublic class ObsoleteAttribute{}

Do specify an AttributeUsage on your attributes to define their usage precisely122.[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]public class ObsoleteAttribute{}

Do seal attribute classes if possible123. This makes for faster look up. Do use positional arguments (constructor parameters) for required parameters.

Do provide a read-only property with the same name (different casing) as each positional argument124. This allows for access of that argument at runtime.

Do use named arguments (read-write properties) for optional parameters. Do provide a read-write property with the same name (different casing) as each named

argument125. Do not define a parameter with both a named and positional arguments.public class NameAttribute : Attribute { public NameAttribute (string username) {..} //positional argument public string UserName {get {..};} public int Age {get {..}; set{..};} //named argument}

Do provide message parameter to all ObsoleteAttribute attributes126. The message should clearly explain what the alternative API is.

5.7 ExceptionSee Section Do not use the Default Instance pattern if the type is mutable. .

5.8 Equals Do see section 7.1 on implementing operator==. Do override GetHashCode() in order for the type to behave correctly in a hashtable127. Do not throw an exception in your Equals implementation. Return false for a null

argument, etc.

122 Fully covered by FxCop rule: DesignRules/AttributesAreAttributeUsageAttributed.123 Fully covered by FxCop rule: PerformanceRules/AvoidUnsealedAttributes.124 Fully covered by FxCop rule: DesignRules/AttributesShouldHaveAccessorsForAllArguments.125 Fully covered by FxCop rule: DesignRules/AttributesShouldHaveAccessorsForAllArguments.126 Coming soon.127 Fully covered by FxCop rule: UsageRules/EqualsOverridesRequireGetHashCodeOverride.

122

Krzysztof Cwalina, 12/13/04,
Are we really saying no exceptions or just don’t throw on null. I think the later.
Brad Abrams, 12/13/04,
Add a good and bad example

.NET Framework Design Guidelines Microsoft Confidential Do follow the contract defined on Object.Equals:

x.Equals(x) returns true. x.Equals(y) returns the same value as y.Equals(x). if (x.Equals(y) && y.Equals(z)) returns true, then x.Equals(z) returns true. Successive invocations of x.Equals(y) return the same value as long as the objects

referenced by x and y are not modified. x.Equals(null) returns false. x.Equals(x) returns true. x.Equals(y) returns the same value as y.Equals(x). (x.Equals(y) && y.Equals(z)) returns true if and only if x.Equals(z) returns true. x.Equals(null) returns false.For some kinds of objects, it is desirable to have Equals test for value equality instead of referential equality. Such implementations of Equals return true if the two objects have the same value, even if they are not the same instance. The definition of what constitutes an object’s value is up to the implementer of the type, but it is typically some or all of the data stored in the instance variables of the object. For example, the value of a string is based on the characters of the string; the Equals method of the String class returns true for any two string instances that contain exactly the same characters in the same order. When the Equals method of a base class provides value equality, an override of Equals in a class derived from that base class should invoke the inherited implementation of Equals. If your programming language supports operator overloading, and if you choose to overload the equality operator for a given type, that type should override the Equals method. Such implementations of the Equals method should return the same results as the equality operator. Following this guideline will help ensure that class library code using Equals (such as ArrayList and Hashtable) behaves in a manner that is consistent with the way the equality operator is used by application code.

If you are implementing a value type, you should follow these guidelines:Consider overriding Equals to gain increased performance over that provided by the default implementation of Equals on System.ValueType128.If you override Equals and the language supports operator overloading, you should overload the equality operator for your value type129.

If you are implementing reference types, you should follow these guidelines:

128 Fully covered by FxCop rule: UsageRules/ConsiderOverridingEqualsAndOperatorEqualsOnValueTypes.129 Fully covered by FxCop rule: UsageRules/ValueTypesEqualsOverridesRequireOperatorEqualsOverride.

123

.NET Framework Design Guidelines Microsoft ConfidentialConsider overriding Equals on a reference type if the semantics of the type are

based on the fact that the type represents some value(s). For example, reference types such as Point and BigNumber should override Equals.Most reference types should not overload the equality operator, even if they override Equals130. However, if you are implementing a reference type that is intended to have value semantics, such as a complex number type, you should override the equality operator.If you implement IComparable on a given type, you should override Equals on that type131.

Example 1The following example contains two calls to the default implementation of Equals.using System;class MyClass { static void Main() { Object obj1 = new Object(); Object obj2 = new Object(); Console.WriteLine(obj1.Equals(obj2)); obj1 = obj2; Console.WriteLine(obj1.Equals(obj2)); }}

The output of the above code is the following.FalseTrue

Example 2The following example shows a Point class that overrides the Equals method to provide value equality and a class Point3D, which is derived from Point. Because the Point class's override of Equals is the first in the inheritance chain to introduce value equality, the Equals method of the base class (which is inherited from Object and checks for referential equality) is not invoked. However, Point3D.Equals invokes Point.Equals because Point implements Equals in a manner that provides value equality.using System;class Point: object { int x, y; public override bool Equals(Object obj) { //Check for null and compare run-time types. if (obj == null || GetType() != obj.GetType()) return false; Point p = (Point)obj; return (x == p.x) && (y == p.y);

130 Fully covered by FxCop rule: UsageRules/ReferenceTypesShouldNotOverrideOperatorEquals131 Fully covered by FxCop rule: UsageRules/IcomparableImplementationsOverrideEquals.

124

.NET Framework Design Guidelines Microsoft Confidential } public override int GetHashCode() { return x ^ y; }}

class Point3D: Point { int z; public override bool Equals(Object obj) { return base.Equals(obj) && z == ((Point3D)obj).z; } public override int GetHashCode() { return base.GetHashCode() ^ z; }}

The Point.Equals method checks that the obj argument is non-null and that it references an instance of the same type as this object. If either of those checks fail, the method returns false. The Equals method uses GetType to determine whether the run-time types of the two objects are identical. (Note that typeof is not used here because it returns the static type.) If the method had used a check of the form obj is Point instead, the check would return true in cases where obj is an instance of a class derived from Point, even though obj and the current instance are not of the same runtime type. Having verified that both objects are of the same type, the method casts obj to type Point and returns the result of comparing the instance variables of the two objects. In Point3D.Equals, the inherited Equals method is invoked before anything else is done; the inherited Equals method checks to see that obj is not null, that obj is an instance of the same class as this object, and that the inherited instance variables match. Only when the inherited Equals returns true does the method compare the instance variables introduced in the derived class. Specifically, the cast to Point3D is not executed unless obj has been determined to be of type Point3D or a class derived from Point3D.

Example 3In the previous example, operator == (the equality operator) is used to compare the individual instance variables. In some cases, it is appropriate to use the Equals method to compare instance variables in an Equals implementation, as shown in the following example.using System;class Rectangle { Point a, b; public override bool Equals(Object obj) { if (obj == null || GetType() != obj.GetType()) return false; Rectangle r = (Rectangle)obj; //Use Equals to compare instance variables return a.Equals(r.a) && b.Equals(r.b); } public override int GetHashCode() { return a.GetHashCode() ^ b.GetHashCode(); }

125

.NET Framework Design Guidelines Microsoft Confidential}

Example 4In some languages, such as C#, operator overloading is supported. When a type overloads operator ==, it should also override the Equals method to provide the same functionality. This is typically accomplished by writing the Equals method in terms of the overloaded operator == as in the following example.using System;public struct Complex { double re, im; public override bool Equals(Object obj) { return obj is Complex && this == (Complex)obj; } public override int GetHashCode() { return re.GetHashCode() ^ im.GetHashCode(); } public static bool operator ==(Complex x, Complex y) { return x.re == y.re && x.im == y.im; } public static bool operator !=(Complex x, Complex y) { return !(x == y); }}

Because Complex is a C# struct (a value type), it is known that there will be no classes derived from Complex. Therefore, the Equals method does not need to compare the GetType() results for each object, but can instead use the is operator to check the type of the obj parameter.

5.9 Finalize

5.10 ToStringToString is intended to be used for general display and debugging purposes. The default implementation simply provides the object type name.

Do override ToString whenever an interesting human-readable identifier is available. Do override ToString even if parsing support is not available. Do try to keep the text short and useful. Do use a unique text name associated with the object instance if possible. Do prefer a friendly name over a unique but not readable ID. It is acceptable to

return numeric ID if no other information is available. Do formatting based on the current thread culture when returning culture dependent

information.

126

Krzysztof Cwalina, 12/13/04,
Redirect people to IDisposable

.NET Framework Design Guidelines Microsoft Confidential Do support overload ToString(string format) if the information is culture sensitive

(i.e. DateTime) or there are various ways to format the data (i.e. Guid). Do not throw exceptions from ToString. Do not require security permissions to invoke the method. Do not return security or privacy sensitive information. Do not return an empty string.

Consider having ToString’s output be a valid format for any parsing methods on this class.

5.11 Serializable [Draft] Do implement the special serialization constructor on any type that implements

ISerializable. [Serializable]public class MyClass : ISerializable {

// this constructor is needed for serialization when exception // propagates from a remoting server to the client. protected MyClass(SerializationInfo info, StreamingContext context) {}

protected void GetObjectData(SerializationInfo info, StreamingContext context) {}

}

Do mark all types that implement ISerializable with the System.Serializable custom attribute132.

Do apply the XxxAttribute (SerializationFormatter) to the serialization constructor and the GetObjectData() method to ensure that semi-trust callers can’t get or set private state.

Do implement ISeriazable on any types that are serialzable and have state. Using just the Serializable custom attribute may cause problems in a future version when you add or change state.

Do make Exception classes serializable133.An exception must be serializable to work correctly across application domain boundaries. To ensure your exception works properly in a distributed environment, it should have the Serializable attribute and, if it defines any fields, it should also implement System.Runtime.ISerializable.GetObjectData and a serialization constructor.

Do mark types that derive from a serializable types as serializable. The SerializableAttribute attribute is not inherited by derived types. For example:

132 Covered by FxCop rule: ISerializableTypesAreMarkedSerializable

133 Fully covered by FxCop rule: UsageRules/ExceptionsAreMarkedSerializable.127

.NET Framework Design Guidelines Microsoft ConfidentialPerson object can be serialized but an Employee object cannot:[Serializable]class Person {...}class Employee : Person {...}

To fix this, you would just apply the SerializableAttribute attribute to the Employee type as well:[Serializable]class Person {...}[Serializable]class Employee : Person {...}

5.12 COM Visibility [Draft]Unmanaged clients are very important to the success of many managed Frameworks however, for a wide range of reasons we generally do not advise managed frameworks to be expose directly to COM clients. C++ is the right long-term solution for clients with large unmanaged code bases that want to take incremental advantage of new functionality in a managed framework. 

Please see Managed\Unmanaged Interop Overview for more details on this topic.

The ComVisibleAttribute attribute determines how COM clients access a managed framework. By default public types within an assembly are directly visible to COM clients which causes a number of problems. 1. Managed APIs would have to be “dumbed down” to support only the subset of funcationality that COM supports. For example that would be no static methods, paramaterized constructors or any usage of generics. 2. COM visible members must adhear to the COM versioning rules rather than the managed code versioning rules. Estintally that means you can not add members to COM visible type. 3. Some internal implemenation details of COM visible members are exposed. For example the excat layout of structs are exposed such that COM Visible structs can not add or remove even private members.

Do make all types in your assembly not visible to COM client by default by put the ComVisible(false) attribute on each assembly. 134

[assembly:ComVisible(false)]

134 Fully covered by FxCop rule: DesignRules/AssembliesShouldBeComVisibleAttributed.128

.NET Framework Design Guidelines Microsoft ConfidentialTypes and Interfaces that must be used directly by COM clients (such as to host in an unmanaged container) should be marked with the ComVisible(true) attribute. The transitive closure of all types referenced by exposed types should all be explicitly marked as ComVisible(true) if not they will be exposed as IUnknown.Note:   Members of a type can also be marked as ComVisible(false); this allows a reduced exposure to COM and therefore less restrictions on what a managed type can use.

Consider not exposing any of your types directly to COM clients and instead encourage COM clients to use C++ IJW support to access your first class managed APIs directly.

See internal guidelines: Interop - IJW Guidelines

Do carefully mark individual types as being visible to COM clients only as needed. These types should all:o Be in a *.Interop subnamespace (see section x.y)o Be seperate wrapper from the first class managed API such that the managed API can version freely without risk to the COM visible layer.o Be marked explicitly with the COMVisible(true) attribute.o Be clearly documented as indended for COM clients. o Expose functionality exclusively in a way that is not usable from COM. Specifically, COM does not support the following:

Static methods135

Parameterized constructors136

o T est the type's functionality from classic COM clients.o U nderstand the Registry impact for making all types cocreateable.

6 Common Design Patterns

6.1 Asynchronous Pattern

6.1.1 Introduction to Asynchronous ProgrammingAsynchronous programming is a feature supported by many areas of the common language runtime, such as Remoting, ASP.NET, and Windows Forms. Because it is a core concept, it is important for the Framework to establish a common design pattern to avoid confusion among developers. This document proposes a design pattern for asynchronous programming.

135 Fully covered by FxCop rule: ComRules/AvoidStaticMembersForComVisibility136 Fully covered by FxCop rule: ComRules/ComCreatableTypesShouldHavePublicDefaultConstructor

129

Brad Abrams, 12/13/04,
ToDo: add fxcop rules
Brad Abrams, 12/13/04,
T

.NET Framework Design Guidelines Microsoft ConfidentialThe philosophy behind these guideline is as follows. It is the client that decides if a particular call should be asynchronous. It is not necessary for a server to do additional programming in order to support its

clients' asynchronous behavior by. The CLI should be able to manage the difference between the client and server views. As a result, the situation where the server has to implement IDispatch and do a large amount of work to support dynamic invocation by clients is avoided.

The server can choose to explicitly support asynchronous behavior either because it can implement it more efficiently than a general architecture, or it wants to support only asynchronous behavior by its clients. It is recommended that such servers follow the design pattern outlined in this document for exposing asynchronous operations.

Enforcing type safety. The CLI will provide the necessary services to support the asynchronous

programming model. The following is a partial list of these services: Synchronization primitives, such as critical sections and ReaderWriterLock

instances Synchronization constructs such as containers that support the

WaitForMultipleObjects method Thread pools Exposure to the underlying infrastructure pieces such as Message objects and

Thread Pools

6.1.2 Asynchronous API DesignConsider the following example of a server class.class PrimeFactorizer{ public boolean Factorize(unsigned long factorizableNum, ref unsigned long primefactor1, ref unsigned long primefactor2) { // Ensure that the given number is factorizable to prime numbers ….. ….. if(IsPrimeFactorizable == false) { primefactor1 = primefactor2 = 0; return(false); }

// Factorize …… primefactor1 = …..; primefactor2 = …..;

return(true); }}

130

.NET Framework Design Guidelines Microsoft ConfidentialThe following code snippet shows a client defining a pattern for invoking the Factorize method asynchronously.delegate FactorizingDelegate(unsigned long factorizableNum, ref unsigned long primefactor1, ref unsigned long primefactor2);PrimeFactorizer pf = new PrimeFactorizer();FactorizingDelegate fd = new FactorizingDelegate(pf.Factorize);

The compiler will define the following FactorizingDelegate class after parsing its definition in the first line in the above example.class FactorizingDelegate extends delegate {

public boolean Invoke(unsigned long factorizableNum, ref unsigned long primefactor1, ref unsigned long primefactor2);

public IAsyncResult BeginInvoke(unsigned long factorizableNum, ref unsigned long primefactor1, ref unsigned long primefactor2, AsyncCallbackDelegate cb);

public boolean EndInvoke(ref unsigned long primefactor1, ref unsigned long primefactor2, IAsyncResult ar);}

The following classes are defined inside the Framework libraries.

delegate AsyncCallback (IAsyncResult ar);

public interface IAsyncResult {

// True if the asynchronous operation has been completed. bool IsCompleted { get; } // Handle to block on for the results. WaitHandle AsyncWaitHandle { get; } // The delegate object on which the async call was invoked. Object AsyncObject { get; } // The state object passed in via BeginInvoke. Object AsyncState { get; } // True if the call completed synchronously. bool CompletedSynchronously { get; }}

Note that the object that implements IAsyncResult must be a waitable object and its underlying synchronization primitive should be signaled after the call is canceled or completed. This enables the client to wait for the call to complete instead polling. The CLI supplies a number of waitable objects that mirror Win32 synchronization primitives. It also supplies methods that support waiting for such synchronization objects to become signaled with "any" or "all" semantics. Such methods will be context aware to avoid deadlocks.

131

.NET Framework Design Guidelines Microsoft ConfidentialThe Cancel method is a request to cancel processing of the method after the desired timeout period has expired. Note that it is only a request by the client and the server is recommended to honor it. Further, the client should not assume that the server has stopped processing the request completely after it got the notification that the method has been canceled. In other words, the client is recommended to not destroy the resources such as file objects as the server may be actively using them. The IsCancelled property will be set to true if the call was canceled and IsCompleted property will be set to true after the server has completed processing of the call. It is illegal for the server to use any client supplied resources outside of the agreed upon sharing semantics after it sets the IsCompleted property to true. Thus, it is safe for the client to destroy the resources after the IsCompleted property returns true.The following code demonstrates the client-side programming model for invoking the Factorize method asynchronously.class FactorizeCallback { public FactorizeCallback(unsigned long number) { _ulNumber = number; } // Note the qualifier one-way. See last paragraph of this section for its explanation. public one-way boolean FactorizedResults(IAsyncResult ar) { unsigned long factor1, factor2; FactorizingDelegate fd = ar.AsyncObject; fd.EndInvoke(factor1, factor2, ar);

// Output the results. Console.Writeline("Factors of" + _ulNumber + ":" + factor1 + " " + factor2); }

private unsigned long _ulNumber}

// Client code.delegate FactorizingDelegate(unsigned long factorizableNum, ref unsigned long primefactor1, ref unsigned long primefactor2);PrimeFactorizer pf = new PrimeFactorizer();FactorizingDelegate fd = new FactorizingDelegate(pf.Factorize);

// --------------------------------------------------------------------------------------------------------// Async Variation 1.unsigned long factorizableNum = 1000589023, temp;

// Define the asynccallback delegate.FactorizeCallback fc = new FactorizeCallback(factorizableNum);AsyncCallbackDelegate cb = new AsyncCallbackDelegate(fc.FactorizedResults);

// Asynchronously invoke the Factorize method on pf.// Note: If we have pure out parameters, we do not need tempfd.BeginInvoke(factorizableNum, temp, temp, cb);

// Proceed to do other work.……

132

.NET Framework Design Guidelines Microsoft Confidential// --------------------------------------------------------------------------------------------------------// Async Variation 2.// Asynchronously invoke the Factorize method on pf.// Note: If we have pure out parameters, we do not need tempunsigned long factorizableNum = 1000589023, temp, factor1, factor2; IAsyncResult ar = fd.BeginInvoke(factorizableNum, temp, temp, NULL);

// Do other work.……

// Wait for the callback.SynchronizationServices.WaitForSingleObject(ar);

// Output the results.fd.EndInvoke(factor1, factor2, ar);Console.Writeline("Factors of" + factorizableNum + ":" + factor1 + " " + factor2);

Note that if the FactorizeCallback is a context-bound class that requires synchronized/thread-affinity context, the callback is dispatched through the context dispatcher infrastructure. In other words, the callback itself may execute asynchronously with respect to its caller for such contexts. That is precisely the semantics of the one-way qualifier on method signatures. It means that any such method call may execute synchronously or asynchronously with respect to caller and the caller cannot make any assumptions about completion of such a call when execution control returns to it.Also, calling EndInvoke before the asynchronous operation is complete will block the caller. Calling it a second time with the same AsyncResult is undefined.

6.1.3 Summary of Asynchronous PatternThe server splits an asynchronous operation into its two logical parts: the part that takes input from the client and kicks off the asynchronous operation and the part that supplies results of the asynchronous operation to the client. In addition to the input needed for the asynchronous operation, the first part also takes an AsyncCallbackDelegate object to be called when the asynchronous operation is completed. The first part returns a waitable object that implements the IAsyncResult interface used by the client to determine the status of the asynchronous operation. The server typically also utilizes the waitable object it returned to the client to maintain any state associated with asynchronous operation. The client uses the second part to obtain the results of the asynchronous operation by supplying the waitable object.The following options are available to the client for initiating asynchronous operations. Supply the callback delegate when beginning an asynchronous operation. Do not supply the callback delegate when beginning an asynchronous operation.The following options are available to the client for completing asynchronous operations. Poll the returned IAsyncResult object for completion. Attempt to complete the operation prematurely thereby blocking until the operation

completes.

133

.NET Framework Design Guidelines Microsoft Confidential Wait on the IAsyncResult object. The difference between this and the previous

option is that the client can use timeouts to wake up periodically. Complete the operation inside the callback routine. File IO is an example where both synchronous and asynchronous read/writes to file object is desirable. An example of how the File object inside classlibs implements read-write operation serves as a good illustration of the design pattern.class File{ // Other methods ………

// Synchronous read unsigned long Read(Byte[] buffer, unsigned long NumToRead);

// Asynchrnous read IAsyncResult BeginRead(Byte[] buffer, unsigned long NumToRead, AsyncCallbackDelegate cb); unsigned long EndRead(IAsyncResult ar);

// Synchronous read unsigned long Write(Byte[] buffer, unsigned long NumToWrite);

// Asynchrnous read IAsyncResult BeginWrite(Byte[] buffer, unsigned long NumToWrite, AsyncCallbackDelegate cb); unsigned long EndWrite(IAsyncResult ar);}

The client cannot easily associate state with a given asynchronous operation without defining a new callback delegate for each operation. This can be fixed by making the begin method take an extra object parameter that represents the state and which is captured in the IAsyncResult.

6.2 Optional FeaturesIn designing your class library, you may find cases where some implementations of your base classes can provide a feature or a behavior, while other implementations cannot. Instead of providing several different base classes each customized to the set of features, you can simply identify these optional features and provide consumers a mechanism to discover whether the particular instance they have access to supports that feature. Creating a large number of similar classes will simply confuse users of your class library and make it more difficult to find the class that they should use.One example of this is System.IO.Stream. There is great benefit in having a single Stream class that encapsulates Read, Write and Seek methods, however not all instances of the Stream class can provide all those capabilities. What if the stream is coming from a read-only source? What if it is the response to a web request? What if it is built upon a file? The Stream concept remains the same yet set of features is different depending upon the source/destination of the stream.When not all implementations or instances of a class can support all the features or behaviors, it is best to implement them as optional features and provide an appropriate

134

.NET Framework Design Guidelines Microsoft Confidentialmechanism for unfamiliar users of your class library to discover whether the optional features are supported by the instance they have.

It is recommended that you use a class or abstract class instead of an interface. See section 4.1.5.

Do use simple Boolean query properties that clients can use to determine whether a feature or behavior is supported. For example, consider the following object model.public abstract class Command { public virtual bool CanExecutePageReader { get { return false; } } public virtual DataReader ExecutePageReader(int startRecord, int count) { throw new NotSupportedException(); } public abstract DataReader ExecuteReader();

}

public class MyCommand : Command { public override bool CanExecutePageReader { get { return true; } } public override DataReader ExecutePageReader(int startRecord, int count) { … } public override DataReader ExecuteReader() { … }}

Consumer’s code that uses the abstract base class can query this property at runtime to determine the whether they can use the optional feature or behavior or must provide their own alternative:Command cmd = GetCommandFromSomewhere();

if (cmd.CanExecutePageReader){ DataReader rdr = cmd.ExecutePageReader(100,10);}else { DataReader rdr = cmd.ExecuteReader();}

Do use virtual methods on the base class that throw NotSupportedException to define optional features and behaviors. This provides clear visibility to the consumer of the base class but allows for implementers of the class to provide optional features and behavior when it is feasible. Throwing the NotSupportedException ensures that the consumer will get an exception distinct from some other invalid operation that may have occurred.

Do not simply define interfaces for optional behavior and not hook them up to your abstract class in some way.interface IPagedCommand { DataReader ExecutePageReader(int startRecord, int maxRecords);}

public abstract class Command { public abstract DataReader ExecuteReader();}

public class MyCommand : Command, IPagedCommand {}

135

.NET Framework Design Guidelines Microsoft ConfidentialWhile this allows you to fully utilize and depend upon the type system to provide optional feature discovery, consumers that are unfamiliar with your class library and that are working with your abstract classes will not know that the object they’re working with is a MyCommand that supports the IPagedCommand optional behavior, because the abstract Command object does not have any indication that there is optional behavior, and will not know to utilize it unless they search through your object model. Consider the following code that a user of your class library would implement.Command cmd = GetCommandFromSomewhere();if (cmd is IPagedCommand){ DataReader rdr = ((IPagedCommand)cmd).ExecutePageReader(100,10);}else { DataReader rdr = cmd.ExecuteReader();}

How will the user unfamiliar to your class library know to check for IPagedCommand? Unless you expect the optional feature to be rarely implemented, you should utilize the Boolean property getters on the base class described above to provide the unfamiliar user a hint that there is an optional feature available. Note: if your expectations are that only a very small percentage of classes deriving from the base class or interface would actually implement the optional feature or behavior, then this may actually be the best pattern. There is no real need to add additional object model to all derived classes when only one of them provides the feature or behavior.

Consider using an interface or an abstract class, in addition to the simple Boolean query properties described above, to encapsulate optional features that require several properties, events or methods, adding a GetXxx method to your base class that throws NotSupportedException, and overriding the GetXxx method in the derived classes where it is supported. This approach should be avoided in high-level APIs. public interface IAsyncCommand { public IAsyncResult BeginExecuteReader(); public IAsyncResult BeginExecuteReader(AsyncCallback callback, object state); public DataReader EndExecuteReader(IAsyncResult asyncResult);}

public abstract class Command { public virtual bool CanGetAsyncCommand { get { return false; } } public virtual IAsyncCommand GetAsyncCommand() { throw new NotSupportedException(); } public abstract DataReader ExecuteReader();}

public class MyCommand : Command, IAsyncCommand { public override bool CanGetAsyncCommand { get { return true; } } public override IAsyncCommand GetAsyncCommand () { return this; } public IAsyncResult BeginExecuteReader() { return BeginExecuteReader(null, null); } public IAsyncResult BeginExecuteReader(AsyncCallback callback, object state) { … } public DataReader EndExecuteReader(IAsyncResult asyncResult) { …

136

.NET Framework Design Guidelines Microsoft Confidential }}

Combining the related optional methods onto an interface or abstract class prevents the class from becoming overly cluttered with optional feature discovery methods and properties, and allows you to create groups of methods that are likely to be used together, also assisting the user of your class library in finding the methods they need. The user of your class will then be able to write the following code to use the optional feature, when it is available, and to fall back to the basic level when it is not.Command cmd = GetCommandFromSomewhere();

if (cmd.CanGetAsyncCommand){ IAsyncCommand asyncCmd = cmd.GetAsyncCommand(); IAsyncResult asyncResult = asyncCmd.BeginExecuteReader(); // Async processing while execution occurs DataReader rdr = asyncCmd.EndExecuteReader(asyncResult);}else { DataReader rdr = cmd.ExecuteReader(); }

While this is essentially what the type system does for you, it provides the unfamiliar user of the base class the visibility of the optional IAsyncCommand interface that they would otherwise not have had without scanning the object model.

Do not use enums to list the optional behaviors and return them from an abstract method on the abstract class. For example, consider the following object model.[Flags()]public enum CommandOptionalFeatures { None = 0, ExecutePageReader = (1 << 0),}

abstract public class Command { public virtual CommandOptionalFeatures OptionalFeatures { get { return CommandOptionalFeatures.None; } }}

The CommandOptionalFeatures enumeration is problematic from a versioning standpoint – it may not be any more extensible than an interface and the implementation above parallels what the type system does for you anyway.Furthermore, there really isn’t a much of a connection between the enumeration value and the method name. Consider the following code that a user of your class library would implement: Command cmd = GetCommandFromSomewhere();

if ((cmd.OptionalFeatures & CommandOptionalFeatures.ExecutePageReader) != 0){ DataReader rdr = ((IPagedCommand)cmd).ExecutePageReader(100,10);}else { DataReader rdr = cmd.ExecuteReader();}

137

.NET Framework Design Guidelines Microsoft ConfidentialHow will the user unfamiliar with your class library know to check the OptionalFeatures property, and look for the ExecutePageReader flag? The simple Boolean property per optional feature described above provides a much more visible clue.

6.3 Searcher

6.4 Resource Proxy

6.5 Builder

6.6 Cannonical Type

6.7 Static Method Holder

6.8 Immutable TypesTradeoff: Immutable types are very useful but API designers need to be aware that immutable types confuse Mort. These developers are not accustomed to working with classes that can only be configured through their constructor. Mort needs mutable types if they’re going to be regularly changing their values.

6.9 Static Methods and Singleton Design

6.9.1 Singleton PatternThe singleton pattern ensures that a class has only one instance and provides a global point of access to it.137

This pattern is used all over the framework: System.DBNull, System.Reflection.Empty, etcpublic sealed class Singleton {

private Singleton () {}public static readonly Singleton Value = new Singleton();//instance members...

}

In this example the DBNull instance will be created the first time any member of the DBNull class is referenced. Notice this class: Is sealed to prevent sub-classing to add instances Has a private constructor (if you don’t specify a constructor a public one will be

added for you by many of the compilers) The instance is static for easy access

137 Gamma E., Helm R. Jonson R. Vlissides J.: Design Patterns - Elements of Reusable Object-Oriented Software, Addison Wesley (1999).

138

Brad Abrams, 12/13/04,
Looks like that is covered below in the Singleton class
Krzysztof Cwalina, 12/13/04,
There is a workitem to modify the pattern to do lazy initialization.
Krzysztof Cwalina, 12/13/04,
It might be worth describing the implications of static methods (they can't be overriden) as well as how developers can utilize them with a private constructor to implement a singleton design pattern. Examples of where you're using this today in the Framework class library (for example: reflection) could also be useful.
Krzysztof Cwalina, 12/13/04,
Can we break this section into two?
Krzysztof Cwalina, 12/13/04,
It might be worth describing how/when class writers should utilize an immutable design pattern in the runtime, and provide examples demonstrating where its used in the Framework class library. The concurrency implications of an immutable pattern should also be highlighted.

.NET Framework Design Guidelines Microsoft Confidential The instance is readonly so it can’t be modified The instance is named “Value” The instance is immutable. It should not have any methods that can mutate its stateIf the design requires the instance to be created only when it is asked for the first time (this is the pure GoF Singleton Pattern) consider implementing Value as a static property and have a private static field for the instance. However, in this model you should be aware of race conditions in creating the instance. public sealed class Singleton {

private Singleton() {}private static volatile Singleton value;private static object syncRoot = new Object();

public static Singleton Value {get {

if (Singleton.value == null) {lock (syncRoot) {

if (Singleton.value == null) {Singleton.value = new Singleton();

}}

}return Singleton.value;

}}

}

Notice this class: We use double-check locking to be sure exactly one instance is created and only

when needed We use a syncRoot instance to lock on rather than locking on the type itself to avoid

deadlocks that can be caused by outside code. The value instance is declared to be volatile in order to assure that the assignment

to value and any writes inside the Singleton constructor complete before the instance can be accessed.

6.9.2 Static ClassesIn a strict OO model you would be unlikely to use a class that contains nothing but static “helper” methods. However from a practical standpoint this pattern can be extremely useful to developers. Commonly these utility classes:Contain convince shortcuts of other operations (example System.File), orHolds methods that would be cumbersome or unwarranted to abstract into classes (example System.Environment)In order to be effective these classes should be used sparingly and should be focused on a well defined set of responsibilities (access to the file system or access the Environment the application in running in for example). public sealed class Environment {

private Environment() {}

139

Brad Abrams, 12/13/04,
TODO: Need to update with C#’s Whidbey feature of static classes

.NET Framework Design Guidelines Microsoft Confidentialpublic static void Exit(int exitCode) {..}public static int ExitCode {

get {..}set {..}

}public static String CommandLine {

get {..}}

}

Notice this class: Is sealed to prevent subclassing. Polymorphism is not needed for this type of utility

class. By sealing the class you clearly communicate that to the consumers.An alternative approach is to mark the class as abstract, there are two problems with this approach: 1) Subclasses could cause the class to be created and 2) It misleads the users to think the class was designed for subclassing.

Has a private default constructor to prevent the class from being instantiated. Has no instance members. It is surprisingly easy to forget the static keyword when

adding members to a holder type. Because the class is not creatable any instance members callable and will undoubtedly baffle your consumers (see Environment.HasShutdownStarted in V1.0 of the Framework)

6.10 CallbacksDelegates, Interfaces and Events can each be used to provide callback functionality. Each has its own specific usage characteristics that make it better suited to particular situations.Use Events if the following are true. One signs up for the callback up front (typically through separate Add and Remove

methods). Typically more than one object will care. You are designing a high-level API, especially a designable Component.Use a Delegate if the following are true. You want a C style function pointer. Single callback. Registered in the call or at construction time (not through separate Add method) Use an Interface if the following is true. The callback entails complex behavior.

6.11 FactoriesThe most common and consistent way to create an instance of a type is via its constructor. However, sometimes a preferable alternative is to use the Factory pattern. A Factory is an operation or collection of operations that abstract the object creation process for API users, allowing for specialized semantics and finer granularity of control

140

.NET Framework Design Guidelines Microsoft Confidentialover an object’s instantiation by the API provider. Simply put, a Factory’s primary purpose in life is to generate and provide instances of objects to callers. Factory methods are sometimes logically aggregated into a dedicated Factory type, but just as often appear on the individual classes which are to be created. Such methods are typically static, although instance-based implementations are sometimes necessary to facilitate polymorphic behavior.

Do prefer constructors over Factories as they are generally more consistent and convenient than specialized construction mechanisms. Factories sacrifice discoverability and consistency for implementation flexibility.

Do implement Factory operations as methods, not properties. Do return instances as method return values, not as out parameters. Consider using a Factory if you need more control over the creation patterns of

instances. For example, consider the Singleton, Builder, or other similar patterns that constrain the ways in which objects are created. A constructor is very limited in its ability enforce rich patterns such as these, while a factory method can easily perform caching, throttling, and sharing of objects, for instance.

Consider naming Factory methods by concatenating “Create” and the name of the type being created. For example, consider naming a Factory method that creates buttons CreateButton. In same cases domain specific name can be used, as in File.Open.

Consider naming Factory types by concatenating the name of type being created and “Factory.” For example, consider naming a Factory type that creates Control objects ControlFactory.

Do not implement your Factory using a static method if the construction operation must be available for subclasses to specialize. Using a static method prevents subclasses from the ability to redefine or customize behavior. Use a standard constructor or an instance Factory method for this scenario.A framework designer is often faced with the difficult choice between using a constructor or a static factory method. Several cases exist in which Factories are the preferred method; in fact, the Framework demonstrates some such scenarios.For instance, consider the standard Parse method available on the primitive value types.

int i = int.Parse(“35”);DateTime d = DateTime.Parse(“10/10/1999”);

The semantics of the Parse operation is such that information is converted from one representation of the value into another. In fact, it doesn’t feel like we are constructing a new instance at all, but rather re-hydrating one from existing state (the string). The System.Convert class exposes many such static Factory methods that take a value type in one representation and convert it to an instance of a different value type, retaining the same logical state in the process. Constructors have a very rigid contract with callers: a unique instance of a specific type will be created, initialized and returned. The aforementioned operations are just a few in which this constraint is too strong.

Do use a Factory for conversion style operations. The use of a Factory also enables conversion specific information to be supplied via parameters without overloading a type’s constructors. This can result in fewer

141

.NET Framework Design Guidelines Microsoft Confidentialconstructors for the API client to choose from and also helps to avoid introducing constructor parameters that are not natural constituents of the type itself, both resulting in an overall less complex type. Conversely, however, constructors are the primary means to create objects, and introducing too many alternatives can be confusing and inconsistent to API users. This is why careful thought and conservatism should go into the creation of any new static Factories. For example, Intellisense will guide a user through the instantiation of a new object using its constructors, but won’t point users in the direction of a type’s Factory methods.

Do use a Factory if an operation requires parameter information which feels unnatural to pass to a constructor.

Do not use a Factory in situations where the creation operation will be used as a core scenario for instantiation of a type. In these situations, discoverability and consistency are paramount.

Consider using a constructor instead of a Factory. Only after this thought process should you proceed with the implementation of a Factory.Factories are also often handy to enable type specialization through polymorphism. Constructors are limited to generating instances of the type to which they belong, but it is often useful to return a subclass to hide implementation details. In many cases, it is a good idea to let users interact with abstract classes and interfaces, so as not to create a dependency on specific implementations. For example, consider this scenario:

public interface IFoo { … }private class FooImplementer : IFoo { … }

public static IFoo CreateFoo(…) { return new FooImplementer(…);}

The user of the CreateFoo() API does not need to be aware of the presence of the FooImplementer class – in fact, it could even be marked private. Should an alternate implementation become appropriate later on, it is not a breaking change to change the type under the hood:

private class FooImplementerSpecial : IFoo { … }

public static IFoo CreateFoo(…) { return new FooImplementerSpecial(…);}

This provides great flexibility for the API provider in cases where users are looking for a generalized algorithm or type, but isn’t necessarily interested in the implementation details. In such situations, it is important that clients do not take dependencies on the implementation class; otherwise, flexibility to change the implementation at a later date is severely compromised.

Do use a Factory if API users will be coding to a base class or interface whose implementation is subject to change over time.

Do use Factory methods in cases where a developer might not know which type to construct, for instance when coding against a base type or interface. A Factory method can often use parameters and other context-based information to make this decision for the user.

142

.NET Framework Design Guidelines Microsoft ConfidentialOften, a collection of related object creation operations are more useful and discoverable when grouped together into a Factory type. The System.IO.File class is one example from the Framework. This type does not need to support polymorphic extension, and as such it implements all of its operations through static methods. For instance, consider the File.Open(…) method:

public class File {    public static FileStream Open(String path, FileMode mode) {        return new FileStream(path, mode);    }  }

//ConstructorFileStream f = new FileStream(“Foo.txt”, FileMode.CreateNew);

//Static Factory MethodFileStream f = File.Create(“Foo.txt”);

This implementation simply constructs a new FileStream, and returns it to the caller. However, the File class is admittedly easier to find than the FileStream type for the average developer (especially one who is not experienced in dealing with the concept of a “Stream”), and provides a convenient directory of file-related operations.In some cases, Factory types such as these must support polymorphic extension, meaning that Factory operations must be implemented as virtual instance methods. This can be accomplished simply by providing an interface or base class from which concrete Factories derive. For example:

public interface IControlFactory {    public Control CreateButton();    public Control CreateListBox();    …} public class WindowsFormsControlFactory: IControlFactory{    …} public class WebFormsControlFactory: IControlFactory{    …}

Consider grouping logically related Factory methods into a single Factory type. Do implement Factory operations as virtual instance methods rather than static if

they must support polymorphic extension. Do use the Singleton pattern for Factories which are instance based so as not to

force developers to instantiate a Factory type just to invoke one of its members.Sometimes using a constructor lacks sufficient context to inform a developer of an operation’s semantics. For example, consider:

public String(char c, int count);

This operation generates a string of count character c’s. Its semantics would have been clearer if a static factory was provided instead, as it provides more guidance through its name. For instance:

143

.NET Framework Design Guidelines Microsoft Confidentialpublic static String Repeat(char c, int count);

Annotation (Brad Abrams): This is, in fact the pattern we use for the same concept in ArrayList.

Do use a Factory method if a constructor would be insufficient to describe the operation being performed, and the additional information gained from an individually named Factory makes an operation’s purpose clearer.

6.12 TimeoutsUse timeouts to specify the maximum time a caller is willing to wait for completion of a method call. A Timeout may take a form of a parameter to the method call as follows.server.PerformOperation(timeout);

An alternative approach is to use a property on the server class as follows. server.Timeout = timeout;server.PerformOperation();

The first approach is favored because it makes the association between the operation and the timeout much clearer. The property-based approach may be better if the server class is designed to be a component used with visual designers.Historically, timeouts have been represented by integers. Integer timeouts can be hard to use for the following reasons.It is not obvious what the unit of the timeout is.It is difficult to translate units of time into the commonly used millisecond. (How many milliseconds are in 15 minutes?)Often, a better approach is to use TimeSpan as the timeout type. TimeSpan solves the problems mentioned above. class Server{

void PerformOperation(TimeSpan timeout) { … } …Server server = new Server();server.PerformOperation(new TimeSpan(0,15,0));

Timeout may seem like more typing for developers but with some help from modern code editors (such as statement completion) it should not be a factor.If the timeout is set to TimeSpan(0), the method should throw System.TimeoutException if the operation is not immediately completed. If the timeout is TimeSpan.MaxValue, the operation should wait forever without timing out, as if there were no timeout set. A server class is not required to support either of these values, but it should throw an InvalidArgumentException if an unsupported timeout value is specified.

144

.NET Framework Design Guidelines Microsoft ConfidentialIf a timeout expires and the System.TimeoutException is thrown, the server class should cancel the underlying operation.Where appropriate, the server class should also include a static DefaultTimeout property if there is some default timeout used if the user does not specify one.class Server{

TimeSpan defaultTimeout = new TimeSpan(1000);

void PerformOperation(){this.PerformOperation(OperationTimeout);

}

void PerformOperation(TimeSpan timeout){…

}

TimeSpan OperationTimeout{get{

return defaultTimeout;}

}}

Types that are not able to resolve timeouts to the resolution of a TimeSpan should round the timeout to the nearest interval that can be accommodated. For example, a type that can only wait in one second increments should round to the nearest second. An exception to this is when a value is rounded down to zero. In this case, the timeout should be rounded upwards to the minimum timeout possible. This rounding away from zero prevents "busy-wait" loops where a zero timeout value causes 100% processor utilization.In addition, we recommend throwing System.TimeoutException when a timeout expires instead of returning an error code. Expiration of a timeout means the operation could not complete successfully and thus should be treated and handled as any other runtime error (see section 5, Error Raising and Handling). In case of an asynchronous operation with a timeout, the callback should be called and an exception thrown when the results of the operation are first accessed.void OnReceiveCompleted(Object source, ReceiveCompletedEventArgs asyncResult){ MessageQueue queue = (MessageQueue)source; // the following line will throw if BeginReceive has timed out Message message = queue.EndReceive(asyncResult.AsyncResult); Console.WriteLine("Message: " + (string)message.Body); queue.BeginReceive(new TimeSpan(1,0,0));}

Please refer to section above for more information about asynchronous execution guidelines.

Do use TimeSpan as the type of all timeouts. Do throw System.TimeoutException when a timeout expires.

Do not return error codes to indicate timeout expiration.

145

Brad Abrams, 12/13/04,
Are we sure this is true, I think some int based timeouts are goodness

.NET Framework Design Guidelines Microsoft Confidential6.13 Default Instance (Empty) Pattern [Draft]

Thanks to the very effecient memory management techinques in the GC, creating instances in the managed code world is orders of magnatude cheaper than allocating memory directly off the OS heap. But, no mater how effecient the GC is at memory allocation, it can not do better than not allocating at all. It is common for the default instance138 to have special meaning in some very common contexts when the type is immutable. If this is the case then consider providing a static Empty property that returns a single instance that all callers can use.

public class EventArgs { public static readonly EventArgs Empty = new EventArgs (); public EventArgs () { } //other members}

Usage://right:

return EventArgs.Empty; //wrong: return new EventArgs ();

This pattern allows multiple callers to share the same instance of MyFooSet rather than each creating their own. Notice the trade off here is that the MyFooSet instance will be created as soon as the MyFooSet type is referenced even if an default instance is never needed. Therefore this patter should only be used if it is very common to use empty instances.Example usage:

String.EmptyEventArg.Empty

Do not use the Default Instance pattern if the type is mutable. Do use the Default Instance pattern only where it is very common to use the default

instance. Do provide a static property called “Empty”. Do use the Empty property if it is available139.

6.14 Obscuring Low Level Funcationality <<TBD, see BradA>>

138 the value returned from calling the constructor with no arguments139 FxCop rule comming

146

.NET Framework Design Guidelines Microsoft Confidential

7 Error Reporting and HandlingException handling can be a point of confusion for developers and designers new to the .NET Framework. There are a number of reasons for this, here are some key reasons:Exception handling in the Framework works similarly to other exception technologies such as Win32 SEH, but the design guidelines are significantly different.Advantages of exception handling are not well understood. Goals of exception handling, as it applies to the Framework, are not well understood.Exception handling for reusable component code must follow guidelines that are stricter than those employed by application code.We will address these by first describing the advantages and goals of exceptions in the Framework and then by prescribing design guidelines for exception handling in managed APIs.In addition to guidelines described in this document, there is excellent coverage on exception handling in the book Applied Microsoft .NET Framework Programming. The Exceptions chapter is the direct result of experience derived from the development of the Framework class library.

7.1 Benefits of Exception HandlingThere are many benefits to exception handling as compared to return value based error reporting. In fact, the Framework exposes more of the benefits of exception handling then some other common exception models such as Win32 SEH or C++ exception handling. Good managed API design does not restrict the application developer from realizing the benefits of exceptions. The following are some of these benefits.

Exceptions Promote API ConsistencyConsistency of API is important to developers. Exceptions promote consistency, because they are designed to be used for failure reporting (and nothing else). In contrast, return values have many uses of which failure reporting is only a subset. For this reason, it is likely that APIs that report failure through return values will find a number of patterns, while exceptions can be constrained to specific patterns. The Win32 API is a clear example of this inconsistency through BOOLs, HRESULTS, and GetLastError() among others.

Exceptions are Compatible with Object Oriented FeaturesObject-Oriented languages tend to impose constraints on method signatures that are not imposed by functions in functional programming. For example, constructor methods, operator overloads, virtual methods, generic methods, interface methods and properties all resolve to functions, and yet the developer writing the method has no choice in the return value (if any) of the method. For this reason, it is not possible to standardize on return value based error reporting for object oriented APIs. An error reporting method, such as exceptions, which is out of band of the method signature is the only option.

With Exceptions, Error Handling Code Need not be Near Failing CodeWith return-value based error reporting error handling code is always very near to the code that could fail. However, with exception handling the application developer has a

147

.NET Framework Design Guidelines Microsoft Confidentialchoice. Code can be written to catch exceptions near the failure point, or the handling code can be further up in the call stack.

With Exceptions, Error Handling Code is More LocalizedVery robust code that reports failure through return values tends to have an if statement for every functional line of code. The job of these if statements is to handle the failure case. With exception oriented code, robust code can often be written such that a number of methods and operations can be performed with the error handling logic grouped at the end of the try block (or even higher in the call-stack). A common argument is that exception handling code is unsightly. This argument is usually being made by someone comparing well written exception handling code with return value oriented code that is not sufficiently checking return values of functions.

Exceptions Are Not Easily IgnoredReturn values can be easily ignored, and often are. Exceptions, on the other hand, take an active role in the flow of your code. This makes failures reported as exceptions difficult to ignore, and improves the robustness of code.For example the Win32 API CloseHandle() fails very rarely, and so it is common (and appropriate) for many applications to ignore the return value of the API. However, if any application has a bug which causes CloseHandle() to be called twice on the same handle, it would not be obvious unless the code was written to test the return value. A managed equivalent to this API would throw an exception in this case and the unhandled exception handler would log the failure and the bug would be found.

Exceptions Allow for Unhandled Exception HandlersIdeally, every application is written to intelligently handle all forms of failure. However, this is not realistic as all forms of failure can’t be known. With return value oriented code, failures that are unexpected are ignored by code and the application continues to run with undefined results. With well written exception based code, unexpected failures eventually cause an unhandled exception handler to be called. This handler can be designed to log the failure, and can also make the choice to shut down the application. This is far preferable to running with indeterminate results, and also provides for logging that makes it possible to add more significant error handling for the previously unexpected case. (Today, Microsoft Office uses an unhandled exception handler to gracefully recover and re-launch the application as well as send error information to Microsoft to improve the product.)You should only have a custom unhandled exception handler, if you have a have specific, app-oriented work to do in the handler. If you just want error reporting to occur, the runtime will handle that automatically for you and you do not need to (and should not) use a UEF. An application should only register a UEF if it can provide functionality above and beyond the standard error reporting that comes with the system and runtime.

Exceptions Provide Robust Error Info for LoggingExceptions provide for a consistent error handling mechanism, and as such make it possible to have consistent logging of error information. The System.Exception type in the Framework encapsulates stack-frame information as well as other useful information such as a nested exception type. This is great for error logging and discovery of unexpected error cases during the QA phase. Exceptions are objects, so it is possible to extend exceptions to add additional information.

148

.NET Framework Design Guidelines Microsoft ConfidentialHandling Errors Consistently and Thoroughly are Essential for Creating a Good User ExperienceThe application developer needs to provide specific information about what error occurred, why it occurred, and what can be done to mitigate it. This requires detailed and specific error returns from API calls. The exception mechanism allows detailed error information to be created by the API developer. There is no need for the API developer to change global header files to add new error codes. The API developer can customize the exception subclass as much as necessary to transmit all of the details of the error to the caller.

Exceptions Promote InstrumentationExceptions are a well-defined method-failure model. Because of this, it is possible for tools such as debuggers, profilers, performance counters, and others to be intimately aware of exceptions. The PerfMon application, for example, keeps track of exception statistics. In the future automatic instrumentation from profiling to auto-documentation will be more sophisticated related to exceptions. Methods that return failure do not share in the benefits of instrumentation.

Exceptions Unify the Error Model (Hard and Logical Errors)Exception handling or interrupts are the only option for hard errors such as null references and divisions by zero (certain operations have no return-value means of reporting failure). Using exception handling for API and logical failure reporting is beneficial in that it unifies error handling for all failure types.

7.2 Working with ExceptionsWorking with exceptions is easy. If you are most familiar with return values for failure management, some of your development habits will change, and this can be tough at first. Failure to address the differences between exceptions and return values in your design, however, can cause your code to forgo many of the benefits of exception handling (or worse, withhold these benefits from application developers using your managed API). This section addresses some of the common misuses of exception handling.

Do Not Swallow Exceptions (By Handling Base Exceptions) Developers new to exceptions tend to think of exceptions as bugs. This leads to the tendency to over-catch exceptions by swallowing all exceptions, as follows:public void Method(){

try{File.Open(...);

}catch(Exception e){ // swallow “all” exceptions - don’t do this!}

}

It is important to remember that an exception is a failure reporting mechanism. Just as in functional programming, failure for a method to complete its task is a bug in some cases but just a logical error in others. Code that swallows all exceptions ultimately swallows failure information. This is problematic for a number of reasons, not the least

149

.NET Framework Design Guidelines Microsoft Confidentialof which is the fact that the swallowing code can’t possibly recover from any and all failure cases.This tendency is additionally problematic for OO design, because there are so many ways that API code can call back into application code such as virtual functions, event handlers, interface methods, etc. Any swallowing code in a managed API can effectively restrict application code from throwing application-defined exceptions that are handled by application code further up the call stack.In addition to restricting application design, swallowing exceptions can introduce catastrophic bugs if the exception swallowed was one thrown by the runtime. For example inadvertently swallowing OutOfMemoryException, StackOverflowException or ThreadInterruptException is almost always a major bug. Minimally swallowing one of these exceptions robs the application of the ability to log an effective bug-entry using an unhandled exception handler.

Swallowing exceptions undermines the following benefits of exceptionsWith Exceptions Error Handling Code Need Not be Near Failing Code, Exceptions Are Not Easily Ignored, Exceptions Allow for Unhandled Exception Handlers, Exceptions Provide Robust Error Info for Logging

Use Finally Blocks LiberallyIt may seem counter-intuitive at first, but catch-blocks are not needed in a surprising number of methods (especially in application code). When approaching the typical method, you should explicitly assume that try-finally may be of use for clean-up to ensure consistent state of the system when an exception is thrown from the method. Usually, the cleanup logic rolls back resource allocations. The implicit (and correct) assumption of a try-finally block is that some exceptions that are raised in your method should not be caught, because it is not for the method to handle. Use finally often, use catch only to catch a specific (not base) exception that is clearly defined in the documentation. C# provides the using statement that can be used instead of plain try-finally to cleanup objects implementing IDisposable interface. Please see C# reference documentation for more details.

Liberal use of finally blocks and sparse use of catch promotes the following benefits of exceptionsWith Exceptions Error Handling Code Need Not be Near Failing Code, Exceptions Are Not Easily Ignored, Exceptions Allow for Unhandled Exception Handlers, Exceptions Provide Robust Error Info for Logging

Understand the Value in Unhandled Exception HandlersApplication developers that are taking full benefit of exception handling will register an unhandled exception handler for their application. This handler will log exceptions for QA purposes as well as exit the application gracefully for unexpected failure in production code.This model is a vast improvement over failures reported by return values. With return values, unless a failure is specifically looked for, the application will ignore the failure and continue to execute with undefined results. Exceptions are aggressive and the result of an unexpected exception is a call to the unhanded exception handler, where the developer can gain knowledge about the unexpected failure through logging.As an API developer it is critically important that API’s not be designed in a way that undermines the value of unhandled exception handlers to application developers. This means that APIs must be designed so that all application models can discover unhandled

150

.NET Framework Design Guidelines Microsoft Confidentialexceptions (even partially trusted code), and that APIs must not artificially swallow exceptions that should reach the unhandled exception handler.Related benefits of exceptionsExceptions Allow for Unhandled Exception Handlers, Exceptions Provide Robust Error Info for Logging

Do Not Treat Exceptions as Optional for API DesignMost developers have become comfortable with using exception handling for hard error cases such as division by zero or null references. With the Framework exception handling is used for both hard errors and logical errors. It can be difficult for API developers to embrace exception handling as the means of reporting all functional failure.Here is the rule: Design all public methods of a managed API to report method-failure by throwing an exception. To follow this rule it is important to understand the meaning of method-failure. Method failure is any time a method cannot do what it was designed to do (what the method name implies). For example if OpenFile() cannot return to the user having opened a file, it must throw an exception.There are a variety of excuses for not using exceptions but most boil down to the following two:Exception handling syntax is undesirable, so this API will return error code.A thrown exception does not perform as well as a returned value.We will address these two concerns in their own sections later.It is worth noting that, without regard to the reason, it is really not possible to write a managed API that only returns failure rather than throwing. There are two reasons for this:A managed API is likely to be implemented in terms of other method calls (including calls that call back into application code). To enforce that an API only return failure (rather than throw), the API would have to have an outer try{}catch{} block that swallows all exceptions raised by inner code. There are significant reasons not to do this, see Do Not Swallow Exceptions .Regardless of any exceptions swallowed by a misapplied try{}catch{}, the runtime can still throw exceptions that you cannot catch or control in any fashion.The bottom line is that if your API returns failure then you may be forcing the conscientious application developer to both check return values and handle exceptions thrown from your API!Treating exceptions as optional in managed API undermine all of the benefits of exceptions, but most notably the followingExceptions Promote API Consistency

Do Not Avoid Exceptions Due To “Undesirable” SyntaxThe syntax concern is largely a matter of familiarity and should not be a consideration. As an API designer we should not make assumptions about the familiarity of the application developers consuming our code.

151

.NET Framework Design Guidelines Microsoft ConfidentialIt is common to say that exception syntax can get bulky, but remember that return values have the same effect. See the following robust pseudo code relies on error codes for error reporting.public Boolean Method(){

Boolean result = false;if(!OpenFile(…)){

goto End;}

if(!ReadFile(…)){goto End;

}

if(!CloseFile()){goto End;

}

result = true;End: return result;

}

Now compare this to similar pseudo code assuming exceptions as the error mechanism. public void Method(){

try{OpenFile(…);ReadBytes(…);CloseFile();

}catch(FileIOException){// handle failure

}}

The equivalent to the preceding code using return values would simply be ignoring potential failures. Such code certainly exists, but it is nice that exceptions do not promote the ignoring of failure.In brief, remember that API design lasts forever, and any syntax will eventually become comfortable. Syntax is not a reason to avoid exceptions.Related benefits of exceptionsExceptions Promote API Consistency, With Exceptions Error Handling Code Need Not be Near Failing Code, With Exceptions Error Handling Code is More Localized, Exceptions Provide Robust Error Info for Logging

Think Twice about Avoiding Exceptions Due To Potential Performance ConcernsPerformance is a very common concern related to exceptions. The concern is that if exceptions are used for code that fails as a routine, then performance can be affected. I would like to show that strict adherence to the exceptions guideline is possible while still promoting good performance.

Break your method’s functionality into two methods.Sometimes performance can be promoted by breaking a single method into two methods, each of which adheres to the exception guideline. Let’s look at the index property for the Hashtable type in the class library:

152

.NET Framework Design Guidelines Microsoft ConfidentialHashtable h = new Hashtable(); …Object o = h["Key"];

The guideline says that the method verb for an index property is get and/or set. So to follow the guideline, Hashtable should throw if the key does not exist in the current set. Instead, the Hashtable returns null for “performance reasons”. The Hashtable developer was worrying about application code having significant Hashtable misses in a tight loop.Performance should have been addressed more appropriately by splitting the functionality of the index property getter into two methods. In other words, the Hashtable class should define a tester method and a doer method. This way code that is not concerned with performance of Hashtable misses would look like this:try{

o = h[“Index”]; // doer method}catch(HashtableException){…}

While code that is performance concerned (like the following) can be written to reduce exceptions.try{

for(int loop=0; loop<10000; loop++){if(h.KeyExists(loop)){

o=h[loop];}

} }catch(HashtableException){…}

Offering two methods instead of one has the advantage of allowing the exception guidelines to be followed while giving the consumer two choices with very obvious results.Tester methods are typically small enough to be inlined by the JIT compiler. If the cost of testing is prohibitive (because you are effectively doing some work twice in the tester and the doer), then you may not need a tester for performance reasons (testers may still be useful for other reasons, like usability). The rationale here is that the higher the cost of the method invocation, the less the overhead of exceptions is a concern, and the less useful it becomes to split the method into two.

Adjust the method verb to include a well-defined test.A rarer alternative to breaking up a method is to adjust the method-verb to make a well-defined test case part of the method’s feature. For example, a type defining a GetObject() method that throws if an Object was not retrieved could also define a corresponding TryGetObject() method which attempts the get but returns false if the “try” portion of the method came up unsuccessful. The return value of the original GetObject method should be returned as an out parameter of the TryGetObject method:public Object GetObject(P1 p1, P2 p2);public Boolean TryGetObject(P1 p1, P2 p2, out Object obj);

It is important when designing in this fashion to define the try functionality of your method in strict terms. If the get functionality cannot be achieved for any reason other than the well defined try functionality, then your method must still throw.For every Try method there must be a non-try version that attempts the work without the test (and throws on failures). Example: TryGet() and Get().

153

.NET Framework Design Guidelines Microsoft ConfidentialThese two options should help for many of the cases where API performance is a concern. However, it is important to remember one overriding point: The design of your API is likely to be unchangeable for years; meanwhile performance is a moving target. Hardware improves rapidly, and the exception handling mechanism of the runtime will continue to be optimized. Related benefits of exceptionsExceptions Promote API Consistency

Be More API Consistent than the FrameworkUnfortunately the Framework class library has some noteworthy cases where the design guidelines outlined in this document are violated. Never defend your API design using examples in the Framework that violate these guidelines. The Framework is a relatively new platform, and only a small percentage of the eventual managed API exists today. This gives API developers inside of Microsoft strong incentive to follow guidelines even where the class library itself fails.

7.2.1 Exception Handling Examples from the FrameworkAs with anything new, it is helpful to learn by example. This section includes exception-handling examples from the Framework class library (v1 RTM), along with comments for each example. Note that this section contains examples of both well designed and poorly designed API.Examples from the Class Library that Make Poor Use of ExceptionsUnfortunately there are a number of examples of API methods in the class library that should throw on method-failure, but do not. Most of them return a Boolean or some other value instead of throwing. Some don’t do anything to report their failure to perform the method’s purpose.

Array.Sort() & Array.BinarySearch()

The Sort() and BinarySearch() methods on the array type call back into application code through the IComparable interface, and yet these methods catch and swallow all exceptions. For more information on why this is undermines the benefits of exception handling see Don’t Swallow Exceptions.

ThreadPool.QueueUserWorkItem()

One of the best examples of a method that should throw but does not is ThreadPool.QueueUserWorkItem(). Instead, the method returns a Boolean value upon failure. In this case, the failure to throw on method-failure is compounded by the fact that developers are unlikely to expect this method to fail at all, so are unlikely to check the return value. In reality, QueueUserWorkItem does have more failure cases then the out-of-memory case, and would benefit from the Exceptions Are Not Easily Ignored benefit of exceptions.

AutoResetEvent & ManualResetEvent classes’s Set() & Reset() methods140

140 The AutoResetEvent class can be used to make a thread wait until some event puts it in the signaled state by calling AutoResetEvent.Set. Unlike the ManualResetEvent, the AutoResetEvent is automatically reset to non-

154

.NET Framework Design Guidelines Microsoft ConfidentialBoth return Boolean values when they should throw on failure. This example becomes increasingly clear when you consider how truly rarely these methods would fail; again making unlikely that the developer is checking the return value losing the benefit: Exceptions Are Not Easily Ignored.

WaitHandle.WaitOne()

This example is pathological. The WaitHandle class includes several overloads of the WaitOne() method, each of which return Boolean. public bool WaitOne();public bool WaitOne(int millisecondsTimeout, bool exitContext);public bool WaitOne(TimeSpan timeout, bool exitContext);

The interesting part is that two of the WaitOne() overloads use the return value to indicate both failure and the return case where a timeout occurred, while the overload with an infinite timeout would only return false in an error scenario. In summary, WaitOne() with no timeout will almost never fail, but if it does it returns false. The WaitOne() with a timeout will return false whenever the timeout count is met before the synchronization object goes signaled, however occasionally it will return false because of error, rather than timeout, and the developer can’t tell the difference.

Hashtable.Item property’s getter method

This method has been nothing if not controversial. In fact, for months before the release of RTM an occasional debate would start-up as to whether this method should throw if the caller passes a key for which there is no value in the Hashtable. By the rules of this guideline it certainly should have thrown in these cases, but making the argument of ‘performance and usability’, this method instead returns null when there is not a matching key in the Hashtable. Let me tell you what is wrong with this. First, null is a valid value for a key in the Hashtable object. What this means is that when you get a null-value you really don’t know if the key was invalid or if it is there and set to null; hopefully these two things are equivalent in your code, because they are in the Hashtable class. The second and more noteworthy reason why this method should have thrown is due to the Exceptions are Compatible with Object Oriented Features benefit of exceptions. Here is the rationale. The Hashtable class is a collection class of object references (and references can be null), and the ‘Exceptions are Compatible with Object Oriented Features’ benefit states that you should standardize on exceptions because with OO you can’t always control your return type or value. This has since happened with the generic version of Hashtable, whose Hashtable.Item property can now return value types as well as reference types. Ooops! The generic Hashtable class can’t return null when the key isn’t found, because there is no way to express null with a value type. So throwing is your only choice, making the generic hashtable incompatible with its non-generic equivenlent (Exceptions Promote API Consistency).

Examples from the Class Library that Make Proper Use of ExceptionsThe following examples show proper use of exceptions in the class library. This list is shorter then the previous list, but you should not take this as an indication that the class library has more bad methods than good, in terms of exceptions. This is not the case. In

signaled by the system after a single waiting thread has been released. If no threads are waiting, the event object's state remains signaled.

155

.NET Framework Design Guidelines Microsoft Confidentialfact, the great majority of methods in the class library throw exceptions on method failure, and follow the spirit of the guidelines in this document.

Stack.Pop, Queue.Dequeue

Both of these methods throw if there is no item available in the collection to pop or de-queue. This may seem like a simple following of the rule that states that your method should throw if it can’t do what it’s method-verb says it does. However, these two classes are noteworthy, because they buck the trend of the other collection classes in the class library (such as Hashtable and SortedList) which unfortunately avoid exceptions for failure reporting.

Monitor.TryEnter()

This method returns a Boolean false if it fails to enter the critical section block. This may seem like a candidate for throwing, but in fact is making good use of the ‘Adjust the method verb to include a well-defined test’ API pattern. The TryEnter() method makes it clear from its method name that there is a test associated with its attempt to enter the critical section.

Hashtable.ContainsKey()

Hashtable provides a ContainsKey() method which follows the tester and doer API pattern discussed above. The only downside here is that the doer (the item property) method doesn’t properly throw. But ContainsKey() taken on its own is a good example of a method that doesn’t throw, and shouldn’t because it is a tester method meant to return a true or false, without doing anything else.

7.3 Exception Usage GuidelinesThe following design guidelines are meant for managed API design, but can be applied to managed application design as well. The rules are divided into three sections: guidelines for throwing exceptions, guidelines for exception error messages and guidelines for handling exceptions.

7.3.1 Throwing ExceptionsThe following guidelines define best practices for throwing exceptions in managed code.

Do strictly define the functionality of your method. In all cases where a method cannot perform its defined functionality, throw an exception to report the failure.

Do design all public methods141 of a managed API to report method-failure142 by throwing an instance of an Exception-derived type. Failure to do so undermines all of the benefits of exception handling for the application developer.If, for performance reasons it is preferable to report a common failure case through return value, then your method name must reflect this possibility in the method verb. Example: Boolean TryGet();

141

142

156

? Methods include: constructors, instance and static methods, properties, indexers, operator overloads, and event add/remove methods.

? Method-failure is the inability for a method to complete the task described by the method-verb. Example: OpenFile() – if the result is not an open file, throw. The method-verb for a constructor is construct. The method-verb for a property method is get for the getter and set for the setter. If your property getter fails to get then throw. Caution: Property getters should be very simple and should not throw besides very unusual circumstances. The method-verb for an event is add for the add-handler method and remove for the remove-hander method.

Krzysztof Cwalina, 12/13/04,
We need to break it into design, usage, handling, etc.

.NET Framework Design Guidelines Microsoft ConfidentialThe prefix “Try” should be applied to the method name in such cases.In cases where a “Try” method exists, a standard version can also be defined which reports failure only through exceptions.For Try* methods the failure case that is reported through a return value must be well defined and all other failure cases will result in an exception.

Do not use exceptions for normal flow of control. Do not use return error codes to report errors. Do not have members that can either throw or not based on some “option.” For example

the following is unacceptable:bool TryParse(string text, out DateTime date, bool shouldThrow){}

Do not have public members that return exceptions as the return value or an out or ref parameter. For example the following is unacceptable:bool TryParse(string text, out DateTime date, out Exception e){}

Do end Exception class names with the Exception suffix143.public class FileNotFoundException : IOException {}

Consider using existing exceptions over creating new ones. Do throw exception types defined in the class library only when the exception type

has a well defined use. Example: ArgumentNullException, DivideByZeroException, InvalidOperationException.

Do throw the most specific exception possible. Do not throw System.Exception, System.SystemException, or any other exception base

types. Do not explicitly throw NullReferenceException or IndexOutOfRangeException. Do

argument checking to avoid throwing these exceptions. Throwing these exceptions expose implementation details of your method that may change over time. 

Do derive exceptions from a common base or common bases derived from System.Exception.

Do derive exceptions from SystemException (or a subclass of SystemException) if and only if the exception is defined in the System namespace.

Do not throw or derive from System.ApplicationException. Do define exception hierarchies that are shallow and wide. Do create new exception types if you have an error condition that can be

programmatically handled in a different way than any other existing exception.

143 Fully covered by FxCop rule: NamingRules/ExceptionNamesHaveExceptionSuffix.157

Krzysztof Cwalina, 12/13/04,
This guideline needs justification as it was changed. The reason is that it does not add any value. People should inherit straight from System.Exception (or an existing base exception).
Brad Abrams, 12/13/04,
Add a note about exceptions being “thrown” not “raised”

.NET Framework Design Guidelines Microsoft ConfidentialAnnotation (Marc Miller): There should be a very high bar for creating new exception types: always try to use the existing exceptions -- don’t create new “MyAppException” types just to be different and cool.  Try to use general exceptions such as InvalidOperationException, InvalidArgumentException, etc.  On the other hand, never throw System.Exception in lieu of a better exception type: if you need to, create one.

Do not create new specialized exceptions just to have "your team's” exception.Annotation (KCWalina) these kind of “MyException”s do not add any value. They only give people false impression that all exceptions thrown from MyCode will be subclasses of MyException which is not possible, nor desirable.

Do make Exception classes Serializable144.An exception must be serializable to work correctly across application domain boundaries. To ensure your exception works properly in a distributed environment, it should have the Serializable attribute and, if it defines any fields, it should also implement System.Runtime.ISerializable.GetObjectData and a serialization constructor.

Do provide these common constructors on all custom exceptions145. public class XxxException : YyyException {

public XxxException() {} public XxxException(string message) {} public XxxException(string message, Exception inner) {}

// this constructor is needed for serialization when exception propagates // from a remoting server to the client. protected XxxException(SerializationInfo info, StreamingContext context) {}}

Do provide exception properties for programmatic access. Include extra information (besides the message string) in an exception only when there is a programmatic scenario where that additional information is useful. You should rarely need to include additional information in an exception.

Do override ToString() when your exception provides extra properties.The code handling the custom exception may not have caught your specific type of exception, and therefore does not have access to the extra information unless you provide it in ToString().public class MyException: Exception{

private string extraData;public MyException(string message):base (message){}//other constructors left out

public string ExtraData{

get { return extraData; }set { extraData = value; }

}

144 Fully covered by FxCop rule: UsageRules/ExceptionsAreMarkedSerializable.145 Fully covered by FxCop rule: DesignRules/ExceptionsRequireMultipleConstructors.

158

.NET Framework Design Guidelines Microsoft Confidential

public override string ToString(){

return base.ToString() + " ExtraData: " + ExtraData;}

}

Do not add extra data to the Message property. The Message property should contain the same value as passed in to the constructor.

Do not provide security sensitive information in an exception message. Do store useful security sensitive information in private exception state. Ensure only

trusted code can get the information. Do report security sensitive information through an override of ToString() only after

demanding an appropriate permission of the caller. Otherwise return a string excluding the security sensitive information.

Do throw an InvalidOperationException if in an inappropriate state. The System.InvalidOperationException exception should be thrown if the property set or method call is not appropriate given the object's current state. Example: Writing to a FileStream that's been opened for reading.

Do throw an exception derived from ArgumentException if bad parameters are passed or detected. Note   The difference between InvalidOperationException and ArgumentException is that ArgumentException does not rely on the state of any other object besides the argument itself to determine whether it needs to be thrown. For example, if client code tries to access a nonexistent resource InvalidOperationException should be thrown. On the other hand, if client code tries to access a resource using an illegal path, ArgumentException should be thrown.

Do realize that the stack trace starts at the point where an exception is thrown. The stack trace does not begin where it is created with the new operator; consider this when deciding where to throw an exception. Note: throw; without a parameter does not restart the stack-trace from the point of rethrow.

Do use exception builder methods. It is common for a class to throw the same exception from different places in its implementation. To avoid code bloat, use helper methods that create the exception using the new operator and return it. For example:class File{ string fileName; public byte[] Read(int bytes){ if (!ReadFile(handle, bytes)) throw NewFileIOException(...); } FileException NewFileException(...){ string description = // build localized string return new FileException(description); }}

Do set all the properties on the exception you use.

159

.NET Framework Design Guidelines Microsoft Confidential Do use Inner exceptions (chained exceptions). Caution: This is not commonly useful,

and is often abused by methods that catch base (or all) exceptions and wrap them in a library exception. However, chaining must be used in instances where it is appropriate to translate a specific exception into another specific exception.

Do argument checking on protected (family) and public members. Clearly state in the documentation if the protected method does not do argument checking. Unless otherwise stated, assume that argument checking is done. There may be performance gains in not doing argument checking.

Do document all exceptions public or protected methods throw because of a violation of the methods contract (rather than a system failure) and treat them as part of your contract. Exceptions that are a part of the contract do not change randomly from one version to the next.

Do not throw exceptions from exception filter blocks146. When an exception filter raises an exception, the exception is caught by the CLR, and the filter returns false. This behavior is indistinguishable from the filter executing and returning false intentionally.Not all CLR languages support exception filters. For example, Visual Basic .NET and Managed C++ support exception filters, but C# does not.

7.3.2 Exception Error Messages Do provide rich and meaningful message text targeted at the developer when

throwing an exception. The following guidelines define best practices for the message text when managed code throws an exception. The exception message explains the error condition to the developer, and helps the developer identify how to correct or avoid the exceptionAnnotation (BradA): Unintelligible, incomplete error messages are the most common reason why developers contact support. Error messages that precisely and lucidly describe the problem, the probable causes, and the solutions or workarounds help developers understand why the error occurred, how to fix it, and how to avoid it in the future. In addition, all exception strings are localized, which makes it especially important to deliver messages that are clearly stated and complete.

Do localize exception messagesAnnotation (BradA): Many developers that use the .NET Framework are non-English speaking. We localize our entire documentation set (including the huge API reference). Localizing the error message helps non-English speakers feel more comfortable on our platform.

Do use grammatically correct exception messages. Make the assumption that code may present the developer with the exception message.Each sentence in a description string of an exception should end in a period. This way code that generically displays an exception message to the developer does not have to handle the case where a developer forgot the final period, which is relatively cumbersome and expensive.

Do provide useful information that helps the developer diagnose the problem. For example, rather than using “Bad link,” try “Link target does not exist”

146 Fully covered by FxCop rule: UsageRules/ExceptionsShouldNotBeThrownFromFilterBlocks.

160

.NET Framework Design Guidelines Microsoft Confidential Do be precise. For example, “Missing file name extension” is better than “File not

found.” Do describe the problem. For example, “Disk full” is better than “File error.” Do use third-person, simple present or past tense, and active voice. Do use a neutral tone. For example, change the tone in “Bad input” to “Command is

unrecognizable.” to avoid blaming the developer. Do start with search-relevant words. Use passive voice or more complex construction if

necessary. For example, “Log file {0} is full.” is preferable to “{0} log file is full.” Do use complete sentences. For example, use “Binding is too long.” rather than “Binding

too long.” Do not use exclamation points. Notice the difference between “Command is

unrecognizable!!” and simply “Command is unrecognizable.” Do not personify (imply that programs think or feel). For example, “Node parameter

cannot use Windows NT protocols.” is better than “Parameter node does not speak any of our protocols.”

Do not start with an article or variable. Use searchable words at the beginning instead. For example, “Log file {0} is full.” is preferred to “{0} log file is full" or “The {0} log file is full."

Do not use quote marks for emphasis. Do not provide security sensitive information in an exception message.

7.3.3 Handling ExceptionsThe following guidelines define best practices for catching and handling exceptions in managed code.

Do not over-catch. In well-written exception code try-finally is far more common than try-catch. Exceptions should often be allowed to propagate up the call-stack.

Do catch exceptions for which you have specific understanding of why it was thrown in a given context, and for which you wish to implement specific recovery. Catch sealed or leaf exceptions in general. Annotation (Eric Gunnerson): I sometimes restate this as, “only catch if there’s something useful you can do”. If you can’t say something like, “oh, I’d tell the user and ask them to enter the data again” or “I’d try to fail over to the backup server”, then you shouldn’t be trying to recover from the exception. There are often cases where you want to catch/log/rethrow, but since this doesn’t affect the final result, it’s really not relevant to this discussion.

Do not swallow base or general exceptions. Catch expected exceptions; do not attempt to handle unexpected exceptions by catching a base type such as System.Exception. Doing so is equivalent to ignoring an error return value in functional programming.

Do re-throw using throw; when catching all to unwind functionality.

161

.NET Framework Design Guidelines Microsoft Confidentialpublic void DoSomething(FileStream fs){ Int64 pos = fs.Position; try{ ... // do some reading with fs }catch{ fs.Position = pos; // unwind on failure throw; // rethrow }}

Do not catch a general exception and wrap it in a more specific exception.This is just another form of swallowing base exceptions. You are encouraged to catch implementation level exceptions and wrap them in an exception that is more appropriate for users of your component if the user is very likely to handle the exceptions in the exact same way. For example, it is reasonable to map FileNotFoundException and XmlParseException in a configuration system because the user is likely to handle these in the same way. catch (FileNotFoundException e){    throw ConfigFileException("File not found", e);}catch (XmlParseException e){    throw ConfigFileException("Invalid XML in config file", e);}

Annotation (Eric Gunnerson): The guideline means that you should not do:catch (Exception e){    throw ConfigFileException("Error doing x", e)}the problem here is that every exception telescopes down to one type, and the handler for FileNotFoundException is unlikely to be correct for OutOfMemoryExcpetion.

To state it another way, your goal should be to make, for reasonable use scenarios that users don't have to write:catch (Exception e){    if (e.InnerException.GetType() == typeof(FileNotFoundException)    {        // recovery for file not found here    }}Because they're very likely to make the error that I made.

Do put cleanup code in finally blocks.Even code that immediately follows a catch() can be interrupted by an asynchronous exceptions (an exception caused by another thread, such as ThreadAbortException. Once the try block is entered, your cleanup code will be guaranteed to run if you put it in a finally block. Notice that the CLR uses a two pass exception model which means that exception filters147 all the way up the call stack are executed after the catch block but before the finally block. TODO: annotation on RudeThreadAbort() why we did it how it effects this guidelineIncorrect: Cleanup() will not be executed in the face of an asynchronous exception

try

147 Exception filters are not supported by C#, but supported by VB, IL, etc

162

.NET Framework Design Guidelines Microsoft Confidential { //... } catch //catching *ALL* exceptions and

// swallowing them { //... } //Execute clean up in the exceptional and

//non-exceptional case Cleanup();

Correct: Cleanup() will be executed even in the face of an asynchronous exception148 try { //... } catch // catching *ALL* exceptions and

// swallowing them { //... } finally { //Execute clean up in the exceptional and

// non-exceptional case Cleanup(); }

Notice that in this example we catch all exceptions, that is rarely the correct coding practice. It is used here to better illustrate the point of the guideline. Please see section X.y on exception handling.

Many methods perform some form of cleanup. All methods that perform cleanup should do so in a finally block. Here is an example:public void UpdateSet(){ Set mySet = new Set(); try{ foreach (string s in GetValues() ) { mySet.Add(s); } ... }finally{ Set.Close(); }}

Do unwind functionality that was unable to complete due to an unexpected exception. Remember to re-throw after unwind.

148 There are some async exceptions such as StackOverflow and Rude Aborts that can cause even code in the finally to be skipped.  However these situations are relatively rare and don't change the spirit of this guideline.

163

.NET Framework Design Guidelines Microsoft Confidentialpublic void DoSomething(FileStream fs){ Int64 pos = fs.Position; try{ ... // do some reading with fs }catch{ fs.Position = pos; // unwind on failure throw; // rethrow }}

Do wrap specific exceptions in a more descriptive exception when appropriate.public Int32 GetInt(Int32[] array, Int32 index){ try{ return array[index]; }catch(IndexOutOfRangeException e){ throw new ArgumentOutOfRangeException( “Parameter index is out of range.”); }}

Do be aware that exceptions could happen at any place, not just method calls. For example OutOfMemoryException, TypeLoadException, ExecutionEngineException can happen anytime.

7.4 Standard Exception TypesThe following table breaks down the standard exceptions provided by the runtime and the conditions for which you should create a derived class.

Exception Type Base Type Description ExampleException Object Base class

for all Exceptions. Do not throw this exception.

SystemException Exception Base class for all Framework or OS generated errors. Do not throw this exception.

IndexOutOfRangeException SystemException Thrown only by the runtime when an array is indexed

Indexing an array outside of its valid range: arr[arr.Len

164

.NET Framework Design Guidelines Microsoft Confidential

improperly. gth+1]NullReferenceException SystemException Thrown only

by the runtime when a null object is referenced.

object o = null; o.ToString();

InvalidOperationException SystemException Thrown by methods when in an invalid state.

Calling Enumerator.GetNext() after removing an Item from the underlying collection.

ArgumentException SystemException Base class for all Argument Exceptions. Derived classes of this exception should be thrown where applicable.

Used when argument passed into a member is not appropriate for that member.

ArgumentNullException ArgumentException

Thrown by methods that do not allow an argument to be null.

String s = null; "foo".IndexOf (s);

ArgumentOutOfRangeException

ArgumentException

Thrown by methods that verify that arguments are in a given range.

String s = "string"; s.Chars[9];

InteropException SystemException Base class for exceptions that occur or are targeted at environment

Used in Interop.

165

.NET Framework Design Guidelines Microsoft Confidential

s outside of the runtime.

ComException InteropException Exception encapsulating COM Hresult information.

Used in COM Interop.

SEHException InteropException Exception encapsulating Win32 structured Exception Handling information.

Used in unmanaged code Interop.

ArgumentException UsageArgumentException and its subtypes have a ParamName string property that represents the name of the parameter that caused the exception to be thrown.

Do use the specific, appropriately cased parameter name when throwing ArgumentException (or a derivative of ArgumentException) from a method

Example: A method is called GetAttributes, and receives a string parameter, being the path to the file to retrieve the attributes for:

static FileAttributes GetAttributes( string path );

If path is null, it throws an ArgumentNullException:

System.ArgumentNullException: Value cannot be null.

Parameter name: path

Do use ‘value’ for the name of the parameter, when throwing an ArgumentException (or a derivative of ArgumentException), from a property.

If we had a property for the same function above, it might look like this:

FileAttributes Attributes { get; }

And we would see this message if the path to the file had not been set:

System.ArgumentNullException: Value cannot be null.

Parameter name: value

7.5 Wrapping Exceptions

166

Krzysztof Cwalina, 13/12/04,
This section needs to be improved. People need more guidance on when to wrap and when not to wrap.

.NET Framework Design Guidelines Microsoft ConfidentialErrors that occur at a layer below where your component sits should be wrapped in an exception that is meaningful to your target users and thrown. It is important to note that the catch statement should catch specific exceptions, not a generic Exception or SystemException.public class ConfigurationReader { public string ReadConfiguration(string key) { try { //read the configuration file } catch (FileNotFoundException e) { throw new ConfigurationFileMissingException ("Configuration file missing", e); } }}

8 Usability

8.1 Problem DefinitionOne of the main goals for the .NET Framework is to create a development platform that is both powerful and easy to use for a wide range of developers. The first version of the Framework indeed provided developers with a powerful set of APIs, but some developer groups found parts of the Framework too difficult to use. Customer feedback and usability studies have shown that a large segment of the VB6 customer group has problems migrating to VB.NET. Part of the problem lays simply in the fact the Framework is different from VB6, but also in several usability issues related to the APIs themselves. Fixing the problem has become a high priority.We will call a platform that is both powerful and easy to use a Progressive Platform. Designing a truly Progressive Platform is not easy. We want to avoid a situation with multiple separated frameworks (VB, ATL, MFC, Win32) for each developer group. Although this approach has proven to be successful in providing APIs optimized for specific developer, it has significant drawbacks. The multiple framework approach creates situation where developers have difficulty transferring knowledge to the next skill and scenario level. When there is a need for them to implement a scenario using a different framework, developers hit a very steep learning curve (see Fig. 1 below).

167

Krzysztof Cwalina, 12/13/04,
Should we rename and even move this section?
Krzysztof Cwalina, 12/13/04,
Get a "real" example here

.NET Framework Design Guidelines Microsoft ConfidentialFig. 1A Progressive Platform that allows for transfer of knowledge from less advanced to more advanced scenarios is a superior approach. Providing a single platform with a gradual learning curve encourages developers to acquire new skills. Easing the cost of acquiring skills in our developer community translates to more and better applications targeting our platform. An additional benefit is developer loyalty; developers have less of a reason to migrate to competition platforms when business needs require them to implement more advanced scenarios.Some other benefits of a single and powerful programming framework include the following: Quicker time to market for new APIsLess duplication of effort.Common tools. The .NET Framework provides such gradual learning curve. The problem we face is that the curve starts too high, creating a barrier to entry for many developers. Until this problem is addressed, the point about advancing, acquiring, and transferring skills is moot. We need to lower the left side of the curve (see Fig. 2 below).

Fig. 2 We believe that achieving a gradual learning curve that with a low entry point is difficult but not impossible. It is difficult because it requires a new approach to the process of Object Model design, much greater design discipline, and has higher design costs.

Though, we need to keep in mind that the developer community is vast. It ranges from office workers recording macros to low level device driver authors. Any framework that attempted to serve all of those users will end up being a mess that could not satisfy any of them. The goal for the .NET Framework and LAPI is to scale though a broad range of developers, not all developers. Clearly this means that those developers that fall outside this target will need specialty APIs. However we feel that this is a very limited and focused set of work.

168

.NET Framework Design Guidelines Microsoft Confidential

It is our intention that the vast majority of the platform is natively exposed to VB, C# and C++ developers with no need for language specific APIs. The Framework and LAPI are targeting a set of developers that have different needs and personalities. This set includes the opportunistic developer Mort, the pragmatic developer Elvis, and the paranoid developer Einstein. Read more about them at http://ddwww/teams/usability/personas/.Some examples of language specific APIs are the MyDot work the VB team is doing for the VB developer. This work organizes and scopes concepts in the .NET Framework in order to make them much easier to find. At the other extreme the VC++ team is implementing the Standard Template Library to provide C++ developer familiar collections. Both of these libraries are done in a way that does not arbitrarily duplicate work in the Framework. They each target a very focused audience and scenarios, and interoperate well with the NET Framework.

8.2 Core Principles of Progressive API DesignThe following Principles are meant to help API designers in avoiding common API usability problems reported in many usability studies and in the customer feedback. We assert that the principles are central to any API design. Some of principles and recommendations are overlapping, which is probably a testimony to their validity.

8.2.1 Principle of Scenario-Driven Design

169

C#

VB

C++

.NET Framework Design Guidelines Microsoft ConfidentialAPI specifications should be driven by scenarios. This means API designers should first write the code that the users of the API will have to write in main scenarios, and then design the Object Model to support these code samples. API designers often make the mistake of starting with the design of the Object Model (using various design methodologies) and then write code samples based on the resulting API. We assert that a good list of scenario with code samples and a header-style Object Model description work best for public API design. Object Model diagrams work great for internal architecture designs, but not for main scenario public API designs.In general, OOD methodologies (e.g. UML) are optimized for maintainability of the resulting design not for usability of the resulting APIs. They are best suited for internal architecture designs not for designs of the API layer of large reusable libraries. Large API design is not something many people do. Because of that, there is no well-established design methodology for library API design. Some of the practices described here can be seen as a rudimentary form of such a methodology.Teams developing reusable libraries should start with producing a scenario-driven API specification. This specification can be either separate from the functional specification or can be bundled together in one specification document. In the latter case, the API specification should precede the functional one in location and time. The scenario section should list the top 5-10 scenarios for given technology area and show code samples that implement these scenarios. The code samples should be in at least two CLR languages (VB.NET, C#, MC++, Avalon Markup). This is very important as sometimes code written using those languages differs significantly. It is also important that these scenarios be written using different coding styles common among users of the particular language (using language specific features). The samples should be written using language specific casing. For example, VB.NET is case-insensitive, so samples should reflect that. C# code should follow the standard casing described in the naming section of the Design Guidelines.

Practice: The API design specification should be the central part of any feature design that includes a publicly accessible API. The scenario section should appear immediately following the executive overview section. You should not design your API first and then write scenario samples. You should write code that users of your library will write when accessing your feature, and then design your object model to support these code samples.

In a few cases, we shipped APIs designed, implemented, and tested using C# that were totally unusable from VB.NET. For example, VB.NET does not allow assignments and evaluation of a conditional in a single statement so that “while(character = file.ReadChar() != EOF)” needs to be implemented as a complicated loop with multiple ReadChar calls and an if statement. Writing samples in multiple languages may be a significant burden but it does provide true benefits.

Usability StudiesUsability studies with a wide range of developers are the key to Scenario-Driven Design. The code that you write for your top scenarios may seem simple to you, but might not actually be that simple to other groups of developers that we are targeting (Mort in particular). Additionally, understanding the way that developers approach each of your scenarios will provide useful insight into the design of your API and how well it meets the need of all of your target developers. You should conduct usability studies of the top scenarios. If the majority of developers cannot implement one of the scenarios, or if the

170

.NET Framework Design Guidelines Microsoft Confidentialapproach they take is significantly different to what you expected, you may need to redesign the API.Note: We did not test usability of the types in the System.IO namespace before shipping version 1.0 of the Framework. Soon after shipping, we received negative customer feedback about System.IO usability. We were quite surprised and decided to conduct usability studies with 8 average VB developers. None of them could read from a file in the 30 minutes we allocated for the task. We believe this was due in part to problems with the documentation search engine and insufficient sample coverage; however it is clear that the API itself had several usability problems. If we had conducted the studies before shipping the product, we could have eliminated a significant source of customer dissatisfaction and avoided the cost of trying to fix the API of a major feature area without introducing breaking changes.

The studies should ideally be performed using the actual development environment with intellisense, editors, and the documentation set most widely used by the targeted developer group. However, it is best to run usability studies early rather than late in the product cycle, so don’t postpone organizing a study just because the whole product is not ready yet.

We have run successful API usability studies in the past using just Notepad and the command line compilers and have been able to provide teams with useful feedback and guidance early on in the cycle.

On top of this, tools are available to you that can be used by you in conjunction with the usability group to gather usability data about your API even before any of your API has been implemented. The Cognitive Dimensions framework is a model for describing the usability of an API and can be used to compare an API with the usability requirements of the different developer personas. You can read more about the framework at http://ddwww/SpecTool/Documents/Usability/DotNet%20APIs/User%20Models/Cognitive%20Dimensions%20of%20APIs%20and%20Developers.doc and http://ddwww/SpecTool/Documents/Usability/DotNet%20APIs/User%20Models/General%20usability%20principles%20for%20designing%20an%20APIv1.doc

Practice: Organize usability studies to test the top scenarios in your feature area. Most subjects should be able to write code for these scenarios without major problems; if they cannot, you need to redesign the API. The studies should be conducted early in the product cycle and again after any major redesign of the object model. While this is a costly practice, we found that it actually saves resources in the long run. The cost of fixing an unusable API without breaking changes is enormous.

8.2.2 Principle of Customizable DefaultsMany developers prefer to code by trial and error as opposed to taking the time to read the documentation and fully understand the feature area. This is particularly true for VB developers. These developers often try to experiment with an API to discover what it does, and adjust their code slowly to get the API to do what they really want. The huge demand for the Edit & Continue feature is a manifestation of this preference. It should be noted that many developers do take time to understand the overall design of the API and do find informative, concise documentation to be a very important part of the product. The fact that some developers prefer learning by experimentation should not be used as an excuse for documentation that is not accessible to a

171

.NET Framework Design Guidelines Microsoft Confidentialwide range of users. The preference is being reinforced when these developers encounter problems in the documentation. Some designs lend themselves to "code by experimentation" and some do not. There are several factors that determine the level of success a developer will achieve using this approach: How easy it is to locate the right API for the task How easy it is to start using an API, regardless of whether it what the developer want

it to do or not How easy it is to discover what the points of customization are for a API How easy it is to discover the correct customization for given scenarioAPIs should be designed to require minimal initialization. Ideally, a default constructor or a constructor with one simple parameter should be sufficient to start working with a type.

` VBDim Owners As New Hashtable()Owners.Add(“System”, “KitG”)Owners.Add(“System.Diagnostics”, “KCwalina”)

// C#Hashtable owners = new Hashtable();owners.Add(“System”,”KitG”);owners.Add(“System.Diagnostics”,”KCwalina”);

Note: System.Data is an example of a feature area that our customers found extremely difficult to use because of the extensive initialization it requires. Even in the simplest scenarios, users are expected to understand complex interactions and dependencies between several object. To use this feature, even in simple scenarios , users must instantiate and hook up several objects (instances of DataSet, DataAdapter, SqlConnection, and SqlCommand).

If some initialization is necessary, the exception that results from not performing the initialization should clearly explain what needs to be done.

‘ VBDim File As New FileObject()‘ If the following line is commented out, an exception saying ‘ “Filename property needs to be set” should be thrown.File.Filename = “c:\foo.txt”File.OpenWrite()File.WriteLine(“Hello World”)File.Close()

Practice: Method specifications should list main preconditions and state what exceptions are thrown if the preconditions are not met. The error messages must be included. For example, the specification for FileObject.WriteLine should state that an InvalidOperationException with a message “The Filename property needs must be set.” is thrown when Filename is an empty string.

A rule of thumb is that the simplest constructor should not have more than 3 parameters and more than 5 is unacceptable. In addition, the simplest constructors should not use complex types as any of the parameters. They should rely on primitive types like enumerations, strings, and integers. Of course, types may implement more complex constructor overloads to support more complex scenarios.

172

.NET Framework Design Guidelines Microsoft ConfidentialAn API can simplify its customization by providing properties with good defaults for all customization points. It is very important that developers are able to add new code to the existing code when customizing their scenarios; they should not be required rewrite the code from scratch using different API.

‘ VBDim File As New FileObject()‘ if the following line is commented out, an exception saying ‘ “Filename property needs to be set” should be thrown.File.Filename = “c:\foo.txt”

File.Encoding = Encoding.Ascii

File.OpenWrite()File.WriteLine(“Hello World”)File.Close()

// C#// I think I will have between 80 and 100 items.Hashtable owners = new Hashtable(100);owners.Add(“System”,”KitG”);owners.Add(“System.Diagnostics”,”KCwalina”);

Practice: API Specification samples should show progression from simple scenarios to more advanced scenarios. Each subsequent sample should show additional code in bold font. Reviewers should pay special attention to how code changes as the scenarios get more advanced.

These recommendations cannot be applied blindly. API designers should avoid providing defaults if the default can lead the user astray. For example, a default should never result in a security hole.Note: System.Messaging.MessageQueue is a good illustration of the concept. The component can send messages after passing just a path string to the constructor and calling the Send method. The message priority, encryption algorithms, and other message properties can be customized by adding code to the simple scenario.

8.2.3 Principle of the Aggregate ComponentMany feature areas may benefit from façade types that act as simplified views over more complex but well-factored rest of the feature area APIs (Factored Types). The façade should cover the top 5-10 scenarios in a given feature area and possibly other high-level operations. We will call such types Aggregate Components. An Aggregate Component should ties multiple lower level factored classes into a higher-level component to support these common scenarios. An example might be a Mail component that ties together SMTP protocol, sockets, encodings, etc. It is key that an Aggregate Component provides a higher abstraction level rather than just a different way of doing things.Providing simplified high-level operations, is crucial for those developers who do not want to learn whole extent of the functionality provided by the feature and just need to get their often very simple tasks done (majority of our customers). Again, as with any duplication, Aggregate Component should only be used when they provide significant, demonstrable value.

173

.NET Framework Design Guidelines Microsoft ConfidentialNote: System.Net.WebClient is an example of an Aggregate Component. It provides an API for simple scenarios in the System.Net namespace. Other examples of such components include: System.Messaging.MessageQueue, and System.Diagnostics.EventLog.

Aggregate Components frequently integrate with Visual Studio designers (implement IComponent). This means they can be dropped onto a Form or a non-visual design surface area such as the Windows Service Application designer. VS integration may substantially improve usability of an Aggregate Component; IComponent properties are settable through the property grid, complex properties can have value editors, etc. Integration with the VS designers is actually quite simple. The basic integration support can be provided by not much more that just inheriting from the Component class, but it gives a tremendous boost to developers who code by experimentation as discussed in section . It is also a great for discoverability; being on the Toolbox, it immediately points the user to the starting place for exploring the feature area.

Component Oriented DesignComponent Oriented Design is a design based on constructors, properties, methods, and events. Aggregate Component is an extreme application of the Component Oriented Design. Constructors: Aggregate Components must have default constructors.Constructors: All constructor parameters correspond to properties.Properties: Most properties have getters and setters. Properties: All properties have sensible defaults.Methods: Methods do not take parameters if the parameters specify options that stay constant across method calls (in the main scenarios). Such options should be specified using properties. Events: Methods do not take delegates as parameters. All callbacks are implemented in terms of events.Component Oriented Design actually has more to do with the way the API is used than with the mere inclusions of the methods, properties, and events in the Object Model. The usage model for Component Oriented Design follows a pattern of instantiating a type with a default or relatively simple constructor, setting some properties on the instance, and finally calling simple methods. We call such pattern the Dim-Set-Call usage pattern.

‘ VB‘ InstantiateDim T As New T()

‘ Set properties/options. T.P1 = V1T.P2 = V2T.P3 = V3

‘ Call methods; optionally change options between calls.T.M1()‘ T.P3 = V4T.M2()

A concrete code example showing the Dim-Set-Call usage pattern would look like the following.

174

Krzysztof Cwalina, 12/13/04,
Page: 9 We will be writing a white paper on the subject. ETA 5/1/2003.

.NET Framework Design Guidelines Microsoft Confidential‘ VB‘ InstantiateDim File As New FileObject()

‘ Set properties.File.Filename = “c:\foo.txt”File.Encoding = Encoding.Ascii

‘ Call methods.File.Open(OpenMode.Write)File.WriteLine(“Hello World”)File.Close()

It is very important that all Aggregate Components support this usage pattern. The pattern is something that main users of Aggregate Components expect and tools, like intellisense and designers, are optimized for.The biggest problem with Component Oriented Design is that it results in types that can have modes and invalid states. For example, a default constructor allows users to instantiate a MessageQueue Component without providing a valid path. Another problem is that properties, which can be set optionally and independently, do not enforce consistent and atomic changes to the state of the object. The benefits of Aggregate Components outweigh these problems.When users call methods that are not valid in the current state of the object, an InvalidOperationException should be thrown. The exception’s message should clearly explain what properties need to be changed to get the object into a valid state.Often, API designers try to design types so that objects cannot exist in an invalid state. This is accomplished by having all required settings as parameters to the constructor, having get-only properties for settings that cannot be changed after instantiation, and breaking functionality into separate types so that properties and methods do not overlap. This approach is strongly recommended for Factored Types (see section below) but does not work for Aggregate Components. For Aggregate Components, we recommend relying on clear exceptions for communicating invalid states to the user. The exceptions should be thrown when an operation is being performed, not when the component is initialized (i.e. constructor called or property is being set). This is important to avoid situations where the invalid state is temporary and gets “fixed” in a subsequent line of code.

// C#PerformanceCounter workingSet = new PerofrmanceCounter();workingSet.Instance = process.ProcessName;// exception is not thrown here despite that the counter is in an // invalid state (counter is not specified).

workingSet.Counter = “Working Set”; // state is “fixed” here!workingSet.Category = “Process”;

Debug.WriteLine(workingSet.NextValue());

Factored Types As described in the section above, an Aggregate Component provides shortcuts for most common high level operations and is usually implemented as a façade over a set of more complex but also richer types. We will call these types Factored Types.

175

.NET Framework Design Guidelines Microsoft ConfidentialFactored Types should not have modes, and should have very clear lifetimes. An Aggregate Component may provide access to its internal Factored Types through some properties or methods. Users would access the internal Factored Types in advanced scenarios or in scenarios where integration with different parts of the system is required. The following example shows an Aggregate Component (FileObject) exposing its internal Factored Type (StreamWriter).

`VBDim File As New FileObject(“c:\foo.txt”)File.Open(OpenMode.Write)File.WriteLine(“Hello World”)AppendMessageToTheWorld(File.StreamWriter)File.Close()…

Public Sub AppendMessageToTheWorld(ByVal Writer As StreamWriter) …End Sub

Note: An easy trick to increase visibility of an Aggregate Component is to choose the most “attractive” name for the Component and less attractive names for the corresponding Factored Types. For example, a name representing a well-known system entity like “File” will attract more attention than “StreamReader”.

High Level OperationsAggregate Components, as high level APIs, should be implemented so they magically work without the user being aware of sometimes complicated things happening underneath. We often refer to this concept as a It-Just-Works. For example, EventLog component hides the fact that a log has read handle and write handle, which need to be opened. As far as user is concerned, the component can be instantiated, properties can be set, and log events can be written.Sometimes, a bit more transparency is required. We recommend more transparency for operations if the user would be required to take an explicit action as a result of an operation. For example, implicitly opening a file and then requiring the user to explicitly close it is probably taking the principle of “It Just Works” a bit too far. Said that, it is often possible to design clever solutions that hide even those complexities. For example, reading a file can be implemented as a single operation that opens a file, reads its content, and closes it, thus shielding the user from all the complexities related to opening and closing the file handles.

// C#StringCollection lines = File.ReadAllLines(@”c:\foo.txt”);

Users of Aggregate Components must not be required to implement any interfaces, modify any configuration files, etc. Library designers should ship default implementations all interfaces they declare. All configuration settings should be optional and backed by sensible defaults. Tools and IDE features should be considered for all common development tasks that are required beyond writing simple lines of code. In other words, library designers should provide full end-to-end solutions, not just the APIs. Note: The System.ServiceProcess namespace greatly simplifies development of Windows Service applications. The library would be more successful if writing a service relied on hooking up event handlers instead of requiring the developer to override methods.

176

.NET Framework Design Guidelines Microsoft Confidential8.2.4 Principle of Self Documenting Object Models

Some developers prefer to code by trial and error and resort to reading documentation only when their intuition fails them. We should design APIs that do not require that developers read documentation every time they want to perform a simple task. We found that following a simple set of guidelines can help in producing intuitive APIs that are relatively Self Documenting. Note: Documentation is still very important. It is impossible to design a completely self-documenting API. Different people, based of skills and past experiences, will find different areas of you library to be self-explanatory. Also, the documentation of your functionality remains critically important for some users and reading a concise, well-written introduction is often exactly what developers want to start with when approaching a new problem.

NamingThe simplest, but also most often missed opportunity for making Object Models self-documenting is to reserve simple and intuitive names for types that users need to use (instantiate) in the most common scenarios. Designers often “burn” the best names for abstractions, with which most users do not have to be concerned. For example, naming the abstract base class File and then providing a concrete type NtfsFile works well if the expectation is that all users will have to understand the inheritance hierarchy before they can start using the APIs. If the users do not understand the hierarchy, the first thing they will try to use, most often unsuccessfully, is the File type. Note: The designers of the .NET Framework spent a lot of time discussing naming alternatives for main types. The majority of the identifiers in the Framework have well-chosen names. The cases where the name choices are not so fortunate resulted from focusing on concepts and abstractions instead of focusing on the top scenarios.

The second recommendation is to use descriptive identifier names that clearly state what each method does and what each type and parameter represents. API designers should not be afraid to be quite verbose when choosing identifier names. For example, EventLog.DeleteEventSource(string source, string machineName) may be seen as rather verbose but we think it is not overly verbose and has positive net usability value. Another thing to keep in mind is that type and parameter names should state what a type or a parameter represents, not what it does. Method names should state what the method does.Verbose method names are only possible for methods that have simple and clear semantics. This is another reason why avoiding complex semantics is a great general design principle to follow. The overall point is that the names of identifiers need to be chosen extremely carefully. Name choices are one of the most important design choices API designers will have to make. It is extremely difficult and costly to make changes to identifier names after the API shipped.

Practice:

177

.NET Framework Design Guidelines Microsoft ConfidentialMake the discussion about naming choices a significant part of specification reviews. What are the types most scenarios start with? What are the names most people will think of first when trying to implement this scenario? Are the names of the common types what users will think of first? For example, since “File” is the name most people think of when dealing with file I/O scenarios, the Aggregate Component for accessing files should be named “File”. Also, you should discuss the most commonly used methods of the most commonly used types and all of their parameters. Can anybody familiar with your technology, but not this specific design, recognize and call those methods quickly, correctly, and easily?

Practice:UE should be involved early in the design process. UE can be a great resource for spotting designs with bad name choices and designs that would be difficult to explain to the customer.

ExceptionsExceptions are a crucial part of Self-Documenting APIs. APIs should lead the user to do the next required thing. Exceptions are great for communicating what is required next. For example, the following sample code should throw an exception with a message “The Path property needs to be set before sending a message to a queue.”

// C# MessageQueue queue = new MessageQueue();// The path is not set.

queue.Send(“Hello World”);

Strong TypingStrong typing is probably the single most important factor determining how intuitive APIs are. Clearly, calling Customer.Name is easier than calling Customer.Properties[“Name”]. Also such Name property returning the name as a String is more usable than if property returned an Object. There are cases where property bags with a string based accessor, late bind calls, and other not strongly types APIs are desired, but they should be an exception to the rule rather than a common practice. Moreover, designers should consider providing strongly typed helpers for the most common operations that the user would perform on the non-strongly typed API layer. For example, the Customer type may have a property bag but in addition provide strongly typed APIs for most common properties like “Name”, “Address”, etc.

ConsistencyConsistency with an existing APIs that are already familiar to the user is yet another powerful technique for designing Self-Documenting APIs. This includes consistency or similarity to some other API in the Framework as well as similarity to some legacy APIs. Do not try to be similar to an API with known design problems (some Framework parts have plenty of them), but also do not change good established patterns and designs without having a good reason to do it.

178

.NET Framework Design Guidelines Microsoft ConfidentialKeeping Things Simple

Standard design methodologies are aimed at producing designs that are optimized for maintainability. This makes sense as the maintenance cost is the largest chunk of the overall cost of developing a software product. One way of improving maintainability is through the use of abstractions. Because of that, modern design methodologies produce a lot of them. The problem is that those design methodologies often assume that users of the resulting designs will become experts in that design before starting to implement even simple scenarios. We found that in the real world, that is often not the case. For simple scenarios, developers demand that Object Model hierarchies be simple enough so that they can be used without having understood how the entire feature area fits together. This is something that the standard design methodologies are not optimized for, and never claimed to be optimized for. A well-designed API requires the developer to understand the scenario being implemented, not the design of the library being used to implement it. Common scenario APIs should not be abstractions but rather should correspond to physical or well-known logical parts of the system. Types that correspond to abstractions are hard to use without understanding the how all the parts of the feature area fit together and are only useful when cross-feature integration is required. Abstractions are almost always necessary but too many abstractions indicate over- engineered systems. We should be careful to design for customers, not for our own intellectual pleasure. Because of the reasons mentioned above, we recommend using standard design methodologies (UML for example) when designing the internal architectures and some of the Factored Types (see Principle of the Aggregate Component) but not when designing the common scenario APIs. We do not have a good design methodology for API design but some of the principles described in this document should provide informal guidance.

Practice: Do not use UML or any other standard design methodology when designing the common scenario APIs. Scenario Driven Design together with prototyping, usability studies, and iteration is a much better approach.

Practice: Contact the VB.NET team or the RADSwat alias to better understand Mort (Persona representing an average VB developer). The VB team can provide you with presentations, usability study reports, feedback, and get you in touch with Morts. Do this early in the design phase. Some usability problems are very costly to fix after the specifications are written.

Clean NamespacesTypes that are used for more advanced scenarios should be placed in sub-namespaces to avoid clutter of the main namespaces. The root namespace of a feature area should contain primarily the Aggregate types while more advanced factored types should be found in subnamespaces.Technology Root Namespace Aggregate or High-level Types.

179

.NET Framework Design Guidelines Microsoft Confidential Core Factored Types [<EditorBrowsable(Advanced), or using “level” in XML comment.] AdvancedSubNamespace1 Advanced Factored Types AdvancedSubNamespace2 Advanced Factored TypesWe have identified several groups of types that should be separated from their main namespaces: Permission types should reside in a .Permissions sub-namespace. Design time only types should reside in a .Design sub-namespace.In the initial design of the .NET Framework namespaces, all types related to given feature area were in the same namespace. During our post Beta 1 cleanup milestone, we moved design-related types to Design sub-namespaces. Unfortunately, we did not have time to do it for the Permission types. This is a problem in several parts of the Framework. For example, a large portion of the types in the System.Diagnostics namespace are types needed for the security infrastructure and very rarely used by the end users of the API.

8.3 Summary of Usability Guidelines

8.3.1 General Usability Guidelines Do design APIs for a wide range of developers with different programming styles and

skill levels. Do learn about developer personas to better understand the range of developers we

are targeting with the platform. Do strictly follow the Design Guidelines even if some of the guidelines may conflict

with expectations of some developer groups. The guidelines are designed to target wide range of developers. We will provide specialty APIs for developers outside of the range.

Do design APIs that are both powerful and easy to use in main scenarios. We call such APIs Progressive APIs.

8.3.2 Scenario Development Guidelines Do define top high-level scenarios for each major feature area. These scenarios

should be described in the API specification document. Average feature area should have 5 to 10 main scenarios.

Do ensure that the scenarios correspond to appropriate abstraction level. They should roughly correspond to Use Cases. For example, reading from a file is a good scenario. Opening a file, reading a line of text from a file, or closing a file are not good scenarios; they are too low-level.

Do design main feature area APIs by first writing code samples for the main scenarios and then defining the Object Model to support the code samples.

180

.NET Framework Design Guidelines Microsoft Confidential Do write main scenario code samples at least two different CLR languages (for

example VB.NET, C#, MC++, Avalon Markup). Do not start API design with Object Model diagrams. Object Model diagrams of the main

Object-Oriented design methodologies are optimized to produce architectures that are easy to maintain, not to produce APIs that are easy to use.

Do organize usability studies to test APIs in main scenarios. The studies should be organized early in the development cycle as the most severe usability problems often require substantial design changes.

8.3.3 Usable Object Model Design Guidelines Do ensure consistency with other parts of the Framework. Consistency is great for

usability. If a user is familiar with some part of the Framework that your API is similar to, they will see your design as natural and intuitive.

Do design APIs that are easy to experiment with. Main factors that make APIs difficult to experiment include: It is difficult to find which type is the starting point in implementing simple scenarios. Extensive initialization is required before types can be used. For example,

constructors take lots of complex parameters or properties do not have sensible defaults. A variation of the problem is that some APIs require users to instantiate multiple types and know hook them up together even in the simple scenarios.

Methods that do not provide simple overloads for the most common tasks. Do provide simple, ideally default, constructor overloads. A simple constructor has a

very small number of parameters, and all parameters are primitives or enumerations. Avoid constructor and method families with the simplest overload having more than 3

simple parameters. Do not have constructor or method families with the simplest overload having more

than 5 parameters. Do provide properties as points of customization for objects. Users should be able to

change what their code is doing by setting properties (to a limit), not by rewriting the code from scratch.

Do provide sensible defaults for all properties as long as the defaults do not result in a security hole or a horribly inefficient design.

Do favor properties over method parameters wherever they make sense. Do provide simple method overloads. A simple method overload has a very small

number of parameters, and all parameters are primitives. Avoid methods that cannot be called on an object instantiated with a simple constructor

because the method requires further initialization of the object. If this is unavoidable, throw an exception clearly stating in the message what needs to be initialized. Usually an InvalidOperationException should be thrown in such cases.

Do not ship any interfaces or abstract types without at least one concrete implementation.

181

.NET Framework Design Guidelines Microsoft Confidential Do design APIs that are intuitive and can be used without constantly referring to the

documentation. Do provide great documentation with all APIs. Not all APIs can be self-explanatory

and there are developers who want to thoroughly understand APIs before they start using them.

Do not be afraid to use verbose identifier names. Most identifier names should clearly state what each method does and what each type and parameter represents.

Do use exception messages to communicate programming mistakes to the user. For example, if a user forgets to set the Path property on a MessageQueue component, any call to a method that requires the Path to be set should state this clearly in the exception message.

Do provide strongly typed APIs. Do not rely exclusively on weekly typed APIs such as property bags. In cases where a property bag is required, provide strongly typed properties for the most common properties in the bag.

Consider placing Code Access Security related types in .Permissions sub-namespace of your main namespace. Consider placing design time related types in .Design sub-namespace. Permission and design time related types are very rarely used by the end user and placing them in a separate namespaces simplifies the main namespace.

8.3.4 Aggregate Component Guidelines Consider providing Aggregate Components in major feature areas. Aggregate

Components provide high-level functionality and are starting points for exploring given technology. They should provide shortcuts for common operations and add significant value over what is already provided by Factored Types. They should not simply duplicate the functionality. Many main scenario code samples should start with an instantiation of an Aggregate Component.

Do model high-level concepts (physical objects) rather than system-level tasks with Aggregate Components. For example the components should model Files, Directories, and Drives, not Streams, Formatters, or Comparers.

Do increasing visibility of Aggregate Components by giving them names that correspond to well known entities of the system. For example File, Directory, MessageQueue, or EventLog.

Do design Aggregate Component so that they can be used after very simple initialization. If some initialization is necessary, the exception resulting from not having the component initialized should clearly explain what needs to be done.

Do not require the users of Aggregate Components to instantiate multiple objects in a single scenario. Simple tasks should be done with just one object. The next best thing is to start with one object which in turn creates other supporting objects. Your top 5 scenario samples showing Aggregate Component usage should not have more than one new statement.Book publishers say that the number of copies a book will sell is inversely proportional to the number of equations in the book. The API designer version of this law is “The number of customers who will use your API is inversely proportional to the number of new statements in your simple scenarios.

182

.NET Framework Design Guidelines Microsoft Confidential Do make sure Aggregate Components support the Dim-Set-Call usage pattern,

where developers expect to be able to implement most scenarios by instantiating the component, setting its properties, and calling simple methods.

Do provide default constructor for all Aggregate Components. Do provide properties with getters and setters corresponding to all parameters of

Aggregate Component constructors. It should always be possible to use the default constructor and then set some properties instead of calling a parameterized constructor.

Do use events instead of properties and parameters of a delegate type in Aggregate Component design.

Consider using events instead of virtual members that need to be overridden. Do not require users of Aggregate Components to inherit, override methods, or

implement any interfaces in common scenarios. Components should mostly rely on properties and composition as the means of modifying their behavior.

Do not require users of Aggregate Components to do anything besides writing code in common scenarios. For example, users should not have to configure components in the configuration file, generate any resource files, etc.

Conside r making changes to Aggregate Components modes automatic. For example, a single instance of MessageQueue can be used to send and receive messages but the user should not be aware that mode switching is occurring.

Do not design Factored Types that have modes. Factored Types should have well defined lifespan scoped to a single mode. For example, instances of Stream can either read or write and an instantiated stream is already opened.

Consider integrating your Aggregate Components with Visual Studio Designers. Integration allows placing the component on the VS Toolbox, adds support for drag & drop, property grid, event hookup, etc. The integration is simple and can be done by implementing IComponent or inheriting from a type implementing the interface, such as Component, Element, or Control.

Consider separating Aggregate Components and Factored Types into different assemblies. This allows the Component to aggregate arbitrary functionality provided by Factored Types without circular dependencies.

Consider exposing access to internal Factored Types of an Aggregate Component. Factored Types are ideal for integrating different feature areas. For example, FileObject exposes access to its streams, thus allows integration with reusable APIs such as compression APIs that operate on streams.

9 Evolving Managed APIs

9.1.1 Consider Existing Consumers

183

.NET Framework Design Guidelines Microsoft ConfidentialAlways consider existing consumers of an API when modifying and adding new APIs. It is important that an existing consumer can successfully bind to, and function correctly when using a newer version of a library.

Do not change the behavior of the existing API or remove it in favor of a new one, if the existing API is exposed publicly (accessible by anyone not in the same assembly in which the API is defined) and existing clients will be relying on its behavior (this is a breaking change).

Do mark an existing API with the ObsoleteAttribute, if a new API is intended to supersede the existing one, and be a superset of its functionality. The message text for the API being made obsolete should:

1. Be in English

2. Contain a full sentence, ending in a period

3. Include a description of why the API has been made obsolete, if the description is short (less than a line)

For example ‘This method will not function on 64bit machines’

4. Be spelled correctly

5. Typically direct users to an alternate, replacement API. If the API is available on the same class, then use just the name of the API. If the API is on a new class, use the classname, and name of the API

Example

[Obsolete("Use either StartLogicalOperation for stack based operations or ActivityId for a Global ID.")]public void StartActivity(object activityId) { /* … */ }

public void StartLogicalOperation(object operationId) { /* … */ }

public Guid ActivityId { get { /* … */ }; set { /* … */ }; }

9.1.2 NamingNaming new members of existing types or new types of existing namespaces can be difficult. Often the best choice for a name is already taken by an existing member or type.

New identifier names are generally needed when creating a new property or method which differs only by a return type. Otherwise, a new overload of the existing identifier is acceptable, and sometimes preferred.

Do use a name similar to the original API, in order to highlight the relationship between the APIs when the newer version is intended to be a replacement for the original, and is functionally similar

Example class AppDomain {

184

.NET Framework Design Guidelines Microsoft Confidential[Obsolete("AppDomain.SetCachePath has been deprecated. Please use

AppDomainSetup.CachePath instead.")]public void SetCachePath(String path) { /* … */ }

}

class AppDomainSetup {public String CachePath { get { /* … */ }; set { /* … */ }; }}

Do prefer adding a suffix rather than a prefix, in order to distinguish the new API. This will assist discovery when searching using documentation, or intellisense, because the similar behaving APIs will be organized to appear close together when searching (based on alphabetical sorting)

Consider making a brand new, but meaningful identifier, as opposed to adding a suffix/prefix

Do not use the ‘Ex’ suffix for an identifier, in order to distinguish it from an earlier version of the same API. Similarly, avoid distinguishing a new API by adding a meaningless suffix to the end (such as ‘New’).

Example (Of Poor Code)[Obsolete(“This type is obsolete. Please use the newer version of the same type,

CarEx.”)]public class Car { /* … */ }// new APIpublic class CarEx { /* … */ } // the wrong waypublic class CarNew { /* … */ } // the wrong waypublic class Car2 { /* … */ } // the right waypublic class Automobile { /* … */ } // the right way

Do use a numeric suffix to distinguish an API from an existing name, if the existing name of the API is the only name that makes sense (example: it is an industry standard), and adding any meaningful suffix (or changing the name) is not an appropriate option.

Example // old API[Obsolete(“This type is obsolete. Please use the new version of the same class, X509Certificate2.”)]public class X509Certificate { /* … */ }// new APIpublic class X509Certificate2 { /* … */ }

Do use the ‘64’ suffix when introducing versions of APIs which return a 64-bit integer (a long) instead of a 32 bit integer. You only need to take this approach when the existing 32-bit API exists, don’t do it for brand new APIs with only a 64-bit version.

Note this guideline only applies to retro-fitting APIs that have already shipped.  When initially designing an API, use the most appropriate type and name for the API that will work on all platforms. You should not create APIs differentiated from each other by using ‘32’ and ‘64’ for brand new areas, this guideline applies only to a newer version of

185

.NET Framework Design Guidelines Microsoft Confidentialan existing API, where overloads of the existing API aren’t possible (because of name conflict issues).

Example Various APIs on System.Diagnostics.Process return Int32 values representing memory sizes, such as PagedMemorySize, or PeakWorkingSet. To appropriately support these APIs on a 64-bit systems, APIs have been added which have the same name, but a ‘64’ suffixpublic class Process {

// old APIspublic int PeakWorkingSet { get; }public int PagedMemorySize { get; }// …// new APIspublic long PeakWorkingSet64 { get; }public long PagedMemorySize64 { get; }

}

10 GenericsA new feature in CLR that allows classes, structures, interfaces, and methods to be parameterized by the types of data they store and manipulate, through a set of features known collectively as generics. CLR generics will be immediately familiar to users of generics in Eiffel or Ada, or to users of C++ templates, though they do not suffer many of the complications of the latter.Without generics, programmers can store data of any type in variables of the base type object. To illustrate, let’s create a simple Stack type with two actions, “Push” and “Pop”. The Stack class stores its data in an array of object, and the Push and Pop methods use the object type to accept and return data, respectively:public class Stack {

private object[] items = new object[100];public void Push(object data) {...}public object Pop() {...}

}

We can then push a value of any type, for example a Customer type, onto the stack. However, when we wanted to retrieve the value, we would need to explicitly cast the result of the Pop method, an object, into a Customer type, which is tedious to write and carries a performance penalty for run-time type checking:Stack s = new Stack();s.Push(new Customer());Customer c = (Customer)s.Pop();

If we pass a value type, such as an int, to the Push method, it will automatically be boxed. Similarly, if we want to retrieve an int from the stack, we would need to explicitly unbox the object type we obtain from the Pop method:Stack s = new Stack();s.Push(3);int i = (int)s.Pop();

The boxing and unboxing operations can be particularly slow when done repeatedly.186

Krzysztof Cwalina, 12/13/04,
The overview should move to an appendix. The guidelines should be moved to API element sections.

.NET Framework Design Guidelines Microsoft ConfidentialFurthermore, in our current implementation, it is not possible to enforce the kind of data placed in the stack. Indeed, we could create a stack and push a Customer type onto it. Later, we could use the same stack and try to pop data off of it and cast it into a different type:Stack s = new Stack();s.Push(new Customer());Employee e = (Employee)s.Pop();

While the code above is an improper use of the Stack class we want to implement and should be a compile-time error, it is actually legal code and the compiler will not have a problem with it. At run-time, however, the application will fail because we have performed an invalid cast operation.Generics provide a facility for creating high-performance data structures that are specialized by the compiler and/or execution engine based on the types that they use. These so-called generic type declarations are created so that their internal algorithms remain the same, but so that the types of their external interface and internal data can vary based on user preference.In order to minimize the learning curve for developers, generics are used in much the same way as C++ templates. Programmers can create classes and structures just as they normally have, and by using the angle bracket notation (< and >) they can specify type parameters. When the generic class declaration is used, each type parameter must be replaced by a type argument that the user of the class supplies.In the example below, we create a Stack generic class declaration where we specify a type parameter, called ItemType, declared in angle brackets after the declaration. Rather than forcing conversions to and from object, instances of the generic Stack class will accept the type for which they are created and store data of that type without conversion. The type parameter ItemType acts as a placeholder until an actual type is specified at use. Note that ItemType is used as the element type for the internal items array, the type for the parameter to the Push method, and the return type for the Pop method:public class Stack<T> {

private T[] items;public void Push(T data) {...}public T Pop() {...}

}

When we use the generic class declaration Stack, as in the short example below, we can specify the actual type to be used by the generic class. In this case, we instruct the Stack to use an int type by specifying it as a type argument using the angle notation after the name:Stack<int> stack = new Stack<int>();stack.Push(3);int x = stack.Pop();

In so doing, we have created a new constructed type, Stack<int>, for which every ItemType inside the declaration of Stack is replaced with the supplied type argument int. Indeed, when we create our new instance of Stack<int>, the native storage of the items array is now an int[] rather than object[], providing substantial storage efficiency. Additionally, we have eliminated the boxing penalty associated with pushing an int onto the stack. Further, when we pop an item off the stack, we no longer need to explicitly cast it to

187

.NET Framework Design Guidelines Microsoft Confidentialthe appropriate type because this particular kind of Stack class natively stores an int in its data structure.If we wanted to store items other than an int into a Stack, we would have to create a different constructed type from Stack, specifying a new type argument. Suppose we had a simple Customer type and we wanted to use a Stack to store it. To do so, we simply use the Customer class as the type argument to Stack and easily reuse our code:Stack<Customer> stack = new Stack<Customer>();stack.Push(new Customer());Customer c = stack.Pop();

Of course, once we’ve created a Stack with a Customer type as its type argument, we are now limited to storing only Customer objects (or objects of a class derived from Customer). Generics provide strong typing, meaning we can no longer improperly store an integer into the stack, like so:Stack<Customer> stack = new Stack<Customer>();stack.Push(new Customer());stack.Push(3); // compile-time errorCustomer c = stack.Pop(); // no cast required

10.1 Generics Related TerminologyTerm DescriptionGenerics A new CLR feature that allows classes, structures, interfaces, and

methods to be parameterized by the types of data they store and manipulate.

Generic Type Declaration Declaration of a generic type. For example,public class List<T> { public void Add(T item) { … }}

Generic Method For example,public class Utils { public static void Swap<T>(ref T ref1, ref T ref2){ … }}

Type Parameter For example, in the following declaration, K and V are type parameters public class Dictionary<K,V> { …}

Type Argument For example, in the following sample, string and int are both type arguments.Dictionary<string,int> map = new Dictionary<string,int>();

Type Parameter Constraint, or Constraint

For example, in the following sample T is constrained to IComparable.public class List<T> where T:IComparable { public void Add<T>(T item) { … }}

Constructor Constraint For example, in the following sample T has a constructor constraint.public class List<T> where T:new() { public AddNew() { this.Add(new T()) }

188

.NET Framework Design Guidelines Microsoft Confidential}

Constructed Type Any type that has type arguments. For example, List<int>.Open Constructed Type A constructed type that involves one or more type parameters, e.g.

List<T> or Dictionary<string,T> where T is a type parameter that is in scope. Intuitively, an open constructed type is "open" because one or more actual arguments for type parameters still need to be specified. It is not possible to have actual object instances of an open constructed type.

Closed Constructed Type A constructed type that involves no type parameters, e.g. List<int> or Dictionary<string,int>. Object instances of generic types are always of closed constructed types because it is only possible to create object instances when all type arguments are known.

10.2 General Generics Usage Guidelines Consider using Generics in public APIs. Generics can significantly improve cleanness

of managed APIs. They allow for strong typing, which is great for usability and performance (by avoiding boxing of value types). Tradeoff: APIs using some advanced features of Generics may be too difficult to use for some developers. The concept of Generics is not widely understood, in some cases the syntax may pose problems, and as any large new feature, Generics may pose a significant learning curve for some entry-level developers. Section 10.2.1 describes the details of usability issues related to Generics.

Sometimes it does not make sense to provide non-generic alternative APIs. For example, see Reference.Swap described in section 10.2.2. If you feel like you are in a similar situation, please contact kcwalina.

Also, please note that until generics are in CLS, you need to apply CLSCompliant(false) attribute to all generic APIs (and CLSCompliant(true) on the assembly level).

Do familiarize yourself with the performance impact of Generics before exposing or calling any Generic APIs. Generics can significantly impact the performance of APIs (positively or negatively). They are significantly different from C++ templates in regards to performance. Section 10.2.2 has details on the subject.

Some Other Things To Consider:

1. Managed C++ is not currently enabled to produce generic types overloaded on type parameter arity (i.e. two generic types in the same namespace named the same but with difference number of type parameters). There are plans to enable that in the close future (LKG6). If your customers are using MC++, you need to sync up with them before you start adding generics to your public APIs. One way to workaround the issue is to write temporary non-generic wrappers that can be used from MC++ to access generic APIs.

2. XAML currently does not understand Generics. This will be enabled at the end of Longhorn M8.1 milestone.

3. Generic APIs cannot be made COM visible. This should not be a problem as the default for WinFX is to not be visible to COM.

189

.NET Framework Design Guidelines Microsoft Confidentiala. Not Supported:

i. Accessing generic interfaces from COM (because COM model doesn’t support concept of generics). For example, QI-ing for IFoo<T> will fail.

ii. Class interfaces for generic classes won’t be generated. For example, _Foo interface won’t be generated for class Foo<T>.

iii. Accessing class interfaces for types that derive from closed generic types.

b. Supported

i. Access to generic classes that implement non generic interfaces. These non generic interfaces are accessible from COM.

Let’s take the following hierarchy as an example:class Foo <T> : IFoo, IEnumerable<int>{ …}COM clients can CoCreate instances of this type, QI for the IFoo interface and make calls on it; however QI calls for either _Foo, _Base<T> or IEnumerable<T> aren’t supported (they will fail with E_NOINTERFACE).

10.2.1 Generics and UsabilityOne of the main reasons to use Generics in reusable APIs is to improve usability by making the APIs more strongly typed. Hopefully it is obvious that strongly typed APIs are much easier to use. The benefit is especially visible when using source code editors supporting statement completion.Unfortunately, Generics can also have a negative impact on usability. As any large new feature, Generics may pose a significant learning curve for some entry-level developers. The syntax may pose problems, especially in some more advanced cases. And finally, advanced usage of generics may be conceptually difficult for some developers. This section will describe some of the usability issues related to Generics. Note: This chapter is based on preliminary usability studies conducted with some limited set of Generic APIs. More research needs to be done to asses the full impact of Generics on usability. We continue working on getting such studies conducted.

Generic types may be difficult to instantiate because: Users may not be familiar or proficient with the syntax of Generics. This is

particularly true when users have to instantiate types with a type argument that is in itself a generic type.List<Nullable<int>> list = new List<Nullalbe<int>>();

190

.NET Framework Design Guidelines Microsoft ConfidentialThis syntax will change in the future. There are plans to build-in support for Nullable<T> into the languages. For example, C# will support something like:

List<int?> list = new List<int?>();int? x = 3;int? y = null;list.Add(x);list.Add(y);

Users may have problems understanding what the Generic parameter represents. This is usually not a problem for simple collections, where it’s rather obvious that the parameter represents the type of the items stored in the collection. It is more problematic in cases where the type parameter relationship to the Generic type is not obvious.DataSession<Presence> session = new DataSession<Presence>(…);

Users may have problems finding types that satisfy the constraints.

Generic methods may be difficult to use because: Users may have problems understanding what the Generic parameter represents. Users may not be familiar or proficient with the syntax calling Generic methods. They

often confuse the type parameters with the regular method parameters.

Usability Guidelines Do freely use Generics when returning instances of the Generic types from object

models. In such cases, the user does not have to instantiate the Generic type and for the most part the user does not have to be even aware that the returned object is an instance of a Generic type.public class Directory {

public Directory(string root) { … }public IEnumerable<FileInfo> Files { get { … } }

}…Directory croot = new Directory(@”c:\”);foreach(FileInfo file in croot){

Console.WriteLine(file.Name);}

Do use Generic collections. The concept of a Generic collection is relatively easy to understand. List<String> is only syntactically, but not conceptually, different from StringCollection. See section for details.

Avoid Generic types with more than 2 type parameters in high-level APIs. Users have difficult understanding what type parameters represent in types with long type parameter lists.

Avoid high-level APIs that require users to instantiate a generic type with another generic type as the type argument. The syntax gets too complex for some users.Foo<Bar<int>> foo = new Foo<Bar<int>>();

191

.NET Framework Design Guidelines Microsoft ConfidentialRequiring that users use triple, or higher, nesting is unacceptable in high-level APIs.Foo<Bar<Nullalbe<int>>> foo = new Foo<Bar<Nullable<int>>>();

Avoid Generic methods that don’t support type parameter inference in high-level APIs. Such methods are often very difficult to call because of the difficulty in understanding the purpose of the type parameter and because of the somewhat difficult syntax.Methods with a formal parameter typed as the generic method type parameter support inference. Methods with no formal parameter typed as the generic method type parameter don’t support inference.public static class RandomHelper {

public static T ChooseOne<T>(params T[] set) {return set[rand.Next(set.Length)];

}

static Random rand = new Random();}

public class Assembly {public T[] GetAttributes<T>() where T:Attribute { … }

}

The RandomHelper.ChooseOne method can be called without explicitly specifying a type argument. The type argument is inferred from the arguments passed to the method. The Assembly.GetAttributes does not support inference and the type parameter needs to be specified explicitly.int i = Util.ChooseOne(5, 213); // Calls Choose<int>string s = Util.ChooseOne("foo", "bar"); // Calls Choose<string>AssemblyVersionAttribute version = assembly.GetAttribute<AssemblyVersionAttribute>();

Do freely use Generic methods that support type parameter inference. Such methods hit the sweet spot of Generics. They support a very convenient syntax.public static class Reference {

public static void Swap<T>(ref T ref1, ref T ref2){T temp = ref1;ref1 = ref2;ref2 = temp;

}}

// Usagestring s1 = “World”;string s2 = “Hello”;// notice that the type argument does not need to be specifiedReference.Swap(s1,s2);

Do not have static members on Generic types in high-level APIs.Some users may not understand the difference between a generic method and a static method on a generic type. They both require the user to pass type arguments, but have slightly different syntax. Foo<int>.GetValues(); // static member on a Generic typeFoo.GetValues<int>(); // Generic method

192

.NET Framework Design Guidelines Microsoft Confidential10.2.2 Generics and Performance

Do consider the performance ramifications of generics. Specific recommendations arise from these considerations and are described in guidelines that follow.

Execution Time Considerations Generic collections over value types (e.g. List<int>) tend to be faster than

equivalent collections of Object (e.g. ArrayList) because they avoid boxing items. Generic collections over all types also tend to be faster because they do not incur a

checked cast to obtain items from the collection. The static fields of a generic type are replicated, unshared, for each constructed

type. The class constructor of a generic type is called for each constructed type. For example, public class Counted<T> { public static int count; public T t; static Counted() { count = 0; } Counted(T t) { this.t = t; ++count; }}

Each constructed type Counted<int>, Counted<string>, etc. has its own copy of the static field, and the static class constructor is called once for each constructed type. These static member costs can quietly add up. Also, accesses to static fields of generic types may be slower than accesses to static fields of ordinary types.

Generic methods, being generic, do not enjoy certain JIT compiler optimizations, but this is of little concern for all but the most performance critical code. For example, the optimization that a cast from a derived type to a base type need not be checked is not applied when one of the types is a generic parameter type.

Code Size Considerations The CLR shares IL, metadata, and some JIT’d/NGEN’d native code across

types/methods constructed from generic types/methods. Thus the space cost of each constructed type is modest, less than that of an empty conventional non-generic type. But see also ‘current limitations’ below.

When a generic type references other generic types, then each of its constructed types constructs its transitively referenced generic types. For example, List<T> references IEnumerable<T>, so use of List<string> also incurs the modest cost of constructing type IEnumerable<string>.

Current Code Sharing LimitationsIn the current CLR implementation, native code method sharing occurs only for types constructed over reference type parameters (e.g., List<object>, List<string>, List<MyReferenceType>). Each type constructed over value type parameters (e.g., List<int>, List<MyStruct>, List<MyEnum>) will incur a separate copy of the native code

193

.NET Framework Design Guidelines Microsoft Confidentialfor the methods in those constructed types. For comparison purposes, this is similar to the runtime cost of creating your own strongly typed collection class.A consequence of this is that using a generic type defined in mscorlib in combination with value type parameters also from mscorlib could cause an NGen image to invoke the JIT during execution, resulting in a negative effect on performance. For generic types that take a single type parameter, it is relatively straightforward to determine whether this will affect your scenario. When instantiating G<VT>, where generic type G and value type parameter VT are both defined in mscorlib149, you will JIT unless G<VT> is found in the following list:

ArraySegment<Byte>

Nullable<Boolean>Nullable<Byte>Nullable<Char>Nullable<DateTime> Nullable<Decimal> Nullable<Double>Nullable<Guid>Nullable<Int16>Nullable<Int32>Nullable<Int64>Nullable<Single>Nullable<TimeSpan>

List<Boolean>List<Byte>List<DateTime>List<Decimal>List<Double>List<Guid>List<Int16>List<Int32>List<Int64>List<SByte>List<Single>List<TimeSpan>List<UInt16>List<UInt32>List<UInt64>

For generic type instantiations that take multiple type parameters, the rules are more complex. Roughly, when instantiating G<T1…Tn>, where generic type G and each T in T1…Tn are defined in mscorlib, at least one of which is a value type, you will JIT unless G<T1…Tn> is found in the following list (note: substitute Object for any reference type parameter):

Dictionary<Char, Object>Dictionary<Int16, IntPtr>Dictionary<Int32, Byte>Dictionary<Int32, Int32>Dictionary<Int32, Object>

149 More precisely, this occurs for assemblies loaded domain-neutral. At the time of this writing, mscorlib is the only assembly in the redist that is loaded in this fashion.

194

.NET Framework Design Guidelines Microsoft ConfidentialDictionary<IntPtr, Int16>Dictionary<Object, Char>Dictionary<Object, Guid>Dictionary<Object, Int32>

KeyValuePair<Char, UInt16>KeyValuePair<UInt16, Double>

Please notice that JIT will neither occur when using a custom generic type with mscorlib type parameters (e.g. MyType<int>), nor when using an mscorlib type with your own type parameters (e.g. List<MyStruct>).What is described above actually describes the worst case scenarios. There are some subtleties that could result in a more relaxed application of these rules. A more comprehensive explanation of these subtle variables follows:

Annotation (RicoM):

Let A be an assembly, G a generic type on n parameters, T1…Tn

A generic type G<T1,…,Tn> shares code with type H<S1,…,Sn> if and only if

- G = H and,- for all i in [1..n] either

- Ti = Si, or,- Ti shares code with Si, or,- both Ti and Si are reference types.

------

Assume that A has been NGen'd, then:

If G is defined in A

- A may use G<T1…Tn> with no restrictions on T1…Tn, no JITting is required, - A will include G<Object,…,Object> even if it is not otherwise mentioned- The above two uses are present in A for other assemblies to use

(Remaining cases G not defined in A)

If all of T1…Tn are defined in A

- A may use G<T1…Tn> with no restrictions on T1…Tn, no JITting is required- Any such G<T1…Tn> will be present in the NGen’d image of A for other assemblies to use

(Remaining case at least one of T1..Tn not defined in A)

If A depends on assembly B and B has a type that shares code with G<T1…Tn>

- A may use G<T1…Tn> as found in B, no JITting is required- A will not contain code for G<T1…Tn>

(Remaining case, no match possible, this is the fallback position)

A copy of G<T1…Tn> will be emitted into the NGen'd code for A, this code is available for other assemblies to use (subject to these same rules)

If A is loaded domain-specific and G, T1..Tn are all loaded from domain-neutral assemblies then

- The CLR will be unable to use the copy in A and will JIT a new one

Otherwise

- The copy of the code in A is used and there is no JITting

195

.NET Framework Design Guidelines Microsoft Confidential

These rules apply transitively to all generic instantiations encountered when JITting the code for both the non-generic classes (which may contain generic members), and generic classes (which may have generic members or parameters themselves) and the “seed” <Object,…,Object> instantiations in the assembly.

In the future, more method sharing may be possible, but a high degree of code sharing over different struct type parameters is unlikely or impossible.

SummaryIn summary, from the performance perspective, generics are a sometimes-efficient facility that should be applied with great care and in moderation.When you employ a new constructed type formed from a pre-existing generic type, with a reference type parameter, the performance costs are modest but not zero.The stakes are much higher when you introduce new generic types and methods for use internal or external to your assembly. If used with value type parameters, each method you define can be quietly replicated dozens of times (when used across dozens of constructed types).WinFX developers may wish to refer the document Generics Collections Performance: Measured Working Set Effects.

Do use the pre-defined System.Collections.Generic types over reference types. Since the cost of each constructed type AGenericCollection<ReferenceType> is modest, it is appropriate to employ such types in preference to defining new strongly-typed-wrapper collection subtypes. Any of the following are appropriate:public class Sample {

public void Method(IEnumerable<MyRefType> param);   public void Method(ICollection<MyRefType> param);

public void Method(IList<MyRefType> param);public void Method(CustomCollection param);public IEnumerable<MyRefType> Property1 { get; }public ICollection<MyRefType> Property2 { get; }public IList<MyRefType> Property3 { get; }public Collection<MyRefType> Property4 { get; }

   public KeyedCollection<MyRefType> Property5 { get; }   public CustomCollection Property6 { get; }}

public class CustomCollection : Collection<MyRefType> {}public class CustomCollection2 : KeyedCollection<MyRefType> {}public class CustomCollection3 : IList<MyRefType> {}public class CustomCollection4 : ICollection<MyRefType> {}

Do use the pre-defined System.Collections.Generic types over value types in preference to defining a new custom collection type. As was the case with C++ templates, there is currently no sharing of the compiled methods of such constructed types – e.g. no sharing of the native code transitively compiled for the methods of List<MyStruct> and List<YourStruct>. Only construct these types when you are certain the savings in dynamic heap allocations of avoiding boxing will pay for the replicated code space costs.

196

.NET Framework Design Guidelines Microsoft Confidential Do use Nullable<T> and EventHandler<T> even over value types. We will work to

make these two important generic types as efficient as possible. Do not introduce new generic types and methods without fully understanding,

measuring, and documenting the performance ramifications of their expected use.

10.2.3 Common PatternsThe following section describes some common patterns where Generics can help in providing cleaner APIs.

Do use generics to provide strongly typed collection APIs. See section 10.4.2 for details.

Consider using generics whenever an API returns Object (or any other type that is not as strong typed as you would wish).

Without Generics

public class WeakReference {public WeakReference(object target){ … }public object Target { get { … } }

}…string s = “Foo”;WeakReference r = new WeakReference(s);s = (string)r.Target;

With Generics

public class WeakReference<T> {public WeakReference(T target) { … }public T Target { get { … } }

}…string s = “Foo”;WeakReference<string> r = new WeakReference<string>(s);S = r.Target;

Consider using generics whenever an API causes boxing.

Without Generics

public class ArrayList {public void Add(object value) { … } // this will box any value type

}…ArrayList list = new ArrayList();List.Add(1); // Int32 is a value type and it will get boxed here.

With Generics

public List<T> {public void Add(T value) { … }

}…List<int> list = new List<int>();List.Add(1); // this one does not box

197

.NET Framework Design Guidelines Microsoft Confidential Consider using generics instead of manual code expansion of patterns that vary

only on type. For example, strongly typed collections only differ on the type of the items being stored in the collections. Generics can be used to provide a single type supporting such variations instead of many, often inconsistent variations like StringCollection, TokenCollection, AttributeCollection, etc. public class List<T> : IList<T> {

public T this[int index] { get; set; }public void Add(T);public IEnumerator<T> GetEnumerator();…

}

Similarly, today EventHandler needs to be inherited just to change the type of EventArgs. With the use of generics, we can define a generic event handler:public delegate void EventHandler<T>(object sender, T args) where T:EventArgs;

Consider using generics whenever an API takes a parameter of type System.Type. For example, currently one of the overloads of Attribute.GetCustomAttribute is defined as follows:class ObjectSpace {

object GetObject(Type type, String queryString, String span);}

It could be implemented as a generic method, which would provide cleaner syntax and compile time type safety. class ObjectSpace {

T GetObject<T>(String queryString, String span);}

This needs to be done carefully. There are a large number of methods that take Type parameters and should not be generic. For example, it does not make sense for Activator.CreateInstance(Type) to be implemented as a generic method. The whole point of CreateInstance is that the type parameter is late bound and not hard-coded at the call site, in which case the operator new is a better way to create the instance.

Consider using generics whenever a type variant API requires ref parameters. References passed to ref parameters must be the exact type of the parameter (a reference to string is not a subclass of a reference to an object). For example, it’s illegal to pass a reference to a string reference to a method that takes a reference to an object reference. This means that, for example, a general purpose Swap routine based on object references is completely impractical.

Without Generics

public sealed class Reference {public static void Swap(ref object o1, ref object o2){

object temp = o1;o1 = o2;o2 = temp;

}}

198

.NET Framework Design Guidelines Microsoft Confidentialstring s1 = "Foo";string s2 = "Bar";

//Note this will not compile: Reference.Swap (s1, s2); object o1 = s1;object o2 = s2;Reference.Swap(ref o1, ref o2);s1 = (string)o1;s2 = (string)o2;

Generics solve the problem, and quite elegantly so.

With Generics

public sealed class Reference {public static void Swap<T>(ref T ref1, ref T ref2){

T temp = ref1;ref1 = ref2;ref2 = temp;

}}

// Using Genericsstring s1 = "Foo";string s2 = "Bar";Reference.Swap(ref s1, ref s2);

Consider using Generics whenever you need a method to take a parameter that implements two or more unrelated interfaces. For example, the following method takes a parameter that is a subclass of Stream and implements IEnumerable<Byte>.void Read<T>(T enumerableStream) where T:Stream,IEnumerable<Byte> {

if(enumerableStream.CanRead){foreach(Byte b in snumerableStream){

Console.Write(b);}

}}

10.3 Naming Guidelines Do name generic type parameters with single letters. For example, prefer

Dictionary<K,V> to Dictionary<Key,Value>.Note: One of the main reasons for this guideline is that we noticed people need to be able to distinguish between type parameters and type names. For example, it’s not clear whether the return type of the following method is a generic parameter or a real type:

public Value GetValue(); Using single letters for type parameters makes this clear.

Consider using T as the type parameter name for types with a single type parameter.

Consider including indication of the constraint in the name of Generic types and method parameters.public class DisposableReference<T> where T:IDisposable {}

void Read<T>(T enumerableStream) where T:Stream,IEnumerable<Byte> {

199

.NET Framework Design Guidelines Microsoft Confidential}

10.4 Usage Guidelines

10.4.1 General Usage Do not use unnecessary constraints. For example, if a Generic method calls members

exposed on System.IO.Stream, type parameter should be constrained to System.IO.Stream, not to System.IO.FileStream.void PrintLengths<T>(IEnumerable<T> streamCollection) where T:Stream {

foreach(Stream stream in streamCollection){Console.WriteLine(stream.Length);

}}

Consider including the constraint type in the parameter related to the constraint. For example, if a method has a parameter ICollection<T> and T is constrained to System.IO.Stream, the parameter should be called streamCollection.void PrintLengths<T>(IEnumerable<T> streamCollection) where T:Stream;

Avoid having “hidden” constraints. For example, you should not dynamically check the type argument and throw if it does not implement some interface.public static class Interlock{

public static T Exchange<T>(ref T location, T value){ // no constraint// do not do this! This is a hidden constraintif(T.default.GetType().IsValueType){

throw new InvaludOperationException(…);}}

}

Note: The only scenario where we allow hidden constraints is when you would like to constrain the type parameter to either of several types. In such case, you should constrain the parameter to the most derived type common to all of the alternatives or do not use a constraint at all if System.Object is the only common base. For example, a generic parameter that can either accept IComparable or IComparable<T> should not have a constraint. If the hidden constraint is not satisfied, an InvalidOperationException should be thrown.

Do not place generic types in special generic-only assemblies just because the types are generic. It is perfectly fine to place generic types in assemblies with non-generic types. In other words, whether a type is generic or not should not affect which assembly it resides in.

Do not place generic types in special generic-only namespaces just because the types are generic. It is perfectly fine to have generic types in namespaces with non-generic types.Annotation (Krzysztof Cwalina): We placed the generic collections in a separate namespace from the non-generic ones because we believed that users will rarely want to, or need to, import both of the namespaces at the same time. We basically see the namespaces (most types in the namespaces) as alternatives, not as parts of one feature area. This may not be true for some scenarios where the non-generic collection interfaces implemented on the generic collections are used, but these are considered relatively advanced scenarios.

200

.NET Framework Design Guidelines Microsoft Confidential10.4.2 Generic Collections

Do prefer generic collection over the non-generic collections. You can optionally provide overloads accepting the non-generic interfaces.static class Enumerable {

static void PrintToConsole<T>(IEnumerable<T> collection);static void PrintToConsole(IEnumerable collection); // optional

}

public class Directory {public Directory(string root);public IEnumerable<FileInfo> Files { get; }

}

Do type method parameters as the least specialized interface that will to the job. For example, if a method just enumerated entries in a collection, the method should take IEnumerable<T>, not IList<T> or List<T>.static void PrintToConsole<T>(IEnumerable<T> collection){

foreach(T item in collection){Console.WriteLine(item);

}}

Consider returning a subclass of a standard collection from high level APIs, even if you don’t presently plan to provide any customization. If your API returns one of the interfaces (IEnumerable<T>, IList<T>, etc.) or one of the standard collections (Collection<T>, ReadOnlyCollection<T>, etc.) the name of the type will not be as descriptive as possible and also you will not be able to add members to the APIs in the future.public class FileInfoCollection : ReadOnlyCollection<FileInfo> {}public class Directory {

public Directory(string root);public FileInfoCollection GetFiles();

}

Do use either a non-indexed collection (IEnumerable<T>, ICollection<T>) or a method returning a snapshot when providing access to collections that are potentially unstable (i.e. can change without the client modifying the collection). In general all collections representing shared resource (a collection of files in a directory) are unstable.public class Directory {

public Directory(string root);public IEnumerable<FileInfo> Files { get; }public FileInfoCollection GetFiles();

}

Do not return “snapshot” collections from properties. Property getters should return “live” collections. public class Directory {

public Directory(string root);public IEnumerable<FileInfo> Files { get; } // returns live collection

}

201

.NET Framework Design Guidelines Microsoft Confidential Do not return “live” collections from methods. Methods should always return Collections

returned from methods should be snapshots.public class Directory {

public Directory(string root);public FileInfoCollection GetFiles(); // returns snapshot collection

}

Do return Collection<T> from object models to provide standard plain vanilla collection API.public Collection<Session> Sessions { get; }

Do return a subclass of Collection<T> from object models to provide high-level collection API.public class ListItemCollection : Collection<ListItem> {}public class ListBox {

public ListItemCollection Items { get; }}

Do not return List<T> from object models. Use Collection<T> instead. List<T> is meant to be used for implementation, not in object model APIs. List<T> is optimized for performance at the cost of long term versioning. For example, if you return List<T> to the client code, you will not ever be able to receive notifications when client code modifies the collection.

Do return ReadOnlyCollection<T> from object models to provide plain vanilla read-only collection API.public ReadOnlyCollection<Session> Sessions { get; }

Do return a subclass of ReadOnlyCollection<T> from object models to provide high level read-only collection APIs.public class XmlAttributeCollection : ReadOnlyCollection<XmlAttribute> {}public class XmlNode {

public XmlAttributeCollection Attributes { get; }}

Note: When inheriting from ReadOnlyCollection, name it XxxCollection. If you have both read-only and read/write versions of the same collection, name them ReadOnlyXxxCollection and XxxCollection, not XxxCollection and XxxFileInfoCollection.

Do use a subclass of KeyedCollection<K,T> for collections of items that have natural unique names. For example, a collection of files in a directory could be represented as a subclass of KeyedCollection<string,FileInfo> where string is the filename. Users of the collection could then index the collection using filenames.public class FileInfoCollection : KeyedCollection<string,FileInfo> {

…}

public class Directory {public Directory(string root);public FileInfoCollection GetFiles();

}

Do use ICollection<T> for unordered collections.

202

.NET Framework Design Guidelines Microsoft Confidential Do implement IEnumerable<T> on strongly typed non-generic collection. Consider

implementing ICollection<T> or even IList<T> where it makes sense.

10.4.3 Nullable<T> Do use Nullable<T> to represent values that are optional. For example, database

wrappers returning values from columns that allow null values or XML wrappers returning values of optional attributes.public class Customer{

internal Customer(ISqlCommand command) { … }internal Customer(XmlReader xml) { … }

public string Name { get; set; } // name is not optionalpublic Nullable<int> Age { get; set; } // age is optionalpublic Nullable<string> Email { get; set; } // email is optional

} …// print customers with specified ageforeach(Customer customer in customerList){

if(customer.Age.HasValue){Console.Writeline(“{0} : {0}”,customer.Name,customer.Age);

}}

Annotation [AndersH]: When you design APIs using Nullalble<T>, you have to be very sensitive to the fact that a Nullable<T> is a lot less convenient to use than a T. Nullable<T> with value types makes sense and solves a real world problem--therefore, users will be amenable to the inconveniences of using it. However, Nullable<T> with reference types makes little sense and solves no real world problem. In fact, it adds nothing but confusion because, in terms capabilities, there is no difference between a string and a Nullable<string>.With respect to having a Value Type constraint on Nullable<T>, we haven't done it because it would severely limit Nullable<T>'s use in generic scenarios. For example, imagine a Find method that returns a T or a null value when an item isn't found. In the generic world, a possible solution is to return Nullable<T>, but only if Nullable<T> works for all types.

If you are shipping pre-Longhorn you will need to provide a CLS compliant alternative (see section 10.2 for details). The CLS compliant alternative to the APIs is to use boxed value types. For example:public class Customer{

public string Name { get; set; }public object Age { get; set; } // this is actually int or null (if Age does not have a value)

}

Second alternative is to use a pair of properties. It has the disadvantage of cluttering the API, but the benefit of strong typing and avoiding boxing:public class Customer{

public string Name { get; set; }public int Age { get; set; } // this is actually int or null (if Age does not have a value)public bool HasAge { get; set; }

}

Avoid using types from System.Data.SqlTypes in high level APIs. You should use Nullable<T> to represent optional or nullable values of Value Types.

10.4.4 EventHandler<T> Do use System.EventHandler<T> instead of System.EventHandler. Do not manually

create new delegates to be used as event handlers.

203

.NET Framework Design Guidelines Microsoft Confidentialinternal class NotifyingContactCollection : Collection<Contact> {

public event EventHandler<ContactAddedEventArgs> ContactAdded { … }

protected override void Add(Contact contact){base.Add(contact);ContactAdded(this,new ContactAddedEventArgs(this.Count-1));

}}

internal class ContactAddedEventArgs : EventArgs {public ContactAddedEventArgs(int index){ .. }public int Index { get ; }

}

10.4.5 Comparer<T> Do use System.Comparer<T> instead of other means of comparing types, like

System.Comparer, Object.Equals, etc.

10.5 Simulating CovarianceGenerics are not covariant. This mean, for example, that List<string> cannot be cast to List<object>. Note that string[] can indeed be cast to object[]. We are working on providing the official guidance related to this limitation. We are leaning towards a solution that would require generic types that need to be used in covariant scenarios to implement non-generic (object based) interfaces, just like List<T> implements IList.

11 Usage Guidelines

11.1 System.URI Usage Use System.Uri to represent URI/URL data. This applies to parameter types, property

types, and return value types.public class Navigator {

public Navigator(Uri initialLocation);public Uri CurrentLocation { get; }public Uri NavigateTo(Uri location);

}

Note: System.Uri is a much safer and richer way of representing URIs. Extensive manipulation of URI related data using plain strings has been shown to cause many security and correctness problems. Please see the excellent whitepaper written by Mark Alcazar describing the issues in more details.

Consider providing string-based overloads for most commonly used members with System.Uri parameters. In cases where the usage pattern of taking a string from a user will be common enough, you should consider adding a convenience overload accepting a string. The string-based overload should be implemented in terms of the Uri-based overload.

public class Navigator { public void NavigateTo(Uri location); public void NavigateTo(string location) {

NavigateTo (new Uri (location));

204

.NET Framework Design Guidelines Microsoft Confidential }}

Do not automatically overload all Uri-based members with a version that accepts a string. Generally, Uri-based APIs are preferred. String-based overloads are meant to be helpers for the most common scenarios. Therefore, you should not automatically provide string-based overloads for all variants of the Uri-based members. Be selective and provide such helpers just for the most commonly used variants.

public class Navigator { public void NavigateTo(Uri location); public void NavigateTo(string location); public void NavigateTo(Uri location, NavigationMode mode);}

Do contact the NCL team (LanceO) when creating new URI schemas.

11.1.1 System.Uri Implementation Rules Call the Uri-based overloads if available.

Do not store URI/URL data in a string. When you accept a URI/URL input as a string, you should convert the string to a System.Uri and store the instance of System.Uri.

11.1.2 FxCop RulesIf a parameter name contains “uri” or “url” or “urn” and it’s typed as string, the parameter type should be changed to System.Uri, unless there is an overload method where the same parameter is types as Uri.

If a function name contains “uri” or “url” or “urn” and the return type is string, the return type should be changed to System.Uri.

If a property name contains “uri” or “url” or “urn” and it’s typed as string, it should be changed to System.Uri.

If a parameter is typed as System.Uri and the member has an overload where a parameter at the same position is typed as System.String, the member should not do anything with the string except to pass it to Uri.TryParse or Uri.ctor, and call the overload that takes Uri.

If there are two overloads one taking System.Uri and one taking System.String, library code should never call the string-based overload.

Note: All of the rules need to exclude common words that contain “uri” or “url”. For example “security”, “purity”, “during”, “heuristics”, etc.

11.2 ResourcesResources can be used in libraries to store error messages, labels, and icons. MSDN article Resources and Localization Using the .NET Framework SDK is a good source of background information on the .NET Framework resource model.There are two models developers can use when they organize their resources. The first one is to have all the resources including the neutral resources in satellite assemblies

205

.NET Framework Design Guidelines Microsoft Confidentialand make the main assembly resources-free. The second model is to put the neutral resources in the main assembly and put the rest of resources in satellite assemblies.Annotation (Ahmed AbouTaleb):The first model described above –All resources in satellites- is not supported in V1.0 and V1.1.

Do not hardcode strings in your source code, store all strings in resourcesError: Reference source not found.string errorMsg = “File not found. Please check the path.”;

This code is hard to localize because the string is inside the code and the only way to localize it is by providing an executable for each culture.

string errorMsg = resourceManager.GetString(“FileNotFound”);

This code is easier to localize and storing all the messages in the resources decouple them from the source code. Also, creating satellite assemblies for your localized resources will make it easier to support more languages in the future.

Do store all resources including the neutral resources in satellite assemblies. This way it is easier to localize, easier to setup and faster to load or download if it is a downloadable library.Note: You may need to consider putting the neutral resources in the main assembly in some situations where your neutral language is the one that will be used by most of your customers.

MS Internal

If your library is shipping with Longhorn you have to have all the resources –including “en-US” resources in satellites, this is one of the requirements to ship with Longhorn.

Do create satellite assemblies with the .resources in the name of the assembly like "MyLibrary.resources.dll" for a main assembly named "MyLibrary.dll”.150

Do not set the culture in the main assembly. Main assembly is used for code and it should contain the neutral resources only.To have a culture-neutral assembly don’t add culture attribute to your assembly and don’t set culture in the linker when generating the main assembly. For example don’t do any of the following.[assembly:AssemblyCultureAttribute(“en”)]// Setting the culture to English

al /out:MyLibrary.DLL /embed:ErrorStrings.resources /culture:en

Do not insert the culture name in manifest resource names in the main assembly.Error: Reference source not found

150 We are planning to create FxCop rule for this check. Bug # 2505.206

.NET Framework Design Guidelines Microsoft ConfidentialThe main assembly contains the neutral language resources and those resources should be culture-neutral. The name of the manifest resource in the main assembly shouldn’t contain the culture name in it like ErrorStrings.en.resources. Instead, the manifest resource name should be ErrorStrings.resources. This can be verified manually by using ildasm.exe tool to check the names of the resources in the assembly manifest.

Do set the culture in the satellite assembly.Error: Reference source not found Do apply NeutralResourcesLanguageAttribute to the main assembly.Error: Reference

source not foundTo use the NeutralResourcesLanguageAttribute in the main assembly where the neutral resources language is “en” and the neutral resources are located in a satellite assembly use the following code.[Assembly:NeutralResourcesLangaugeAttribute(“en”, UltimateResourceFallbackLocation.ResourceLocation = Satellite)]

To use the NeutralResourcesLanguageAttribute in the main assembly where the neutral resources language is “en” and the neutral resources are located in the main assembly use the following code.[Assembly:NeutralResourcesLangaugeAttribute(“en”, UltimateResourceFallbackLocation.ResourceLocation = MainAssembly)]

Do not add code to the satellite assemblies as they are meant only for resources.151

Satellite assemblies are culture specific. Each executable can have many satellite assemblies containing the resources localized for many cultures. If you add code to the satellite assemblies, you will have many copies of the code, which increases the maintenance cost.

11.3 OptionalValue<T> UsageNote: The type will be renamed to Nullable<T> in the Whidbey M3 Milestone.

Do use OptionalValue<T> to represent values that are optional. For example, database wrappers returning values from columns that allow null values or XML wrappers returning values of optional attributes.public class Customer{

internal Customer(ISqlCommand command) { … }internal Customer(XmlReader xml) { … }

public string Name { get; set; } // this property is not optionalpublic OptionalValue<int> Age { get; set; } // this is optionalpublic OptionalValue<string> Email { get; set; } // this is optional

} …// print customers with specified ageforeach(Customer customer in customerList){

if(customer.Age.HasValue){Console.Writeline(“{0} : {0}”,customer.Name,customer.Age);

}}

151 We are planning to create FxCop rule for this check. Bug # 2505.207

.NET Framework Design Guidelines Microsoft ConfidentialIf you are shipping pre-Longhorn you will need to provide a CLS compliant alternative. The CLS compliant alternative to the APIs is to use boxed value types. For example:public class Customer{

public string Name { get; set; }public object Age { get; set; } // this is actually int or null (if Age does not have a value)

}

Second alternative is to use a pair of properties. It has the disadvantage of cluttering the API, but the benefit of strong typing and avoiding boxing:public class Customer{

public string Name { get; set; }public int Age { get; set; } // this is actually int or null (if Age does not have a value)public bool HasAge { get; set; }

}

Avoid using types from System.Data.SqlTypes in high level APIs. You should use OptionalValue<T> to represent optional or nullable values of Value Types.Do not use both OptionalValue<T> and null to represent optional values in a single feature area. For example, the Customer class above uses OptionalValue<string> to represent optional e-mail address despite that technically null could be used as string is a reference type.

11.4 System.Xml Usage Do provide overloads that accept and System.Xml.XmlReader and System.String for

properties of a class that represent an XML document or fragment. This gives users a friendly way to access the XML by using String and an efficient way to interact with the XML via the XmlReader. The following example shows what an implementation of this would look like. Note that it is merely illustrative and does not imply that you should always use XmlDocument as your mechanism of representing a property that is XML. public class Email {

private XmlDocument body = new XmlDocument(); public string Body {

get { return body.OuterXml; }set { body.Load(new System.IO.StringReader(value));}

} public void SetBody(XmlReader reader) {

body.Load(reader); }

public XmlReader GetBody() {return new XmlNodeReader(body);

}}

Do choose System.Xml.XmlReader or System.Xml.XPath.XPathNavigator as input or output for methods that accept or return XML. In the cases where the user needs to edit the XML use the XPathEditableNavigator. Using these abstractions instead of XmlDocument, XmlNode or XPathDocument as this decouples the methods from specific implementations of an in-memory XML document and also allows them to work with virtual XML data sources that expose an XmlReader or XPathNavigator.

Do implement IXPathEditable or IXPathNavigable on your classes when creating an XML view of an underlying object model or data source.

208

Brad Abrams, 12/13/04,
We should have an FxCop rule for this

.NET Framework Design Guidelines Microsoft Confidential Do not create a subclass of XmlDocument if you want to create an XML view of an

underlying object model or data source. This means classes like System.Xml.XmlDataDocument are an example of what not to do.

Do not use the XmlNode or XmlDocument classes as parameters to your methods. Favor using instances of IXPathNavigable or IXPathEditable instead. This decouples your API from one specific implementation of an XML data source.

12 SecurityClass library authors need to consider two perspectives with respect to security. Whether these perspectives are applicable will depend upon the class itself. Some classes, such as System.IO.FileStream represent objects that need protection with permissions; the implementation of these classes is responsible for checking the appropriate permissions of the caller required for each action and only allowing authorized callers to perform the actions for which they have permission. The System.Security namespace contains some classes to help make these checks easier. Additionally, class library code often is fully-trusted or at least highly-trusted code. Any flaws in the code represent a serious threat to the integrity of the entire security system. Therefore, extra care is required when writing class library code as detailed below.

12.1 Protecting objects with permissionsPermissions are defined to protect specific resources, and any class library that performs operations on protected resources needs to be responsible for enforcing this protection. Before acting on any request on a protected resource, such as deleting a file, the code first needs to check that the caller (and usually all callers, by means of a stack walk) has the appropriate delete permission for that resource. If the caller has the permission, the action is considered authorized and may be completed. If the caller does not have the permission, a security exception should be raised. In code, protection is typically implemented with either a declarative or imperative check of the appropriate permissions.For example, use of files is protected by the FileIOPermission which separately grants the ability to create, read, write, and delete selected named groups of files. When the File class's (or possibly any other class that exposes the same functionality) delete file method is called to delete a specific file, the caller stack walk check for delete permission on that file must pass before the action delete operation can happen. The code of the File class is responsible for performing the necessary check that binds together the semantics of the permission object to the potential actions taken by the protected object itself.It is important that classes protect all possible kinds of exposure of resources, not only direct access. For example, a cached file object is responsible for checking file read permission even if the actual data is only retrieved from a cache in memory and no actual file operation happens, because the effect of handing the data to the caller is the same as an actual read.

12.2 Fully-trust class library code

209

.NET Framework Design Guidelines Microsoft ConfidentialMany class libraries are implemented as fully trusted code that wraps platform specific functionality, such as COM or system APIs, as managed objects. Because this code is fully-trusted it is a potential weakness to the security of the entire system and consequently deserves careful design and review. In a very real sense, placing a heavy security burden on a relatively small set of class libraries and the underlying core CLI security allows the larger body of managed code to acquire the security benefits in that managed code only represents a potential security threat in proportion to the level of trust granted to it.A common class library security scenario is a fully trusted class that exposes a resource that is protected by a permission; the actual resource is accessed by a native code API. Again, the typical example would be a File class that uses a platform file API to do some file operation such as delete. The following lists the steps taken to protect the resource. The caller requests delete file "c:\test.txt" by calling the appropriate method of the

File class. The delete method creates a permission object representing the "delete c:\test.txt"

permission. Use IPermission.Check to test if all callers on the stack have this permission; if not

a security exception is raised. Assert full-trust; the File class asserts its right to call native code (since its callers

may not have this permission). The File class uses a native API to perform the file delete operation. The File class returns to its caller, completing the file delete request successfully.

12.3 Precautions for highly trusted codeAny code in a trusted class library will be granted permissions that normally are not available to most application code. Therefore particular care must be taken to avoid creating a security weakness. Note that there might be classes that do not require special permissions but might be granted them because they are in an assembly with code that does require special permissions. The same potential for trouble exists in this situation.Any trusted code needs to be designed so it can potentially be called by any kind of semi-trusted code on the system without exposing security holes. Protection of resources is normally safe by virtue of the stack walk. If the caller has insufficient permissions, attempted access will be blocked. However, any time trusted code asserts permission, it is taking responsibility and requires checking. Normally, the assert should only follow the necessary permission check of the caller as described above. The window of asserted high permission should be kept as small as possible to reduce risk of unintended exposure (see the note on performance below).Fully trusted code is implicitly granted all other permissions. In addition, it is allowed to violate rules of type safety and object usage. Independent of protection of resources, any aspect of the programmatic interface that might break type safety or afford access to data not normally available to the caller could lead to a security problem.

12.4 Performance210

.NET Framework Design Guidelines Microsoft ConfidentialSecurity checks involve checking the stack for permissions of all callers. Depending upon the depth of the stack, these operations have the potential to be very expensive. If one operation actually consists of a number of actions at a lower level that require security checks, it may greatly improve performance to check caller permissions once and then assert the necessary permission before performing the actions. The assert will stop the stack walk from propagating further up the stack so that the check will stop there and succeed. Typically this results in a performance improvement when three or more permission checks can be covered together.

12.5 General Code Access Security Guidelines Do design for semi-trusted callers. Appropriate functionality should be exposed to

semi-trusted callers. Do not just require callers of your library to have unmanaged code permissions. Exceptions to the rule include libraries that would have to demand permissions equivalent to the unmanaged code permissions. For example, a component allowing callers to disable code access security checks will have to demand the unmanaged code permissions.

If you violate the guideline above, you should not ship in System, Microsoft, or any other official company namespace.

Do protect resources that need protection by demanding appropriate permissions. For example, protect access to COM ports, database connections, etc. Don’t just let anybody access your resource. This enables administrators to control what code can access your resource.

Avoid creating new permissions. Try finding an existing permission that could suit your needs. If there is an existing permission but it does not quite suit your needs, contact the team that developed the permission and suggest they add the features you need. Large number of permissions complicates administrative scenarios.

Do create a new permission if the new permission is an overlap of two or more existing permissions and having single permission results in substantial improvement in administrative scenarios. Try contacting the owners of those overlapped permissions to be sure they all agree.

Do create a new permission that overlaps existing permissions if the new permission can be granted to code with lower level of trust than the overlapped permissions could. For example, if your component would otherwise require full file system access and full registry access but the component will access just a specific file and a specific registry key.

Do not create a new permission that is just a subset of an existing permission. For example, don’t create TempDirectoryPermission because it would be just a subset of FileIOPermission.

Do not assert permissions without demanding other permissions unless you are absolutely sure you don not compromise security152. The usual pattern of a demand followed by an assert is shown below.public void WriteLog(string message) {

152 Fully covered by FxCop rule: SecurityRules/AssertRequiresDemand.211

.NET Framework Design Guidelines Microsoft Confidential new LogPermission(LogPermission.Write).Demand();

// SECURITY REVIEW // The permission can be asserted because the caller has no control // over the path to the log file and the LogPermission has been // demanded above. new FileIOPermission(FilePermissionAccess.Write,this.path).Assert(); // write to log file now …}

Do comment all permission asserts, clearly stating why you think the assertion is safe. See sample above.

Consider modifying the default policy or provide tools to help administrators modify the policy, if you create a new permission.

Contact the Framework team if you do so.

Do not weaken the existing policy.

12.6 Security Related Coding ConventionsPerforming security reviews of libraries calling into native code can be difficult. The following coding conventions are designed to make reviewing interop code a bit easier. The basic idea is to group all your PInvoke declarations in each assembly using the naming convention NativeMethods, SafeNativeMethods and UnsafeNativeMethods for your classes. There are two primary benefits to this approach:

1. The classes are hard to miss in a code review. The convention helps reviewers quickly understand the security implications of platform invocations in your library. Following this guideline helps prevent security related errors by making it easier to review classes that invoke native methods.

2. If used correctly, this pattern can increase performance where methods are known to be safe.

For accessing Win32 APIs where the runtime will require a security demand, create a class NativeMethods. These APIs can safely be used anywhere because (unless an assert is used) a stack walk will always be performed. Typically all of your PInvoke declarations should go in this class. Example 1:

internal class NativeMethods{

[DllImport("msvcrt.dll")]internal static extern int puts(string str);

[DllImport("msvcrt.dll")]internal static extern int _flushall();

}

The CLR assumess responsibility for the security of these methods by performing a full stack walk. In many cases this runtime performance cost is insignficant and not an issue. Where there are performance issues, consider using one of the following patterns.

212

.NET Framework Design Guidelines Microsoft ConfidentialFor accessing Win32 APIs where a security demand is not required (benign methods, for example QueryPerformanceFrequency) and performance is an issue, create a class SafeNativeMethods. These APIs can safely be used anywhere because they are inherently safe operations. Accessing them is also very fast because no stack walk is done by the runtime. Security for calls to this class is the responsibility of the interop class developer. Example 2:

[SuppressUnmanagedCodeSecurityAttribute()]internal class SafeNativeMethods {

[DllImport("user32.dll")]internal static extern MessageBox(string text);

}

For accessing Win32 APIs that are inherently unsafe but performance is an issue, create a class UnsafeNativeMethods. These APIs can only be safely used if the calling code performs the appropriate level of permission checking. Accessing methods in UnsafeNativeMethods is fast because no stack walk is done by the runtime. There are some cases where calls are completely isolated from the public API and no demand is needed (such as Isolated Storage creating a physical file), but in most cases the caller will have to demand so some stack walk is necessary. The caller is responsible for the security of calls into this class.

[SuppressUnmanagedCodeSecurityAttribute()]internal class UnsafeNativeMethods {

[DllImport("user32.dll")]internal static extern void CreateFile(string fileName);

}

The below table summarizes the pattern, risk and responsibility:

Class Name Security Responsibility

SuppressStack Walk?

Risk Level

Comments

NativeMethods CLR No Medium

Runtime handles security but performance may be an issue

SafeNativeMethods Library Yes Low Much better performance but library developer must look carefully at all methods in code reviews.

UnsafeNativeMethods

Caller Yes High For performance-sensitive and potentially-dangerous methods. Look carefully at all usage of these methods in code reviews.

213

.NET Framework Design Guidelines Microsoft Confidential Do place your PInvoke declarations in classes with strictly specified names:

NativeMethods, SafeNativeMethods or UnsafeNativeMethods153. No PInvoke declarations should appear in any other classes.

Do not expose PInvokes publicly; Designate all interop classes and methods as internal154.

Do use class name NativeMethods when the methods for your native method class that can safely be used anywhere because a stack walk will be performed (unless an assert is used)155.new FileIOPermission(secAccess, filePath).Demand();// SECURITY REVIEW – assert is safe, line above demans FileIO permnew SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();NativeMethods.CreateFile(filePath, fAccess);

Do use class name UnsafeNativeMethods where native methods are dangerous. Calls to these APIs typically require a security demand. The [SuppressUnmanagedCode] attribute is on this class for performance reasons. Any caller into UnsafeNativeMethods must do a full security review to ensure that the usage is safe and protected. Ideally, every call into UnsafeMethods has a comment explaining why the call is safe.new FileIOPermission(secAccess, filePath).Demand();// LoadLibrary call is safe here because myputs is benign.UnsafeNativeMethods.LoadLibrary(“myputs”);

Do use class name SafeNativeMethods where the methods of this class can be used safely and the caller does not need to do full security reviews. Use this class only for methods that don’t do anything potentially dangerous or expose sensitive information. It is safe to add the [SuppressUnmanagedCode] attribute to this class -- No stack walk will be performed. Calls to Win32 APIs in this class should not require security Demands or Asserts.SaveNativeMethods.GetTickCount();

Don’t place the [SuppressUnmanagedCode] attribute on the NativeMethods class156.

12.7 Specific Security IssuesThis section details some specific concerns around security and managed code. For up to date information check out <http://net/security>.

12.7.1 Culture Aware String ConcernsStrings in the Framework are designed to work in different ways depending on the culture they are being used with. The most obvious way is that if you sort a list of

153 FxCop Bug 1707.154 Covered by FxCop Rule: TypesDoNotHavePublicPInvokeMethodsAndSuppressUnmanagedCodeSecurityAttribute.155 Coverd by FxCop Rule: ConsiderMovingDllImportsToNativeMethodsClass.156 FxCop Rule coming: Bug 1706.

214

.NET Framework Design Guidelines Microsoft Confidentialstrings, the actual ordering will be different depending on which culture is active on the thread. By default, String.Compare will return a result that can vary from one culture to another. The security issue here is that the expectation of the developer writing the library is different than what actually happens if the culture is changed or just different than the culture the developer tested with. Here is an example based on the Turkish I. For most Latin alphabets, the letter < i Unicode 0069> is the lowercase version of < I Unicode 0049 >. However the Turkish alphabet has two versions of the letter I, one with a dot and one without. In Turkish, the character < I Unicode 0049> is considered the upper case version of a different character < I Unicode 0131>, and < i Unicode 0069> is considered the lower case version of yet another character < İ Unicode 0130>.Here is some code that demonstrates what this means:Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");Console.WriteLine("Culture = {0}",Thread.CurrentThread.CurrentCulture.DisplayName);Console.WriteLine("(file == FILE) = {0}", (string.Compare("file", "FILE", true) == 0));

Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");Console.WriteLine("Culture = {0}",Thread.CurrentThread.CurrentCulture.DisplayName);Console.WriteLine("(file == FILE) = {0}", (string.Compare("file", "FILE", true) == 0));

Because of the difference of the comparison of I, results of the comparisons change when the thread culture is changed. This is the output:Culture = English (United States)(file == FILE) = TrueCulture = Turkish (Turkey)(file == FILE) = False

If a trust decision were being made based on this compare it could be subverted by changing the culture.This problem is easily fixed by specifying that the Invariant Culture should be used for all sorting and comparisons. This insures that the code always executes in the manner the developer tested it in.Here is an example of the problem:static string IsFileURI(String path) { return (String.Compare(path, 0, "file:", 0, 5, true) == 0);}

This code will return the incorrect result on Turkish. The file system in Turkish does not use the linguistic casing rules, so file names always need to be compared in an invariant manner. The correct code is this:static string IsFileURI(String path) { return (String.Compare(path, 0, "file:", 0, 5, true, CultureInfo.InvariantCulture) == 0);

215

.NET Framework Design Guidelines Microsoft Confidential}

Primary Affected APIsAll calls to these APIs should include a culture. If they are intended for end user visible strings then CultureInfo.CurrentCulture should be passed. Otherwise CultureInfo.Invariant Culture should be passed. String.Compare()String.ToUpper()String.ToLower()Char.ToUppder()Char.ToLower()String.CompareTo()

Secondarily affected APIsThese APIs call through to String.Compare so they are also affected. All calls to these constructors need to specify a culture as described above.CaseInsensitiveComparerCaseInsensitiveHashCodeProvider

Do explicitly specify a culture when calling a culture-dependent string routine or any API mentioned above157.For more information on this issue see the writing culturally aware managed code at xxxx.

12.7.2 Restricting Access (Friends)It is best development practice to expose functionality to the narrowest set of clients possible. If the functionality only needs to be accessed from within a class encapsulate it in a private method. If the functionality only needs to be accessed from other code within the same assembly encapsulates it in an internal type or method. If the functionality needs to be accessed by 1 or 2 other assemblies that are part of the same area make them “friends” as described below. And, of course, if the functionality needs to be generally available make it public or protected as appropriate.

Consider using the linker to share access between assemblies written in to different languages rather than using Friend assemblies (TODO: link to info on the linker). FxCop rule 3232

Do use the narrowest visibility possible. Do use friend assemblies to expose access to a set of functionality that needs to be

shared between a small number of closely related assemblies.In assembly “library”:

157 Fully covered by FxCop rule: GlobalizationRules/StringMethodsAreCalledWithCultureInfoParameters.

216

.NET Framework Design Guidelines Microsoft Confidential[assembly: InternalsVisibleTo("System.Web, Culture=neutral, PublicKeyToken=32ab4ba45e0a69a1")]using System.Runtime.CompilerServices;

internal class SharedClass{}

In assembly “System.Web”:class Program{

static void Main(string[] args){

SharedClass sc = new SharedClass();}

}

MS Internal: See the spec at: http://devdiv/SpecTool/Documents/Whidbey/CLR/CurrentSpecs/FriendAssemblies.doc

Do specify all parts of the assembly name (exception the version) to ensure only appropriate callers have access.

Right: [assembly: InternalsVisibleTo("System.Web, Culture=neutral, PublicKeyToken=32ab4ba45e0a69a1")]

Wrong (no public key): [assembly: InternalsVisibleTo("System.Web ")]

Wrong (publickey must be included): [assembly: InternalsVisibleTo("System.Web, Culture=neutral, PublicKeyToken=null")]

Wrong (culture must be specified): [assembly: InternalsVisibleTo("System.Web, PublicKeyToken=null")]

FxCop rule TBD (3002)

Do be aware that by making an assembly your friend, all the internal types and members of the assembly are available to be called. Only use friends in cases where you can carefully manage what is being used.

Do not use friends between two assemblies that ship on different schedules. The interdependency between friend assemblies is so high that shipping out of band of each other is likely to cause compatibility problems. You are better off exposing well design public interfaces in this case.

Do be aware that when servicing an assembly all of its friends will likely have to be serviced as well. (the Ngen image gets invalidated).

217

.NET Framework Design Guidelines Microsoft Confidential Consider consolidating assemblies if possible to avoid the need for friend assembly

specification. There is a working set and load time hit for each assembly used in an application. As such it is a good idea to minimize the number of assemblies loaded. See section x.y on assembly factoring for more information.

Do not use StrongNameIdentityPermissionAttribute to restrict access to otherwise public types. FxCop rule 3234

Annotation (iancarm): Of course, the corollary of the guidelines above is that if you don't essentially think of the assemblies as a single unit, and have control over both of them, friend is probably wrong.

Annotation (BradA): This is one of those rare times when we have had to completely reverse a guideline. In V1 we recommended using StrongNameIdentityPermissions for this concept, but as we discovered the issues with them that lead the creation of friends support it became clear we needed to update this guideline.

Annotation (CBrumme): StrongNameIdentityPermissions (SNIP) are far less controlled than ‘friend’. By this I mean that SNIPs are often used to open up accessibility to any and all assemblies that are signed with a particular key. I would describe this as promiscuous, because the author no longer has any control of or knowledge of everyone who has taken dependencies on his internal details. It is very hard to evolve code in the presence of these unknown dependencies. So it’s a bad engineering practice.

FxCop Rule: FxCop should warn against all StrongNameIdentityPermissions and suggest Friend instead (3002).

Annotation (BradA): I have been asked several times if it makes sense to use FriendAssemblies to making testing easier. That is have your product assembly declare a test assembly as a friend such that the test assembly can access (and therefore more easily test) internal members of the product assembly. The short answer is No, this is not a good idea as shipping with a declared friend assembly may open you up to attaches if someone as able to pretend to be your test assembly. The simple rule here is: Don't declare something as a Friend assembly if you don't ship it.

MS Internal:  The namespace for restricted types should be named <YourNamesapce>.Internal

12.8 Summary of Security IssuesDo consider the following guidelines.

Any class library that uses protected resources must ensure that it does so only within the permissions of its callers.

Assertion of a permission should be done only when necessary, and should be preceded by the necessary checks.

Consider how a semi-trusted malicious caller might potentially use the class to bypass security.

218

.NET Framework Design Guidelines Microsoft Confidential To improve performance, aggregate operations that will involve security checks and

consider the use of assert to limit stack walks without compromising security.

Do not do the following. Assume that code will only be called by callers with certain permissions. Define non-type-safe interfaces that might be used to bypass security elsewhere. Expose functionality that allows a semi-trusted caller to take advantage of higher

trust of the class.

12.8.1 Unsealed TypesAlthough the type design guidelines mandate that types are unsealed unless there are specific reasons to seal them, library developers and users should be careful when dealing with unsealed types that implement interfaces. This is especially true for security sensitive execution paths. Let’s consider the following code. public interface IInterface { void InterfaceMethod();}public class Base : IInterface { // this method is sealed (i.e. cannot be overriden) public void InterfaceMethod() { Console.WriteLine("Base Called"); }}public static class Something { public static void InvokeMethodOnBase(Base obj) { InvokeMethodOnInterface(obj); } static void InvokeMethodOnInterface(IInterface obj) { obj.InterfaceMethod(); }}

The developer may assume that Something.InvokeMethodOnBase will always call Base.InterfaceMethod implementation because the method is sealed. But the quick test below can show that the assumption is not correct. public class Derived : Base, IInterface { public new void InterfaceMethod() { Console.WriteLine("Derived Called"); }

static void Main(){ Something.InvokeMethodOnBase(new Derived()); }}

When the test is run, it will print “Derived Called”. A subclass of Base can reimplement the IInterface interface and this hides the implementation of the same interface on the Base class.

219

.NET Framework Design Guidelines Microsoft Confidential

13 Misc

13.1 Interoperating Between Managed and Unmanaged Code

The purpose of this section is to give simple guidelines and best practices for accessing and wrapping any kind of unmanaged API from managed code, and exposing managed API to unmanaged callers. The guidelines below, for the sake of brevity, just touch on the issues that library designers must consider. For complete interop guidelines, it is strongly suggested that you read the complete documents at http://devdiv/SpecTool/Documents/Whidbey/CLR/Guidelines/Managed_Unmanaged_Code_Interop_Overview.doc as well as the product documentation.

13.1.1 Exposing Managed API to Unmanaged CodeUnmanaged clients are extremely important to the success of many managed .NET Framework applications; however, for a wide range of reasons we generally do not advise managed frameworks to be exposed directly to COM clients. C++ is the right long-term solution for clients with large unmanaged code bases that want to take incremental advantage of new functionality in a managed framework. 

Please see Managed\Unmanaged Interop Overview for more details on this topic.

The ComVisibleAttribute attribute determines how COM clients access a managed framework. By default, public types within an assembly are directly visible to COM clients, and that causes a number of problems.  1. Managed APIs would have to be greatly simplified to contain only a subset of the functionality that COM supports. For example, there would be no static methods, parameterized constructors, or any usage of generics.  2. COM-visible members must adhere to the COM versioning rules rather than the managed code versioning rules. That means you cannot add members to COM visible types.  3. Some internal implementation details of COM-visible members are exposed.  For example, the exact layout of struct types is exposed such that COM-visible structures cannot add or remove private members.

Do make all types in your assembly not visible to COM client by default by applying the ComVisible(false) attribute to each assembly. [assembly:ComVisible(false)]

Consider not exposing any of your types directly to COM clients and instead encourage COM clients to use C++ support to access your first-class managed APIs directly.

See internal guidelines detailing C++ interop support: Interop - IJW Guidelines

Do carefully mark individual types as being visible to COM clients only as needed.

220

.NET Framework Design Guidelines Microsoft Confidential Do provide separate COM visible wrappers for the first-class managed API such that

the managed API can version freely without risk to the COM-visible layer. Do marke COM visible wrappers explicitly with the ComVisible(true) attribute. Do use ClassInterfaceType.None on a managed class and implement interfaces

directly. Do use a namespace with the .Interop suffix to contain types which provide

interop functionality for a base namespace. For example COM wrappers for first-class System.Media APIs should be in System.Media.Interop namespace.

If your managed API has to be visible to COM, these are the three ways to expose managed classes to COM based on the ClassInterfaceAttribute: Default AutoDispatch: expose just an empty IDispatch interface, AutoDual: expose all class methods as well as all base class methods in a dual interface,

and None: expose just explicitly implemented interfaces as a dual interfacesThe first and second ways for exposing a managed class to COM are not recommended as they can hide potential versioning problems from managed class developers. The third method is recommended since it requires managed class developers to explicitly express their contract for COM consumers and more importantly, exposes any versioning problems. If a managed class developer wants to update an interface in a new version and adds a method, he/she will need to create a new interface instead of just updating the old one, since interfaces shouldn’t be changed in any way.Note that the following two rules are most important, but for a more complete list of scenarios, please read the list at http://devdiv/SpecTool/Documents/Whidbey/CLR/Guidelines/Interop%20-%20Exposing%20to%20COM%20Guidelines.doc.

One of the most important features any library can have is interoperability with legacy components. Due diligence should be used in designing interoperability from the ground up. However, by the nature of interop the shape and style of interop APIs is often quite different from what we want to prompt going forward. As such it makes sense to put interop related functionality in a subnamespace. Here is one example of COM friendly managed class that correctly wraps COM invisible managed class.namespace Sample.SerialLcd.Interop {

[ComVisible(true)][Guid("0FBFE17F-AF14-48c6-8BB0-DCB6C0293222")]public interface ISerialLCD {

//method definitions...

}

[ComVisible(true)][Guid("742F27D9-4BEC-434c-9560-11B14022602B")][ClassInterface(ClassInterfaceType.None)][ComDefaultInterface(typeof(ISerialLCD))]public class ComFriendlySerialLCD : ISerialLCD{

//interface method implementation...//private member to managed only API

221

.NET Framework Design Guidelines Microsoft Confidentialprivate SerialLCD sLCD;

}}

13.1.2 Using Unmanaged Code from Managed CodeChoosing the Right Interop TechnologyThere are several types of unmanaged APIs and several types of interop technologies available to use them. Recommendations about how and when to use them are described in this section. These rules address the most common issues, but for a more complete list, see the document at http://devdiv/SpecTool/Documents/Whidbey/CLR/Guidelines/Managed_Unmanaged_Code_Interop_Overview.doc.

Using Unmanaged Flat APIs Do check if there is equivalent functionality available in the .NET Framework. The

recommendation is to use managed code functionality instead of calling an unmanaged API if possible.

Do use platform invoke (p/invoke) if you are calling a few unmanaged methods or simple flat APIs.For calling just a few unmanaged methods or for calling simple flat APIs, the recommended way is to use P/Invoke. Writing P/Invoke declarations for simple flat APIs is straightforward. The runtime will take care of loading DLLs and all parameter marshaling. Even the cost of writing a few P/Invoke declarations for complex flat APIs is negligible compared with the cost of introducing a new module written in MC++.

Do use C++ if you are wrapping complex unmanaged flat APIs or wrapping unmanaged flat APIs that are changing while managed code is under development.For wrapping complex unmanaged flat APIs or for wrapping unmanaged flat APIs that are changing while managed code is under development, C++ is recommended. This MC++ layer can be very thin and the rest of the managed code can be written in any other managed language of choice. Using p/invoke in these scenarios would require a lot of effort to re-declare complex parts of the API in managed code and possibly to keep them in sync with the unmanaged APIs. Using C++ solves this problem by allowing direct access to unmanaged APIs (no rewriting, just include a header file).

Using COM APIs Do use COM Interop for calling OLE Automation-compatible COM components. The

runtime will take care of COM component activation and parameter marshaling. Do use C++ for calling IDL-based COM components.

This MC++ layer can be very thin and the rest of the managed code can be written in any other managed language of choice. COM interop relies on information from type libraries to make the correct interop call, but type libraries typically do not contain all information present in IDL files. Using C++ solves this problem by allowing direct access to these COM APIs.

222

.NET Framework Design Guidelines Microsoft Confidential Do consider shipping primary interop assemblies (PIAs) if you own COM APIs that

have already shipped and make them easy to consume for managed clients.

For details about producing PIAs, see the PIA FAQ document at http://devdiv/SpecTool/ Documents/Whidbey/CLR/Guidelines/Interop%20PIA%20FAQ.doc.

13.1.3 Using COM from Managed C++ Do use Managed C++ interop templates for storing unmanaged interface pointers as

fields in managed structures and classes. Do use Managed C++ interop templates for passing unmanaged interface pointers

as parameters of managed methods. Do use Managed C++ interop templates when accessing COM objects from MC++.

These templates are part of the MC++ library.

For a complete list of scenarios and corresponding rules you have to respect in order to ensure that your interop code works correctly in all cases, please refer to http://devdiv/SpecTool/Documents/Whidbey/CLR/Guidelines/Interop%20-%20IJW%20Guidelines.doc.

13.1.4 Using ReleaseComObject Do call ReleaseComObject if it's important to release the underlying COM object in a

timely fashion (for example, when the underlying COM object holds on to precious resources), and you know for sure that no other managed code will try to access this COM object after you have called ReleaseComObject.

Do not use ReleaseComObject for a client application using a modest number of COM objects that are passed around freely in your managed code.

For more detailed information on ReleaseComObject, see http://blogs.gotdotnet.com/cbrumme/PermaLink.aspx/940d1191-3cc5-4b8d-a8b3-68b47f2f8dcb.

13.2 Platform SupportManaged assemblies should be word size agnostic (i.e. should be designed to work on both 32 and 64 bit platforms). In most cases, making an assembly word size agnostic is very simple or even automatic. In other cases, it may require careful design of the interop layer.

Do use IntPtr to represent pointers and handles. Do not use Int32, UInt32, or any other fixed size types. Pointers and handles are 64-bit wide on 64-bit OS. [DllImport("user32.dll", CharSet=CharSet.Auto)]static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);

Do not assume fixed pointer size. Use IntPtr.Size in any word size dependent code.IntPtr addr = Marshal.ReadIntPtr(address, offset * IntPtr.Size);

Do pay special attention to any code doing pointer arithmetic.223

.NET Framework Design Guidelines Microsoft Confidential

13.3 Threading Avoid providing static methods that mutate static state158.

In common server scenarios, static state is shared across requests, which means multiple threads can execute that code at the same time. This opens up the possibility for threading bugs. Consider using a design pattern that encapsulates data into instances that are not shared across requests.

Do design your library with consideration for the stress of running in a server scenario. Avoid taking locks if at all possible.

Do be aware that instance state does not always need to be thread-safe .By default, the libraries should not be thread-safe. Adding locks to create thread safe code decreases performance and increases lock contention (as well as opening up deadlock bugs). In common application models, only one thread at a time executes user code, which minimizes the need for thread safety. For this reason, the .NET libraries are not thread safe by default. In cases where it is interesting to provide a thread safe version provide a static Synchronized() method that returns a thread safe instance of that type. (See System.Collections.ArrayList.Synchronized() and System.Collections.ArrayList.IsSynchronized as an example).  Annotation (RicoM): When you decide to do the locking yourself you're saying you know a lot about the threading context of the usage.  That is generally not true. For example if you're a collection class you generally have no business locking anything because the real unit of work is bigger than you are and your additional locks will only slow things down. 

Do make all static state must be thread safe.If you must use static state, make it thread safe. In common server scenarios, static data is shared across requests, which means multiple threads can execute that code at the same time. For this reason it is necessary to protect static state.

Do be aware of non-atomic operations.Value types whose underlying representations are greater than 32 bits may have non-atomic operations. Specifically, because value types are copied bitwise (by value as opposed to by reference), race conditions can occur in what appears to be straightforward assignments within code.For example, consider the following code (executing on two separate threads) where the variable x has been declared as type Int64.// Code executing on Thread "A".x = 54343343433;// Code executing on Thread "B".x = 934343434343;

At first glance it seems to indicate that there is no possibility of race conditions (since each line looks like a straight assignment operation). However, because the underlying variable is a 64-bit value type, the actual code is not doing an atomic assignment operation. Instead, it is doing a bitwise copy of two 32 bit halves. In the event of a context switch, halfway during the value type assignment operation on one of the

158 Fully covered by FxCop rule: UsageRules/AvoidNonConstantStaticFields.224

Brad Abrams, 12/13/04,
Add: “Avoid taking the same lock recursively” would be a good recommendation in my opinion, but mostly from the design point of view, not so much because extra locks hurt performance. Even though lock() allows recursive locking, it’s better design if every function “knows” if it’s supposed to take the lock itself, or if the lock has to be already taken.
Brad Abrams, 12/13/04,
We should add this one: In general, I think we should mention that if the code has to acquire more than one lock at the same time, it should prioritize locks and make sure they are always acquired in the same order to avoid deadlocks.
Brad Abrams, 12/13/04,
Add more data from: http://www.sgi.com/tech/stl/thread_safety.html
Brad Abrams, 12/13/04,
Rationalize with this blog posting: blog

.NET Framework Design Guidelines Microsoft Confidentialthreads, the resulting x variable can have corrupt data (for example, the resulting value will be composed of 32 bits of the first number, and 32 bits of the second number).Addressing this problem by taking an internal lock within the value type tends to be a prohibitively expensive solution (in terms of lock contention and lock overhead). Note that this problem does not exist only for Int64 types. It also exists for the Guid, Decimal, TimeSpan, and DateTime types, as well as any value type that is greater than 64 bits.

Do be aware of method calls in locked sections.Deadlocks can result when a static method in class A calls static methods in class B and vice versa. If A and B both synchronize their static methods, this will cause a deadlock. You might only discover this deadlock under heavy threading stress.Performance issues can result when a static method in class A calls a static method in class A. If these methods are not factored correctly, performance will suffer because there will be a large amount of redundant synchronization. Excessive use of fine-grained synchronization might negatively impact performance. In addition, it might have a significant negative impact on scalability. Every synchronized block requires a minimum of two lock prefixes even without contention. I worry about what this means on a quadproc server.

Consider using System.Threading.Interlocked for simple atomic updates . It's tempting to use the lock statement in C# to solve all threading problems. But the System.Threading.Interlocked class is superior for updates that must be made atomically. It only executes a single lock prefix if there is no contention. A code review should watch out for instances like the following.lock(syncRoot) { myField++;}

Alternatively, it might be better to use more elaborate code to create rhs outside of the lock as in the following example. Then, you can use an interlocked compare exchange to update x only if it is still null. This assumes that creation of duplicate rhs values does not cause negative side effects.if (x == null) { lock (syncRoot) { if (x == null) { //Perform some elaborate code to create rhs x = rhs; } }}

Do not lock on any public types, or on instances you do not control.  Notice that the common constructconstructs lock (this), lock (typeof (MyType)), and lock (“myLock”) violate this guideline.

o lock(this) is a problem if the instance can be accessed publicly. 225

Brad Abrams, 12/13/04,
example would be useful showing how this can be “public” and cause problems when used to lock.
Brad Abrams, 12/13/04,
Change to use Interlocked???
Brad Abrams, 12/13/04,
Consider adding something on double checked locking: This part should probably be a separate guideline (“Double-checked locking”). Note that we have publicly stated in the past that such code needs explicit ‘volatile’ barriers:   http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/singletondespatt.asp http://msdn.microsoft.com/practices/type/patterns/enterprise/impsingletonincsharp/
Brad Abrams, 12/13/04,
Put an “X” icon by this as it is bad code
Brad Abrams, 12/13/04,
Fold in: Also, we should mention that this can only be done if the update is not a part of a larger operation that has to be atomic as a whole

.NET Framework Design Guidelines Microsoft Confidentialo lock (typeof(MyType)) is a problem if MyType is publicly accessableo lock (“myLock”) is a problem because literal strings are interned by the CLR

thus anyone else in the process using the same string will share the same lock.

The best practice is to create an object solely for the purpose of lock.

Annotation (Dmitry Robsman) – In Whidbey we changed lots of ASP.NET code from using lock(this). This is the pattern we used:public class A { … lock(this) { … } …}

to this:public class A { private Object thisLock = new Object(); … lock(thisLock) { … } …}

Do not lock on string literals, This is bad because string literals are normally interned, meaning that there is one instance of any given string literal for the entire program.  The exact same object represents the literal in all running appdomains, on all threads. class MyClass {     private static String myLock = “LockString“;    public void Foo()    {     lock(myLock) { ... }    } }

If someone else comes along and locks a literal named “LockString” her lock will interfere with yours.

Avoid locking at a too low level; consider if thread safety should be the responsibility of the caller Perhaps your caller should do the locking. Annotation (Glenn Hackney) – This is the approach generally taken by the .NET Frameworks. It speeds up processing in the most common case, and requires extra work only when synchronization is absolutely needed. I've always thought this was an extremely good feature of FX.

Granularity trade-off – concurrency vs. cost

Consider Interlocked.Exchange() is atomic exchange is all that is needed or ReaderWriterLock if you have a lot of readers and the occasional writer.

Annotation (Rico Mariani) – The ReaderWriterLock class is the best implementation of reader-writer locks I can imagine, I got to code review it not too long ago. It's still not free, but it's darn good. Regular lock is cheaper, but if you need RWLock then that's what you should use. But don't use what you don't need. If you get a concurrency win from RWLock it often pays for itself.

226

Brad Abrams, 12/13/04,
This is similar to the synchronized collection wrappers issue. In fact, I think that this could be merged with the “Do be aware that instance state does not need to be thread-safe” guideline.

.NET Framework Design Guidelines Microsoft Confidential Do use the ThreadPool for best performance instead of creating and managing your own

threads. ] Avoid creating architectures which require developers to deal with threading or

concurrency issues. Wherever possible, try to have the infrastructure, not the user, handle threading complexities on behalf of user code. In your documentation, be sure to call out scenarios (like shared mutable data) where users do need to be aware of concurrency.Annotation (Brad Abrams):ASP.NET does a great job of this. With ASP.NET we get great scaling but the user does not typically have to deal with threading issues.

Avoid the need for synchronization if possible.Obviously for high traffic pathways it is nice to avoid synchronization. Sometimes the algorithm can be adjusted to tolerate races rather than eliminating them.

14 Appendixes

14.1 Appendix I: The .NET Framework Overview

14.1.1 Generics Overview

14.2 Appendix II: FxCop

14.3 Appendix III: C# Style GuideFuture Topics

14.3.1 Exposing Platform Specific

Some managed libraries want to take advantage of the cross-platform nature of the runtime. These classes should not directly expose platform specific constructors in their APIs.

Need to flush out the NativePtr deal and the implication to the verifier (if any). Specifically we need to hit on if "full trust" security calls will be needed in these cases or not.

14.3.2 Synchronization and Concurrency

Add concurrency patterns that class designers should use in the Managed world. Specific explanations of class, method and inter-method synchronization could be useful, along with a description of the Interlocked class.

227

Krzysztof Cwalina, 12/13/04,
This should be covered ASAP.
Krzysztof Cwalina, 12/13/04,
Let’s remove this section and make sure we have it in the PS database.

.NET Framework Design Guidelines Microsoft ConfidentialIt would also be useful to highlight some of the decisions the Framework class library has made regarding synchronization (for example, for performance reasons, collections do not provide built-in synchronization semantics), and how developers can help communicate these design choices to customers.

14.3.3 Remoting

How do class designers plan for Remoting (what the rules/implications)? How/when should developers provide serialization capabilities on their classes?

14.3.4 Internationalization

How do developers design for localization or external resource usage?

14.3.5 Deployment

What are the recommended patterns for packaging up class frameworks into assemblies? Windows Forms seems to? Have adopted a strategy whereby all namespace units (System.Data, etc.) are packaged into separate DLLs. Should other class developers follow this?

14.3.6 Component Model

What is it? How and when should these classes be used? How does this aid in tools support?

14.3.7 Callback mechanisms

Events vs. callback delegates vs. callback interfaces. We provide several "callback" mechanisms: events (example: button), delegate (example: refelection member filters), interface (example: IComparer). What are the guidelines for selecting between these mechanisms?

14.3.8 Remoting vs. Messages

What are the guidelines for using explicit message transfer instead of a remote method call?

228

Krzysztof Cwalina, 12/13/04,
Some people indicated they need this topic.