0% found this document useful (0 votes)
902 views84 pages

Framework Design Guidelines PDF

Uploaded by

saljic
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
902 views84 pages

Framework Design Guidelines PDF

Uploaded by

saljic
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 84

Praise for Framework Design Guidelines

Framework Design Guidelines is one of those rare books that can be read at differ-
ent reading levels and can be useful to different kinds of developers. Regardless
of whether you want to design an effective object model, improve your under-
standing of the .NET Framework, borrow from the experience of software
gurus, stay clear of the most common programming mistakes, or just get an
idea of the huge effort that led to the .NET initiative, this book is a must-read.
Francesco Balena, The VB Migration Partner Team (www.vbmigration.com),
Code Architect, Author, and Microsoft Regional Director, Italy

Frameworks are valuable but notoriously difficult to construct: your every


decision must be geared toward making them easy to be used correctly and
difficult to be used incorrectly. This book takes you through a progression of
recommendations that will eliminate many of those downstream I wish Id
known that earlier moments. I wish Id read it earlier.
Paul Besly, Principal Technologist, QA

Not since Brooks The Mythical Man Month has the major software maker of
its time produced a book so full of relevant advice for the modern software
developer. This book has a permanent place on my bookshelf and I consult it
frequently.
George Byrkit, Senior Software Engineer, Genomic Solutions

Updated for the new language features of the .NET Framework 3.0 and 3.5,
this book continues to be the definitive resource for .NET developers and
architects who are designing class library frameworks. Some of the existing
guidelines have been expanded with new annotations and more detail, and
new guidance covering such features as extension methods and nullable
types has also been included. The guidance will help any developer write
clearer and more understandable code, while the annotations provide invalu-
able insight into some of the design decisions that made the .NET Framework
what it is today.
Scott Dorman, Microsoft MVP and President,
Tampa Bay International Association of Software Architects
Filled with information useful to developers and architects of all levels, this
book provides practical guidelines and expert background information to
get behind the rules. Framework Design Guidelines takes the already pub-
lished guidelines to a higher level, and it is needed to write applications
that integrate well in the .NET area.
Cristof Falk, Software Engineer

This book is an absolute must read for all .NET developers. It gives clear do
and dont guidance on how to design class libraries for .NET. It also offers
insight into the design and creation of .NET that really helps developers under-
stand the reasons why things are the way they are. This information will aid
developers designing their own class libraries and will also allow them to take
advantage of the .NET class library more effectively.
Jeffrey Richter, Author/Trainer/Consultant, Wintellect

The second edition of Framework Design Guidelines gives you new, important
insight into designing your own class libraries: Abrams and Cwalina frankly
discuss the challenges of adding new features to shipping versions of their prod-
ucts with minimal impact on existing code. Youll find great examples of how to
create version N+1 of your software by learning how the .NET class library team
created versions 2.0, 3.0, and 3.5 of the .NET library. They were able to add gener-
ics, WCF, WPF, WF, and LINQ with minimal impact on the existing APIs, even
providing capabilities for customers wanting to use only some of the new fea-
tures, while still maintaining compatibility with the original library.
Bill Wagner, Founder and Consultant, SRT Solutions,
author of Effective C# and More Effective C#

This book is a must read for all architects and software developers thinking
about frameworks. The book offers insight into some driving factors behind
the design of the .NET Framework. It should be considered mandatory reading
for anybody tasked with creating application frameworks.
Peter Winkler, Sr. Software Engineer, Balance Technology Inc.
Framework Design Guidelines
Second Edition

Microsoft .NET Development Series

Visit informit.com /msdotnetseries for a complete list of available products.

he award-winning Microsoft .NET Development Series was


T established in 2002 to provide professional developers with the
most comprehensive, practical coverage of the latest .NET technologies.
Authors in this series include Microsoft architects, MVPs, and other
experts and leaders in the field of Microsoft development technologies.
Each book provides developers with the vital information and critical
insight they need to write highly effective applications.
Framework
Design
Guidelines
Conventions, Idioms, and Patterns
for Reusable .NET Libraries
Second Edition
Krzysztof Cwalina
Brad Abrams

Upper Saddle River, NJ Boston Indianapolis San Francisco


New York Toronto Montreal London Munich Paris Madrid
Capetown Sydney Tokyo Singapore Mexico City
Many of the designations used by manufacturers Library of Congress Cataloging-in-Publication Data
and sellers to distinguish their products are claimed
Cwalina, Krzysztof.
as trademarks. Where those designations appear in
Framework design guidelines : conventions,
this book, and the publisher was aware of a trade-
idioms, and patterns for reusable .NET libraries /
mark claim, the designations have been printed
Krzysztof Cwalina, Brad Abrams. 2nd ed.
with initial capital letters or in all capitals.
p. cm.
Includes bibliographical references and index.
The .NET_logo is either a registered trademark or
ISBN 978-0-321-54561-9 (hardcover : alk. paper)
trademark of Microsoft Corporation in the United
1. Microsoft .NET Framework. 2. Application
States and/or other countries and is used under
program interfaces (Computer software) I.
license from Microsoft.
Abrams, Brad. II. Title.

Microsoft, Windows, Visual Basic, Visual C#, and


QA76.76.M52C87 2008
Visual C++ are either registered trademarks or
006.7882dc22
trademarks of Microsoft Corporation in the U.S.A.
2008034905
and/or other countries/regions.
Copyright 2009 Microsoft Corporation
The authors and publisher have taken care in the
preparation of this book, but make no expressed or
All rights reserved. Printed in the United States of
implied warranty of any kind and assume no
America. This publication is protected by copy-
responsibility for errors or omissions. No liability is
right, and permission must be obtained from the
assumed for incidental or consequential damages in
publisher prior to any prohibited reproduction,
connection with or arising out of the use of the infor-
storage in a retrieval system, or transmission in any
mation or programs contained herein.
form or by any means, electronic, mechanical, pho-
tocopying, recording, or likewise. For information
The publisher offers excellent discounts on this book
regarding permissions, write to:
when ordered in quantity for bulk purchases or spe-
cial sales, which may include electronic versions
Pearson Education, Inc.
and/or custom covers and content particular to your
Rights and Contracts Department
business, training goals, marketing focus, and brand-
501 Boylston Street, Suite 900
ing interests. For more information, please contact:
Boston, MA 02116
Fax (617) 671 3447
U.S. Corporate and Government Sales
(800) 382-3419
ISBN-13: 978-0-321-54561-9
corpsales@pearsontechgroup.com
ISBN-10: 0-321-54561-3

For sales outside the United States please contact:


Text printed in the United States on recycled paper
at Donnelley in Crawfordsville, Indiana.
International Sales
Third printing, December 2009
international@pearson.com

Visit us on the Web: informit.com/aw


To my wife, Ela,
for her support throughout the long process of writing this book,
and to my parents,
Jadwiga and Janusz, for their encouragement.
Krzysztof Cwalina

To my wife, Tamara:
Your love and patience strengthen me.
Brad Abrams
This page intentionally left blank
Contents

Figures xvii
Tables xix
Foreword xxi
Foreword to the First Edition xxiii
Preface xxv
Acknowledgments xxxi
About the Authors xxxiii
About the Annotators xxxv

1 Introduction 1
1.1 Qualities of a Well-Designed Framework 3
1.1.1 W
ell-Designed Frameworks Are Simple 3
1.1.2 W
ell-Designed Frameworks Are Expensive to Design 4
1.1.3 W
ell-Designed Frameworks Are Full of Trade-Offs 5
1.1.4 W
ell-Designed Frameworks Borrow from the Past 5
1.1.5 W
ell-Designed Frameworks Are Designed to Evolve 5
1.1.6 W
ell-Designed Frameworks Are Integrated 6
1.1.7 W
ell-Designed Frameworks Are Consistent 6

2 Framework Design Fundamentals 9


2.1 Progressive Frameworks 11
2.2Fundamental Principles of Framework Design 14
2.2.1 T
he Principle of Scenario-Driven Design 15
2.2.2 T
he Principle of Low Barrier to Entry 21

ix
x Contents

2.2.3 T
he Principle of Self-Documenting Object Models 26
2.2.4 T
he Principle of Layered Architecture 33

3 Naming Guidelines 37
3.1 Capitalization Conventions 38
3.1.1 C
apitalization Rules for Identifiers 38
3.1.2 C
apitalizing Acronyms 40
3.1.3 C
apitalizing Compound Words and Common Terms 43
3.1.4 C
ase Sensitivity 45
3.2 General Naming Conventions 46
3.2.1 W
ord Choice 46
3.2.2 U
sing Abbreviations and Acronyms 48
3.2.3 A
voiding Language-Specific Names 49
3.2.4 N
aming New Versions of Existing APIs 51
3.3 Names of Assemblies and DLLs 54
3.4 Names of Namespaces 56
3.4.1 N
amespaces and Type Name Conflicts 58
3.5 Names of Classes, Structs, and Interfaces 60
3.5.1 N
ames of Generic Type Parameters 64
3.5.2 N
ames of Common Types 64
3.5.3 N
aming Enumerations 66
3.6 Names of Type Members 68
3.6.1 N
ames of Methods 68
3.6.2 N
ames of Properties 68
3.6.3 N
ames of Events 70
3.6.4 N
aming Fields 72
3.7 Naming Parameters 73
3.7.1 N
aming Operator Overload Parameters 74
3.8 Naming Resources 74

4 Type Design Guidelines 77


4.1 Types and Namespaces 79
4.1.1 S
tandard Subnamespace Names 83
4.2 Choosing Between Class and Struct 84
Contents xi

4.3 Choosing Between Class and Interface 88


4.4 Abstract Class Design 95
4.5 Static Class Design 97
4.6 Interface Design 98
4.7 Struct Design 101
4.8 Enum Design 103
4.8.1 D
esigning Flag Enums 110
4.8.2 A
dding Values to Enums 114
4.9 Nested Types 115
4.10 Types and Assembly Metadata 118

5 Member Design 121


5.1 General Member Design Guidelines 121
5.1.1 M
ember Overloading 121
5.1.2 I mplementing Interface Members Explicitly 128
5.1.3 C
hoosing Between Properties and Methods 132
5.2 Property Design 138
5.2.1 I ndexed Property Design 140
5.2.2 P
roperty Change Notification Events 142
5.3 Constructor Design 144
5.3.1 T
ype Constructor Guidelines 151
5.4 Event Design 153
5.4.1 C
ustom Event Handler Design 159
5.5 Field Design 159
5.6 Extension Methods 162
5.7 Operator Overloads 168
5.7.1 Overloading Operator == 173
5.7.2 C
onversion Operators 173
5.8 Parameter Design 175
5.8.1 C
hoosing Between Enum and Boolean Parameters 177
5.8.2 V
alidating Arguments 179
5.8.3 P
arameter Passing 183
5.8.4 M
embers with Variable Number of Parameters 186
5.8.5 P
ointer Parameters 190
xii Contents

6 Designing for Extensibility 193


6.1 Extensibility Mechanisms 193
6.1.1 U
nsealed Classes 194
6.1.2 P
rotected Members 196
6.1.3 E
vents and Callbacks 197
6.1.4 V
irtual Members 201
6.1.5 A
bstractions (Abstract Types and Interfaces) 203
6.2 Base Classes 206
6.3 Sealing 207

7 Exceptions 211
7.1 Exception Throwing 216
7.2 Choosing the Right Type of Exception to Throw 221
7.2.1 E
rror Message Design 225
7.2.2 E
xception Handling 227
7.2.3 W
rapping Exceptions 232
7.3 Using Standard Exception Types 234
7.3.1
Exception and SystemException 234
7.3.2
ApplicationException 234
7.3.3
InvalidOperationException 235
7.3.4
A
 rgumentException, ArgumentNullException, and
ArgumentOutOfRangeException 235
7.3.5
N
 ullReferenceException, IndexOutOfRangeException, and
AccessViolationException 237
7.3.6
StackOverflowException 237
7.3.7
OutOfMemoryException 238
7.3.8 
ComException, SEHException, and ExecutionEngine
Exception 239
7.4 Designing Custom Exceptions 239
7.5 Exceptions and Performance 240
7.5.1 T
ester-Doer Pattern 241
7.5.2 T
ry-Parse Pattern 242
Contents xiii

8 Usage Guidelines 245


8.1 Arrays 245
8.2 Attributes 247
8.3 Collections 250
8.3.1 C
ollection Parameters 252
8.3.2 C
ollection Properties and Return Values 253
8.3.3 C
hoosing Between Arrays and Collections 258
8.3.4 I mplementing Custom Collections 259
8.4 DateTime and DateTimeOffset 261
8.5
ICloneable 263
8.6
IComparable<T> and IEquatable<T> 264
8.7
IDisposable 266
8.8
Nullable<T> 266
8.9 Object 268
8.9.1 O
bject.Equals 268
8.9.2 O
bject.GetHashCode 270
8.9.3 O
bject.ToString 271
8.10 Serialization 274
8.10.1 Choosing the Right Serialization Technology to Support 275
8.10.2 S
upporting Data Contract Serialization 276
8.10.3 S
upporting XML Serialization 280
8.10.4 S
upporting Runtime Serialization 281
8.11
Uri 283
8.11.1
System.Uri Implementation Guidelines 284
8.12 System.Xml Usage 284
8.13 Equality Operators 286
8.13.1 E
quality Operators on Value Types 287
8.13.2 E
quality Operators on Reference Types 287

