Framework Design Guidelines PDF
Framework Design Guidelines PDF
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
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
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
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
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
Glossary 413
Suggested Reading List 419
Index 423
This page intentionally left blank
Figures
xvii
This page intentionally left blank
Tables
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
Miguel de Icaza
Boston, MA
Foreword to the First Edition
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:
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
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
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
xxxiii
This page intentionally left blank
About the Annotators
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
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
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
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
The following sections will help you choose the right method of sup-
porting LINQ.
Doing so allows for the following code, despite the fact that
RangeOfInt32s did not implement a Where method:
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.
T ElementAt(this S<T>,int)
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
// 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; }
// 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
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.
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
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.
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
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.
n
KRZYSZTOF CWALINA Of course, PrintValue could be a generic
n
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.
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.
...
foreach(IFoo<object> foo in foos){
Console.WriteLine(foo.Property1);
Console.WriteLine(foo.GetMethod2().Property);
}
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 (...);
}
#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);
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
class Server {
void PerformOperation(TimeSpan timeout){
...
}
}
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.
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; }
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.
[ContentProperty("Image")]
public class Button {
public object Image { get; set; }
}
<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
423
424 I ndex
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
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