9 Common Design Patterns 289


9.1 Aggregate Components 289
9.1.1 C
omponent-Oriented Design 291
9.1.2 F
actored Types 294
9.1.3 A
ggregate Component Guidelines 295
xiv Contents

9.2 The Async Patterns 298


9.2.1 C
hoosing Between the Async Patterns 298
9.2.2 C
lassic Async Pattern 300
9.2.3 C
lassic Async Pattern Basic Implementation Example 304
9.2.4 E
vent-Based Async Pattern 305
upporting Out and Ref Parameters 307
9.2.5 S
9.2.6 S
upporting Cancellation 308
9.2.7 S
upporting Progress Reporting 309
9.2.8 S
upporting Incremental Results 311
9.3 Dependency Properties 312
9.3.1 D
ependency Property Design 313
9.3.2 A
ttached Dependency Property Design 315
9.3.3 D
ependency Property Validation 316
9.3.4 D
ependency Property Change Notifications 317
9.3.5 D
ependency Property Value Coercion 318
9.4 Dispose Pattern 319
9.4.1 B
asic Dispose Pattern 322
9.4.2 F
inalizable Types 328
9.5 Factories 332
9.6 LINQ Support 337
9.6.1 O
verview of LINQ 337
9.6.2 W
ays of Implementing LINQ Support 339
upporting LINQ through IEnumerable<T> 339
9.6.3 S
upporting LINQ through IQueryable<T> 340
9.6.4 S
9.6.5 S
upporting LINQ through the Query Pattern 341
9.7 Optional Feature Pattern 344
9.8 Simulating Covariance 348
9.9 Template Method 354
9.10 Timeouts 356
9.11 XAML Readable Types 358
9.12 And in the End... 361

A C# Coding Style Conventions 363


A.1 General Style Conventions 364
A.1.1 B
race Usage 364
A.1.2 S
pace Usage 365
Contents xv

A.1.3 I ndent Usage 367


A.1.4 O
ther 367
A.2 Naming Conventions 367
A.3 Comments 368
A.4 File Organization 369

B Using FxCop to Enforce the Framework Design Guidelines 371


B.1 What Is FxCop? 371
B.2 The Evolution of FxCop 372
B.3 How Does It Work? 373
B.4 FxCop Guideline Coverage 374
B.4.1 F
xCop Rules for the Naming Guidelines 374
B.4.2 F
xCop Rules for the Type Design Guidelines 384
B.4.3 F
xCop Rules for Member Design 387
B.4.4 F
xCop Rules for Designing for Extensibility 394
B.4.5 F
xCop Rules for Exceptions 395
B.4.6 F
xCop Rules for Usage Guidelines 397
B.4.7 F
xCop Rules for Design Patterns 402

C Sample API Specification 405

Glossary 413
Suggested Reading List 419
Index 423
This page intentionally left blank
Figures

Figure 2-1: Learning curve of a multiframework platform 12


Figure 2-2: Learning curve of a progressive framework platform 13
Figure 4-1: The logical grouping of types 77
Figure 9-1: Query Pattern Method Signatures 341

xvii
This page intentionally left blank
Tables

5BCMF Capitalization Rules for Different Types of Identiers 40


5BCMF Capitalization and Spelling for Common Compound
Words and Common Terms 43
5BCMF CLR Type Names for Language-Specic Type Names 50
5BCMF Name Rules for Types Derived from or Implementing
Certain Core Types 65
5BCMF Operators and Corresponding Method Names 172
5BCMF .NET Framework Serialization Technologies 274
5BCMF# Sufxes for Common Base Types and Interfaces 379
5BCMF# Symmetric Operators 392
5BCMF# Exceptions to Avoid Throwing 396

YJY
This page intentionally left blank
Foreword

When the .NET Framework was first published, I was fascinated by the
technology. The benefits of the CLR (Common Language Runtime), its
extensive APIs, and the C# language were immediately obvious. But
underneath all the technology were a common design for the APIs and a
set of conventions that were used everywhere. This was the .NET culture.
Once you had learned a part of it, it was easy to translate this knowledge
into other areas of the Framework.
For the past 16 years, I have been working on open source software.
Since contributors span not only multiple backgrounds but multiple years,
adhering to the same style and coding conventions has always been very
important. Maintainers routinely rewrite or adapt contributions to soft-
ware to ensure that code adheres to project coding standards and style. It
is always better when contributors and people who join a software project
follow conventions used in an existing project. The more information that
can be conveyed through practices and standards, the simpler it becomes
for future contributors to get up-to-speed on a project. This helps the proj-
ect converge code, both old and new.
As both the .NET Framework and its developer community have
grown, new practices, patterns, and conventions have been identified.
Brad and Krzysztof have become the curators who turned all of this new
knowledge into the present-day guidelines. They typically blog about a
new convention, solicit feedback from the community, and keep track of

xxi
xxii Foreword

these guidelines. In my opinion, their blogs are must-read documents


for everyone who is interested in getting the most out of the .NET
Framework.
The first edition of Framework Design Guidelines became an instant clas-
sic in the Mono community for two valuable reasons. First, it provided us
a means of understanding why and how the various .NET APIs had been
implemented. Second, we appreciated it for its invaluable guidelines that
we too strived to follow in our own programs and libraries. This new edi-
tion not only builds on the success of the first but has been updated with
new lessons that have since been learned. The annotations to the guide-
lines are provided by some of the lead .NET architects and great program-
mers who have helped shape these conventions.
In conclusion, this text goes beyond guidelines. It is a book that you
will cherish as the classic that helped you become a better programmer,
and there are only a select few of those in our industry.

Miguel de Icaza
Boston, MA
Foreword to the First Edition

In the early days of development of the .NET Framework, before it was


even called that, I spent countless hours with members of the develop-
ment teams reviewing designs to ensure that the final result would be a
coherent platform. I have always felt that a key characteristic of a frame-
work must be consistency. Once you understand one piece of the frame-
work, the other pieces should be immediately familiar.
As you might expect from a large team of smart people, we had many
differences of opinionthere is nothing like coding conventions to spark
lively and heated debates. However, in the name of consistency, we grad-
ually worked out our differences and codified the result into a common
set of guidelines that allow programmers to understand and use the
Framework easily.
Brad Abrams, and later Krzysztof Cwalina, helped capture these
guidelines in a living document that has been continuously updated and
refined during the past six years. The book you are holding is the result of
their work.
The guidelines have served us well through three versions of the .NET
Framework and numerous smaller projects, and they are guiding the
development of the next generation of APIs for the Microsoft Windows
operating system.

xxiii
xxiv Foreword to the First Edition

With this book, I hope and expect that you will also be successful in
making your frameworks, class libraries, and components easy to under-
stand and use.
Good luck and happy designing.

Anders Hejlsberg
Redmond, WA
June 2005
Preface

This book, Framework Design Guidelines, presents best practices for design-
ing frameworks, which are reusable object-oriented libraries. The guide-
lines are applicable to frameworks in various sizes and scales of reuse,
including the following:

Large system frameworks, such as the .NET Framework, usually


consisting of thousands of types and used by millions of developers.
Medium-size reusable layers of large distributed applications or
extensions to system frameworks, such as the Web Services
Enhancements.
Small components shared among several applications, such as a grid
control library.

It is worth noting that this book focuses on design issues that directly
affect the programmability of a framework (publicly accessible APIs1). As
a result, we generally do not cover much in terms of implementation
details. Just as a user interface design book doesnt cover the details of
how to implement hit testing, this book does not describe how to imple-
ment a binary sort, for example. This scope allows us to provide a definitive
guide for framework designers instead of being yet another book about
programming.

1. This includes public types, and their public, protected, and explicitly implemented mem-
bers of these types.

xxv
xxvi Preface

These guidelines were created in the early days of .NET Framework


development. They started as a small set of naming and design conven-
tions but have been enhanced, scrutinized, and refined to a point where
they are generally considered the canonical way to design frameworks at
Microsoft. They carry the experience and cumulative wisdom of thousands
of developer hours over three versions of the .NET Framework. We tried
to avoid basing the text purely on some idealistic design philosophies, and
we think its day-to-day use by development teams at Microsoft has made
it an intensely pragmatic book.
The book contains many annotations that explain trade-offs, explain
history, amplify, or provide critiquing views on the guidelines. These anno-
tations are written by experienced framework designers, industry experts,
and users. They are the stories from the trenches that add color and setting
for many of the guidelines presented.
To make them more easily distinguished in text, namespace names,
classes, interfaces, methods, properties, and types are set in monospace font.
The book assumes basic familiarity with .NET Framework program-
ming. A few guidelines assume familiarity with features introduced in
version 3.5 of the Framework. If you are looking for a good introduction to
Framework programming, there are some excellent suggestions in the
Suggested Reading List at the end of the book.

Guideline Presentation
The guidelines are organized as simple recommendations using Do,
Consider, Avoid, and Do not. Each guideline describes either a good or
bad practice, and all have a consistent presentation. Good practices have
a 3 in front of them, and bad practices have an 7 in front of them. The
wording of each guideline also indicates how strong the recommendation
is. For example, a Do guideline is one that should always2 be followed (all
examples are from this book):

2. Always might be a bit too strong a word. There are guidelines that should literally be always
followed, but they are extremely rare. On the other hand, you probably need to have a
really unusual case for breaking a Do guideline and still have it be beneficial to the users of
the framework.
Preface xxvii

3 DO name custom attribute classes with the suffix Attribute.


public class ObsoleteAttribute : Attribute { ... }

On the other hand, Consider guidelines should generally be followed,


but if you fully understand the reasoning behind a guideline and have a
good reason to not follow it anyway, you should not feel bad about break-
ing the rules:

3 CONSIDER defining a struct instead of a class if instances of the type are


small and commonly short-lived or are commonly embedded in other
objects.

Similarly, Do not guidelines indicate something you should almost


never do:

7 DO NOT assign instances of mutable types to read-only fields.


Less strong, Avoid guidelines indicate that something is generally not a
good idea, but there are known cases where breaking the rule makes sense:

7 AVOID using ICollection<T> or ICollection as a parameter just to


access the Count property.

Some more complex guidelines are followed by additional background


information, illustrative code samples, and rationale:

3 DO implement IEquatable<T> on value types.


The Object.Equals method on value types causes boxing and its default
implementation is not very efficient because it uses reflection.
IEquatable<T>.Equals can offer much better performance and can be
implemented so it does not cause boxing.

public struct Int32 : IEquatable<Int32> {


public bool Equals(Int32 other){ ... }
}
xxviii Preface

Language Choice and Code Examples


One of the goals of the Common Language Runtime (CLR) is to support a
variety of programming languages: those with implementations provided
by Microsoft, such as C++, VB, C#, F#, Python, and Ruby, as well as third-
party languages such as Eiffel, COBOL, Fortran, and others. Therefore, this
book was written to be applicable to a broad set of languages that can be
used to develop and consume modern frameworks.
To reinforce the message of multilanguage framework design, we con-
sidered writing code examples using several different programming lan-
guages. However, we decided against this. We felt that using different
languages would help to carry the philosophical message, but it could
force readers to learn several new languages, which is not the objective of
this book.
We decided to choose a single language that is most likely to be read-
able to the broadest range of developers. We picked C#, because it is a
simple language from the C family of languages (C, C++, Java, and C#), a
family with a rich history in framework development.
Choice of language is close to the hearts of many developers, and we
offer apologies to those who are uncomfortable with our choice.

About This Book


This book offers guidelines for framework design from the top down.
Chapter 1, Introduction, is a brief orientation to the book, describing
the general philosophy of framework design. This is the only chapter with-
out guidelines.
Chapter 2, Framework Design Fundamentals, offers principles and
guidelines that are fundamental to overall framework design.
Chapter 3, Naming Guidelines, contains common design idioms and
naming guidelines for various parts of a framework, such as namespaces,
types, and members.
Chapter 4, Type Design Guidelines, provides guidelines for the gen-
eral design of types.
Preface xxix

Chapter 5, Member Design, takes a further step and presents guide-


lines for the design of members of types.
Chapter 6, Designing for Extensibility, presents issues and guidelines
that are important to ensure appropriate extensibility in your framework.
Chapter 7, Exceptions, presents guidelines for working with excep-
tions, the preferred error reporting mechanisms.
Chapter 8, Usage Guidelines, contains guidelines for extending and
using types that commonly appear in frameworks.
Chapter 9, Common Design Patterns, offers guidelines and examples
of common framework design patterns.
Appendix A, C# Coding Style Conventions, contains a short descrip-
tion of coding conventions used in this book.
Appendix B, Using FxCop to Enforce the Framework Design Guide-
lines, describes a tool called FxCop. The tool can be used to analyze frame-
work binaries for compliance with the guidelines described in this book. A
link to the tool is included on the DVD that accompanies this book.
Appendix C, Sample API Specification, is a sample of an API speci-
fication that framework designers within Microsoft create when design-
ing APIs.
Included with the book is a DVD that contains several hours of video
presentations covering topics presented in this book by the authors, a sam-
ple API specification, and other useful resources.
This page intentionally left blank
Acknowledgments

This book, by its nature, is the collected wisdom of many hundreds of


people, and we are deeply grateful to all of them.
Many people within Microsoft have worked long and hard, over a
period of years, proposing, debating, and finally, writing many of these
guidelines. Although it is impossible to name everyone who has been
involved, a few deserve special mention: Chris Anderson, Erik Christensen,
Jason Clark, Joe Duffy, Patrick Dussud, Anders Hejlsberg, Jim Miller,
Michael Murray, Lance Olson, Eric Gunnerson, Dare Obasanjo, Steve
Starck, Kit George, Mike Hillberg, Greg Schecter, Mark Boulter, Asad
Jawahar, Justin Van Patten, and Mircea Trofin.
Wed also like to thank the annotators: Mark Alcazar, Chris Anderson,
Christopher Brumme, Pablo Castro, Jason Clark, Steven Clarke, Joe Duffy,
Patrick Dussud, Mike Fanning, Kit George, Jan Gray, Brian Grunkemeyer,
Eric Gunnerson, Phil Haack, Anders Hejlsberg, David Kean, Rico Mariani,
Anthony Moore, Vance Morrison, Christophe Nasarre, Dare Obasanjo,
Brian Pepin, Jon Pincus, Jeff Prosise, Brent Rector, Jeffrey Richter, Greg
Schechter, Chris Sells, Steve Starck, Herb Sutter, Clemens Szyperski, Mircea
Trofin, and Paul Vick.
Their insights provide much needed commentary, color, humor, and
history that add tremendous value to this book.
Sheridan Harrison and David Kean actually wrote and edited
Appendix B on FxCop, which would not have been done without their
skill and passion for this tool.

xxxi
xxxii Acknowledgments

For all of the help, reviews, and support, both technical and moral, we
thank Martin Heller. And for their insightful and helpful comments, we
appreciate Pierre Nallet, George Byrkit, Khristof Falk, Paul Besley, Bill
Wagner, and Peter Winkler.
We would also like to give special thanks to Susann Ragsdale, who
turned this book from a semi-random collection of disconnected thoughts
into seamlessly flowing prose. Her flawless writing, patience, and fabulous
sense of humor made the process of writing this book so much easier.
About the Authors

Brad Abrams was a founding member of the Common Language Run-


time and .NET Framework teams at Microsoft Corporation. He has been
designing parts of the .NET Framework since 1998 and is currently Group
Program Manager of the .NET Framework team. Brad started his frame-
work design career building the Base Class Library (BCL) that ships as a
core part of the .NET Framework. Brad was also the lead editor on the
Common Language Specification (CLS), the .NET Framework Design
Guidelines, and the libraries in the ECMA\ISO CLI Standard. Brad has
authored and coauthored multiple publications, including Programming
in the .NET Environment and .NET Framework Standard Library Annotated
Reference, Volumes 1 and 2. Brad graduated from North Carolina State
University with a B.S. in computer science. You can find his most recent
musings on his blog at http://blogs.msdn.com/BradA.
Krzysztof Cwalina is a program manager on the .NET Framework team
at Microsoft. He was a founding member of the .NET Framework team and
throughout his career has designed many .NET Framework APIs and
framework development tools, such as FxCop. He is currently leading a
companywide effort to develop, promote, and apply framework design
and architectural guidelines to the .NET Framework. He is also leading the
team responsible for delivering core .NET Framework APIs. Krzysztof
graduated with a B.S. and an M.S. in computer science from the University
of Iowa. You can findhis blog at http://blogs.msdn.com/kcwalina.

xxxiii
This page intentionally left blank
About the Annotators

Mark Alcazar wanted to be a famous sportsman. After discovering he had


no hand-eye coordination or athletic ability, however, he decided a better
career might be computers. Mark has been at Microsoft for the last nine
years, where hes worked on the HTML rendering engine in Internet
Explorer and has been a member of the Windows Presentation Foundation
team since its inception. Mark is a big fan of consistent white space, peach-
nectarine Talking Rain, and spicy food. He has a B.Sc. from the University
of the West Indies and an M.Sc. from the University of Pennsylvania.
Chris Anderson is an architect at Microsoft in the Connected Systems
Division. Chriss primary focus is on the design and architecture of .NET
technologies used to implement the next generation of applications and
services. From 2002 until recently he was the lead architect of the WPF
team. Chris has written numerous articles and white papers, and he has
presented and been a keynote speaker at numerous conferences (Microsoft
Professional Developers Conference, Microsoft TechEd, WinDev, DevCon,
etc.) worldwide. He has a very popular blog at www.simplegeek.com.
Christopher Brumme joined Microsoft in 1997, when the Common
Language Runtime (CLR) team was being formed. Since then, he has con-
tributed to the execution engine portions of the codebase and more broadly
to the design. He is currently focused on concurrency issues in managed
code. Prior to joining the CLR team, Chris was an architect at Borland and
Oracle.

xxxv
xxxvi About the Annotators

Pablo Castro is a technical lead in the SQL Server team. He has contrib-
uted extensively to several areas of SQL Server and the .NET Framework,
including SQL-CLR integration, type-system extensibility, the TDS client-
server protocol, and the ADO.NET API. Pablo is currently involved with
the development of the ADO.NET Entity Framework and also leads the
ADO.NET Data Services project, which is looking at how to bring data and
Web technologies together. Before joining Microsoft, Pablo worked in vari-
ous companies on a broad set of topics that range from distributed infer-
ence systems for credit scoring/risk analysis to collaboration and groupware
applications.
Jason Clark works as a software architect for Microsoft. His Microsoft
software engineering credits include three versions of Windows, three
releases of the .NET Framework, and WCF. In 2000 he published his first
book on software development and continues to contribute to magazines
and other publications. He is currently responsible for the Visual Studio
Team System Database Edition. Jasons only other passions are his wife
and kids, with whom he happily lives in the Seattle area.
Steven Clarke has been a user experience researcher in the Developer
Division at Microsoft since 1999. His main interests are observing, under-
standing, and modeling the experiences that developers have with APIs in
order to help design APIs that provide an optimal experience to their users.
Joe Duffy is the development lead for parallel extensions to .NET at
Microsoft. He codes heavily, manages a team of developers, and defines
the teams long-term vision and strategy. Joe previously worked on con-
currency in the CLR team and was a software engineer at EMC. While not
geeking out, Joe spends his time playing guitar, studying music theory,
and blogging at www.bluebytesoftware.com.
Patrick Dussud is a Technical Fellow at Microsoft, where he serves as
the chief architect of both the CLR and the .NET Framework architecture
groups. He works on .NET Framework issues across the company, helping
development teams best utilize the CLR. He specifically focuses on taking
advantage of the abstractions the CLR provides to optimize program
execution.
Michael Fanning is the current development lead for Expression Web
at Microsoft. He was an early member of the team that produced FxCop
About the Annotators xxxvii

for internal use and ultimately added it to Visual Studio 2005 for release to
the general public.
Kit George is a program manager on the .NET Framework team at
Microsoft. He graduated in 1995 with a B.A. in psychology, philosophy,
and mathematics from Victoria University of Wellington (New Zealand).
Prior to joining Microsoft, he worked as a technical trainer, primarily in
Visual Basic. He participated in the design and implementation of the first
two releases of the Framework for the last two years.
Jan Gray is a software architect at Microsoft who now works on con-
currency programming models and infrastructure. He was previously a
CLR performance architect, and in the 1990s he helped write the early
MS C++ compilers (e.g., semantics, runtime object model, precompiled
headers, PDBs, incremental compilation, and linking) and Microsoft
Transaction Server. Jans interests include building custom multiproces-
sors in FPGAs.
Brian Grunkemeyer has been a software design engineer on the .NET
Framework team at Microsoft since 1998. He implemented a large portion
of the Framework Class Libraries and contributed to the details of the
classes in the ECMA/ISO CLI standard. Brian is currently working on
future versions of the .NET Framework, including areas such as generics,
managed code reliability, versioning, contracts in code, and improving the
developer experience. He has a B.S. in computer science with a double
major in cognitive science from Carnegie Mellon University.
Eric Gunnerson found himself at Microsoft in 1994 after working in
the aerospace and going-out-of-business industries. He has worked on
the C++ compiler team, as a member of the C# language design team, and
as an early thought follower on the DevDiv community effort. He worked
on the Windows DVD Maker UI during Vista and joined the Microsoft
HealthVault team in early 2007.He spends his free time cycling, skiing,
cracking ribs, building decks, blogging, and writing about himself in the
third person.
Phil Haack is a program manager with the ASP.NET team working on
the ASP.NET MVC Framework, which is being developed in a community-
driven transparent manner. The Framework driving goal is to embody and
encourage certain principles of good software design: separation of
xxxviii About the Annotators

c oncerns, testability, and the single responsibility principle, among others.


Phil is also a code junkie and loves to both write software as well as write
about software development on his blog.
Anders Hejlsberg is a technical fellow in the Developer Division at
Microsoft. He is the chief designer of the C# programming language and
a key participant in the development of the .NET Framework. Before join-
ing Microsoft in 1996, Anders was a principal engineer at Borland Inter-
national. As one of the first employees of Borland, he was the original
author of Turbo Pascal and later worked as the chief architect of the Delphi
product line. Anders studied engineering at the Technical University of
Denmark.
David Kean is a developer on the .NET Framework team at Microsoft,
where he works on the Managed Extensibility Framework (MEF), a set of
building blocks for developing extensible and dynamic applications. He
worked earlier on the often well-loved but also greatly misunderstood tool
FxCop and its related sibling, Visual Studio Code Analysis. He graduated
with a B.CS. from Deakin University in Melbourne, Australia, and is now
based in Seattle with his wife, Lucy, and two children, Jack and Sarah.
Rico Mariani began his career at Microsoft in 1988, working on lan-
guage products, beginning with Microsoft C version 6.0, and he contrib-
uted there until the release of the Microsoft Visual C++ version 5.0
development system. In 1995, Rico became development manager for what
was to become the Sidewalk project, which started his seven years of
platform work on various MSN technologies. In the summer of 2002, Rico
returned to the Developer Division as a performance architect on the CLR
team. His performance work led to his most recent assignment as chief
architect of Visual Studio. Ricos interests include compilers and language
theory, databases, 3D art, and good fiction.
Anthony Moore is a development lead for the Connected Systems
Division. He was the development lead for the Base Class Libraries of the
CLR from 2001 to 2007, spanning FX V1.0 to FX 3.5. Anthony joined
Microsoft in 1999 and initially worked on Visual Basic and ASP.NET. Before
that he worked as a corporate developer for eight years in his native Aus-
tralia, including a three-year period working in the snack food industry.
Vance Morrison is a performance architect for the .NET Runtime at
Microsoft. He involves himself with most aspects of runtime performance,
About the Annotators xxxix

with current attention devoted to improving startup time. He has been


involved in designs of components of the .NET runtime since its inception.
He previously drove the design of the .NET Intermediate Language (IL)
and has been the development lead for the JIT compiler for the runtime.
Christophe Nasarre is a software architect and development lead for
Business Objects, a multinational software company from SAP that is
focused on business intelligence solutions. During his spare time, Christophe
writes articles for MSDN Magazine, MSDN, and ASPToday. Since 1996, he
has also worked as a technical editor on numerous books on Win32, COM,
MFC, .NET, and WPF. In 2007, he wrote his first book, Windows via C/C++
from Microsoft Press.
Dare Obasanjo is a program manager on the MSN Communication
Services Platform team at Microsoft. He brings his love of solving prob-
lems with XML to building the server infrastructure utilized by the MSN
Messenger, MSN Hotmail, and MSN Spaces teams. He was previously a
program manager on the XML team responsible for the core XML applica-
tion programming interfaces and W3C XML Schema-related technologies
in the .NET Framework.
Brian Pepin is a software architect at Microsoft and is currently work-
ing on the WPF and Silverlight designers for Visual Studio. Hes been
involved in developer tools and frameworks for 14 years and has provided
input on the design of Visual Basic 5, Visual J++, the .NET Framework,
WPF, Silverlight, and more than one unfortunate experiment that luckily
never made it to market.
Jonathan Pincus was a senior researcher in the Systems and Network-
ing Group at Microsoft Research, where he focused on the security, pri-
vacy, and reliability of software and software-based systems. He was
previously founder and CTO of Intrinsa and worked in design automation
(placement and routing for ICs and CAD frameworks) at GE Calma and
EDA Systems.
Jeff Prosise is a cofounder of Wintellect (www.wintellect.com). His
most recent book, Programming Microsoft .NET, was published by Micro-
soft Press in 2002, and his writings appear regularly in MSDN Magazine
and other developer magazines. Jeffs professional life revolves around
ASP.NET, ASP.NET AJAX, and Silverlight. A reformed engineer who dis-
covered after college that theres more to life than computing loads on
xl About the Annotators

mounting brackets, Jeff is known to go out of his way to get wet in some of
the worlds best dive spots and to spend way too much time building and
flying R/C aircraft.
Brent Rector is a program manager at Microsoft on a technical strategy
incubation effort. He has more than 30 years of experience in the software
development industry in the production of programming language com-
pilers, operating systems, ISV applications, and other products. Brent is
the author and coauthor of numerous Windows software development
books, including ATL Internals, Win32 Programming (both Addison-Wesley),
and Introducing WinFX (Microsoft Press). Prior to joining Microsoft, Brent
was the president and founder of Wise Owl Consulting, Inc. and chief
architect of its premier .NET obfuscator, Demeanor for .NET.
Jeffrey Richter is a cofounder of Wintellect (www.Wintellect.com), a
training, debugging, and consulting firm dedicated to helping companies
build better software faster. He is the author of several best-selling .NET
and Win32 programming books, including Applied Microsoft .NET Frame-
work Programming (Microsoft Press). Jeffrey is also a contributing editor at
MSDN Magazine, where he writes the Concurrent Affairs column. Jeff has
been consulting with Microsofts .NET Framework team since 1999 and
was also a consultant on Microsofts Web Services and Messaging Team.
Greg Schechter has been working on API implementation and API
design for over 20 years, primarily in the 2D and 3D graphics realm, but
also in media, imaging, general user interface systems, and asynchronous
programming. Greg is currently an architect on the Windows Presentation
Foundation and Silverlight teams at Microsoft. Prior to coming to Micro-
soft in 1994, Greg was at Sun Microsystems for six years. Beyond all of
that, Greg also loves to write about himself in the third person.
Chris Sells is a program manager for the Connected Systems Division
at Microsoft. Hes written several books, including Programming WPF,
Windows Forms 2.0 Programming, and ATL Internals. In his free time, Chris
hosts various conferences and makes a pest of himself on Microsoft inter-
nal product team discussion lists.
Steve Starck is a technical lead on the ADO.NET team at Microsoft,
where he has been developing and designing data access technologies,
including ODBC, OLE DB, and ADO.NET, for the past ten years.
About the Annotators xli

Herb Sutter is a leading authority on software development. During


his career, Herb has been the creator and principal designer of several
major commercial technologies, including the PeerDirect peer replication
system for heterogeneous distributed databases, the C++/CLI language
extensions to C++ for .NET programming, and most recently the Concur
concurrent programming model. Currently a software architect at Micro-
soft, he also serves as chair of the ISO C++ standards committee and is the
author of four acclaimed books and hundreds of technical papers and arti-
cles on software development topics.
Clemens Szyperski joined Microsoft Research as a software architect in
1999. He focuses on leveraging component software to effectively build
newkinds ofsoftware. Clemens is cofounder of Oberon Microsystems and
its spin-off, Esmertec, and he was anassociate professor at the School of Com-
puter Science, Queensland University of Technology, Australia, where he
retains an adjunct professorship. He is the author of the Jolt award-winning
Component Software (Addison-Wesley) and the coauthor of Software Ecosystem
(MIT Press). He has a Ph.D. in computer science from the Swiss Federal Insti-
tute of Technology in Zurich and an M.S. in electrical engineering/computer
engineering from the Aachen University of Technology.
Mircea Trofin is a program manager with the .NET Application Frame-
work Core group at Microsoft. He is primarily responsible for driving the
effort for ensuring and improving the architecture of the .NET Framework.
He is also responsible for a number of upcoming features in .NET in the
area of component-based programming. He received his B.A.Sc. in com-
puter engineering from University of Waterloo, and his Ph.D. in computer
science from University College Dublin.
Paul Vick is the language architect for Visual Basic, leading the language
design team. Paul originally began his career working at Microsoft in 1992
on the Microsoft Access team, shipping versions 1.0 through 97 of Access.
In 1998, he moved to the Visual Basic team, participating in the design and
implementation of the Visual Basic compiler and driving the redesign of
the language for the .NET Framework. He is the author of the Visual Basic
.NET Language Specification and the Addison-Wesley book The Visual Basic
.NET Language. His weblog can be found at www.panopticoncentral.net.
This page intentionally left blank
9.6 LINQ Suppor t 337

3 CONSIDER naming factory types by concatenating the name of the type


being created and Factory. For example, consider naming a factory
type that creates Control objects ControlFactory.

The next section discusses when and how to design abstractions that
might or might not support some features.

9.6LINQ Support
Writing applications that interact with data sources, such as databases,
XML documents, or Web Services, was made easier in the .NET Frame-
work 3.5 with the addition of a set of features collectively referred to as
LINQ (Language-Integrated Query). The following sections provide a very
brief overview of LINQ and list guidelines for designing APIs related to
LINQ support, including the so-called Query Pattern.

9.6.1Overview of LINQ
Quite often, programming requires processing over sets of values. Exam-
ples include extracting the list of the most recently added books from a
database of products, finding the e-mail address of a person in a directory
service such as Active Directory, transforming parts of an XML document
to HTML to allow for Web publishing, or something as frequent as looking
up a value in a hashtable. LINQ allows for a uniform language-integrated
programming model for querying datasets, independent of the technology
used to store that data.

n
n Rico Mariani Like everything else, there are good and bad ways to
use these patterns. The Entity Framework and LINQ to SQL offer good
examples of how you can provide rich query semantics and still get very
good performance using strong typing and by offering query compilation.
The Pit of Success notion is very important in LINQ implementations.
Ive seen some cases where the code that runs as a result of using a LINQ
pattern is simply terrible in comparison to what you would write the con-
ventional way. Thats really not good enoughEF and LINQ to SQL let you
write it nicely, and you get high-quality database interactions. Thats what
to aim for.
338 Common De sign Patterns

In terms of concrete language features and libraries, LINQ is embod-


ied as:

A specification of the notion of extension methods. These are


described in detail in section 5.6.
Lambda expressions, a language feature for defining anonymous
delegates.
New types representing generic delegates to functions and proce-
dures: Func<...> and Action<...>.
Representation of a delay-compiled delegate, the Expression<...>
family of types.
A definition of a new interface, System.Linq.IQueryable<T>.
The Query Pattern, a specification of a set of methods a type must
provide in order to be considered as a LINQ provider. A reference
implementation of the pattern can be found in System.Linq. Enumerable
class. Details of the pattern will be discussed later in this chapter.
Query Expressions, an extension to language syntax allowing for
queries to be expressed in an alternative, SQL-like format.

//using extension methods:


var names = set.Where(x => x.Age>20).Select(x=>x.Name);

//using SQL-like syntax:


var names = from x in set where x.Age>20 select x.Name;

n
n Mircea Trofin The interplay between these features is the follow-
ing: Any IEnumerable can be queried upon using the LINQ extension
methods, most of which require one or more lambda expressions as param-
eters; this leads to an in-memory generic evaluation of the queries. For cases
where the set of data is not in memory (e.g., in a database) and/or queries
may be optimized, the set of data is presented as an IQueryable. If lambda
expressions are given as parameters, they are transformed by the compiler
to Expression<...> objects. The implementation of IQueryable is respon-
sible for processing said expressions. For example, the implementation of
an IQueryable representing a database table would translate Expression
objects to SQL queries.
9.6 LINQ Suppor t 339

9.6.2Ways of Implementing LINQ Support


There are three ways by which a type can support LINQ queries:

The type can implement IEnumerable<T> (or an interface derived


from it).
The type can implement IQueryable<T>.
The type can implement the Query Pattern.

The following sections will help you choose the right method of sup-
porting LINQ.

9.6.3Supporting LINQ through IEnumerable<T>


3 DO implement IEnumerable<T> to enable basic LINQ support.
Such basic support should be sufficient for most in-memory data
sets. The basic LINQ support will use the extension methods on
IEnumerable<T> provided in the .NET Framework. For example,
simply define as follows:

public class RangeOfInt32s : IEnumerable<int> {


public IEnumerator<int> GetEnumerator() {...}
IEnumerator IEnumerable.GetEnumerator() {...}
}

Doing so allows for the following code, despite the fact that
RangeOfInt32s did not implement a Where method:

var a = new RangeOfInt32s();


var b = a.Where(x => x>10);

n
n Rico Mariani Keeping in mind that youll get your same enumera-
tion semantics, and putting a LINQ faade on them does not make them
execute any faster or use less memory.

3 CONSIDER implementing ICollection<T> to improve performance of


query operators.
340 Common De sign Patterns

For example, the System.Linq.Enumerable.Count methods default


implementation simply iterates over the collection. Specific collection
types can optimize their implementation of this method, since they
often offer an O(1) - complexity mechanism for finding the size of the
collection.
3 CONSIDER supporting selected methods of System.Linq.Enumerable
or the Query Pattern (see section 9.6.5) directly on new types imple-
menting IEnumerable<T> if it is desirable to override the default
ystem.Linq.Enumerable implementation (e.g., for performance opti-
S
mization reasons).

9.6.4Supporting LINQ through IQueryable<T>


3 CONSIDER implementing IQueryable<T> when access to the query
expression, passed to members of IQueryable, is necessary.
When querying potentially large datasets generated by remote pro-
cesses or machines, it might be beneficial to execute the query remotely.
An example of such a dataset is a database, a directory service, or Web
service.

7 DO NOT implement IQueryable<T> without understanding the perfor-


mance implications of doing so.
Building and interpreting expression trees is expensive, and many que-
ries can actually get slower when IQueryable<T> is implemented.
The trade-off is acceptable in the LINQ to SQL case, since the alterna-
tive overhead of performing queries in memory would have been far
greater than the transformation of the expression to an SQL statement
and the delegation of the query processing to the database server.

3 DO throw NotSupportedException from IQueryable<T> methods that


cannot be logically supported by your data source.
For example, imagine representing a media stream (e.g., an Internet
radio stream) as an IQueryable<byte>. The Count method is not logi-
cally supportedthe stream can be considered as infinite, and so the
Count method should throw NotSupportedException.
9.6 LINQ Suppor t 341

9.6.5Supporting LINQ through the Query Pattern


The Query Pattern refers to defining the methods in Figure 9-1 without
implementing the IQueryable<T> (or any other LINQ interface).
Please note that the notation is not meant to be valid code in any par-
ticular language but to simply present the type signature pattern.
The notation uses S to indicate a collection type (e.g., IEnumerable<T>,
ICollection<T>), and T to indicate the type of elements in that collec-
tion. Additionally, we use O<T> to represent subtypes of S<T> that are
ordered. For example, S<T> is a notation that could be substituted with
IEnumerable<int>, ICollection<Foo>, or even MyCollection (as long as
the type is an enumerable type).
The first parameter of all the methods in the pattern (marked with this)
is the type of the object the method is applied to. The notation uses
extension-method-like syntax, but the methods can be implemented as
extension methods or as member methods; in the latter case the first param-
eter should be omitted, of course, and the this pointer should be used.
Also, anywhere Func<...> is being used, pattern implementations may
substitute Expression<Func<...>> for it. You can find guidelines later that
describe when that is preferable.

S<T> Where(this S<T>, Func<T,bool>)

S<T2> Select(this S<T1>, Func<T1,T2>)


S<T3> SelectMany(this S<T1>, Func<T1,S<T2>>, Func<T1,T2,T3>)
S<T2> SelectMany(this S<T1>, Func<T1,S<T2>>)

O<T> OrderBy(this S<T>, Func<T,K>), where K is IComparable


O<T> ThenBy(this O<T>, Func<T,K>), where K is IComparable

S<T> Union(this S<T>, S<T>)


S<T> Take(this S<T>, int)
S<T> Skip(this S<T>, int)
S<T> SkipWhile(this S<T>, Func<T,bool>)

S<T3> Join(this S<T1>, S<T2>, Func<T1,K1>, Func<T2,K2>,


Func<T1,T2,T3>)

T ElementAt(this S<T>,int)

Figure 9-1: Query Pattern Method Signatures


342 Common De sign Patterns

3 DO implement the Query Pattern as instance members on the new type,


if the members make sense on the type even outside of the context of
LINQ. Otherwise, implement them as extension methods.
For example, instead of the following:

public class MyDataSet<T>:IEnumerable<T>{...}


...
public static class MyDataSetExtensions{
public static MyDataSet<T> Where(this MyDataSet<T> data, Func<T,bool>
query){...}
}

Prefer the following, because its completely natural for datasets to


support Where methods:

public class MyDataSet<T>:IEnumerable<T>{


public MyDataSet<T> Where(Func<T,bool> query){...}
...
}

3 DO implement IEnumerable<T> on types implementing the Query


Pattern.
3 CONSIDER designing the LINQ operators to return domain-specific
enumerable types. Essentially, one is free to return anything from a
Select query method; however, the expectation is that the query result
type should be at least enumerable.
This allows the implementation to control which query methods get
executed when they are chained. Otherwise, consider a user-defined
type MyType, which implements IEnumerable<T>. MyType has an opti-
mized Count method defined, but the return type of the Where method
is IEnumerable<T>. In the example here, the optimization is lost after
the Where method is called; the method returns IEnumerable<T>, and so
the built-in Enumerable.Count method is called, instead of the opti-
mized one defined on MyType.

var result = myInstance.Where(query).Count();


9.6 LINQ Suppor t 343

7 AVOID implementing just a part of the Query Pattern if fallback to the


basic IEnumerable<T> implementations is undesirable.
For example, consider a user-defined type MyType, which implements
IEnumerable<T>. MyType has an optimized Count method defined but
does not have Where. In the example here, the optimization is lost after
the Where method is called; the method returns IEnumerable<T>, and so
the built-in Enumerable.Count method is called, instead of the opti-
mized one defined on MyType.

var result = myInstance.Where(query).Count();

3 DO represent ordered sequences as a separate type, from its unordered


counterpart. Such types should define ThenBy method.
This follows the current pattern in the LINQ to Objects implementa-
tion and allows for early (compile-time) detection of errors such as
applying ThenBy to an unordered sequence.
For example, the Framework provides the IOrderedEnumerable<T>
type, which is returned by OrderBy. The ThenBy extension method is
defined for this type, and not for IEnumerable<T>.
3 DO defer execution of query operator implementations. The expected
behavior of most of the Query Pattern members is that they simply con-
struct a new object which, upon enumeration, produces the elements of
the set that match the query.
The following methods are exceptions to this rule: All, Any, Average,
Contains, Count, ElementAt, Empty, First, FirstOrDefault, Last,
LastOrDefault, Max, Min, Single, Sum.
In the example here, the expectation is that the time necessary for eval-
uating the second line will be independent from the size or nature (e.g.,
in-memory or remote server) of set1. The general expectation is that
this line simply prepares set2, delaying the determination of its com-
position to the time of its enumeration.

var set1 = ...


var set2 = set1.Select(x => x.SomeInt32Property);
foreach(int number in set2){...} // this is when actual work happens
 $PNNPO%F TJHO1BUUFSOT

a %0 place query extensions methods in a Linq subnamespace of the


main namespace. For example, extension methods for System.Data fea-
tures reside in System.Data.Linq namespace.
a %0 use Expression<Func<...>> as a parameter instead of Func<...>
when it is necessary to inspect the query.
As discussed earlier, interacting with an SQL database is already done
through IQueryable<T> (and therefore expressions) rather than
IEnumerable<T>, since this gives an opportunity to translate lambda
expressions to SQL expressions.
An alternative reason for using expressions is performing optimiza-
tions. For example, a sorted list can implement look-up (Where clauses)
with binary search, which can be much more efcient than the standard
IEnumerable<T> or IQueryable<T> implementations.

 0QUJPOBM'FBUVSF1BUUFSO
When designing an abstraction, you might want to allow cases in which
some implementations of the abstraction support a feature or a behav-
ior, whereas other implementations do not. For example, stream imple-
mentations can support reading, writing, seeking, or any combination
thereof.
One way to model these requirements is to provide a base class with
APIs for all nonoptional features and a set of interfaces for the optional
features. The interfaces are implemented only if the feature is actually sup-
ported by a concrete implementation. The following example shows one
of many ways to model the stream abstraction using such an approach.

// framework APIs
public abstract class Stream {
public abstract void Close();
public abstract int Position { get; }
}
public interface IInputStream {
byte[] Read(int numberOfBytes);
}
9.7 Optional Feature Pattern 345

public interface IOutputStream {


void Write(byte[] bytes);
}
public interface ISeekableStream {
void Seek(int position);
}
public interface IFiniteStream {
int Length { get; }
bool EndOfStream { get; }
}

// concrete stream
public class FileStream : Stream, IOutputStream, IInputStream,
ISeekableStream, IFiniteStream {
...
}

// usage
void OverwriteAt(IOutputStream stream, int position, byte[] bytes){
// do dynamic cast to see if the stream is seekable
ISeekableStream seekable = stream as ISeekableStream;
if(seekable==null){
throw new NotSupportedException(...);
}
seekable.Seek(position);
stream.Write(bytes);
}

You will notice the .NET Frameworks System.IO namespace does not
follow this model, and with good reason. Such factored design requires
adding many types to the framework, which increases general complexity.
Also, using optional features exposed through interfaces often requires
dynamic casts, and that in turn results in usability problems.

n
nKrzysztof Cwalina Sometimes framework designers provide inter-
faces for common combinations of optional interfaces. For example, the
OverwriteAt method would not have to use the dynamic cast if the frame-
work design provided ISeekableOutputStream. The problem with this
approach is that it results in an explosion of the number of different inter-
faces for all combinations.

Sometimes the benefits of factored design are worth the drawbacks, but
often they are not. It is easy to overestimate the benefits and underestimate
346 Common De sign Patterns

the drawbacks. For example, the factorization did not help the developer
who wrote the OverwriteAt method avoid runtime exceptions (the main
reason for factorization). It is our experience that many designs incorrectly
err on the side of too much factorization.
The Optional Feature Pattern provides an alternative to excessive fac-
torization. It has drawbacks of its own but should be considered as an
alternative to the factored design described previously. The pattern pro-
vides a mechanism for discovering whether the particular instance sup-
ports a feature through a query API and uses the features by accessing
optionally supported members directly through the base abstraction.

// framework APIs
public abstract class Stream {
public abstract void Close();
public abstract int Position { get; }

public virtual bool CanWrite { get { return false; } }


public virtual void Write(byte[] bytes){
throw new NotSupportedException(...);
}

public virtual bool CanSeek { get { return false; } }


public virtual void Seek(int position){
throw new NotSupportedException(...);
}
... // other options
}

// concrete stream
public class FileStream : Stream {
public override bool CanSeek { get { return true; } }
public override void Seek(int position) { ... }
...
}

// usage
void OverwriteAt(Stream stream, int position, byte[] bytes){
if(!stream.CanSeek || !stream.CanWrite){
throw new NotSupportedException(...);
}
stream.Seek(position);
stream.Write(bytes);
}
9.7 Optional Feature Pattern 347

In fact, the System.IO.Stream class uses this design approach. Some


abstractions might choose to use a combination of factoring and the
Optional Feature Pattern. For example, the Framework collection inter-
faces are factored into indexable and nonindexable collections (IList<T>
and ICollection<T>), but they use the Optional Feature Pattern to differ-
entiate between read-only and read-write collections (ICollection<T>.
IsReadOnly property).

3 CONSIDER using the Optional Feature Pattern for optional features in


abstractions.
The pattern minimizes the complexity of the framework and improves
usability by making dynamic casts unnecessary.

n
n Steve Starck If your expectation is that only a very small percent-
age of classes deriving from the base class or interface would actually imple-
ment the optional feature or behavior, using interface-based design might
be better. There is no real need to add additional members to all derived
classes when only one of them provides the feature or behavior. Also, fac-
tored design is preferred in cases when the number of combinations of the
optional features is small and the compile-time safety afforded by factoriza-
tion is important.

3 DO provide a simple Boolean property that clients can use to determine


whether an optional feature is supported.

public abstract class Stream {


public virtual bool CanSeek { get { return false; } }
public virtual void Seek(int position){ ... }
}

Code that consumes the abstract base class can query this property at
runtime to determine whether it can use the optional feature.

if(stream.CanSeek){
stream.Seek(position);
}
348 Common De sign Patterns

3 DO use virtual methods on the base class that throw NotSupported


Exception to define optional features.

public abstract class Stream {


public virtual bool CanSeek { get { return false; } }
public virtual void Seek(int position){
throw new NotSupportedException(...);
}
}

The method can be overridden by subclasses to provide support for the


optional feature. The exception should clearly communicate to the user
that the feature is optional and which property the user should query
to determine if the feature is supported.

9.8Simulating Covariance
Different constructed types dont have a common root type. For example,
there would not be a common representation of IEnumerable<string> and
IEnumerable<object> if not for a pattern implemented by IEnumerable<T>
called Simulated Covariance. This section describes the details of the
pattern.
Generics is a very powerful type system feature added to the .NET
Framework 2.0. It allows creation of so-called parameterized types. For
example, List<T> is such a type and it represents a list of objects of type T.
The T is specified at the time when the instance of the list is created.

var names = new List<string>();


names.Add("John Smith");
names.Add("Mary Johnson");

Such generic data structures have many benefits over their nonge-
neric counterparts. But they also have somesometimes surprising
limitations. For example, some users expect that a List<string> can be
cast to List<object>, just as a String can be cast to Object. But unfortu-
nately, the following code wont even compile.
9.8 Simulating Covariance 349

List<string> names = new List<string>();


List<object> objects = names; // this won't compile

There is a very good reason for this limitation, and that is to allow for
full strong typing. For example, if you could cast List<string> to a
List<object> the following incorrect code would compile, but the pro-
gram would fail at runtime.

static void Main(){


var names = new List<string>();

// this of course does not compile, but if it did


// the whole program would compile, but would be incorrect as it
// attempts to add arbitrary objects to a list of strings.
AddObjects((List<object>)names);

string name = names[0]; // how could this work?


}

// this would (and does) compile just fine.


static void AddObjects(List<object> list){
list.Add(new object()); // it's a list of strings, really. Should we throw?
list.Add(new Button());
}

Unfortunately, this limitation can also be undesired in some scenarios.


For example, lets consider the following type:

public class CountedReference<T> {


public CountedReference(T value);
public T Value { get; }
public int Count { get; }
public void AddReference();
public void ReleaseReference();
}

There is nothing wrong with casting a CountedReference<string> to


CountedReference<object>, as in the following example.

var reference = new CountedReference<string>(...);


CountedReference<object> obj = reference; // this won't compile
350 Common De sign Patterns

In general, having a way to represent any instance of this generic type


is very useful.

// what type should ??? be?


// CountedReference<object> would be nice but it won't work
static void PrintValue(??? anyCountedReference){
Console.WriteLine(anyCountedReference.Value);
}

n
KRZYSZTOF CWALINA Of course, PrintValue could be a generic
n

method taking CountedReference<T> as the parameter.

static void PrintValue<T>(CountedReference<T> any){


Console.WriteLine(any.Value);
}

This would be a fine solution in many cases. But it does not work as a
general solution and might have negative performance implications. For
example, the trick does not work for properties. If a property needed to be
typed as any reference, you could not use CountedReference<T> as the
type of the property. In addition, generic methods might have undesirable
performance implications. If such generic methods are called with many
differently sized type arguments, the runtime will generate a new method
for every argument size. This might introduce unacceptable memory con-
sumption overhead.

Unfortunately, unless CountedReference<T> implemented the Simu-


lated Covariance Pattern described next, the only common representation
of all CountedReference<T> instances would be System.Object. But
ystem.Object is too limiting and would not allow the PrintValue
S
method to access the Value property.
The reason that casting to CountedReference<object> is just fine, but
casting to List<object> can cause all sorts of problems, is that in case of
CountedReference<object>, the object appears only in the output position
(the return type of Value property). In the case of List<object>, the object
represents both output and input types. For example, object is the type of
the input to the Add method.
9.8 Simulating Covariance 351

// T does not appear as input to any members except the constructor


public class CountedReference<T> {
public CountedReference(T value);
public T Value { get; }
public int Count { get; }
public void AddReference();
public void ReleaseReference();
}

// T does appear as input to members of List<T>


public class List<T> {
public void Add(T item); // T is an input here
public T this[int index]{
get;
set; // T is actually an input here
}
}

In other words, we say that in CountedReference<T>, the T is at covari-


ant positions (outputs). In List<T>, the T is at covariant and contravariant
(inputs) positions.
To solve the problem of not having a common type representing the
root of all constructions of a generic type, you can implement whats called
the Simulated Covariance Pattern.
Consider a generic type (class or interface) and its dependencies
described in the code fragment that follows.

public class Foo<T> {


public T Property1 { get; }
public T Property2 { set; }
public T Property3 { get; set; }
public void Method1(T arg1);
public T Method2();
public T Method3(T arg);
public Type1<T> GetMethod1();
public Type2<T> GetMethod2();
}
public class Type1<T> {
public T Property { get; }
}
public class Type2<T> {
public T Property { get; set; }
}
352 Common De sign Patterns

Create a new interface (root type) with all members containing a T at


contravariant positions removed. In addition, feel free to remove all mem-
bers that might not make sense in the context of the trimmed-down type.

public interface IFoo<out T> {


T Property1 { get; }
T Property3 { get; } // setter removed
T Method2();
Type1<T> GetMethod1();
IType2<T> GetMethod2(); // note that the return type changed
}
public interface IType2<T> {
T Property { get; } // setter removed
}

The generic type should then implement the interface explicitly and
add back the strongly typed members (using T instead of object) to its
public API surface.

public class Foo<T> : IFoo<object> {


public T Property1 { get; }
public T Property2 { set; }
public T Property3 { get; set;}
public void Method1(T arg1);
public T Method2();
public T Method3(T arg);
public Type1<T> GetMethod1();
public Type2<T> GetMethod2();

object IFoo<object>.Property1 { get; }


object IFoo<object>.Property3 { get; }
object IFoo<object>.Method2() { return null; }
Type1<object> IFoo<object>.GetMethod1();
IType2<object> IFoo<object>.GetMethod2();
}

public class Type2<T> : IType2<object> {


public T Property { get; set; }
object IType2<object>.Property { get; }
}

Now, all constructed instantiations of Foo<T> have a common root type


IFoo<object>.

var foos = new List<IFoo<object>>();


foos.Add(new Foo<int>());
foos.Add(new Foo<string>());
9.8 Simulating Covariance 353

...
foreach(IFoo<object> foo in foos){
Console.WriteLine(foo.Property1);
Console.WriteLine(foo.GetMethod2().Property);
}

In the case of the simple CountedReference<T>, the code would look


like the following:

public interface ICountedReference<out T> {


T Value { get; }
int Count { get; }
void AddReference();
void ReleaseReference();
}

public class CountedReference<T> : ICountedReference<object> {


public CountedReference(T value) {...}
public T Value { get { ... } }
public int Count { get { ... } }
public void AddReference(){...}
public void ReleaseReference(){...}

object ICountedReference<object>.Value { get { return Value; } }


}

3 CONSIDER using the Simulated Covariance Pattern if there is a need to


have a representation for all instantiations of a generic type.
The pattern should not be used frivolously, because it results in additional
types in the framework and can makes the existing types more complex.

3 DO ensure that the implementation of the roots members is equivalent


to the implementation of the corresponding generic type members.
There should not be an observable difference between calling a mem-
ber on the root type and calling the corresponding member on the
generic type. In many cases, the members of the root are implemented
by calling members on the generic type.

public class Foo<T> : IFoo<object> {

public T Property3 { get { ... } set { ... } }


object IFoo<object>.Property3 { get { return Property3; } }
...
}
354 Common De sign Patterns

3 CONSIDER using an abstract class instead of an interface to represent


the root.
This might sometimes be a better option, because interfaces are more
difficult to evolve (see section 4.3). On the other hand, there are some
problems with using abstract classes for the root. Abstract class mem-
bers cannot be implemented explicitly and the subtypes need to use the
new modifier. This makes it tricky to implement the roots members by
delegating to the generic type members.
3 CONSIDER using a nongeneric root type if such type is already
available.
For example, List<T> implements IEnumerable for the purpose of sim-
ulating covariance.

9.9Template Method
The Template Method Pattern is a very well-known pattern described in
much greater detail in many sources, such as the classic book Design Pat-
terns by Gamma et al. Its intent is to outline an algorithm in an operation.
The Template Method Pattern allows subclasses to retain the algorithms
structure while permitting redefinition of certain steps of the algorithm.
We are including a simple description of this pattern here, because it is one
of the most commonly used patterns in API frameworks.
The most common variation of the pattern consists of one or more non-
virtual (usually public) members that are implemented by calling one or
more protected virtual members.

public Control{
public void SetBounds(int x, int y, int width, int height){
...
SetBoundsCore (...);
}

public void SetBounds(int x, int y, int width, int


height, BoundsSpecified specified){
...
SetBoundsCore (...);
}
9.9 Template Method 355

protected virtual void SetBoundsCore(int x, int y, int width, int


height, BoundsSpecified specified){
// Do the real work here.
}
}

The goal of the pattern is to control extensibility. In the preceding exam-


ple, the extensibility is centralized to a single method (a common mistake
is to make more than one overload virtual). This helps to ensure that the
semantics of the overloads stay consistent, because the overloads cannot
be overridden independently.
Also, public virtual members basically give up all control over what
happens when the member is called. This pattern is a way for the base
class designer to enforce some structure of the calls that happen in the
member. The nonvirtual public methods can ensure that certain code exe-
cutes before or after the calls to virtual members and that the virtual mem-
bers execute in a fixed order.
As a framework convention, the protected virtual methods participat-
ing in the Template Method Pattern should use the suffix Core.
7 AVOID making public members virtual.
If a design requires virtual members, follow the template pattern and
create a protected virtual member that the public member calls. This
practice provides more controlled extensibility.

3 CONSIDER using the Template Method Pattern to provide more con-


trolled extensibility.
In this pattern, all extensibility points are provided through protected
virtual members that are called from nonvirtual members.

3 CONSIDER naming protected virtual members that provide extensibil-


ity points for nonvirtual members by suffixing the nonvirtual member
name with Core.

public void SetBounds(...){


...
SetBoundsCore (...);
}
protected virtual void SetBoundsCore(...){ ... }
 $PNNPO%F TJHO1BUUFSOT


#3*"/1&1*/ I like to take the template pattern one step further and
implement all argument checking in the nonvirtual public method. This
way I can stop garbage entering methods that were possibly overridden by
another developer, and it helps to enforce a little more of the API contract
across implementations.

 5JNFPVUT
Timeouts occur when an operation returns before its completion because
the maximum time allocated for the operation (timeout time) has elapsed.
The user often species the timeout time. For example, it might take a form
of a parameter to a method call.

server.PerformOperation(timeout);

An alternative approach is to use a property.

server.Timeout = timeout;
server.PerformOperation();

The following short list of guidelines describes best practices for the
design of APIs that need to support timeouts.
a %0 prefer method parameters as the mechanism for users to provide
timeout time.
Method parameters are favored over properties because they make the
association between the operation and the timeout much more appar-
ent. The property-based approach might be better if the type is designed
to be a component used with visual designers.
a %0 prefer using TimeSpan to represent timeout time.
  5JNFPVU T 

Historically, timeouts have been represented by integers. Integer time-


outs can be hard to use for the following reasons:
s It is not obvious what the unit of the timeout is.
s It is difcult 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 preceding problems.

class Server {
void PerformOperation(TimeSpan timeout){
...
}
}

var server = new Server();


server.PerformOperation(TimeSpan.FromMinutes(15));

Integer timeouts are acceptable if:


s The parameter or property name can describe the unit of time used by
the operation, for example, if a parameter can be called milliseconds
without making an otherwise self-describing API cryptic.
s The most commonly used value is small enough that users wont
have to use calculators to determine the value, for example, if the
unit is milliseconds and the commonly used timeout is less than
1 second.
a %0 throw System.TimeoutException when a timeout elapses.
Timeout equal to TimeSpan.Zero means that the operation should
throw if it cannot complete immediately. If the timeout equals TimeSpan.
MaxValue, the operation should wait forever without timing out.
Operations are not required to support either of these values, but they
should throw an InvalidArgumentException if an unsupported time-
out value is specied.
If a timeout expires and the System.TimeoutException is thrown, the
server class should cancel the underlying operation.
358 Common De sign Patterns

In the case of an asynchronous operation with a timeout, the callback


should be called and an exception thrown when the results of the oper-
ation 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));
}

For more information on timeouts and asynchronous operation, see


section 9.2.
7 DO NOT return error codes to indicate timeout expiration.
Expiration of a timeout means the operation could not complete suc-
cessfully and thus should be treated and handled as any other runtime
error (see Chapter 7).

9.11XAML Readable Types


XAML is an XML format used by WPF (and other technologies) to repre-
sent object graphs. The following guidelines describe design consider-
ations for ensuring that your types can be created using XAML readers.
3 CONSIDER providing the default constructor if you want a type to work
with XAML.
For example, consider the following XAML markup:

<Person Name="John" Age="22" />

It is equivalent to the following C# code:

new Person() { Name = "John", Age = 22 };

Consequently, for this code to work, the Person class needs to have a
default constructor. Markup extensions, discussed in the next guideline
in this section, are an alternative way of enabling XAML.
9.11 X AML Readable Type s 359

n
nChris Sells In my opinion, this one should really be a DO, not a
CONSIDER. If youre designing a new type to support XAML, its far pref-
erable to do it with a default constructor than with markup extensions or
type converters.

3 DO provide markup extension if you want an immutable type to work


with XAML readers.
Consider the following immutable type:

public class Person {


public Person(string name, int age){
this.name = name;
this.age = age;
}
public string Name { get { return name; } }
public int Age { get { return age; } }

string name;
int age;
}

Properties of such type cannot be set using XAML markup, because the
reader does not know how to initialize the properties using the param-
eterized constructor. Markup extensions address the problem.

[MarkupExtensionReturnType(typeof(Person))]
public class PersonExtension : MarkupExtension {
public string Name { get; set; }
public int Age { get; set; }

public override object ProvideValue(IServiceProvider serviceProvider){


return new Person(this.Name,this.Age);
}
}

Keep in mind that immutable types cannot be written using XAML


writers.
7 AVOID defining new type converters unless the conversion is natural
and intuitive. In general, limit type converter usage to the ones already
provided by the .NET Framework.
 $PNNPO%F TJHO1BUUFSOT

Type converters are used to convert a value from a string to the appro-
priate type. Theyre used by XAML infrastructure and in other places,
such as graphical designers. For example, the string #FFFF0000 in the
following markup gets converted to an instance of a red Brush thanks
to the type converter associated with the Rectangle.Fill property.

<Rectangle Fill="#FFFF0000"/>

But type converters can be dened too liberally. For example, the Brush
type converter should not support specifying gradient brushes, as
shown in the following hypothetical example.

<Rectangle Fill="HorizontalGradient White Red" />

Such converters dene new minilanguages, which add complexity to


the system.
a $0/4*%&3 applying the ContentPropertyAttribute to enable conve-
nient XAML syntax for the most commonly used property.

[ContentProperty("Image")]
public class Button {
public object Image { get; set; }
}

The following XAML syntax would work without the attribute:

<Button>
<Button.Image>
<Image Source="foo.jpg">
</Button.Image>
</Button>

The attribute makes the following much more readable syntax possible.

<Button>
<Image Source="foo.jpg">
</Button>
9.12 And in the End... 361

9.12 And in the End...


The process of creating a great framework is demanding. It requires dedi-
cation, knowledge, practice, and a lot of hard work. But in the end, it can
be one of the most fulfilling jobs software engineers ever get to do. Large
system frameworks can enable millions to build software that was not pos-
sible before. Application extensibility frameworks can turn simple appli-
cations into powerful platforms and make them shine. Finally, reusable
component frameworks can inspire and enable developers to take their
applications beyond the ordinary. When you create a framework like that,
please let us know. We would like to congratulate you.
This page intentionally left blank
This page intentionally left blank
Index

A Action<...> delegates, 198200


Abbreviations, 48, 377 Addition through subtraction, 24
Abstract classes Adjective phrases, naming interfaces,
choosing between interfaces and, 6061
8894 Aggregate Components, 289298
constructor design for, 148 component-oriented design, 291294
designing, 9597 design guidelines, 295298
extensibility using, 78 factored types, 294295
FxCop rules for, 384 overview of, 289291
implementing abstractions as, Alias names, avoiding, 50
203205 API specification, sample, 405412
Optional Feature Pattern and, API specification, 407408
344348 functional specification, 409412
Abstract types overview of, 406
abstract class design, 95 requirements, 406
choosing between interfaces and, 93, APIs, naming new versions of, 5154,
203205, 384 378
defined, 417 _AppDomain, 63
Abstractions Application model
implementing with base classes, defined, 417
206207 namespaces, 5859
in low vs. high-level APIs, 3336 Argument exceptions
providing extensibility with, 203205 ArgumentException, 235236
in scenario-driven design, 17 ArgumentNullException, 180,
in self-documenting APIs, 3132 235236
using classes vs. interfaces, 8695 ArgumentOutOfRangeException,
AccessViolationException, 237 235236
Acronyms FxCop rules for, 396
avoiding in framework identifiers, 49 Arguments
capitalization rules for, 4042, 375 avoiding space between, 366
correct spelling of, 377 validating, 179183
naming conventions for, 48 ArrayList, 251

423
424 I ndex

Arrays beforefieldinit metadata, 389


choosing between collections and, Begin method, Classic Async Pattern,
245, 258259 301303, 305
FxCop rules for, 387 Binary operators, 366
of reference vs. value types, 8485 Blogs, suggested, 415
usage guidelines, 245247, 397398 Blue screens, Windows, 214
using params, 186189 Books, suggested reading list, 413415
working with properties that return, Boolean properties
136138 choosing for parameters, 177179
ASP.NET, layered architecture, 3536 implementing Optional Feature
Assemblies Pattern, 347
defined, 417 selecting names for, 6970
FxCop rules for naming, 378 Boxing, 417
naming conventions, 5455 Brace usage, 364367
type design guidelines, 118119
AssemblyCopyrightAttribute, 119
AssemblyFileVersionAttribute, 119 C
AssemblyVersionAttribute, 119 C# coding style conventions, 363370
Assignments, 85 brace usage, 364365
Async Patterns, 298312 comments, 368369
choosing between, 298300 file organization, 369370
Classic Async Pattern, 300304 indent usage, 367
Classic Async Pattern example, naming conventions, 367368
304305 space usage, 365366
Event-Based Async Pattern, 305312 var keyword usage, 367
overview of, 298 Callbacks
Asynchronous methods, Event-Based Data Contract Serialization, 277
Async Pattern, 305307 defined, 417
Attached dependency property, 315316, mechanisms of, 153
417 providing extensibility with, 197201
Attribute class, 247 camelCasing convention
Attributes C# coding style, 368
assembly, 119 capitalizing acronyms, 41
defined, 417 FxCop rules for, 375
usage guidelines, 247250, 398 parameter names using, 3940, 7374
using properties vs. methods, 134135 Cancellation, Event-Based Async
AttributeUsageAttribute, 248, 398 Pattern, 308309
Capitalization conventions, 3846
acronyms, 4042
B case sensitivity, 4546
Base classes common terms, 4346
designing for extensibility, 206207, compound words, 4346
394 defined, 38
naming conventions, 6263 FxCop rules for, 374375, 383
Basic Dispose Pattern identifiers, 3840
finalizable types and, 328332 Case sensitivity, 4546, 376
overview of, 322328 Case statements, omitting braces in, 365
when to implement, 321322 Change notifications, 142144, 317318
* OEFY 

Class constructors. See Type constructors Collection<T> base class


Classes designing extensibility, 206207
base. See Base classes implementing custom collections,
choosing interfaces vs., 8895 259260
choosing structs vs., 8488 properties and return values, 253254,
FxCop rules for, 384385 256
naming conventions, 6067, 379381 ComException, 239
as reference types, 78 Comments, C# conventions, 368369
sealing, 207210 Common Language Infrastructure (CLI),
unsealed, 194195 414
Classic Async Pattern Common Language Specification (CLS),
choosing between async patterns, 414
298300 Common names
example, 304305 capitalization, 4345
overview of, 300304 naming classes, structs and interfaces,
CLI (Common Language Infrastructure), 6061
414 Common types, names of, 6466
Client-first programming test, 3 CompletedSynchronously property,
Clone method, ICloneable interface, IAsyncResult, 302
204, 264 Component class, 205
Close( ) method, Basic Dispose Pattern, Component-oriented design, 291294
327 Compound words
CLR capitalization rules, 4345, 375376
allowing overloading, 122123 FCC rules for naming resources, 383
avoiding language-specific type ComVisible(false), assembly attribute,
names, 5051 119
case sensitivity of, 45 Consistency
releasing managed memory, 319 designing frameworks for, 67
releasing unmanaged resources with exceptions promoting, 212
finalizers, 319320 in self-documenting APIs, 31
CLS (Common Language Specification), Constant fields, 161
414 Constraints, 64
CLSCompliant (true) attribute, 421 Constructed type, 414
Coercion logic, dependency properties, Constructor design, 144153
318319 Constructors
Collection parameters, 252253 abstract class design and, 95
Collections, usage guidelines, 250261 attribute usage guidelines, 249
choosing between arrays and, 245, design guidelines, 144150, 389
258259 designing custom exceptions, 240
collection parameters, 252 factories vs., 333335
FxCop rules, 398399 type constructor guidelines, 151152
implementing custom collections, ContentPropertyAttribute, 360
259260 Conversion operators, 173175, 336
naming custom collections, 260261 Core namespaces, 59
overview of, 250251 Create-Call-Get-Pattern, 293
properties and return values, 253257 Create-Set-Call-Pattern, 291293
property names, 69 CriticalFinalizerObject, 332
snapshots vs. live collections, 257258 Custom attributes, interfaces vs., 99100
 * OEFY

% Design Patterns (Gamma et al), 354


Data class, 25 .Design subnamespace, 83
Data Contract Serialization Directories, file organization, 369
choosing, 275 Dispose method, 320328, 402403
defined, 274 Dispose Pattern, 319332
supporting, 276280 Basic Dispose Pattern, 322328
XML Serialization vs., 280 finalizable types, 328332
DataContractAttribute, 276 FxCop rules for, 402403
DataMemberAttribute, 276 IDisposable interface, 266
DateTime, 261263 overview of, 319322
DateTimeKind, 263 Distributed computing, 6
DateTimeOffset, 261263 DLLs
Deadlock, 201 naming conventions, 5455, 378
Debugging, 134, 213 type design guidelines, 118119
Default arguments, member overloading Documentation
vs., 127128 naming conventions for new APIs, 52
Default constructors purpose of providing, 27
aggregate components using, 294, 297 self-documenting object models vs..
avoiding defining on structs, 101, 149 See Self-documenting object
constructor design using, 145, models
147149 DPs (dependency properties), 312319
defined, 144, 414 attached, 315316
XAML readable types using, 358359 change notifications, 317318
Delegates, 153, 414 defined, 414
Dependency, designing extension designing, 313315
methods, 164 overview of, 312313
Dependency properties. See DPs validation, 316317
(dependency properties) value coercion, 318319
Descriptive names DWORD, 110
designing extension methods, 167
designing generic type parameters, 64
designing resources, 7475 &
designing self-documenting APIs e parameter, 71
using, 28 Edit & Continue feature, 22
Design patterns, 289361 EditorBrowsable attribute, 81
Aggregate Components. See Aggre- EF (Entity Framework), 337
gate Components 80/20 rule, 10
Async Patterns. See Async Patterns Encapsulation, principle of, 159160
dependency properties, 312319 End method, Classic Async Pattern,
Dispose Pattern. See Dispose Pattern 301303, 305
factories, 332337 EnumIsDefined, 181182
FxCop rules for, 402404 Enums (enumerations), designing,
LINQ support, 337344 103115
Optional Feature Pattern, 344348 adding values to, 114115
Simulated Covariance Pattern, choosing between Boolean param-
348354 eters and, 177179
Template Method Pattern, 354356 defined, 105
timeouts, 356358 flag enums, 109114
XAML readable types, 358360 FxCop rules for, 385386
* OEFY 

naming guidelines, 6667, 380381 framework design using, 22, 30


simple enums, 103109 FxCop rules for, 395397
validating arguments, 180181 overview of, 211215
as value types, 78 performance and, 240243
Environment class, 98, 218 standard types of, 234239
Equality operators, 286287 throwing, 216221
Equals throwing from equality operators,
overriding equality operators, 286 286
usage guidelines, 268270, 400 throwing from finalizers, 332
Error conditions. See Exceptions Exceptions, choosing type to throw,
Error message design, 225226, 232 221234
Event-Based Async Pattern, 305312 error message design, 225226, 232
choosing between async patterns, exception handling, 227232
298300 overview of, 221225
defining asynchronous methods, wrapping exceptions, 232234
305307 Execution failures, 218, 222
supporting cancellation, 308309 ExecutionEngineException, 239
supporting incremental results, EXEs (executables), 421
311312 Expense, of framework design, 4
supporting out and ref parameters, Explicit interface member implementa-
307308 tion, 128132
supporting progress reporting, Expression<...> types, 198200
309311 Expression<Func<...>>, 343
Event design Extensibility, designing for, 193210
custom event handler design, 159 with abstractions, 203205
overview of, 153158 base classes, 206207
Event handlers with events and callbacks, 197201
custom design for, 159 FxCop rules for, 394
defined, 153, 414 with protected members, 196
event design guidelines, 153158, sealing, 207210
389390 with unsealed classes, 194195
naming, 7172 with virtual members, 201203
Event handling method, 156, 414 Extension methods, 162168, 414
EventArgs suffix, 7172, 156
EventHandler<T>, 155
Events
defined, 414 '
FxCop rules for design, 389390 Faades. See Aggregate Components
naming conventions, 7072, 381 Factored types, aggregate components,
property change notification, 142144 294295
providing extensibility with, 197201 Factories
Ex suffix, 45, 53 Optional Feature Pattern vs., 346
Exception, 234235 overview of, 332337
Exception filters, 221 Factory methods, 145, 332336
Exception handling, 227232 Fail fasts, 218
Exceptions, 211243 Fields
constructor design using, 146147, designing, 159162
151 FxCop rules for design, 390391
customizing, 239240 naming conventions, 7273, 383
 * OEFY

File organization, C#, 369370 (


Finalizable types, Dispose Pattern and, GC (Garbage Collector), 319, 320
328332 GC.SuppressFinalize method
Finalize method, 146147 constructor design, 147
Finalizers FxCop rules for design patterns, 403
defined, 414 overview of, 320
finalizable types, 328332 Generic methods, 350, 414
FxCop rules for, 403404 Generic type parameters, names of, 64
limitations of, 320 Generics, 348354, 419
overview of, 319 Get methods, 69
Flag enums GetHashCode, usage guidelines, 270271,
defined, 104 400
designing, 109114 GetObjectData, ISerializable, 282283
naming, 67, 110 Getter method, 419
FlagsAttribute, 110111, 386 Glossary, 417421
Flow control statements, 366 Grid.Column, 316
Framework design
characteristics of, 36 )
history of, 13 Hashtable, 251
overview of, 911 Hierarchy
principle of layered architecture, designing custom exceptions, 239
3236 namespace, 5758
principle of low barrier to entry, organizing directory, 369
2126 organizing types into namespace,
principle of scenario-driven, 1521 7980
principle of self-documenting object High-level APIs, 3336
models, 2632 High-level components, 419
principles of, overview, 1415 Hungarian notation
progressive frameworks, 1114 C# coding style conventions, 368
Func<...> delegates, 198200 positive and negative effects of, 4647
FxCop, 371404
defined, 371 *
design patterns, 402404 I prefix, 6263
designing for extensibility, 394 IAsyncResult object, 301303
evolution of, 372373 ICloneable interface, 204, 263264
exceptions, 395397 ICollection interface, 252253, 398399
how it works, 373374 ICollection<T> interface
member design. See Member design implementing custom collections,
naming conventions. See Naming 259260
conventions, FxCop rules supporting LINQ through
overview of, 371372 IEnumerable<T>, 339
parameter design, 392394 usage guidelines, 252254
spelling rules, 377 IComparable<T> interface, 264266
type design guidelines, 384386 IComponent interface, 205
usage guidelines. See Usage guide- ID vs. id (identity or identifier), 44, 375
lines, FxCop rules Identifiers, naming conventions
FxCopcmd.exe, 373 abbreviations or contractions, 4849
FxCop.exe, 373 acronyms, 49
I ndex 429

avoiding naming conflicts, 48 Intellisense


capitalization rules, 3840 naming conventions for new APIs, 52
choosing names, 2830 naming conventions in self-docu-
IDictionary<TKey,TValue>, 251, 260 menting APIs, 29
IDisposable interface operator overloads not showing in,
as Dispose Pattern, 266 169
FxCop rules for design patterns, overview of, 27
402403 strong typing for, 31
implementing Basic Dispose Pattern, support for enums, 105
322324 type design guidelines, 81
releasing unmanaged resources with, Interfaces
320321 choosing between classes and, 8895,
rules for finalizers, 403404 384385
usage guidelines, 266 defining nested types as members of,
IEnumerable interface, 252255, 259260 117
IEnumerable<T> interface designing, 98101, 385
Query Pattern and, 342 designing abstractions with, 8895,
supporting LINQ through, 339340 205
usage guidelines for collections, designing extension methods for,
252254 163164
IEnumerator interface, 251252 implementing members explicitly,
IEnumerator<T> interface, 251252 128132, 387
IEquatable<T> interface, 103, 264266 naming conventions, 6067, 379381
IExtensibleDataObject interface, 279 reference and value types implement-
IList<T> interface, 259260 ing, 78
Immutable types .Interop subnamespace, 84
defined, 86, 419 InvalidCastException, 175
enabling XAML readers with, 359 InvalidOperationException, 235
Impl suffix, 404 IQueryable interface, 338
Implementation, framework, 4 IQueryable<T> interface, 340341
Incremental results, Event-Based Async ISerializable interface, 281283
Pattern, 311312 Issue messages, FxCop, 373
Indent usage, C#, 367 It-Just-Works concept, 290
Indexed property design, 140142, 388 IXmlSerializable interface, 280281
IndexOutOfRangeException, 237 IXPathNavigable interface, 285
Infrastructure namespaces, 59
Inheritance hierarchy J
base classes in, 206 Jagged arrays, 246247
naming classes, structs and interfaces, JIT (Just-In-Time) compiler, 160, 419
61
Inlining, 419
Instance constructors, 144, 146 K
Instance method, 419 Keyed collections, 256, 259260
Instrumentation, exceptions promoting, Keywords
215 avoiding naming identifiers that
Int32 enum, 109 conflict with common, 48
Integer timeouts, 357 FxCop rules for naming, 377
Integration, framework, 6 KnownTypeAttribute, 278279
430 I ndex

L Member design, FxCop rules for,


Lamba Expressions, 338, 419 387394
Language Integrated Query. See LINQ constructor design, 389
(Language Integrated Query) event design, 389390
Language-specific names field design, 390391
avoiding, 4951 general guidelines, 387388
FxCop rules for avoiding, 378 operator overloads, 391392
resource names avoiding, 75 parameter design, 392394
Layered architecture principle, frame- property design, 388
works, 3236 Member overloading, 121138
Libraries, reusable, 5, 122123 avoiding inconsistent ordering, 124
LINQ (Language Integrated Query), avoiding ref or out modifiers,
337344 125126
defined, 419 choosing between properties and
overview of, 337338 methods, 132138
supporting through IEnumerable<T>, default arguments vs., 127128
339340 implementing interface members
supporting through IQueryable<T>, explicitly, 128132
340 overview of, 121123
supporting through Query Pattern, passing optional arguments, 126127
341344 semantics for same parameters, 126
ways of implementing, 339 using descriptive parameter names
LINQ to SQL, 337 for, 123124
List<T>, 251 Members
Live collections, snapshots vs., 257258 defined, 420
Local variables, avoiding prefixing, 368 PascalCasing for naming, 3940
Low barrier to entry principle, frame- providing extensibility with virtual,
work design, 2126 201203
Low-level APIs, 3336 renaming, 130131
Low-level component, 419 sealing, 207210
with variable number of parameters,
186189
M Memory, reference vs. value types, 85
Managed code, 420 Metadata
Marker interfaces, avoiding, 99 capitalization guidelines, 44
Markup Extensions, enabling XAML defined, 420
with, 358359 PropertyMetadata, 318
MarshalByRefObject, 93 types and assembly, 118119
Member design, 121191 Methods
constructor design. See Constructor choosing between properties and,
design 132138, 386387
event design, 153158 designing extension, 162168
extension methods, 162168 exception builder, 220221
field design, 159162 naming conventions for, 2830, 68
member overloading. See Member naming for operator overloads,
overloading 171173
operator overloads, 168175 supporting timeouts with parameters,
parameter design. See Parameter 356
design Microsoft Office, for FxCop spelling
property design, 138144 rules, 377
I ndex 431

Microsoft Office Proofing Tools, for resources, 7475


FxCop spelling rules, 377 self-documenting APIs, 2830
Microsoft Windows, blue screens, 214 structs, 6067
Microsoft Word development, 10 word choice, 4648
Multidimensional arrays, jagged arrays Naming conventions, FxCop rules,
vs., 246247 374383
Multiline syntax (/*...*/), 369 assemblies and DLLs, 378
Multiple inheritance, 98101 classes, structs, and interfaces,
Mutable types, 101102, 162 379381
general, 376378
namespaces, 378379
N overview of, 374376
Namespaces parameters, 383
defining extension methods in, resources, 383
164167 type members, 381383
for experimentation, 2224 NativeOverlapped*, 305
exposing layers in same, 3536 Nested types
exposing layers in separate, 35 defined, 420
placing base classes in separate, 207 designing, 115117
standard subnamespace names, 8384 FxCop rules for, 386
type design guidelines, 7983 FxCop type design guidelines, 386
Namespaces, naming .NET Framework
FxCop rules, 378379, 384 designing self-documenting APIs,
overview of, 5659 3132
PascalCasing for, 3940 main goals of, 14
type name conflicts and, 5860 as progressive framework, 13
Naming conventions, 3775 .NET Remoting, 281
abbreviations, 48 NotSupportedException, 340, 348
acronyms, 48 Nouns/noun phrases
assemblies, 5455 naming classes, structs and interfaces
avoiding language-specific names, with, 6061
4951 property names, 6869
C# coding style, 367368 Nullable<T> interface, 266268
capitalization. See Capitalization NullReferenceException, 237
conventions
classes, 6067
common types, 6466 O
custom collections, 260261 Object models, 17. See also Self-docu-
DLLs, 5455 menting object models
enumerations, 6667 Object-oriented (OO) design, 2, 211212
events, 7072 Object-oriented programming (OOP), 2,
fields, 7273 79
generic type parameters, 64 Object, usage guidelines, 268273
interfaces, 6067 defining extension methods on, 165
methods, 68 Object.Equals, 268270
namespaces, 5660 Object.GetHashCode, 270271
new versions of APIs, 5154 Object.ToString method, 271273
overview of, 3738 Object.Equals
parameters, 7374 overriding equality operators, 286
properties, 6870 usage guidelines, 268270, 400
432 I ndex

Object.GetHashCode, 270271, 400 indexed properties, 141


Objects, defined, 420 members with variable number of
Object.ToString method, 271273 parameters, 186189
Ok, capitalizing, 44 overview of, 175177
OnDeserializedAttribute, 277278 parameter passing, 183185
OO (object-oriented) design, 2, 211212 pointer parameters, 190191
OOP (object-oriented programming), 2, providing good defaults, 2526
79 space usage, 366
Open sets, and enums, 105 validating arguments, 179183
Operator overloads Parameter names
conversion operators, 173175 camelCasing for, 3940
defined, 123 conventions, 7374
descriptive parameter names for, 74, conventions for overloads, 123124
123124 event handlers and, 71
extension methods similar to, 167 FxCop rules for, 383
FxCop rules, 391392 operator overload and, 74
overloading operator ==, 173 Parameter passing, 183185
overview of, 168173 params keyword, 186188
Operators, FxCop usage guidelines, Parentheses, space usage and, 366
401402 PascalCasing convention
Optional Feature Pattern, 344348 C# coding style conventions, 368
Organizational hierarchies, 57 field names, 72
out parameters FxCop rules for, 375
avoiding use of, 184185 identifier names, 3840
Classic Async Pattern, 302 namespace names, 57
Event-Based Async Pattern, 307308 property names, 6869
FxCop rules for parameter passing, resource names, 7475
393 Patterns, common design. See Design
member overloading and, 125126 patterns
parameter design, 176177 Performance
passing arguments through, 184 exceptions and, 240243
OutOfMemoryException, 238 implications of throwing exceptions,
Overlapped class, 305 219
Overloading supporting LINQ through
avoiding for custom attribute IEnumerable<T>, 340
constructors, 249 .Permission subnamespace, 83
defined, 420 Pit of Success notion, LINQ, 337
designing APIs for experimentation Plural namespace names, 57
using, 24 Pointer parameters, 190191
equality operators, 286287 Post-events, 153154, 420
member. See Member overloading PowerCollections project, 205
Overloading operator ==, 173, 175 Pre-events
allowing end user to cancel events,
158
P defined, 420
Parameter design, 175191 examples of, 153
enum vs. boolean parameters, Prefixes
177179 Boolean properties, 69
FxCop rules for, 392394 class names, 61
I ndex 433

enum names, 67 R
field names avoiding, 72 Raising events, usage guidelines,
interface names, 6263 154155
namespace names, 56 readonly fields, 161162
Program errors, 222224 ReadOnly prefix, custom collections,
Programming languages 261
case sensitivity guideline for, 4546 ReadOnlyCollection<T>, 252256,
choice of programming model and, 12 259260
designing framework to work well Recursive acquires, 201
with variety of, 11 Reentrancy, 201
exception handling syntax, 217 ref parameters
writing scenario code samples in Classic Async Pattern and, 302
different, 16, 18 Event-Based Async Pattern and,
Progress reporting, 309311 307308
ProgressChanged event, 309312 member overloading and, 125126
Progressive frameworks, 1314, 420 parameter design and, 176
Properties passing arguments through, 183185
accessing fields with, 160 Reference types
choosing between methods and, defined, 420
132138, 386387 equality operators and, 269270, 287
collection, 399 overview of, 77
defined, 420 parameter passing guidelines, 185, 393
designing, 388 value types vs., 8488
naming, 6870, 381 References, reading list for this book,
providing good defaults for, 2526 413415
setting with constructor parameters, #region blocks, 370
145146 Reserved parameters, 176
usage guidelines for collections, Resources, naming, 7475, 383
253254 Return-code error handling model,
using attribute, 247248 212213, 217
Property change notification events, Return values
142144 error reporting based on, 212213
Property design usage guidelines for collections,
indexed, 140142 253254
overview of, 138140 Ruby, 18
property change notification events, Runtime, layered APIs at, 36
142144 Runtime Serialization
PropertyMetadata, 318319 choosing, 275
Protected members, 194, 196 defined, 274
Prototyping, implementation vs., 4 supporting, 281283
Public nested type guidelines, 117
Python, 18 S
SafeHandle resource wrapper, 329330
Scenario-driven principle
example of. See API specification,
Q sample
Query Expressions, 338 overview of, 1519
Query Pattern, 338, 341344 usability studies, 1921
 * OEFY

Sealing Static methods


of custom attribute classes, 250 defined, 421
defined, 420 extension methods invoking, 162, 166,
FxCop rules for, 394 414
preventing extensibility with, 207210 Stream class, 322, 347
Security Strong typing, 3031, 105
avoiding explicit members, 131 Structs
designing custom exceptions, 240 defining default constructors in, 149
SEHException, 239 defining operator overloads in, 170
Self-documenting object models, 2632 designing, 101103, 385
consistency, 3132 naming conventions, 6067, 379381
limiting abstractions, 32 type design guidelines, 8488,
overview of, 2630 384385
strong typing, 3031 as value types, 78
sender parameter, event handlers, 71 Subnamespace names, 8384
Sentinel values, and enums, 107108 Suffixes
SerializableAttribute interface, 281 naming common types, 6466
Serialization, usage guidelines, 274283 naming enums, 67
choosing right technology, 275 naming new APIs, 5254
overview of, 274275 SuppressFinalize, Basic Dispose
supporting Data Contract Serializa- Pattern, 324325
tion, 276280 Synchronization, event design, 157
supporting Runtime Serialization, System failure, 222, 225
281283 System namespaces, 59
supporting XML Serialization, System._AppDomain, 63
280281 System.Attribute class, 247
Setter method, 420 System.ComponentModel.Component
Simplicity, well-designed frameworks, class, 205
34 System.ComponentModel.IComponent,
Simulated Covariance Pattern, 348354 205
Single-statement blocks, brace usage, System.Data, 25
364365 System.Enum, 110
Singleline syntax (//...), comments, 369 System.Environment class, 98
64 suffix, 5354 System.Environment.FailFast, 218
Snapshots, live collections vs., 257258 System.EventHandler<T>, 155
SomeClass.GetReader, 334 SystemEvents, 200
Source files, organizing, 369 SystemException, 234235
Space usage, C#, 365366 System.FlagsAttribute, 110111
Spelling rules, FxCop, 377 System.InvalidCastException, 175
Sponsor class, 163 System.IO namespace, 20
StackOverflowException, 237238 System.IO.Stream class, 322, 347
State object, 301 System.Object, usage guidelines,
Static classes, designing, 9798, 384385 268273
Static constants, using enums, 105 defining extension methods on, 165
Static constructors. See Type constructors Object.Equals, 268270
Static fields Object.GetHashCode, 270271
defined, 421 Object.ToString method, 271273
initializing inline, 152, 389 System.ServiceProcess namespace, 291
naming conventions for, 4748, 72 System.TimeoutException, 357
* OEFY 

System.Uri. See Uri, usage guidelines nested types, 115117


System.ValueType, 103 overview of, 7779
System.Xml, usage guidelines, 284286, simple enums, 103109
401 static classes, 9798
structs, 101103
Type members, naming, 6873
5 conflicts with namespace names,
TDD (test-driven development) 5860
defined, 15 designing self-documenting APIs,
framework design and, 67 2830
scenario-driven design, 19 events, 7072, 382
unsealed classes, 195 fields, 7273, 383
Technology namespace groups, 5960 methods, 68
Template method, 404 PascalCasing for, 3940
Template Method Pattern, 203, 354356 properties, 6870, 381
Tense, for event names, 7071 Type parameters, 64, 421
Test-driven development. See TDD
(test-driven development)
Tester-Doer Pattern, 219, 241242 6
ThenBy method, Query Pattern, 343 UEFs (unhandled exception filters), 215
This, defined, 421 Unary operators, 366
Throwing exceptions, 216221. See also Unboxing, 421
Exceptions, choosing type to throw Underscores (_), 73, 75
TimeoutException, 357 Unhandled exception handlers, 214215
Timeouts, in API design, 356358 Unmanaged code, 421
TimeSpan, 356 Unmanaged resources, 319
ToString method, 240, 271273 Unsealed classes, 194195
Trade-offs, design, 56 Uri, usage guidelines, 283284, 400401
Transparency, Aggregate Components, UrtCop (Universal Runtime Cop), 373
290 Usability, consistency for, 3132
Try-Parse Pattern, 219, 242243 Usability studies, API, 1921, 25
Type arguments Usage errors, 222223
calling generic methods with, 350 Usage guidelines, 245287
in constructed types, 414 arrays, 245247
defined, 421 attributes, 247250
Type constructors collections. See Collections, usage
defined, 144 guidelines
designing, 151152, 389 DateTime and DateTimeOffset,
Type converters, and XAML readers, 261263
359360 equality operators, 286287
Type design guidelines ICloneable, 263264
abstract classes, 9597 IComparable<T> and IEquatable<T>,
adding values to enums, 114115 264266
assembly metadata and, 118119 IDisposable, 266
choosing class vs. struct, 8488 Nullable<T>, 266268
choosing classes vs. interfaces, 8895 Object, 268273
flag enums, 109114 serialization. See Serialization, usage
FxCop rules for, 384386 guidelines
interfaces, 98101 System.Xml usage, 284286
namespaces and, 7984 Uri, 283284
436 I ndex

Usage guidelines, FxCop rules, 397402 Virtual members, 149150, 201203


arrays, 397398 Visual Basic developers
attributes, 398 case insensitivity of VB, 45
collections, 398399 designing frameworks for, 10
common operators, 401402 experimental approach of, 22
Object, 400 moving to .NET platform, 34
Object.GetHashCode, 400 problems with VB.NET, 15
System.Xml, 401 Visual Studio, 299
System.Xml usage, 401 VisualOperations class, WPF, 22
Uri, 400401 <V>.<S>.<B>.<R> format, assemblies,
User education experts, 29 119
using directives, file organization, 370

W
V Wait handles, Classic Async Pattern, 300
Validation Word choice
argument, 179183 FxCop rules for, 376377
dependency property, 316317 naming conventions, 4648
Value coercion, dependency property, WPF (Windows Presentation Founda-
318319 tion) project, 2223, 168
Value types Wrapping exceptions, 232234
defined, 421
equality operators on, 269, 287
explicitly implementing members on, X
129 XAML, 358360, 421
finalizable, 330 XML Serialization
implementing interface with, 94 choosing, 275
mutable, 101102 defined, 274
overview of, 7778 supporting, 280281
reference types vs., 8488 XmlDataDocument, usage guidelines,
Values 285286
adding to enums, 114115 XmlNode, usage guidelines, 285
enum design and, 105109 XmlReader, usage guidelines, 285
using properties vs. methods, 135 XNode, usage guidelines, 285
ValueType, 103 XPathDocument, usage guidelines, 285
var keyword usage, 367 XPathNavigator, usage guidelines, 286
varargs methods, 189
Variance, 130
Verbs/verb phrases Z
event names, 70 Zero values
method names, 68 enum design, 108109
Versions, naming new API, 5154 flag enums, 113

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy