0% found this document useful (0 votes)
19 views

(en) Programming Microsoft Visual C# 2005 - The Language (MS Press , 2006)

Programming Microsoft Visual C# 2005: The Language by Donis Marshall is a comprehensive guide designed for both new and experienced developers to enhance their skills in creating applications for Microsoft Windows and the Web. The book covers core language features, essential skills, debugging techniques, and advanced concepts, with practical examples and code samples provided throughout. It serves as a valuable resource for understanding the enhancements in Visual C# 2005 and effectively utilizing the Microsoft Visual Studio IDE.

Uploaded by

marijaandjeo
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views

(en) Programming Microsoft Visual C# 2005 - The Language (MS Press , 2006)

Programming Microsoft Visual C# 2005: The Language by Donis Marshall is a comprehensive guide designed for both new and experienced developers to enhance their skills in creating applications for Microsoft Windows and the Web. The book covers core language features, essential skills, debugging techniques, and advanced concepts, with practical examples and code samples provided throughout. It serves as a valuable resource for understanding the enhancements in Visual C# 2005 and effectively utilizing the Microsoft Visual Studio IDE.

Uploaded by

marijaandjeo
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1264

ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.

html

Programming Microsoft
Visual C# 2005: The
Language
byDonis Marshall
Microsoft Press 2006 (704 pages)
ISBN:0735621810

Offering expert guidance,


hands-on programming
instruction, and practical
examples, this straightforward
book will help both new and
experienced developers
advance their proficiency in
developing applications for
Microsoft Windows and the Web.

Table of Contents
Programming Microsoft Visual C# 2005 —The Language
Introductio n
Part I - Core Languag e
Chapter 1 - Introduction to Visual C# Programmin g
Chapter 2 - Type s
Chapter 3 - Inheritanc e
Part II - Core Skill s
Chapter 4 - Introduction to Visual Studio 200 5
Chapter 5 - Arrays and Collection s
Chapter 6 - Generic s
Chapter 7 - Iterator s
Part III - More C# Languag e
Chapter 8 - Delegates and Event s
Chapter 9 - Exception Handlin g
Part IV - Debuggin g
Chapter 10 - Metadata and Reflectio n
Chapter 11 - MSIL Programmin g
Chapter 12 - Debugging with Visual Studio 200 5
Chapter 13 - Advanced Debuggin g
Part V - Advanced Concept s
Chapter 14 - Memory Managemen t
Chapter 15 - Unsafe Cod e
Appendix A - Operator Overloadin g
Index
List of Figures
List of Tables
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Back Cover

Get hands-on, expert guidance for developing with Visual C# 2005.

Get the essential, straightforward information you need to master the core capabilities of Visual C# 2005. Both
new and experienced developers get expert guidance, hands-on programming instruction, and practical
examples to help advance their proficiency in developing applications for Microsoft Windows and the Web.

Discover how to:

 Refine class usage with inheritance, polymorphism, and other strategies

 Implement generics to define a type-safe data structure

 Work with stacks, queues, arrays, dictionaries, and other collections

 Use iterators to implement and standardize enumerator patterns

 Know when to catch exceptions —and handle them locally or propagate them

 Interrogate metadata and facilitate late binding by using reflection

 Synchronize threads with locks, events, mutexes, and other tools

 Use the Microsoft Visual Studio Debugger and explore advanced debugging techniques and tools

About the Author

Donis Marshall is a trainer, a consultant and an author with 20 years of development experience and an
in-depth background on Microsoft .NET technologies. He is the author of several books, including .NET Security
Programming. Donis teaches classes on .NET programming, debugging, security, and design and architecture.
In addition, he is the president of DebugNow.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Programming Microsoft Visual C# 2005—The


Language
Donis Marshall

PUBLISHED BY Microsoft Press A Division of Microsoft Corporation


One Microsoft Way Redmond, Washington 98052-6399
Copyright © 2006 by Donis Marshall
ISBN:0735621810

All rights reserved. No part of the contents of this book may be reproduced or transmitted in any form or by
any means without the written permission of the publisher.

Library of Congress Control Number 2005934153

Printed and bound in the United States of America.

1 2 3 4 5 6 7 8 9 QWT 0 9 8 7 6 5

Distributed in Canada by H.B. Fenn and Company Ltd.

A CIP catalogue record for this book is available from the British Library.

Microsoft Press books are available through booksellers and distributors worldwide. For further information
about international editions, contact your local Microsoft Corporation office or contact Microsoft Press
International directly at fax (425) 936-7329. Visit our Web site at www.microsoft.com/mspress. Send
comments to [email protected].

Microsoft, IntelliSense, Microsoft Press, MSDN, Visual Basic, Visual C#, Visual Studio, the Visual Studio
logo, Win32, Windows, Windows CE, the Windows logo, Windows NT, and WinFX are either registered
trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Other product
and company names mentioned herein may be the trademarks of their respective owners.

The example companies, organizations, products, domain names, e-mail addresses, logos, people, places,
and events depicted herein are fictitious. No association with any real company, organization, product,
domain name, e-mail address, logo, person, place, or event is intended or should be inferred.

This book expresses the author's views and opinions. The information contained in this book is provided
without any express, statutory, or implied warranties. Neither the authors, Microsoft Corporation, nor its
resellers, or distributors will be held liable for any damages caused or alleged to be caused either directly or
indirectly by this book.

Acquisitions Editor: Ben Ryan

Project Editor: Valerie Woolley

Technical Editor: James D. Rogers

Copy Editor: Nancy Sixsmith

Indexer: Tony Ross and Lee Ross

Body Part No. X11-50074

This book is dedicated to my father, Herbert Marshall. He was a nuclear engineer, an artist, a confidant, a
doting husband to my mother, and most of all a compassionate person. He was a giant amongst men and
touched innumerable lives. His three sons, including myself, miss him every day.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Acknowledgments

Programming Microsoft Visual C# 2005: The Language was completed with the collaboration of several
people. I am credited on the cover, but the contribution of others is no less important. I want to especially
acknowledge the contributions of Valerie Woolley, Ben Ryan, and Jim Rogers. If possible, they would also
receive cover credit. Valerie was the project manager and provided support, encouragement, patience, and
the occasional nudge when necessary. Ben, who was the acquisitions editor, had unyielding confidence in
my ability, which is greatly appreciated. Jim Rogers was the technical editor and diligently reviewed
hundreds of pages of manuscript and code. He helped assure the superb quality of the book.

I also want to thank John Bruno, who is an exceptional engineer, for reviewing and commenting on each
chapter, which was very helpful.

Writing a book is an all-consuming project. Unfortunately, much of this burden is carried by friends and loved
ones. I appreciate the patience and support of my mother, Lynn, and of my friends Herb, Jr., Chuck, and
Patty, along with a long list of other friends who were treated shabbily during this project. Thanks for your
understanding.

Finally, I want to acknowledge my children: Jason, Kristen, and Adam. They make every day special. They
are my motivation. A special acknowledgment is reserved for Jason. During most of this project, Jason was
stationed in Iraq as a Marine. He recently returned home safely. We are proud of you.

Donis Marshall

Donis Marshall is currently one of the few trainers endorsed by Microsoft Global Learning Services to
conduct Microsoft technology classes for Microsoft employees. In this capacity, Mr. Marshall travels
internationally, delivering dozens of classes to Microsoft developers and engineers in the United States,
Europe, and Asia. His repertoire includes classes on Advanced .NET UMD Debugging, Advanced .NET
Debugging workshops, .NET Design and Architecture, Visual Basic .NET Programming, .NET Interoperability
and Security, .NET Web Services, and ASP.NET. He also teaches .NET classes at Autodesk, NCCI, and
NASA.

Donis Marshall is a nationally recognized teacher of computer technology to developers and scientists. As
founder and lead instructor for The Training Alliance, he taught advanced technical classes for many Fortune
500 clients. He also managed a staff of technical instructors as Director of Advanced Technical Learning
Services at Productivity Point International, a national franchiser of training services.

Mr. Marshall is President of DebugNow (www.debugnow). DebugNow offers an assortment of innovative tools
for support engineers and developers to debug and monitor Win32 and .NET applications.

As a contractor, Donis Marshall has written thousands of lines of code for various entities.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Introduction
Microsoft Visual C# 2005 includes several enhancements to earlier versions of the language. If you want to
learn the new features of the language, Programming Microsoft Visual C# 2005: The Language offers detailed
explanations of each improvement. One of the most awaited additions to the .NET environment is generics.
Other additions include anonymous methods, static classes, and new classes that affect garbage collection.
This book introduces these new features, provides context, and displays sample code.

Enhancements are not limited to the language. The Microsoft Visual Studio IDE has also been enhanced in
Visual Studio 2005. Microsoft continues to expand upon the impressive assortment of rapid application
development (RAD) tools that are available. The Exception Assistant, code snippets, and visualizers are
some of the more notable advancements, where the emphasis is on providing helpful information that
markedly increases developer productivity. This book details these and other improvements to previous
versions of Visual Studio.

A larger portion of the lifetime of an application is spent in maintenance and debugging. Efficient and effective
debugging tools and techniques can facilitate a more robust application, which reduces the need to debug.
You can also resolve problems more quickly when they inevitably occur. A managed application has a
managed veneer and an unmanaged underpinning. Debugging requires an understanding of both realms
where a managed application exists: managed and unmanaged. From a debugging context, Chapter 12
examines both realms of a managed application and helps developers understand how to effectively debug a
managed application.

Who Is This Book For?


Programming Microsoft Visual C# 2005: The Language is for developers who want a comprehensive
explanation of Visual C# 2005 or want to explore a specific aspect of the language. It is a composite of
chapters sequenced to provide a rational and complete review of the language. Each chapter is also
reviewable as an independent unit that encapsulates a specific topic.

This book targets both professional and casual developers. Practical, in-depth explanations are offered for
even the most ardent developers. Sample code is provided as a complement to the content. For casual
developers, code is often the clearest explanation of in-depth concepts. Actually, even for professional
developers, sample code is often invaluable. For this reason, this book contains reams of code examples.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Organization of This Book


Programming Microsoft Visual C# 2005: The Language is organized into five parts.

The first part, "Core Language," introduces the basic concepts of the language. Chapter 1 contains a general
overview of the language. Chapter 2 introduces types, which include classes and value types. Chapter 3
explains inheritance in C# and the related keywords, such as virtual, override, sealed, and abstract.

The second part, "Core Skills," covers the core skills required to create a C# application. Chapter 4 reviews
Visual Studio 2005, which is the central tool in developing a managed application. Chapter 5 explains arrays
and collections. It is hard to imagine a competent C# application that does not employ arrays or collections.
Chapter 6 introduces generics, which is a new feature of .NET Framework 2.0. Chapter 7 pertains to iterators
and the capability to enumerate collection-related classes.

The third part, "More C# Language," focuses on additional language features. Chapter 8 details managed
function pointers, which are represented by delegates and events in managed code. Chapter 9 explains
structured exception handling in the run time and within the C# language.

The fourth part, "Debugging," is an all-inclusive explanation of debugging managed code. The first two
chapters in this section provide an internal view of an assembly, which is critical for anyone debugging a
managed application: Chapter 10 introduces metadata and reflection; Chapter 11 is an overview of Microsoft
intermediate language (MSIL) programming. Chapter 12 discusses debugging with Visual Studio, which is
the preferred debugging environment for most developers. Finally, Chapter 13 discusses advanced debugging
using the MDbg, Windbg, and SOS debugger extensions.

The final part is "Advanced Concepts." Chapter 14 covers managed memory and garbage collection in the
managed environment. Chapter 15 explains unsafe code and direct pointer manipulation. This chapter also
discusses calling functions that are in unmanaged (native) libraries.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

System Requirements
You'll need the following hardware and software to build and run the code samples for this book:
 Microsoft Windows XP with Service Pack 2, Microsoft Windows Server 2003 with Service Pack 1,
or Microsoft Windows 2000 with Service Pack 4
 Microsoft Visual Studio 2005 Standard Edition or Microsoft Visual Studio 2005 Professional
Edition
 600 MHz Pentium or compatible processor (1 GHz Pentium recommended)
 192 MB RAM (256 MB or more recommended)
 Video (800 × 600 or higher resolution) monitor with at least 256 colors (1024 × 768 High Color
16-bit recommended)
 2 GB available space on installation drive; 1 GB available space on system drive. With MSDN, the
hard disk requirements are 2.8 GB and 1 GB, respectively.
 CD-ROM or DVD-ROM drive
 Microsoft Mouse or compatible pointing device
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Technology Updates
As technologies related to this book are updated, links to additional information will be added to the
Microsoft Press Technology Updates Web page. Visit this page periodically for updates on Visual Studio
2005 and other technologies:
 http://www.microsoft.com/mspress/updates/
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Code Samples
All the code samples discussed in this book can be downloaded from the book's companion content Web
page at the following address:
 http://www.microsoft.com/mspress/companion/0-7356-2181-0/
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Support for This Book


Every effort has been made to ensure the accuracy of this book and the companion content. As corrections
or changes are collected, they will be added to a Microsoft Knowledge Base article. To view the list of known
corrections for this book, visit the following article:
 http://support.microsoft.com/kb/905044

Microsoft Press provides support for books and companion content at the following Web site:
 http://www.microsoft.com/learning/support/books/

Questions and Comments

If you have comments, questions, or ideas regarding the book or the companion content, or questions that
are not answered by visiting the previous sites, please send them to Microsoft Press via e-mail to

[email protected]

Or via postal mail to

Microsoft Press

Attn: Developer Series Editor

One Microsoft Way

Redmond, WA 98052-6399

Please note that Microsoft software product support is not offered through the preceding addresses.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Part I: Core Language


Chapter List

Chapter 1: Introduction to Visual C# Programming

Chapter 2: Types

Chapter 3: Inheritance
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 1: Introduction to Visual C# Programming


Overview
Microsoft Visual C# 2005 is an object-oriented programming language used to develop applications targeting
the .NET environment. Programming languages are not unlike natural languages such as Spanish, Latin,
French, Chinese, or English—human languages that are written or spoken. Each natural language includes
rules that describe proper syntax and structure; we use these rules to convey cohesive thoughts and ideas.
A natural language also evolves over time, sometimes from or within a genus of other languages.
Programming languages share many of these attributes and also include rules for proper syntax and
structure and often evolve from other languages.

Acquiring proficiency in a programming language is similar to obtaining a high level of competency in a


natural language. Having acquired a level of competency in FORTRAN, Turkish, English, COBOL, Spanish,
German, C, and other languages (not necessarily in that order), I speak from experience. Languages are
languages. When you're learning a human language, your goals are literacy and being able to have a
conversation. If, as a student of French, you can sit in a Parisian café and read the menu while discussing
current events with the locals, your language skills are a fait accompli. The goal of this chapter is the same:
for you to become conversational in C#.

Learning a language typically begins with core elements of language. In English, these elements include
consonants, vowels, nouns, verbs, adjectives, phrases, and sentences. They represent the building blocks of
the language; you cannot read, write, or speak English without a fundamental understanding of these
language components. The key elements of C# are symbols and tokens, keywords, expressions,
statements, functions, and classes. Effective C# programming requires, of course, a fundamental
understanding of these elements, which this chapter will provide.

As you know, a sentence in English is more than random words terminated with a period. Likewise, in C#, a
programming statement is more than a collection of random clauses. The following English sentence and C#
statement are both nonsensical:
 Programming fun is C#.

for(i<5;int i=0;++i)

In both cases, the correct elements are present, but the structure is incorrect. Using either a human
language or a programming language to convey cohesive ideas, concepts, tasks, or instructions requires
organizing the words and other elements of the language correctly. In the English language, syntax (the
rules of a language) indicates where a linking verb is placed in relation to the noun object. By comparison,
C# syntax orders the clauses of a for statement. According to C# syntax, the previous for statement should
be structured like this: for(int i=0;i<5;++i). Understanding the underlying language syntax is equally
important for natural and programming languages. This chapter will also provide the basic syntax of the C#
language.

Mandarin Chinese is a tonal language, whereas English is a stress language. Learning Chinese is more than
simply assimilating new words and sentence structures. You must also learn tones because the meaning of
a Chinese word can change based on tone. Speaking Chinese with English enunciation would be confusing
and amusing at best. Similarly, C# is an object-oriented language, not a procedural language (more on this
difference later). C#, C++, Java, SmallTalk, Eiffel, and other object-oriented languages are only as effective
as your appreciation of object-oriented concepts and programming techniques. I recommend a basic
knowledge of object-oriented analysis and design concepts as a complement to the newly acquired C# skills
this book will give you.

Finally, languages do not emerge spontaneously. Natural languages have been evolving for nearly 150,000
years, and knowing the heritage of and the influences on a language can be informative and helpful. For
example, English, French, German, Yiddish, and related languages are heavily influenced by their Latin
language heritage. As such, they have common words, syntax, and structures that are characteristic of the
Latin metalanguage. The origin of C# does not date back centuries, but an understanding of its evolution is
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

invaluable.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Language Origin
From the time when the first natural language appeared, hundreds of thousands of languages have emerged.
Many of these languages are now extinct, leaving about six thousand languages that are currently spoken.
Some of these languages are similar and grouped by classification. Other languages are quite distinct, such
as Kora, which incorporates a series of click sounds and is spoken by bushmen in Africa.

A list of programming languages is modest when compared with the catalogue of natural languages.
Beginning in the 1940s with Plankalkül, more than 1,000 programming languages have been documented.
Like natural languages, the variety and diversity of these languages is impressive: the succinctness of
assembler, the verbosity of COBOL, and the efficiency of C. For a comprehensive list of programming
languages, visit this link: http://oop.rosweb.ru/Other/.

The motivations that inspire the creation of languages are diverse: FORTRAN was created for scientific
analysis, COBOL for building business applications, RPG for report generation, and so on. Some languages
serve as refinements of earlier languages. CPL combined the best ingredients of several languages, including
ALGOL, FORTRAN, and COBOL. C# is an independently developed, object-oriented language and a member
of the C family of languages. It shares similar syntax and some concepts with other C-family languages;
more important, however, C# has few if any vestiges of procedural programming, in which the basic
programming element is the procedure (that is, a named sequence of statements, such as a routine,
subroutine, or function). Unfortunately, C++ inherited many of the artifacts of procedural programming from C.
C#, however, was designed to be a purely object-oriented language.

ALGOL is arguably the most influential programming language in history. The language was introduced in
1958 but became popular when ALGOL-60 was released in 1960. ALGOL quickly became the dominant
language in Europe during the 1960s. Its impact on future languages such as Pascal, C, and Java is
undeniable—these languages' grammatical syntax borrows heavily from ALGOL. I've programmed
professionally in ALGOL, assembler, COBOL, FORTRAN, C, C++, C#, Basic (in various renditions), Forth,
JavaScript, HTML, XML, MISL, and many more—and ALGOL remains my favorite language. The major
design goals of ALGOL were portability, a formal grammar, and support for algorithms. ALGOL-68 extended
the language, but the additions increased complexity and furthered abstraction from hardware. This
abstraction prevented developers from easily accessing devices and the lower tiers of the operating
environment. Soon, languages were introduced that were less complex and not as abstracted from the
architecture. One of these new languages was C.

The journey from ALGOL to C began with CPL. CPL, a derivative of ALGOL-60, was developed at the
Computer Lab of Cambridge University. CPL was created in 1963 by David Barron, Christopher Strachey,
and Martin Richards. Although CPL is not as abstracted as ALGOL, it did maintain one characteristic of
ALGOL: complexity. Martin Richards introduced Basic CPL (BCPL) in 1967 as a lean version of CPL. Ken
Thompson of Bell Labs drafted B in 1970 as the successor to BCPL. B was lighter, faster, and more
appropriate for systems programming. C was developed by Dennis Ritchie, also of Bell Labs, in 1972. C
returned some of the abstraction removed from B while keeping that language simple and quick. Although
initially consigned to the UNIX operation system and systems programming, C is a general-purpose
language and has been used for a diverse assortment of applications across a variety of platforms and
operating systems.

FORTAN, ALGOL, and COBOL dominated the procedural programming landscape in the 1960s. On a
separate track, Simula was created between 1962 and 1965 by Ole-Johan Dahl and Kristen Nygaard at the
Norwegian Computing Center. Simula is notable for being the first object-oriented programming (OOP)
language. It was designed for simulation, but evolved into a general-purpose language. Simula introduced the
important OOP concepts of classes, inheritance, and dynamic binding.

Combining aspects of C and Simula, Bjarne Stroustrup introduced C with Classes in 1979 as an
enhancement of the C programming language. Later, under Stroustrup's stewardship, C++ was created as a
direct descendant of C with Classes and was publicly recognized in 1983. C++ rapidly became the premier
object-oriented programming language and introduced structured exception handling, templates, and much
more.

C# premiered at the Professional Developers Conference (PDC) held in Orlando, Florida, in 2000. The
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

primary architects of C# were Anders Hejlsberg, Scott Wiltamuth, Peter Sollichy, Eric Gunnerson, and Peter
Golde. C# was designed to be a fully object-oriented language focusing on developing components in a
distributed environment and was launched as part of a larger initiative by Microsoft called Microsoft .NET.
Underscoring the importance of .NET to Microsoft, Bill Gates was the keynote speaker at the PDC that year.
I attended the PDC in 2000 and was both intrigued and motivated by the introduction of .NET and C#. .NET
is emblematic of a philosophical change at Microsoft and an embracing of the standards community.

Both .NET, as defined by the Common Language Infrastructure (CLI), and C# were submitted to two
international standards organizations: ECMA and ISO/IEC. Also, .NET and .NET languages, described in the
Common Language Specification (CLS), continue the trend toward truly portable code. You can write an
application in one environment and run it anywhere else. Simultaneously, a new version of Microsoft Visual
Studio was announced: Visual Studio .NET. Visual Studio .NET provides rapid application development tools
for developing a wide variety of .NET applications.
More For information on the various standards for C# and .NET, follow these links. The current
Info ECMA standards for the C# Language Specification:
http://www.ecma-international.org/publications/standards/Ecma-334.htm. The current
ECMA standards for the Common Language Infrastructure:
http://www.ecma-international.org/publications/standards/Ecma-335.htm. The current
ISO/IEC standards for the C# Language Specification:
http://www.iso.org/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=36768&ICS1
=35&ICS2=60&ICS3=. The current ISO/IEC standards for the CLI:
http://www.iso.org/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=36769&scop
elist=.

Figure 1-1: Evolution of programming languages from inception to C#


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

C# Core Language Features


Natural and programming languages consist of both simple and complex structures. The complex structures
can be decomposed into simple elements. When learning a new natural language, you probably wouldn't
start with a review of sentence structure. Instead, you probably would begin with an exploration of nouns,
verbs, and the simpler components of the language. For C#, the simpler components are symbols, tokens,
white space, punctuators, comments, preprocessor statements, and other elements. This is an excellent
place to start when learning C#.

Symbols and Tokens

Symbols and tokens are the basic constituents of the C# language. Sentences are composed of spaces,
tabs, and characters. Similarly, C# statements consist of symbols and tokens. Indeed, statements cannot
be articulated without an understanding of these basic elements. Table 1-1 provides a list of the C# tokens.
Table 1-1: C# Symbols and Tokens

Description Symbols or Tokens

White space Space

Tab Horizontal_tab, Vertical_tab

Punctuator ,:;

Line terminator carriage_returns

Comment // /* */ /// /**

Preprocessor directive #

Block {}

Generics <>

Nullable Type ?

Character Unicode_character

Escape character \code

Numeric Suffix f d m u l ul lu

Operator +, -, >, <, *, ??, () and so on

White Space
White space is defined as a space, horizontal tab, vertical tab, or form feed character. White space
characters can be combined; where one character is required, two or more contiguous characters of white
space can be substituted. Where white space is permitted, one or more instances of white space are
allowed.

Tabs
Tabs—horizontal and vertical—are white space characters. Refer to the preceding explanation of white space.

Punctuators
Punctuators separate and delimit elements of the C# language. Punctuators include the semicolon (;), dot
(.), colon (:), and comma (,), which are discussed in this section.

Semicolon punctuator In a natural language, sentences consist of phrases and clauses and are units of
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

cohesive expression. Sentences are terminated with a period (.). Statements consist of one or more
expressions and are the commands of the C# programming language. Statements are terminated by a
semicolon (;). C# is a free-form language in which a statement can span multiple lines of source code and
start in any position. Conversely, multiple statements can be combined on a single source code line,
assuming that each statement is delimited by a semicolon. This statement is not particularly good style, but
it is syntactically correct:

int variablea=
variableb +
variablec;

Dot punctuator Dot syntax connotes membership. The dot character (.) binds a target to a member, in
which the target can be a namespace, type, structure, enumeration, interface, or object. This assumes the
member is accessible. Membership is sometimes nested and therefore described with multiple dots.

Dot punctuator:
 Target? Member

This is an example of the dot punctuator:

System.Windows.Forms.MessageBox.Show("A nice day!")

Colon punctuator The colon punctuator is used primarily to delimit a label, to describe inheritance, to
indicate the implementation of an interface, to set a generic constraint, and as part of the conditional
operator. (The conditional operator, the only ternary operator in C#, is reviewed later in this chapter.
Inheritance and generic constraints are discussed in later chapters.) Labels are tags where program
execution can be transferred. A label is terminated with a colon punctuator. The scope of a label is limited to
the containing block and any nested block. Jump to a label with the goto statement.

Label punctuator:
 label_identifier: statement

A statement must follow a label, even if it's an empty statement.

Comma punctuator The comma punctuator delimits array indexes, function parameters, types of an
inheritance list, statement clauses, and most other lists of C# language elements. The comma punctuator is
separating statement clauses in the following code:

for(int iBottom=1, iTop=10; iBottom < iTop; ++iBottom, --iTop) {


Console.WriteLine("{0}x{1} {2}", iBottom, iTop, iBottom*iTop);
}

A statement clause is similar to a sentence phrase or clause, which are also sometimes delimited by
commas. A statement clause is a substatement in which multiple statement clauses can be substituted for
a single statement. Not all statements are replaceable with statement clauses—check the documentation of
the statement to be sure.

Line Terminators
Line terminators separate lines of source code. A carriage-return, line-feed, line-separator, and
paragraph-separator are the line terminators of C#. Where one line terminator is inserted, two or more are
acceptable. Line terminators can be inserted anywhere white space is allowed. The following code is
syntactically incorrect:

int variablea=var
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

iableb+variablec;

As an identifier, variablea cannot contain spaces. Thus, line terminators are also disallowed.

Comments
C# supports four styles of comments: single-line, delimited, single-line documentation, and delimited
documentation comments. Comments cannot be nested. Although comments are not mandated, liberal
comments are considered good programming style. Self-documenting code and comments in your source
code aid in later maintenance. Be kind to the maintenance program—comment! In Code Complete, Second
Edition, (Microsoft Press, 2004), Steve McConnell gives valuable best practices on programming, including
how to properly document your source code.

Single-line comments: // Single-line comments start at the symbol and end at the line terminator:

Console.WriteLine(objGreeting.French); // Display Hello (French)

Delimited comments: /* and */ Delimited comments, also called multiline or block comments, are
bracketed by the /* and */ symbols. Delimited comments can span multiple lines of source code:

/*
Class Program: Programmer Donis Marshall
*/
class Program {
static int Main(string[] args) {
Greeting objGreeting = new Greeting();// Display Hello (French)
Console.WriteLine(objGreeting.French);
return 0;
}
}

Single-line documentation comments: /// Use documentation comments to apply a consistent format to
source code comments. Documentation comments precede types, members, parameters, delegates,
enums, and structs; they do not precede namespaces. Documentation comments use XML tags to classify
comments. These comments are exportable to an XML file using the documentation generator. The resulting
file is called the documentation file, which can be bound to a Visual Studio project to augment the
information presented in IntelliSense and the Object Browser.

Single-line documentation comments are automated in the Visual Studio IDE, which makes them more
popular than delimited documentation comments. Visual Studio IDE has Smart Comment Editing that
inserts the comment framework after immediately inputting the /// symbol.

The following code snippet shows the previous code after preceding the Main method with a single-line
documentation comment ///. From there, Smart Comment Editing completed the remainder of the comment
framework, including adding comments and XML tags for the method parameter and return. You only need to
add specific comments.

/// <summary>
///
/// </summary>
class Program {
/// <summary>
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

///
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
static int Main(string[] args) {
Greeting objGreeting = new Greeting();
Console.WriteLine(objGreeting.French
return 0;
}
}

Here are the documentation comments with added details:

/// <summary>
/// Starter class for Simple HelloWorld
/// </summary>
class Program {
/// <summary>
/// Program Entry Point
/// </summary>
/// <param name="args">Command Line Parameters</param>
/// <returns>zero</returns>
static int Main(string[] args) {
Greeting objGreeting = new Greeting();
Console.WriteLine(objGreeting.French);
return 0;
}
}

The C# compiler is a documentation generator. The /doc compiler option instructs the compiler to generate
the documentation file. Alternatively, you can request that the documentation file be generated in the Visual
Studio IDE. Select the Properties menu item from the Project menu. From the Properties window, switch to
the Build options. In the Build pane (see Figure 1-2), you can activate and enter the name of the XML
documentation file.

Figure 1-2: The Build pane of the Project Settings window


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Delimited documentation tags Delimited documentation tags can be used instead of the single-line
version. Smart Comment Editing is not available with delimited documentation tags. Documentation
symbols, XML tags, and comments must be entered manually, which is the primary impediment to using
delimited documentation tags. Here is an example of delimited documentation tags:

/**<summary>
Starter class for Simple HelloWorld</summary>
*/

This is the documentation file generated by the C# compiler from the preceding source code:

<?xml version="1.0" ?>


<doc>
<assembly>
<name>HelloWorld</name>
</assembly>
<members>
<member name="T:HelloWorld.Program">
<summary>Starter class for Simple HelloWorld</summary>
</member>
<member name="M:HelloWorld.Program.Main(System.String[])">
<summary />
<param name="args" />
<returns />
</member>
</members>
</doc>

The documentation generator assigns IDs to element names. T is the prefix for a type, whereas M is a prefix
for a method. Here's a listing of IDs:
E Ev
ent
F Fie
ld
M Me
tho
d
N Na
me
sp
ac
e
P Pro
per
ty
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

T Ty
pe
! Err
or

Preprocessor Directives
Use preprocessor directives to define symbols, include source code, exclude source code, name sections of
source code, and set warning and error conditions. The variety of preprocessor directives is limited when
compared with C++, and many of the C++ preprocessor directives are not available in C#. There is not a
separate preprocessor for preprocessor statements. Preprocessor statements are processed by the normal
C# compiler. The term "preproccesor" is used for historical connotations only.

Preprocessor directive:
 #command expression

This is a list of preprocessor commands available in C#:


#d #u #if
efi nd
ne ef
#el #eli #e
se f ndi
f
#lin #er #w
e ror arn
ing

#re #e #pr
gio ndr ag
n egi ma
on

The preprocessor symbol and subsequent command are optionally separated with a space, but must be on
the same line. For this reason, preprocessor commands can be followed only with a single line comment.

Declarative preprocessor directives The declarative preprocessor directives are #define and #undef, which
define and undefine a preprocessor symbol, respectively. Defined symbols are implicitly true, whereas
undefined symbols are false. Declarative symbols must be defined in each compilation unit where the
symbol is referenced. Undeclared symbols default to undefined and false. The #define and #undef directives
must precede any source code. Redundant #define and #undef directives are trivial and have no affect.

Declarative preprocessor directives:


 #define identifier
 #undef identifier

Conditional preprocessor directives Conditional preprocessor directives are the #if, #else, #elif, and #endif
directives, which exclude or include subsequent source code. A conditional preprocessor directives begins
with #if and ends with #endif. The intervening conditional preprocessing directives, #else and #elif, are
optional.

Conditional preprocessor directives:


 #if boolean_expression
 #elif boolean_expression
 #else
 #endif

The boolean_expression of the #if and #elif directive is a combination of preprocessor symbols and normal
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Boolean operators. If the boolean_expression is true, the source code immediately after the #if or #elif
directive is included in the compilation. If the boolean_expression is false, the source code is hidden. The
#else directive can be combined with an #if or #elif directive. If the boolean_expression of #if or #elif is false,
the code following the #else is included in the compilation. When true, the source code after the #else is
hidden. Here's sample code with preprocess symbols and related directives:

#define DEBUGGING

using System;

namespace Donis.CSharpBook {
class Starter{
#if DEBUGGING
static void OutputLocals() {
Console.WriteLine("debugging...");
}
#endif
static void Main() {
#if DEBUGGING
OutputLocals();
#endif
}
}
}

Finally, the #elif directive essentially nests #if conditional preprocessor directives:

#if expression
source_code
#elif expression
source_code
#else
source_code
#endif

Diagnostic directives Diagnostic directives include the #error, #warning, and #pragma directives. The #error
and #warning directives display error and warning messages, correspondingly. The diagnostic messages are
displayed in the Error List window of the Visual Studio IDE. Similar to standard compilation errors, an #error
directive prevents the program from compiling; a #warning directive does not prevent the program from
successfully compiling. Use conditional directives to conditionally apply diagnostic directives.

Diagnostic directives:

#error error_message
#warning error_message

The error_message is of string type and is optional.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The #pragma directive enables or disables standard compilation warnings.

Pragma directives:

#pragma warning disable warning_list


#pragma warning restore warning_list

The warning_list contains one or more warnings delimited with commas. The status of a warning included in
the warning_list remains unchanged until the end of the compilation unit unless altered in a later #error
directive.

This #pragma directive disables the 219 warning, which is the "variable is assigned but its value is never
used" warning:

#pragma warning disable 219


class Starter{
static void Main() {
int variablea=10;
}
}

Region directives Region directives mark sections of source code. The #region directive starts a region,
whereas the #endregion directive ends the region. Region directives can be nested. The Visual Studio IDE
outlines the source code using region tags. In Visual Studio, you can collapse or expand regions of source
code.

Region directives:

#region identity
source_code
#endregion

Line directives Line directives modify the line number reported in subsequent compiler errors and warnings.
There are three versions of the line directive.

Line directives:

#line line_number source_filename


#line default
#line hidden

The first #line directive shown renumbers the source code from the location of the directive until the end of
the compilation unit is reached or overridden by another #line directive. In the following code, the #line
directive resets the current line to 25:

#line 25
static void Main() {
Console.WriteLine("#line application");
int variablea=10; // 219 warning
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The second type of #line directive resets or undoes any previous #line directive. The line number is reset to
the natural line number.

The third #line directive is only tangentially related to the line number. This directive does not affect the line
number; it hides source code from the debugger. Excluding another #line hidden directive, the source code is
hidden until the next #line directive is encountered.

Blocks
Blocks define the scope of a type, where type is a class, struct, or enum. Additionally, members of the type
are listed inside the block.

Block:

type typename{ // block


}

Blocks are used as compound statements. Paragraphs join related sentences that convey an extended
thought or concept. A statement block combines related statements as a single entity. In this context, a
statement block is a compound statement and can contain one or more statements. Each statement of the
statement block is delimited by a semicolon. In most circumstances in which a single statement is allowed,
a statement block can be substituted. Statement blocks are prevalent as method bodies but are used with
conditional and iterative statements.

The if statement in the following code, which is a conditional statement, controls a single statement. The
Console.WriteLine is controlled by the if statement that precedes it, so a statement block is not required.

static void Main() {


int variablea=5, variableb=10;
if(((variablea*variableb)%2)==0)
Console.WriteLine("the sum is even");
}

In the modified code, the if statement controls multiple statements, and a statement block is needed. Some
would suggest, and I agree, that always using statement blocks with conditional statements is a good
practice. This prevents a possible future omission when additional statements are added to the realm of the
conditional statement:

static void Main() {


int variablea=5, variableb=10;
if(((variablea*variableb)%2)==0) {
Console.WriteLine("{0} {1}", variablea,
variableb);
Console.WriteLine("the sum is even");
}
}

Generic Types
Generic types are templated types. A type is an abstraction of identity: a car class is an abstraction of a
type of car, an employee class is an abstraction of an employee, and a generic type is an abstraction of the
specifics of a type.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The NodeInt class partially implements and is an abstraction of a node within a linked list of integers:

class NodeInt {
public NodeInt(int f_Value, NodeInt f_Previous) {
m_Value=f_Value;
m_Previous=f_Previous;
}

// Remaining methods

private int m_Value;


private NodeInt m_Previous;
}

The Node class is further abstracted when compared with the NodeInt class. The integer specifics of the
NodeInt class have been removed. This resulting type could be a link list of any type:

class Node<T> {
public Node(T f_Value, Node<T> f_Previous) {

m_Value=f_Value;
m_Previous=f_Previous;
}

// Remaining methods

private T m_Value;
private Node<T> m_Previous;
}

The generics symbol bounds the type parameters, which is T in the preceding program.

There is much more about generics later in the book.

Nullable Types
Nullable types are value types that can be assigned a null value. Nullable types provide a consistent
mechanism for determining whether a value type is empty (null).

Nullable type:

valuetype? identifier;

Nullable types are discussed in detail later in this chapter.

Characters
C# source files contain Unicode characters, which are the most innate of symbols. (Every element, keyword,
operator, or identifier in the source file is a composite of Unicode characters.)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Numeric Suffixes
Numeric suffixes cast a literal value to a related type. Literal integer values can have the L, U, UL, and LU
suffixes appended to them; literal real values can have the F, D, and M suffixes added. The suffixes are case
insensitive. Table 1-2 describes each suffix.
Table 1-2:
Description of
Suffixes

De Ty Su
scr pe ffix
ipti
on

Un uin u
sig t
ne or
d lon
int g
eg
er
or
un
sig
ne
d
lon
g

Lo lon l
ng g
or or
un ulo
sig ng
ne
d
lon
g

Un ulo ul
sig ng
ne
d
lon
g

Flo floa f
at t

Do do d
ubl ubl
e e

Mo de m
ne ci
y ma
l

When casting a real type using the M suffix, rounding might be required. If so, banker's rounding is used,
which rounds to the nearest possible value. If midway between two values, the even number is returned.
Gaussian rounding, albeit harder to pronounce, is another name for banker's rounding.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Here is an example:

int variable=10u;

The next statement causes a compile error. You cannot append a real suffix to an integral literal value
because they are not related types.

long variable = 456f;

Escape Characters
The escape character provides an alternate means of encoding Unicode characters, especially special
characters that are not available on a standard keyboard. Escape sequences can be used as characters
within identifiers and elsewhere.

Unicode escape sequences must have four hexadecimal digits and are therefore limited to a single character.

Escape sequence:

\uhexadecimal digit1 digit2 digit3 digit4

Hexadecimal escape sequences define one or more Unicode characters and contain one or more digits.

Hexadecimal sequence:

\xhexadecimal digit1 digit2 digitn

Table 1-3 shows a list of the predefined escape sequences in C#.


Table 1-3:
Predefined
Escape
Sequences

Si Se
mp qu
le en
Es ce
ca
pe

Sin \'
gle
qu
ote

Do \"
ubl
e
qu
ote

Ba \\
ckl
as
h

Nul \0
l
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-3:
Predefined
Escape
Sequences

Si Se
mp qu
le en
Es ce
ca
pe

Ale \a
rt

Ba \b
ck
sp
ac
e

For \f
m
fee
d

Ne \n
w
line

Car \r
ria
ge
ret
urn

Hor \t
izo
nta
l
tab

Uni \u
co
de
ch
ara
cte
r

Ver \v
tic
al
tab
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-3:
Predefined
Escape
Sequences

Si Se
mp qu
le en
Es ce
ca
pe

He \x
xa
de
ci
ma
l
ch
ara
cte
r(s)

This is an unconventional version of the traditional Hello World program:

class HelloWorld {
static void Main() {
Console.Write("\u0048\u0065\u006C\u006C\u006f\n");
Console.Write("\x77\x6F\x72\x6c\x64\x21\b");
}
}

Verbatim Characters
The verbatim character prevents the translation of a string or identifier, where it is treated "as-is." To create a
verbatim string or identifier, prefix it with the verbatim character.

A verbatim string is a string literal prefixed with the verbatim character. The characters of the verbatim string,
including escape sequences, are not translated. The exception is the quote escape character, which is
translated even in a verbatim string. Unlike a normal string, verbatim strings can contain physical line feeds.

Here is a sample verbatim string:

class Verbatim{
static void Main() {
string fileLocation=@"c:\datafile.txt";
Console.WriteLine("File is located at {0}",
fileLocation);
}
}

A verbatim identifier is an identifier prefixed with the verbatim character that prevents the identifier from being
parsed as a keyword. Although this is of limited usefulness, porting source code from another language—in
which the keywords are different—is a circumstance in which verbatim identifiers might be helpful.
Otherwise, it is a best practice not to use this language feature because verbatim identifiers make your code
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

less readable and harder to maintain.

This is a partial translation of French to English:


 L'espoir is a waking dream.

Can you decipher this sentence? Unless you are fluent in French, the partial translation is ineffectual at best.
The original sentence was ''L'espoir est un rêve de réveil." The following is an equally unskillful translation,
although technically acceptable:

public class ExampleClass {


public static void Function() {
int @for = 12;
MessageBox.Show(@for.ToString());
}
}

In the preceding code, the for statement is being used as a variable name. Although technically acceptable,
it is confusing at best. The for statement is common in C# and many other programming languages. For this
reason, most developers would view the for as a statement regardless of the usage, which will inevitably lead
to confusion.

Operators
Operators are used in expressions and always return a value. There are three categories of operators: unary,
binary, and ternary. The following sections describe most of the operators in C#.

Unary operators Table 1-4 is a list of unary operators.


 Unary operators have a single parameter.
 Prefix operators are evaluated before the encompassing expression.
 Postfix operators are evaluated after the encompassing expression.
Table 1-4: Unary
Operators

Op Sy Sa
er mb mp
ato ol le
r

Un + vari
ary abl
Plu e=
s +5;
5

Un - vari
ary abl
mi e=-
nu (-
s 10)
;
10
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-4: Unary


Operators

Op Sy Sa
er mb mp
ato ol le
r

Bo ! vari
ole abl
an e=!
Ne tru
gat e;
ion fal
se

Bit ~ vari
wis abl
e e=
1's ~((
co uin
mp t)1)
le ;
me 42
nt 94
96
72
94

Pre ++ ++
fix vari
Inc abl
re e;
me 11
nt

Pre -- --
fix vari
De abl
cre e;
me 10
nt

Po ++ vari
stfi abl
x e
Inc ++;
re 11
me
nt

Po -- vari
stfi abl
x e --
De ;
cre 10
me
nt
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-4: Unary


Operators

Op Sy Sa
er mb mp
ato ol le
r

Ca () vari
st abl
Op e
era =(i
tor nt)
12
3.4
5;
12
3

Fu () Fu
nct nct
ion ion
Op Cal
era l(p
tor ara
me
ter)
;
ret
urn
val
ue

Arr [] arr
ay ayn
Ind am
ex e[iI
Op nd
era ex]
tor ;
nth
ele
me
nt

Glo ::
bal
Na
me
sp
ac
e
Qu
alifi
er

Binary operators This section lists and discusses the use of binary operators.
 Binary operators have two operands: a left and right operand.
 Integer division truncates the floating point portion of the result.
 Bitwise Shift Left (value << bitcount).
 Bitwise Shift Right (value >> bitcount).
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-5 details the binary operators.


Table 1-5: Binary Operators

Op Sy Sa Re
er mb mp sul
ato ol le t
r

As = vari 10
sig abl
nm e=
ent 10;

Bin + vari 15
ary abl
Plu e=
s vari
abl
e
+
5;

Bin - vari 5
ary abl
Mi e=
nu vari
s abl
e-
10;

Mu * vari 25
ltipl abl
ica e=
tio vari
n abl
e*
5;

Divi / vari 5
sio abl
n e=
vari
abl
e/
5;

Mo % vari 2
dul abl
us e=
vari
abl
e
%
3;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-5: Binary Operators

Op Sy Sa Re
er mb mp sul
ato ol le t
r

Lo & vari 1
gic abl
al e=
An 5
d &
3;

Lo | vari 7
gic abl
al e=
Or 5|
3;

Bit ^ vari 6
wis abl
e e=
XO 5
R ^
3;

Bit << vari 40


wis abl
e e=
Shi 5
ft <<
Lef 3;
t

Bit >> vari 2


wis abl
e e=
Shi 5
ft >>
Rig 1;
ht

Nul ?? vari 2
l abl
Co eb
ale =v
sci ari
ng abl
ea
??
5

Compound operators Compound operators combine an assignment and another operator. If the expanded
expression is 'variablea=variablea operator value', the compound operator is 'variable operator= value'.

variable=variable+5;

The preceding compound operation is equivalent to this:


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

variable+=5;

Compound operations are a shortcut and are never required in lieu of the expanded operation. Table 1-6 lists
the compound operators.
Table 1-6: List of
Compound Operators

Op Sy Sa
er mb mp
ato ol le
r

Ad += vari
diti abl
on e+
As =5;
sig
nm
ent

Su -= vari
btr abl
act e-
ion =1
As 0;
sig
nm
ent

Mu *= vari
ltipl abl
ica e*=
tio 5;
n
As
sig
nm
ent

Divi /= vari
sio abl
n e/=
As 5;
sig
nm
ent

Mo %= vari
dul abl
us e%
As =3;
sig
nm
ent
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-6: List of


Compound Operators

Op Sy Sa
er mb mp
ato ol le
r

An &= vari
d abl
As e&
sig =3;
nm
ent

Or |= vari
As abl
sig e|=
nm 3;
ent

XO ^= vari
R abl
As e^
sig =
nm 3;
ent

Lef << vari


t-S = abl
hift e<
As <=
sig 3;
nm
ent

Rig >> vari


ht- = abl
Shi e>
ft >=
As 1
sig
nm
ent

Boolean operators Boolean expressions evaluate to true or false. The integer values of nonzero and zero
cannot be substituted for a Boolean true or false.

There are two versions of the logical And and Or operators. The && and || operators support short-circuiting,
whereas & and | do not. What is short-circuiting? If the result of the expression can be determined with the
left side, the right side is not evaluated. Without disciplined coding practices, short-circuiting might cause
unexpected side effects.

This is an example of possible short-circuiting:

if(FunctionA() && FunctionB()) {

}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

In the preceding code, assuming that FunctionA returns false, the entire expression evaluates to false.
Therefore, the expression short-circuits and FunctionB is not invoked.

Table 1-7 shows the Boolean operators.


Table 1-7: List
of Boolean
Operators

Op Sy
er mb
ato ol
r

Eq ==
ual
s

Not !=
Eq
ual

Le <
ss
Th
an

Gr >
eat
er
Th
an

An &&
d
(Sh
ort
Cir
cui
tin
g)

Or ||
(Sh
ort
Cir
cui
tin
g)

An &
d

Or |

Le <=
ss
Th
an
or
Eq
ual
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-7: List


of Boolean
Operators

Op Sy
er mb
ato ol
r

Gr >=
eat
er
Th
an
or
Eq
ual

Lo ^
gic
al
XO
R

Ternary operators The conditional operator is the sole ternary operator in C# and is an abbreviated if else
statement.

Conditional operator:

boolean_expression?truth_statement:false_statement

This is the conditional operator in source code:

variable>5?Console.WriteLine(">5"):Console.WriteLine("<= 5");

Pointer operators Pointer operators are available in unsafe mode and support conventional pointers. The
unsafe compiler option builds a program in unsafe mode. Alternatively, in Visual Studio IDE, set the Allow
Unsafe Mode option on the Build Page of Project Settings. Table 1-8 includes the pointer operators.
Table 1-8: List of
Pointer Operators

Op Sy De
er mb scr
ato ol ipti
r on

Ast * De
eri cla
sk re
Op a
era poi
tor 1 nte
r
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-8: List of


Pointer Operators

Op Sy De
er mb scr
ato ol ipti
r on

Ast * Der
eri efe
sk ren
Op ce
era a
tor 2 poi
nte
r

Am & Ob
per tai
sa n
nd an
Op ad
era dre
tor ss

Arr -> Der


ow efe
Op ren
era ce
tor a
poi
nte
r
an
d
me
mb
er
ac
ce
ss

Here is some sample code using pointers:

static void Main(string[] args)


{
unsafe {
int variable = 10;
int* pVariable = &variable;
Console.WriteLine("Value at address is {0}.",
*pVariable);
}
}

The above code must be compiled with the unsafe compiler option on. A more extensive review of pointers is
presented later in the book.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Identifiers
An identifier is the name of a C# entity, which includes type, method, property, field, and other names.
Identifiers can contain Unicode characters, escape character sequences, and underscores. A verbatim
identifier is prefixed with the verbatim character (as discussed earlier in this chapter).

Keywords

One of the strengths of C# is that the language offers relatively few keywords. C# keywords represent the
verbs, nouns, and adjectives of the language. The nouns of C# are instances of classes, structs, interfaces,
delegates, and namespaces. Verbs infer an action. The goto, for, while, and similar keywords have that role
in C#. The adjectives, including the public, private, protected, and static keywords, are modifiers of the C#
nouns.

Table 1-9 is an overview of the C# keywords. Extended explanations of each keyword are provided in context
at the appropriate location in the book.
Table 1-9: Overview
of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ab ab Th
str str e
act act cla
1 cla ss
ss ide
ide ntif
ntif ier
ier ca
nn
ot
be
ins
tan
tiat
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ab ab Th
str str e
act act me
2 ret tho
urn d
ide ide
ntif ntif
ier ier
is
not
im
ple
me
nte
d
in
the
cur
ren
t
cla
ss.

as ide Ca
ntif sts
ier obj
as ect
typ ide
e ntif
ier
to
a
rel
ate
d
typ
e
or
null
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ba ba Ac
se se. ce
ide ss
ntif es
ier the
me
mb
er
ide
ntif
ier
of
the
ba
se
cla
ss.

bre Bre Exi


ak ak ts
cur
ren
t
loo
p
or
swi
tch
sta
te
me
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ca ca Sw
se se itc
lab h
el sta
te
me
nts
ju
mp
s
to
a
ma
tch
ing
ca
se
lab
el.

cat cat Filt


ch ch( ers
filt ex
er) ce
pti
on
s
thr
ow
n
fro
m
a
try
blo
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ch ch Ex
ec ec ce
ke ke pti
d1 d( on
exp is
res rai
sio se
n) d
if
exp
res
sio
n
ove
rflo
ws.

ch ch Ex
ec ec ce
ke ke pti
d2 d{ on
sta is
te rai
me se
nt_ d
blo if
ck an
} y
ex
pre
ssi
on
wit
hin
sta
te
me
nt
blo
ck
ove
rflo
ws.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

cla cla Def


ss ss ine
ide s
ntit a
y ne
w
cla
ss
na
me
d
ide
ntit
y.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

co co De
nst nst cla
typ res
e a
ide co
ntit nst
y ant
vari
abl
e
or
me
mb
er
na
me
d
ide
ntit
y.
Co
nst
ant
ins
tan
ce
s
ca
nn
ot
be
mo
difi
ed
at
run
tim
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

co Co Ju
nti nti mp
nu nu s
e e to
the
en
d
of
a
loo
p
an
d
sta
rts
a
ne
w
iter
ati
on.

def def Th
aul aul e
t t def
aul
t
lab
el
to
ju
mp
to
in
a
swi
tch
sta
te
me
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

del del Def


eg eg ine
ate ate s
ret a
urn typ
me e
tho tha
d t
hol
ds
fun
cti
on
poi
nte
rs.

do do Def
{ ine
sta s
te a
me do
nt_ loo
blo p
ck wit
} h
whi the
le( iter
exp ativ
res e
sio tes
n) t
at
the
en
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

els els Th
e e{ e
sta els
te e
me sta
nt_ te
blo me
ck nt
} is
ma
tch
ed
to
the
ne
are
st
if
sta
te
me
nt
an
d
pro
vid
es
the
fals
e
sta
te
me
nt_
blo
ck .

en en Def
um um ine
en s
um an
na en
me um
era
tio
n
typ
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

eve eve Def


nt nt ine
del s
eg an
ate eve
_id nt
ent na
ifie me
r d
ide ide
ntif ntif
ier ier
of
the
del
eg
ate
_id
ent
ifie
r
typ
e.

exp ex Usi
licit plic ng
it the
op us
era er-
tor defi
co ne
nve d
rsi co
ont nve
ype rsi
on
op
era
tor
req
uir
es
an
ex
plic
it
ca
st.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ext ext A
ern ern me
ret tho
urn d
me im
tho ple
d me
nte
d
ext
ern
ally
.

fal fals A
se e Bo
ole
an
val
ue.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

fin fina Pai


ally lly red
{ wit
sta h
te a
me try
nt_ blo
blo ck.
ck Cle
} an
up
or
mu
st
exi
t
co
de
pla
ce
d
in
fina
lly
sta
te
me
nt_
blo
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

fixe fixe Fix


d d( es
de a
cla poi
rati nte
on) r
in
me
mo
ry
an
d
pre
ven
ts
rel
oc
ati
on
of
vari
abl
e
by
the
gar
ba
ge
coll
ect
or.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

for for( For


initi loo
aliz p
ers tha
; t
bo iter
ole ate
an s
_ex unt
pre il
ssi bo
on; ole
iter an
ato _ex
rs) pre
ssi
on
is
fals
e.

for for Iter


ea ea ate
ch ch( ele
ele me
me nts
nt in
in an
en en
um um
era era
ble ble
_c _c
olle olle
cti cti
on on.
)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

get get Ac
ce
ss
or
me
tho
d
of
pro
per
ty
me
mb
er.

got got Ju
o1 o mp
ide s
ntif to
ier a
lab
el
na
me
d
ide
ntif
ier.

got got Ju
o2 o mp
ca s
se to
ide an
ntif ide
ier ntif
ier
lab
el
insi
de
a
swi
tch
sta
te
me
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

got got Ju
o3 o mp
def s
aul to
t a
def
aul
t
ca
se
insi
de
a
swi
tch
sta
te
me
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

im im Wh
plic plic en
it it ne
op ed
era ed,
tor a
co us
nve er-
rsi defi
ont ne
ype d
co
nve
rsi
on
op
era
tor
ca
sts
im
plic
itly
.
An
ex
plic
it
ca
st
is
not
req
uir
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

in for Iter
ea ate
ch( ele
ele me
me nts
nt in
in an
en en
um um
era era
ble ble
_c _c
olle olle
cti cti
on) on.

int int Def


erf erf ine
ac ac s
e e an
ide int
ntif erf
ier ac
e
na
me
d
ide
ntif
ier.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

int int Ide


ern ern ntif
al al ier
ide is
ntif a
ier typ
e
or
me
tho
d
an
d
ac
ce
ssi
ble
onl
y
wit
hin
the
cur
ren
t
as
se
mb
ly.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

is obj Ex
ect pre
is ssi
typ on
e eva
lua
tes
to
tru
e
if
obj
ect
is
rel
ate
d
to
typ
en
am
e;
oth
erw
ise
,
eva
lua
tes
to
fals
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

loc loc Sta


k k( te
obj me
ect nt_
) blo
{st ck
ate s
me loc
nt_ ke
blo d
ck} wit
h
the
sa
me
obj
ect
are
pro
tec
ted
by
a
sh
are
d
crit
ical
se
cti
on.

na na Cre
me me ate
sp sp s
ac ac a
e e na
ide me
ntif sp
ier ac
e
call
ed
ide
ntif
ier.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ne ne All
w1 w oc
ide ate
ntif s
ier( me
co mo
nst ry
ruc for
tor) a
cla
ss
ide
ntif
ier
on
a
ma
na
ge
d
he
ap
an
d
ret
urn
s
a
ref
ere
nc
e
to
the
obj
ect
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ne ne Me
w2 w tho
ret d
urn hid
me es
tho the
d sa
me
me
tho
d
in
the
ba
se
cla
ss.

null null Set


s
un
us
ed
ref
ere
nc
es
an
d
null
abl
e
val
ue
typ
es
to
null
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

obj obj Obj


ect ect ect
is
an
alia
s
for
Sy
ste
m.
Ob
jec
t,
whi
ch
is
the
ba
se
cla
ss
to
all
.N
ET
obj
ect
s
(val
ue
or
ref
ere
nc
e
typ
e).
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

op op Im
era era ple
tor tor me
op nts
era a
tor us
_n er-
am defi
e ne
d
op
era
tor
_n
am
e
in
the
cur
ren
t
typ
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

rea rea Ide


do do ntif
nly nly ier
typ is
e a
ide fiel
ntif d
ier na
me
an
d
ca
n
be
initi
aliz
ed
at
de
cla
rati
on
or
in
a
co
nst
ruc
tor
onl
y.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ref ref Th
typ e
e act
par ual
am par
ete am
r ete
r
is
pa
ss
ed
int
o
the
me
tho
d
an
d
ca
n
be
mo
difi
ed.
Par
am
ete
r
mu
st
be
initi
aliz
ed
bef
ore
fun
cti
on
inv
oc
ati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

ret ret Ret


urn urn urn
obj s
ect an
obj
ect
fro
m
a
me
tho
d.
Me
tho
ds
tha
t
ret
urn
voi
d
ca
n
hav
e
an
em
pty
"ret
urn
;".

se se Ide
ale ale ntif
d d ier
ide is
ntif a
ier cla
ss
na
me
an
d
is
not
inh
erit
abl
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

set set As
sig
nm
ent
me
tho
d
of
pro
per
ty
me
mb
er.

siz siz Siz


eof eof eof
( ret
val urn
ue s
na the
me siz
) e
of
a
val
ue
typ
e;
su
pp
ort
ed
onl
y
in
un
saf
e
mo
de.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

sta sta All


ck ck oc
allo allo ate
c c s
typ an
e[ arr
exp ay
res of
sio typ
n] e
on
the
sta
ck;
su
pp
ort
ed
onl
y
in
un
saf
e
mo
de.
Ex
pre
ssi
on
det
er
mi
ne
s
the
siz
e
of
the
arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

sta sta Me
tic tic tho
ret d
urn is
me cla
tho ss-
d bo
un
d
an
d
not
as
so
cia
ted
wit
h
a
sp
ecif
ic
ins
tan
ce.

str str Def


uct uct ine
ide s
ntit a
y str
uct
ure
na
me
d
ide
ntit
y.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

swi swi Co
tch tch ntr
(ex ol
pre is
ssi tra
on) nsf
{ err
sta ed
te to
me eit
nt_ her
blo the
ck ma
} tch
ing
swi
tch
lab
el,
if
an
y,
or
to
the
def
aul
t
ca
se
in
the
sta
te
me
nt_
blo
ck .
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

thi Thi Th
s s e
thi
s
obj
ect
is
a
ref
ere
nc
e
to
the
cur
ren
t
obj
ect
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

thr thr Thr


ow ow ow
obj s
ect a
us
er-
defi
ne
d
ex
ce
pti
on.
Ob
jec
t
sh
oul
d
be
der
ive
d
fro
m
Sy
ste
m.
Ex
ce
pti
on.

tru Tru Tru


e e e
is
a
Bo
ole
an
val
ue.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

try try Try


{ gu
sta ard
te s
me for
nt_ ex
blo ce
ck pti
} on
s
in
the
sta
te
me
nt_
blo
ck .

typ typ Ret


eof eof urn
( s
obj the
ect typ
) e
of
the
obj
ect
.

un un Ex
ch ch pre
ec ec ssi
ke ke on
d1 d( is
exp tru
res nc
sio ate
n) d
if
ove
rflo
we
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

un un If
ch ch an
ec ec ex
ke ke pre
d2 d{ ssi
sta on
te wit
me hin
nt_ sta
blo te
ck me
} nt
blo
ck
is
ove
rflo
we
d,
the
ex
pre
ssi
on
is
tru
nc
ate
d.

un un Cla
saf saf ss
e1 e ide
cla ntif
ss ier
ide ca
ntif n
ier hav
e
un
saf
e
co
de
su
ch
as
poi
nte
rs.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

un un Th
saf saf e
e2 e me
ret tho
urn d
me ca
tho n
d co
nta
in
un
saf
e
co
de
su
ch
as
poi
nte
rs.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

usi usi Ide


ng1 ng ntif
ide ier
ntif is
ier a
na
me
sp
ac
e.
Th
e
usi
ng
ke
yw
ord
ma
ke
s
the
na
me
sp
ac
e
im
plic
it.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

usi usi IDi


ng2 ng( sp
ide os
ntifi abl
er) e.D
blo isp
ck os
e,
whi
ch
is
the
ex
plic
it
de
str
uct
or,
is
call
ed
on
ide
ntif
ier
wh
en
blo
ck
is
exi
ted
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

virt virt Virt


ual ual ual
me ma
tho ke
d s
the
me
tho
d
ove
rrid
abl
e
in
a
der
ive
d
cla
ss.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

voi voi A
d1 d voi
me d
tho ret
d urn
me
an
s
tha
t
the
me
tho
d
do
es
not
ret
urn
a
val
ue.
Th
e
me
tho
d
ca
n
om
it
a
ret
urn
sta
te
me
nt
or
hav
e
an
em
pty
ret
urn
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

voi voi Ide


d2 d* ntif
ide ier
ntif is
ier a
poi
nte
r
na
me
.
A
voi
d
poi
nte
r
is
a
co
nve
nti
on
al
an
d
typ
ele
ss
poi
nte
r;
su
pp
ort
ed
onl
y
in
un
saf
e
mo
de.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

vol vol Ac
atil atil ce
e e ss
fiel es
dn to
am a
e vol
atil
e
fiel
dn
am
e
are
im
me
dia
te,
whi
ch
is
us
eful
in
a
mu
ltit
hre
ad
ed
env
iro
nm
ent
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

wh cla Th
ere ss e
cla wh
ss ere
na cla
me us
<p e
ara set
me s
ter co
s> nst
wh rai
ere nts
co on
nst the
rai cla
nt ss
na
me
. It
mu
st
be
a
ge
ner
ic
cla
ss.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

whi whi Th
le le( e
bo sta
ole te
an me
_ex nt_
pre blo
ssi ck
on) of
{ the
sta whi
te le
me loo
nt_ p
blo is
ck rep
} eat
ed
unt
il
the
bo
ole
an
_ex
pre
ssi
on
is
fals
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-9: Overview


of C# Keywords with
Explanations

Ke Sy Ex
yw nta pla
or x nat
d ion

yiel yiel In
d d the
iter en
ato um
r_v era
alu tor
e pat
ter
n,
the
yiel
d
ke
yw
ord
ad
ds
val
ue
s
to
be
en
um
era
ted
.

Primitives

Intrinsic data types, commonly called primitives, are predefined in C#. Primitives historically found in C-base
languages, including int, long, and many others, inure to C#. The intrinsic types are declared as C#
keywords but are alias for types in the .NET Framework Class Library. Except for the string type, the
primitives are value types and allocated on the stack as structures. The string type is a class and allocated
on the managed heap.

As indicated, primitives in C# (see Table 1-10) are value types but are nonetheless objects with a published
interface. For numeric types, the min property, max property, and Parse methods of the public interface are
particularly useful. The min and max property are invaluable for bounds checking, whereas the Parse method
converts the string to the primitive.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-10: Primitives in C#

Ty Pri De Ra
pe mit scr ng
ive ipti e
on

bo Sy Bo tru
ol ste ole e
m. an or
Bo fals
ole e
an

byt Sy 8-b 0
e ste it to
m. int 25
Byt eg 5
e er

ch Sy 16- /u0
ar ste bit 00
m. Uni 0
Ch co to
ar de /ufff
ch f
ara
cte
r

de Sy 12 ±1.
ci ste 8-b 0
ma m. it ×
l De de 10
ci ci -28

ma ma to
l l ±7.
9
×
10
28 ,

wit
h
28
to
29
digi
ts
of
pre
cisi
on
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-10: Primitives in C#

Ty Pri De Ra
pe mit scr ng
ive ipti e
on

do Sy 64- -1.
ubl ste bit 79
e m. floa 76
Do tin 93
ubl g 13
e poi 48
nt 62
32
e3
08
to
1.7
97
69
31
34
86
23
2e
30
8

floa Sy 32- ±1.


t ste bit 5
m. floa ×
Sin tin 10
gle g -45

poi to
nt ±3.
4
×
10
38 ,

wit
h
7
digi
ts
of
pre
cisi
on
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-10: Primitives in C#

Ty Pri De Ra
pe mit scr ng
ive ipti e
on

int Sy 32- -2,


ste bit 14
m.I un 7,4
nt3 sig 83,
2 ne 64
d 8
int to
eg 2,1
er 47,
48
3,6
47

lon Sy 64- -9,


g ste bit 22
m.I int 3,3
nt6 eg 72,
4 er 03
6,8
54,
77
5,8
08
to
9,2
23,
37
2,0
36,
85
4,7
75,
80
7

sb Sy 8-b -12
yte ste it 8
m. int to
SB eg 12
yte er 7

sh Sy 16- -32
ort ste bit ,76
m.I int 8
nt1 eg to
6 er 32,
76
7
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 1-10: Primitives in C#

Ty Pri De Ra
pe mit scr ng
ive ipti e
on

stri Sy not Stri


ng ste ap ng
m. plic is
Stri abl an
ng e im
mu
tab
le
vari
abl
e
len
gth
stri
ng.

uin Sy 32- 0
t ste bit to
m. un 4,2
UIn sig 94,
t32 ne 96
d 7,2
int 95
eg
er

ulo Sy 64- 0
ng ste bit to
m. un 18,
UIn sig 44
t64 ne 6,7
d 44,
int 07
eg 3,7
er 09,
55
1,6
15

us Sy 16- 0
hor ste bit to
t m. un 65,
UIn sig 53
t16 ne 5
d
int
eg
er
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Sample C# Program
In deference to Martin Richards, the founder of the BCPL language and author of the first "Hello, World!"
program, I present a "Hello, World!" program. Actually, I offer an enhanced version that displays "Hello,
World" in English, Italian, or Spanish. The program is a console application. For simplicity, no error checking
is performed. C# is case sensitive.

Here is my version of the HelloWorld program:

using System;

namespace HelloNamespace {

class Greetings{
public static void DisplayEnglish() {
Console.WriteLine("Hello, world!");
}
public static void DisplayItalian() {
Console.WriteLine("Ciao, mondo!");
}
public static void DisplaySpanish() {
Console.WriteLine("Hola, imundo!");
}
}

delegate void delGreeting();

class HelloWorld {
static void Main(string [] args) {

int iChoice=int.Parse(args[0]);
delGreeting [] arrayofGreetings={
new delGreeting(Greetings.DisplayEnglish),
new delGreeting(Greetings.DisplayItalian),
new delGreeting(Greetings.DisplaySpanish)};

arrayofGreetings[iChoice-1]();
}
}
}

Csc.exe is the C# compiler. The following csc command compiles the hello.cs source file to create the
executable hello.exe, which is a .NET assembly:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

csc hello.cs

As a .NET assembly, the Hello.exe contains metadata and MISL code but not native binary.

Run the Hello application from the command line. Enter the program name and the language (1 for English, 2
for Italian, or 3 for Spanish). For example, the following command line displays "Ciao, mondo" ("Hello, world"
in Italian).

Hello 2

The source code of the Hello application has the features common to most .NET applications: a using
statement, a namespace, types, access modifiers, methods, and data.

The HelloNamespace namespace contains the Greetings and HelloWorld types. The Greetings class has
three static methods, and each method displays "Hello, World" in a different language. Static methods are
invoked on the type (classname.member), not an instance of that type. The static methods of the Greetings
type are also public and therefore visible inside and outside the class.

Delegates define a type of function pointer. The delGreeting delegate is a container for functions pointers that
point to functions that return void and have no parameters. This is not so coincidentally the function signature
of the methods in the Greetings type.

The entry point of this and any other C# application is the Main method. Command-line parameters are
passed as the args parameter, which is a string array. In the Hello program, the first element of the args
array is a number indicating the language of choice, as inputted by the user. The Hello application converts
that element to an integer. Next, the program defines an array of function pointers, which is initialized with
function pointers to methods of the Greetings class. This statement invokes a function pointer to display the
chosen Hello message:

arrayofGreetings[iChoice-1]()

The variable iChoice is an index into the delegate array. It is decremented to account for the fact that arrays
in C# are zero-based.

The remainder of the chapter discusses the important features of the Hello and any other C# application,
except for types that will be reviewed in the next chapter.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Namespaces
Namespaces provide hierarchical clarity and organization of types and other members. A container of
hundreds of classes, the .NET Framework Class Library (FCL) is an example of effective use of
namespaces. The Framework Class Library would sacrifice clarity if planned as a single namespace with a
flat hierarchy. Instead, the Framework Class Library organizes its members into numerous namespaces.
System, which is the root namespace of the FCL, contains the classes ubiquitous to .NET, such as the
Console class. Types related to data services are grouped in the System.Data namespace. Data services
are further delineated in the System.Data.SqlClient namespace, which contains types specific to Microsoft
SQL. The remaining types are organized similarly in other namespaces.

A namespace identifier must be unique within the namespace declaration space, which contains the current
namespace but not a nested namespace. A nested namespace is considered a member of the containing
namespace. Use the dot punctuator (.) to access members of the namespace.

A namespace at file scope, not nested within another namespace, is considered part of the compilation unit
and included in the global namespace. A compilation unit is a source code file. A program partitioned into
several source files has multiple compilation units—one compilation unit for each source file. Any
namespace, including the global namespace, can span multiple compilation units. For example, all types
defined at file scope are included into a single global namespace that spans separate source files.

The following code has two compilation units and three namespaces. Because of identical identifiers sharing
the same scope, errors occur when the program is compiled.

// file1.cs

public class ClassA {


}

public class ClassB {


}

namespace NamespaceZ {
public class ClassC {
}
}

// file2.cs

public class ClassB {


}

namespace NamespaceY {
public class ClassA {
}
}

namespace NamespaceZ {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class ClassC {


}

public class ClassD {


}
}

Compile the code into a library:

csc /t:library file1.cs file2.cs

In the preceding code, the global namespace has four members. NamespaceY and NamespaceZ are
members. The classes ClassA and ClassB are also members of the global namespaces. The members
span the File1.cs and File2.cs compilation units, which both contribute to the global namespace.

ClassB and ClassC are ambiguous. ClassB is ambiguous because it is defined twice in the global
namespace, once in each compilation unit. ClassC is defined in the NamespaceZ namespace in both
compilation units. Because NamespaceZ is one cohesive namespace, ClassC is also ambiguous.

The relationship between compilation units, the global namespace, and nonglobal namespaces are
illustrated in the Figure 1-3.

Figure 1-3: Global vs. non-global namespaces

The using directive makes a namespace implicit. You can access members of the named namespace
directly without the fully qualified name. Do you refer to members of your family by their fully qualified names
or just their first names? Unless your mother is the queen, you probably refer to everyone directly by simply
using their first names, for the sake of convenience. The using directive means that you can treat members
of a namespace like family members.

The using directive must precede any members in the namespace where it is defined. The following code
defines the namespace member ClassA. The fully qualified name is NamespaceZ.NamespaceY.ClassA.
Imagine having to type that several times in a program!

using System;

namespace NamespaceZ {

namespace NamespaceY {
class ClassA {
public static void FunctionM() {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("FunctionM");
}
}
}
}

namespace Application {
class Starter {
public static void Main() {
NamespaceZ.NamespaceY.ClassA.FunctionM();
}
}
}

The following using directive makes NamespaceZ.NamespaceY implicit. Now you can directly access
ClassA.

namespace Application {
using NamespaceZ.NamespaceY;
class Starter {
public static void Main() {
ClassA.FunctionM();
}
}
}

Ambiguities can occur when separate namespaces with identically named members are made implicit.
When this occurs, the affected members can be assessed only with their fully qualified names.

The using directive can also define an alias for a namespace or type. Aliases are typically created to resolve
ambiguity or as a convenience. The scope of the alias is the declaration space where it is declared. The
alias must be unique within that declaration space. In this source code, an alias is created for the fully
qualified name of ClassA:

namespace Application {
using A=NamespaceZ.NamespaceY.ClassA;
class Starter {
public static void Main() {
A.FunctionM();
}
}
}

In this code, A is a nickname for NamespaceZ.NamespaceY.ClassA and can be used synonymously.

Using directive statements are not cumulative and are evaluated independently.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Main Entry Point


Main is the entry point method for a C# application and a member function of a class or struct (the entry
point method is where the C# application starts executing). There are four valid signatures of Main being
used as the entry point method:

static void Main() {


// main block
}

static int Main() {


// main block
}

static void Main(string [] args ){


// main block
}

static int Main(string [] args ){


//
}

Notice that the entry point method must be static.

A class or struct can contain only one valid entry point method. The accessibility of the Main entry point
method is irrelevant to the invocation of that method. Even a private Main method is reachable as an entry
point method.

Entry point methods can pass command line arguments into an application as a string array. Arrays in .NET
derive from System.Array. You can use the properties and methods of System.Array to examine the
command line arguments, including the Length field to determine the count of arguments. The command
arguments start at element zero of the string array. When no arguments are passed, the arg parameter is
non-null but the array count is zero.

The return of an entry point method is cached internally for interprocess communication. If the application is
part of a system and spawned to complete a specific task, the return could represent a status code or the
result of the task. The default exit code of an application is zero. The exit code of a process is stored in the
Process Environment Block (PEB) and readable through the GetExitCodeProcess API.

What if the entry point is ambiguous?

using System;

namespace Application{
class StarterA{
static void Main() {

}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

class StarterB{
static void Main() {
}
}
}

The preceding code has two valid entry points, which is inherently ambiguous. The main compiler is available
to select between multiple entry points. This command successfully compiles the program:
csc/main:Application.StarterB main.cs.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Local Variables
Local variables are objects declared in a statement block. Local variables can be declared anywhere in the
block, but must be defined before use. Local variables can be either value or reference types. A value type is
allocated storage on the stack, whereas reference types have memory allocated on the managed heap. The
storage for value types is released deterministically at the end of a statement block. Reference types are
allocated with the new keyword and removed nondeterministically by the Garbage Collector, which is a
component of the Common Language Runtime (CLR).

Variables can be declared with or without the assignment operator and they can be declared without being
initialized. That is not a good practice, however. Use the assignment operator to declare and initialize a
variable. Variables can be declared in a single declaration statement individually or by daisy-chaining the
variable names:

int variablea=5, variableb, variablec=10;

The scope and visibility of a local variable is the statement block, where it is declared, and any nested
statement blocks. This is called the variable declaration space, in which local variables must be uniquely
identified.

A variable that is not to be modified at run time should be const. (Const variables must be initialized at
compile time and cannot be changed later at run time.)

In the following code, several local variables are defined. The storage for variablea, variableb, variablec, and
variabled are released at the end of the function block. However, the lifetime of variablee, a local variable, is
managed by the Garbage Collector. Setting variablee to null is a hint to the Garbage Collector that the object
is no longer required, and that it should hasten cleanup:

void Function() {
int variablea=0;
int variableb=1,variablec, variabled=4;
const double PI=3.1415;
UserDefined variablee=new UserDefined();

/ function code

variablee=null;
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Nullable Types
In the previous code, a reference type is set to null. Assigning a null to an object indicates that it is unused.
This is consistent for all reference types. Can you similarly flag an integer as unused? Nulls are not
assignable to primitive value types. (It would cause a compiler error.)

int variablea=null;

Setting an integer to -1 is a possible solution, assuming that this value is outside the set of expected values.
However, this is a proprietary solution; it requires explicit documenting and is not very extensible. A
consistent solution is required for all integers and indeed for all value types.

Nullable types are a consistent solution for determining whether a value object is empty. Declare a nullable
type by adding the ? type modifier in a value type declaration. Here is an example:

double? variable1=null;

The object variable1 is a nullable type and the underlying type is double. A nullable type extends the
interface of the underlying type with the HasValue and Value properties. Both properties are public and
read-only. HasValue is a Boolean property, whereas the type of Value is the same as the underlying type. If
the nullable type is assigned a non-null value, HasValue is true and the Value property is accessible.
Otherwise, HasValue is false, and an exception is raised if the Value property is accessed. The acceptable
range of values for a nullable type includes the null value and the extents of the underlying type.

Set the default value of a nullable type with the null coalescing operator. The operator is ??. The default value
must be the same type as the underlying type. The default value is returned if the nullable type is null—
otherwise empty. This code sets the default value for variablea to zero. Otherwise, variable2 is assigned the
value of variable1:

double variable2=variable1??0;

This code demonstrates nullable types:

static void Main() {


int? variablea=null;
Console.WriteLine(variablea.HasValue); // false
int variableb=variablea??5;
Console.WriteLine(variableb); // 5
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Expressions
Expressions evaluate one or more operators. Most expressions and the operators therein return a value.
Operators have operands: Unary operators have a right-side operand, whereas binary operators have a
left-side and right-side operand. Although expression statements should assign the result of an expression,
expression statements consisting of function invocation, increment, decrement, and new operators are
exempted from this requirement.

With the exception of the assignment operator, operands of an expression are evaluated from left to right.
Expressions can contain multiple operators; operators are evaluated in order of precedence. Use
parentheses to change the precedence or simply clarify the default precedence.

Table 1-11 lists the order of precedence.


Table 1-11: Order of Precedence for Expressions

Precedence Operator

1 array '[ ]', checked , function '()', member operator '.', new, postfix decrement , postfix
increment, typeof, and unchecked operators

2 unary addition '+', casting '()', one complement '~', not '!', prefix decrement, prefix
increment, unary subtraction '-'operators

3 division '/', and modulus '%', multiplication '*' operators

4 binary addition '+' and binary subtraction '-' operators

5 left-shift '<<' and right-shift '>>' operators

6 as, is, less than '<', less than or equal to '<=', greater than '>', greater than or equal to '>='
operators

7 equals '==' and not equal '!=' operators

8 Logical And '&' operator

9 Logical XOR '^' operator

10 Logical Or '|' operator

11 Conditional And '&&' operator

12 Conditional Or '||' operator

13 Conditional '?:' operator

14 Assignment '=', compound '*=, /-=, %=, +=, -=, <<=, >>=, &=, ^=, and |=', and null
coalescing '??' operator
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Selection Statements
A selection statement evaluates an expression to determine what code is executed next. Based on the
expression, a selection statement transfers control to either the next or some other statement.

An if statement evaluates a Boolean expression. If the expression is true, control is transferred to the next
statement_block. If the expression is false, execution is transferred to the first statement after the
statement_block.

Here's an example of an if statement:

if(boolean_expression) {statement_block}

When combined with an else condition, the if statement has true_statement_block and
false_statement_block. The false_statement_block immediately follows the else statement. When the
boolean_expression is true, you are transferred to the true_statement_block. If it is false, control is
transferred to the false_statement_block. If nested, the else statement belongs to the nearest if statement,
and each else statement must have a matching if statement.

Here is the syntax:

if(boolean_expression)
true_statement;
else
false_statement;

An alternative to nested if and else statements is the else if clause, which is particularly useful in evaluating
choices. The else if statement can also be combined with an else statement.

The syntax appears here:

if(boolean_expression 1)
true_statement;
else if(boolean_expression 2)
true_statement 2;
else if(boolean_expression n)
true_statement n;
else
false_statement;

The following code is typical:

static void Main() {


Console.WriteLine("Enter command:");
string menuChoice=(Console.ReadLine()).ToLower();

if(menuChoice=="a")
Console.WriteLine("Doing Task A");
else if(menuChoice=="b")
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("Doing Task B");


else if(menuChoice=="c")
Console.WriteLine("Doing Task C");
else
Console.WriteLine("Bad choice");
}

A switch statement, which is a better solution to the preceding code, jumps to the switch label that matches
a switch expression. The switch expression must resolve to an integral, char, enum, or string type. The
switch label is a constant or literal and must have the same underlying type as the switch expression.

Switch statement:

switch(switch_expression)
{
case switch_label 1:
switch_statement 1;
case case_label n:
switch_statement n;
default:
default_statement;
}

A switch statement has a switch expression that is followed by a switch block, which should contain one or
more case statements. A case statement identifies a switch label. After the switch expression is evaluated,
control is transferred to the matching switch label. A matching label has the same value as the switch
expression. Each switch label must be unique. If no switch label matches the switch expression, control is
transferred to the default label or to the first statement after the switch statement if a default label is not
provided.

Unlike C and C++, cascading between case statements is not allowed—you cannot "crash the party" of
another case statement. A break, goto, return, or throw are some of the ways to preclude falling into the
next case. There is one exception to this rule, however: You can fall through cases that have no statements.

This is an alternative to the if code presented earlier:

static void Main() {


Console.WriteLine("Enter command:");
string resp=(Console.ReadLine()).ToLower();
switch(resp) {
case "a":
Console.WriteLine("Doing Task A");
break;
case "b":
Console.WriteLine("Doing Task B");
break;
case "c":
Console.WriteLine("Doing Task C");
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

break;
default:
Console.WriteLine("Bad choice");
break;
}
}

Any object, value, or reference type that is convertible to an integral, char, enum, or string type is acceptable
as the switch_expression, which is demonstrated in the following code. It must be a one-step conversion to
one of the acceptable types.

class Employee {
public Employee(string f_Emplid) {
m_Emplid=f_Emplid;
}

static public implicit operator string(Employee f_this) {


return f_this.m_Emplid;
}

private string m_Emplid;


}

class Starter {
static void Main() {
Employee newempl=new Employee("1234");
switch(newempl) {
case "1234":
Console.WriteLine("Employee 1234");
return;
case "5678":
Console.WriteLine("Employee 5678");
return;
default:
Console.WriteLine("Invalid employee");
return;
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Iterative Statements
C# has the full repertoire of C-style iterative statements plus the foreach statement. Iterative statements
repeat statement_blocks until a condition has been satisfied.

The for statement is designed for structured iteration when a proper iterator is available. The for statement
contains three clauses. First is the initializer_clause in which the loop iterators are declared. The scope of
an iterator is the for statement and statement_block. Second is the boolean_expression that must evaluate
to a Boolean type. The expression normally compares the iterator to an end value. Third, the
iterator_expression is executed at each iteration and is usually responsible for updating iterator values. Each
clause is optional and delimited with a semicolon. The statement_block is repeated until the
boolean_expression is false.

The statement_block is repeated zero or more times. If the boolean_expression is initially false, the
statement_block is executed zero times.

This is a for statement:

for(initializer_clause;boolean_expression;iterator_expression) {
statement_block }

This is a rather mundane for loop:

static void Main() {


for(int iCounter=0;iCounter<10;++iCounter) {
Console.Write(iCounter);
}
}

Both the initializer_clause and iterator_expression can contain multiple statements delimited by commas.
This allows additional flexibility and complexity than shown previously. Here is an example:

static void Main() {


for(int iBottom=1, iTop=10; iBottom < iTop; ++iBottom, --iTop) {
Console.WriteLine("{0}x{1} {2}", iBottom, iTop, iBottom*iTop);
}
}

The while statement, which is an iterative statement, is more free-form than the for statement. The
statement_block of the while statement is executed while the boolean_expression is true. The
statement_block is executed zero or more times. If the boolean_expression is initially false, the
statement_block is executed zero times.

Typically, the statement_block is responsible for altering an iterator or something else where-upon the
boolean_expression evaluates to false, which ends the loop. Care should be taken to avoid unattended
infinite loops.

This is an example of a while statement:

while(boolean_expression) { statement_block }

This is source code for selecting a choice rewritten with a while statement:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

static void Main() {


string resp;
Console.WriteLine("Enter command ('x' to end):");
while((resp=(Console.ReadLine()).ToLower()) != "x") {
switch(resp) {
case "a":
Console.WriteLine("Doing Task A");
break;
case "b":
Console.WriteLine("Doing Task B");
break;
default:
Console.WriteLine("Bad choice");

break;
}
}
}

A do statement is a loop with the boolean_expression after the statement_block. This is the reverse of the
while statement. The impact is that the statement_block of the do statement is repeated one or more times.
The niche for the do statement is when the statement_block needs to execute once before the
boolean_expression. The iteration of the statement_block continues while the boolean_expression is true.

This is a do statement:

do { statement_block } while(conditional_statement)

Here is sample code of the do statement:

static void Main() {


string resp;
do {
Console.WriteLine("Menu\n\n1 - Task A");
Console.WriteLine("2 - Task B");
Console.WriteLine("E - E(xit)");
resp=(Console.ReadLine()).ToLower();
}
while(resp!="e");
}

The foreach statement is a convenient mechanism for automatically iterating elements of a collection. The
alternative is manually iterating a collection with the requested enumerator object. The foreach statement is
unquestionably simpler. Collections implement the IEnumerable interface.

This is the syntax of the foreach statement:

foreach(type identifier in collection) { statement_block }


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The foreach statement iterates the elements of the collection. As each element is enumerated, the identifier
is assigned the new element, and the statement_block is repeated. The scope of the identifier is the foreach
statement and statement_block. When the collection is fully iterated, the iteration stops, and the
statement_block no longer repeats.

The identifier is a class, struct, or interface. The identifier type should be related to the type of elements
extracted from the collection. In addition, the identifier is read-only. Even using the identifier in a context that
implies change, such as passing the identifier as a ref function parameter, is an error.

The foreach statement confirms that the enumerator or elements of the collection are disposable objects. If
so, the foreach statement calls the Dispose method on the applicable objects. Disposable objects
implement the IDisposable interface.

This code iterates an array of numbers:

static void Main() {


string [] numbers={ "uno", "dos", "tres",
"quatro", "cinco"};
foreach(string number in numbers) {
Console.WriteLine(number);
}
}

The break statement prematurely exits the containing switch or iterative statement and transfers control to
the statement after the statement_block. For switch statements, the break prevents fall through between
switch_labels. For an iterative statement, the break stops the iteration unconditionally and exits the loop.
Control is transferred to the statement following the iterative loop. If the switch or iterative statement_block is
nested, only the immediately statement_block is exited.

The continue statement transfers control to the end of a statement_block where execution continues. The
boolean_expression of the iterative statement then determines whether the iteration continues, and the
statement_block is repeated. This is sample code of the break statement:

static void Main() {


string resp;
while(true) {
Console.WriteLine("Menu\n\n1 - Task A");
Console.WriteLine("2 - Task B");
Console.WriteLine("E - E(xit)");
resp=(Console.ReadLine()).ToLower();
if(resp=="e") {
break;
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Classes
This chapter introduced the fundamental ingredients of any C# program. The next chapter expands upon
classes, which is the most important of those ingredients. It is hard to envision a functional or nontrivial C#
program without at least one class. Classes are the nouns of the C# language, and it is certainly difficult to
write a great story without any nouns. It is doubly difficult to write a C# program without classes.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 2: Types
Overview
Types are the places, persons, and things of an application. As part of the object design, scenarios are often
drafted as a "day in the life" of a problem domain. The scenarios are mined for nouns, which become
potential future classes. Object-oriented programs model real-world problems, in which types represent
identities from your problem domain. An employee in a personnel program, a general ledger entry in an
accounting package, and geometric shapes in a paint application are examples of types. Types include
reference types, value types, and unsafe pointers. The topic of unsafe pointers is included in Chapter 14,
"Memory Management."

A reference type refers to an object created on the managed heap, and the lifetime of the resulting object is
controlled by garbage collection services provided by the Common Language Runtime (CLR). The reference
holds the location of an object created on the managed heap. Reference types derive from System.Object
implicitly and are created with the new keyword. The archetypal reference type is a class. Other reference
types are interfaces, arrays, and delegates.

Value types are lightweight components that are placed on the stack. Value types directly contain their
value. Value types are customarily created statically. For custom initialization, a value type can be
constituted using the new statement. This does not fabricate a value type on the managed heap. It still
resides on the stack. Value types derive from System.ValueType, which is derived from System.Object.
System.ValueType defines a value type by rewriting most of the semantics of System.Object. Primitives
such as int, float, char, and bool are archetypal value types. As a primitive, a string is a hybrid. Strictly
speaking, strings are reference types. However, strings have some of the characteristics of a value type.
Structures and enumerations complete the list of value types.

Classes and structures are the primary focus of this chapter. A class or structure is a blueprint for creating
components of similar behavior and attributes. A class instance is called an object, whereas an instance of a
structure is a value. An Employee class would describe the common attributes and behavior an employee. A
Fraction structure would calculate fractions. Each instance of an Employee or a Fraction shares common
behavior with their siblings but has a distinct state. Within a classification of objects, the GetHashCode
method returns a unique value that distinguishes a specific component from any other sibling.

View classes and structures as independent contractors. They should be isolated and selfsufficient. Types
collaborate through a published interface and hide extraneous details. Classes and structures should be fully
abstracted. This avoids dependencies between components, which leads to error-prone and
harder-to-maintain software.

Enumerations, also described in this chapter, represent a discrete set of constant values. The months of the
year are ideal for enumeration. There are a discrete number of months: 12. Months can logically be assigned
constant values from 1 to 12. Liberal use of enumerations can make code safer and more readable.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Classes
Classes are the irreplaceable ingredient of any .NET assembly. First, all executable code must be contained
in a type, usually a class. Global functions and variables are not permitted in C#, preventing problematic
dependences caused by disparate references to global entities. Second, classes published in the .NET
Framework Class Library provide important services that are integral to any .NET application.

Classes are described in a class declaration. A class declaration consists of a class header and body. The
class header includes attributes, modifiers, the class keyword, the class name, and the base class list. The
class body encapsulates the members of the class, which are the data members and member functions.
Here is the syntax of a class declaration:
 attributes accessibility modifiers class classname : baselist { class body };

Attributes further describe the class. If a class is a noun, attributes are the adjectives. For example, the
Serializable attribute identifies a class that can be serialized to storage. There is an assortment of
predefined attributes. You can also define custom attributes. Attributes are optional, and there are no
defaults. Further details on attributes are contained in Chapter 11, "Metadata and Reflections."

Accessibility is the visibility of the class. Public classes are visible in the current assembly and assemblies
referencing that assembly. Internal classes are visible solely in the containing assembly. The default
accessibility of a class is internal. Nested classes have additional accessibility options, which are described
later in this chapter.

Modifiers refine the declaration of a class. For example, the abstract keyword prevents instances of the
class from being created. Modifiers are optional, and there is no default. Table 2-1 elucidates the modifiers.
Table 2-1: Class Modifier Table

Modifier Description

Abstract Class is abstract; future instances of the class cannot be created.

Sealed Class cannot be inherited and refined in a derived class.

static Class contains only static members.

Unsafe Class can contain unsafe constructs, such as a pointer; requires the unsafe compiler option.

A class can inherit the members of a single base class. Multiple inheritance is not supported in the Common
Language Specification of .NET. However, a class can inherit and implement multiple interfaces. The baselist
lists the class inherited and any interfaces to be implemented. By default, classes inherit the System.Object
type. Inheritance and System.Object are expanded upon in Chapter 3, "Inheritance."

The class body encompasses the members of the class that entail the behavior and state of a class. The
member functions are the behavior, whereas data members are the state. As a design goal, classes should
expose an interface composed of the public functions of the class. The state of the class should be
abstracted and described through the behavior of the class. You manage the state of an object through its
public interface.

Classes do not require members. All members can be inherited. In addition, an empty class can function as
a valuable marker or cookie at run time when ascertaining Run-time Type Information (RTTI).

The semicolon at the end of the class is optional.

XInt is a class and a thin wrapper for an integer:

internal sealed class XInt {


.....public int iField=0;
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The XInt class has internal accessibility and visibility in the current assembly, but is not visible to an
external assembly. The sealed modifier means that the class cannot be refined through inheritance.

The following code uses the new statement to create an instance of a class:

.....public void Func() {


.........XInt obj=new XInt();
.........obj.iField=5;
.....}

Class Members

Classes are composed of members: member functions and data members. Use the dot syntax to access
members. The dot binds an instance member to an object or a static member to a class. In the following
code, Fred.name accesses the name field of the Fred object:

using System;
namespace Donis.CSharpBook{
public class Employee{
public string name;
}
public class Personnel{
static void Main(){
Employee Jim=new Employee();
Fred.name="Wilson, Jim";
}
}
}

Table 2-2 describes the list of potential class members.


Table 2-2:
Type
Members

Me De
mb scr
er ipti
on

Cla Ne
ss ste
es d
cla
ss
es
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-2:
Type
Members

Me De
mb scr
er ipti
on

Co Inv
nst ari
ant abl
s e
dat
a
me
mb
ers

Co Sp
nst eci
ruc aliz
tor ed
me
tho
ds
tha
t
initi
aliz
es
a
co
mp
on
ent
or
cla
ss
for
sta
tic
co
nst
ruc
tor
s
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-2:
Type
Members

Me De
mb scr
er ipti
on

Del Ty
eg pe-
ate saf
e
co
nta
ine
rs
of
on
e
or
mo
re
fun
cti
on
poi
nte
rs

De Sp
str eci
uct aliz
or ed
me
tho
d
tha
t
per
for
ms
cle
an
up
of
obj
ect
res
our
ce
s
up
on
gar
ba
ge
coll
ect
ion
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-2:
Type
Members

Me De
mb scr
er ipti
on

Ev Cal
ent lba
s ck
s
to
me
tho
ds
pro
vid
ed
by
a
su
bs
cri
ber

Fie Dat
lds a
me
mb
ers

Ind Sp
ex eci
er aliz
ed
pro
per
ty
tha
t
ind
ex
es
the
cur
ren
t
obj
ect

Int Ne
erf ste
ac d
es int
erf
ac
e
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-2:
Type
Members

Me De
mb scr
er ipti
on

Me Re
tho us
d abl
e
co
de
se
qu
en
ce

Op Op
era era
tor tor
s me
mb
er
fun
cti
on
s
tha
t
ove
rrid
e
im
plic
it
op
era
tor
be
hav
ior
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-2:
Type
Members

Me De
mb scr
er ipti
on

Pro Ge
per t
tie an
s d
set
fun
cti
on
s
pre
se
nte
d
as
a
fiel
d

Str Ne
uct ste
ure d
s str
uct
ure
wit
hin
a
cla
ss

When a member is declared, attributes can be applied and accessibility defined. Members are further
described with attributes. Accessibility sets the visibility as class member.

Member Accessibility
Members defined in a class are scoped to that class. However, the visibility of the member is defined by
accessibility keywords. The most common accessibility is public and private. Public members are visible
inside and outside of the class. The visibility of private members is restricted to the containing class. Private
is the default accessibility of a class member. Table 2-3 details the accessibility keywords:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-3:
Accessibility

Ac De
ce scr
ssi ipti
bili on
ty

int Vis
ern ible
al in
co
nta
inin
g
as
se
mb
ly

int Vis
ern ible
al in
pro co
tec nta
ted inin
g
as
se
mb
ly
or
de
sc
en
da
nts
of
the
cur
ren
t
cla
ss

priv Vis
ate ible
insi
de
cur
ren
t
cla
ss
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-3:
Accessibility

Ac De
ce scr
ssi ipti
bili on
ty

pro Vis
tec ible
ted insi
de
cur
ren
t
cla
ss
an
d
an
y
de
sc
en
da
nts

pu Vis
bli ible
c in
co
nta
inin
g
as
se
mb
ly
an
d
as
se
mb
lies
ref
ere
nci
ng
tha
t
as
se
mb
ly

Member Attributes
Attributes are usually the first element of the member declaration and further describe a member and extend
the metadata. The Obsolete attribute exemplifies an attribute and marks a function as deprecated. Attributes
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

are optional. By default, a member has no attributes.

Member Modifiers
Modifiers refine the definition of the applicable member. Modifiers are optional and there are no defaults.
Some modifiers are reserved for classification of members. For example, the override modifier is applicable
to member functions, not data members. Table 2-4 lists the available modifiers.
Table 2-4:
Modifiers

Mo De
difi scr
er ipti
on

ab A
str me
act mb
er
fun
cti
on
ha
s
no
im
ple
me
nta
tio
n
an
d
is
de
scr
ibe
d
thr
ou
gh
inh
erit
an
ce.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-4:
Modifiers

Mo De
difi scr
er ipti
on

Ext Im
ern ple
me
nte
d
in
a
for
eig
n
dy
na
mi
c-li
nk
libr
ary
(DL
L).

Ne Hid
w es
a
si
mil
ar
me
mb
er
or
me
mb
ers
in
the
ba
se
cla
ss.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-4:
Modifiers

Mo De
difi scr
er ipti
on

Ov Indi
erri cat
de es
tha
ta
fun
cti
on
in
a
der
ive
d
cla
ss
ove
rrid
es
a
virt
ual
me
tho
d
in
the
ba
se
cla
ss.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-4:
Modifiers

Mo De
difi scr
er ipti
on

Re Re
ad ad-
onl onl
y y
fiel
ds
are
initi
aliz
ed
at
de
cla
rati
on
or
in
a
co
nst
ruc
tor.

Se Th
ale e
d me
mb
er
fun
cti
on
ca
nn
ot
be
furt
her
refi
ne
d
thr
ou
gh
inh
erit
an
ce.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-4:
Modifiers

Mo De
difi scr
er ipti
on

Sta Me
tic mb
er
bel
on
gs
to
a
cla
ss
an
d
not
an
ins
tan
ce.

Virt Virt
ual ual
fun
cti
on
s
are
ove
rrid
abl
e
in
a
der
ive
d
cla
ss.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-4:
Modifiers

Mo De
difi scr
er ipti
on

Vol Vol
atil atil
e e
fiel
ds
are
mo
difi
abl
e
by
the
env
iro
nm
ent
,a
se
par
ate
thr
ea
d,
or
har
dw
are
.

Instance and Static Members


Members belong either to an instance of a class or to the class itself. Members bound to a class are
considered static. Except for constants, class members default to instance members and are bound to an
object via the this object. Constant members are implicitly static. Static members are classwise and have no
implied this context. Not all members can be static or instance members; destructors and operator member
functions are representative of this. Destructors cannot be static, whereas operator member functions cannot
be instance members.

Instance members are qualified by the object name. Here is the syntax of a fully qualified instance member:
 objectname.instancemember

Static members are prefixed with this class name:


 classname.staticmember

The lifetime of static members is closely linked to the lifetime of the application. Instance members are
inexorably linked to an instance and are accessible from the point of instantiation. Access to instance
members ceases when the instance variable is removed. Therefore, the lifetime of an instance member is a
subset of the lifetime of an application. Static members are essentially always available, whereas instance
members are not. Static members are similar to global functions and variables but have the benefit of
encapsulation. Static members can be private.

Your design analysis should determine which members are instance versus static members. For example, in
a personnel application for small businesses, there is an Employee class. The employee number is an
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

instance member of the class. Each employee is assigned a unique identifier. However, the company name
member is static because all employees work for the same company. The company name does not belong
to a single employee, but to the classification.

Static class A static class is a class that contains static members and no instance members. Because
static classes have no instance data, a static class cannot be instantiated. This is a static class:

public static class ZClass {


public static void MethodA() {}
public static void MethodB() {}
}

this Object
The this reference refers to the current object. Instance members functions are passed a this reference as
the first and hidden parameter of the function. In an instance function, the this reference is automatically
applied to other instance members. This assures that within an instance member function, you implicitly
refer to members of the same object. In this code, GetEmployeeInfo is an instance member function referring
to other instance members (the this reference is implied):

public void GetEmployeeInfo(){


PrintEmployeeName();
PrintEmployeeAddress();
PrintEmployeeId();
}

Here is the same code, except that the this pointer is explicit (the behavior of the function is the same):

public void GetEmployeeInfo(){


this.PrintEmployeeName();
this.PrintEmployeeAddress();
this.PrintEmployeeId();
}

In the preceding code, the this reference was not required. The this reference is sometimes required as a
function return or parameter. In addition, the this reference can improve code readability and provide
IntelliSense for class members when editing the code in Microsoft Visual Studio.

Static member functions are not passed a this reference as a hidden parameter. For this reason, a static
member cannot directly access nonstatic members of the class. For example, you cannot call an instance
method from a static member function. Static members are essentially limited to accessing other static
members. Instance members have access to both instance and static members of the class.

The this reference is a read-only reference. As part of error handling, setting a this reference to null would
sometimes be beneficial. Alas, it is not allowed.

Data and Function Members


Members are broadly grouped into data and function members. This chapter reviews constants, fields, and
nested types, which are data members. Methods, constructors, destructors, and properties are member
functions (and are covered in this chapter). The remaining members, such as events and delegates, are
discussed in Chapter 8, "Delegates and Events."

Data members are typically private to enforce encapsulation and the principles of data hiding and
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

abstraction. Abstraction abstracts the details of a class and restricts collaboration to the public interface.
The developer responsible for the class obtains implementation independence and has the freedom to modify
the implementation when required as long as the interface is unchanged. The interface is immutable—like a
contract between the class and any client. As a best practice, data members should be private and
described fully through the public interface. The class interface consists of the public member functions. Do
not make every member function public; internal functionality should remain private.

Except for constructors and destructors, members should not have the same name as the containing class.
As a policy, class names should differ from the surrounding namespace.

Constants
Constants are data members. They are initialized at compile time using a constant expression and cannot
be modified at run time. Constants have a type designation and must be used within the context of that type.
This makes a constant type-safe. Constants are usually a primitive type, such as integer or double. A
constant can be a more complex type. However, classes and structures are initialized at run time, which is
prohibited with a constant. Therefore, constant class and structures must be assigned null, which limits their
usefulness. Following is the syntax of a constant member:

const syntax:
 accessibility modifier const constname=initialization;

The only modifier available is new, which hides inherited members of the same name. Constants are tacitly
static. Do not use the static keyword explicitly. The initialization is accomplished with a constant
expression. You can declare and initialize several constants simultaneously.

The following code presents various permutations of how to declare and initialize a constant data member:

public class ZClass {


public const int fielda=5, fieldb=15;
public const int fieldc=fieldd+10; // Error

public static int fieldd=15;


}

The assignment to fieldc causes a compile error. The fieldd member is a nonconstant member variable and
is evaluated at run time. Thus, fieldd cannot be used in a constant expression, as shown in the preceding
code. Constant expressions are limited to literals and constant types.

Fields
As a data member, fields are the most prevalent. Instance fields hold state information for a specific object.
The state information is copied into the managed memory created for the object. Static fields are data owned
by the class. A single instance of static data is created for the class. It is not replicated for each instance of
the class. Fields can be reference or value types. Here is the syntax for declaring a field:
 accessibility modifier type fieldname=initialization;

Fields support the full assortment of accessibility. Valid modifiers for a field include new, static, read-only,
and volatile. Initialization is optional but recommended. Uninitialized fields are assigned a default value of
zero or null. Alternatively, fields can be initialized in constructor functions. Like constants, fields of the same
type are declarable individually or in aggregate in the initialization list.

Initialization is performed in the textual order in which the fields appear in the class, which is top-down. This
process is demonstrated in the following code:

using System;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

namespace Donis.CSharpBook{
internal class ZClass {
public int iField1=FuncA();
public int iField2=FuncC();
public int iField3=FuncB();

public static int FuncA() {


Console.WriteLine("ZClass.FuncA");
return 0;
}

public static int FuncB() {


Console.WriteLine("ZClass.FuncB");
return 1;
}

public static int FuncC() {


Console.WriteLine("ZClass.FuncC");
return 2;
}
}

public class Starter{


public static void Main(){
ZClass obj=new ZClass();
}
}
}

Running this code confirms that FuncA, FuncC, and FuncB are called in sequence the textual order of the
initialization. Avoid writing code dependent on the initialization sequence—writing code that way makes the
program harder to maintain without clear documentation.

Private fields exposed through accessor functions, a get and set method, are read-write. Eliminate the get or
set method to make the field read-only or write-only, respectively. However, this relies on programmer
discipline. The read-only keyword is safer.

A read-only field is enforced by the run time. These fields are different from constants. Although constants
can be initialized only at compile time, read-only fields can also be initialized in a constructor. Alternatively,
read-only fields can be initialized with nonconstant expressions. These are subtle but important nuances and
provide considerable more flexibility to a read-only field. In addition, read-only fields can be instance or static
members, whereas constant are only static.

This code highlights read-only fields:

public class ZClass {


public ZClass() { // constructor
fieldc=10;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static int fielda=5;


public readonly int fieldb=fielda+10;
public int fieldc;
};

Volatile Fields
Because of the intricacy of program execution, writes and reads to a field might not be immediate. This
latency can cause problems, particularly in a multithreaded application. Reads and writes to volatile fields
are essentially immediate. Volatile makes automatic what locks do programmatically. Locks are explained
in Chapter 9, "Threading."

Member Functions

Member functions contain the behavior of the class. Methods, properties, and indexers are the member
functions. Methods are straightforward functions that accept parameters as input and return the result of an
operation. Properties are accessor methods, a get and set method, masked as a field. An indexer is a
specialized property. Indexers apply get and set methods to the this reference, which refers to the current
object. The discussion of indexers is deferred to Chapter 6, "Arrays and Collections."

Function Code
Functions encapsulate a sequence of code and define the behavior of the class. A function is not necessarily
executed in sequential order and sometimes contains iterative and conditional transfer control statements.
Return statements provide an orderly exit to a function. Void functions can simply fall through the end of the
function. The compiler extrapolates the code paths of a function and uncovers any unreachable code, which
is subsequently flagged by the compiler. All paths must conclude with an orderly exit. The following code
includes both unreachable code and a code path without an orderly exit:

public static int Main(){


if(true) {
Console.WriteLine("true");
}

else {
Console.WriteLine("false");
}
}

The if statement is always true. Therefore, the else code is unreachable. Main returns int. However, the
method has no return. For these reasons, the application generates the following errors when compiled:

unreachable.cs(10,17): warning CS0162: Unreachable code detected


unreachable.cs(5,27): error CS0161: ' Donis.CSharpBook.Starter.Main()': not
all code paths
return a value

Keep functions relatively short. Extended functions are modestly harder to debug and test. A class
comprised of several functions is preferable to class of a few convoluted functions. Remoted components are
the exception: A narrower interface is preferred to minimize client calls and optimize network traffic.
Comparatively, local invocations are relatively quick and efficient.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Methods own a code sequence, local variables, and parameters. The local variables and parameters
represent the private state of the method.

Local Variables
Local variables and parameters represent the private state of the function. Local variables are reference or
value types. Declare a local variable anywhere in a method. However, a local variable must be defined before
use. Optionally, initialize local variables at declaration. There are competing philosophies as to when to
declare local variables: Some developers prefer to declare local variables at the beginning of a method or
block, where they are readily identifiable; other developers like to declare and initialize local variables
immediately prior to use. They feel that local variables are more maintainable when situated near the affected
code. Local variables are not assigned a default value prior to initialization. For this reason, using an
unassigned local variable in an expression causes a compile error. This is the syntax of a local variable:
 modifier type variablename=initialization;

The const modifier is the only modifier that is applicable. Variables that are const must be initialized at
compile time.

The scope of a local variable or function parameter is the entire function. Therefore, local variables and
function parameters must have unique names. Local variables of the same type can be declared individually
or in aggregate.

Scope Local variables are declared at the top level or in a nested block within the method. Although the
scope of a local variable is the entire function, the visibility of a local variable starts where the local variable is
declared. Visibility ends when the block that the local variable is declared is exited. Local variables are
visible in descendant blocks, but not ascendant blocks. Because local variables maintain scope throughout
a function, names of local variable cannot be reused—even in a nested block. Figure 2-1 illustrates the
relationship between scope and visibility of local variables.

Figure 2-1: Figure diagramming the scope and visibility of a local variable

Local variables of a value type are removed from the stack when a function is exited. Local references are
also removed from the stack at that time, whereas the objects they referred to become candidates for
garbage collection. This assumes that no other references to the object exist at that time. If other
outstanding references exist, the object associated with the reference remains uncollectible. When a
reference is no longer needed, assign null to the reference. This is a hint to the garbage collector that the
related object is no longer needed.

Local variables are private to the current function. Functions cannot access private data of another function.
Identically named local variables in different functions are distinct and separate entities, which are stored at
different memory addresses. To share data between functions, declare a field.

Methods
Methods are the most common function member. Methods accept parameters as input, perform an
operation, and return the result of the operation. Both parameters and the return result are optional. Methods
are described through the method header, and implemented in the method body. Here is the syntax of a
method:

Method syntax:
 attributes accessibility modifiers returntype methodname(parameter list) { method body };
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Any attribute that targets a method can prefix the method. The accessibility of methods included in the class
interface is public. Methods not included in the interface are typically protected or private. Methods can be
assigned the sealed, abstract, new, and other modifiers, as explained in Chapter 3. The return is the result of
the method. Methods that return nothing stipulate a void returntype. The parameter list, which consists of
zero or more parameters, is the input of the method. The method body contains the statements of the
method.

Method Return Execution of a function starts at the beginning and ends at a return. The return keyword
provides the result of function or an error code. A value or reference type can be returned from a method as
defined by the return type. Functions can contain multiple returns, each on a separate code path. More than
one return along a single code path results in unreachable code, which causes compiler warnings.

Functions with a void return type can be exited explicitly or implicitly. An empty return statement explicitly
exits a function of a void return type. For an implicit exit, execution is allowed to exit the function without a
return statement. At the end of the function block, the function simply exits. Implicit returns are reserved for
functions that return void. A function can have multiple explicit returns but only one implicit return. The end of
a function must be reached for an implicit return, whereas an explicit return can exit the function
prematurely. In the following code, Main has both an explicit and implicit exit:

static void Main(string [] arg){


if(arg.Length>0) {
// do something
return;
}

// implicit return
}

A function that returns void cannot be used in an assignment. This type of method evaluates to nothing and
is thereby not assignable. This prevents a function that returns void from being used as a left- or right-value of
an assignment. Other functions are usable in assignments and more generally in expressions. A function
evaluates to the return value. When a reference type is returned, a function is available as a left- or right-value
of an assignment. Functions that return a value type are restricted to right-values of an assignment. The
following code demonstrates the use of methods in expressions:

public class ZClass {


public int MethodA() {
return 5;
}

public void MethodB() {


return;
}

public int MethodC(){


int value1=10;
value1=5+MethodA()+value1; // Valid
MethodB(); // Valid
value1=MethodB(); // Invalid
return value1;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

At the calling site, the return of a function is temporarily copied to the stack. The return is discarded after
that statement. To preserve the return, assign the method return to something. Returns are copy by value.
When returning a value type, a copy of the result is returned. For reference types, a copy of the reference is
returned. This creates an alias to an object in the calling function. Look at the following code:

using System;

namespace Donis.CSharpBook{

public class XInt {


public int iField=0;
}

public class Starter{

public static XInt MethodA() {


XInt inner=new XInt();
inner.iField=5;
return inner;
}

public static void Main(){


XInt outer=MethodA();
Console.WriteLine(outer.iField);
}
}
}

In the preceding code, MethodA creates an instance of XInt, which is subsequently returned from the
method. The scope of the reference called inner, which is a local variable, is MethodA. After the return, outer
is an alias and refers to the inner object, which prevents the object from becoming a candidate for garbage
collection, even thought the inner reference is no longer valid.

A method returns a single item. What if you want to return multiple values? The solution is to return a
structure containing a data member for each value. Structures are lightweight and appropriate for copying by
value on the stack.

Function parameters Functions have zero or more parameters, where an empty function call operator
indicates zero parameters. Parameter lists can be fixed or variable length. Use the param keyword to
construct a variable length parameter list, which is discussed in Chapter 6. Parameters default to pass by
value. When the parameter is a value type, changes to the parameter are discarded when the method is
exited and the value is removed from the stack. In the following code, changes made in the function are
discarded when the function returns:

using System;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

namespace Donis.CSharpBook{
public class Starter{

public static void MethodA(int parameter) {


parameter=parameter+5;
} // change discarded

public static void Main(){


int local=2;
MethodA(local);
Console.WriteLine(local); // 2 outputted
}
}
}

As a parameter, reference types are also passed by value. A copy of the reference, which is the location of
the object, is passed by value. Therefore, the function now has an alias to the actual object, which can be
used to change the object. Those changes will persist when the function exits.

This code revises the preceding code. An integer wrapper class is passed as a parameter instead of an
integer value. Changes made to the object in MethodA are not discarded later.

using System;

namespace Donis.CSharpBook{

public class XInt {


public int iField=2;
}

public class Starter{

public static void MethodA(XInt alias) {


alias.iField+=5;
}

public static void Main(){


XInt obj=new XInt();
MethodA(obj);
Console.WriteLine(obj.iField); // 7
}
}
}

Pass a parameter by reference using the ref modifier. The location of the parameter is passed into the
function. The ref attribute must be applied to the parameter in the function signature and at the call site. The
function now possesses the location of the actual parameter and can change the parameter directly. The
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

following code has been updated to include the ref modifier. Unlike the first revision of this code, changes
made in MethodA are not discarded.

using System;

namespace Donis.CSharpBook{
public class Starter{

public static void MethodA(ref int parameter) {


parameter=parameter+5;
}

public static void Main(){


int var=2;
MethodA(ref var);
Console.WriteLine(var); // 7
}
}
}

What happens when a reference type is passed by reference? The function receives the location of the
reference. Because a reference contains a location to an object, the location of the location is passed into
the function. In the following code, a reference type is passed by value, which creates an alias. Because the
reference is passed by value, changes to the alias are discarded when the function exits.

using System;

namespace Donis.CSharpBook{

public class XInt {


public int iField=2;
}

public class Starter{

public static void MethodA(XInt alias) {


XInt inner=new XInt();
inner.iField=5;
alias=inner;
} // reference change lost

public static void Main(){


XInt obj=new XInt();
MethodA(obj);
Console.WriteLine(obj.iField); // 2
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
}

Next, the code is slightly modified to include the ref attribute. The assignment in MethodA is not discarded
when the method exits. Therefore, obj is updated to reference the object created in the method.

using System;

namespace Donis.CSharpBook{

public class XInt {


public int iField=2;
}

public class Starter{

public static void MethodA(ref XInt alias) {


XInt inner=new XInt();
inner.iField=5;
alias=inner;
}

public static void Main(){


XInt obj=new XInt();
MethodA(ref obj);
Console.WriteLine(obj.iField); // 5
}
}
}

Local variables must be initialized before use. The following code is in error. The obj reference is unassigned
but initialized in the method. However, the compiler is unaware of this and presents an error for using an
unassigned variable. The out parameter is a hint to the compiler that the parameter is being set in the
function, which prevents the compiler error. The out parameter is not required to be initialized before the
method call. These parameters are often used to return multiple values from a function.

using System;

namespace Donis.CSharpBook{

public class XInt {


public int iField=5;
}

public class Starter{


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static void MethodA(ref XInt alias) {


XInt inner=new XInt();
alias=inner;
}

public static void Main(){


XInt obj;
MethodA(ref obj); // Error
}
}
}

In the following code, the parameter modifier is changed to out. The program compiles and runs successfully
when the attribute is changed to out:

using System;

namespace Donis.CSharpBook{

class XInt {

public int iField=5;


}

class Starter{

public static void MethodA(out XInt alias) {


XInt inner=new XInt();
alias=inner;
}

public static void Main(){


XInt obj;
MethodA(out obj);
Console.WriteLine(obj.iField); // 5
}
}
}

Function Overloading
Function overloading permits multiple implementations of the same function in a class, which promotes a
consistent interface for related behavior. The SetName method would be overloaded in the Employee class to
accept variations of an employee name. Overloaded methods share the same name but have unique
signatures. Parameter attributes, such as out, are considered part of the signature. (The signature is the
function header minus the return type.) Because they are excluded from the signature, functions cannot be
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

overloaded on the basis of a different return type. The number of parameters or the type of parameters must
be different. With the exception of constructors, you cannot overload a function based on whether a member
is a static or instance member.

The process of selecting a function from a set of overloaded methods is called function resolution, which
occurs at the call site. The closest match to a specific function is called as determined by the number of
parameters and the types of parameters given at function invocation. Sometimes a function call matches
more than one function in the overloaded set. When function resolution returns two or more methods, the call
is considered ambiguous, and an error occurs. Conversely, if no method is returned, an error is also
manifested.

This sample code overloads the SetName method:

using System;

namespace Donis.CSharpBook{

public class Employee {

public string name;

public void SetName(string last) {


name=last;
}

public void SetName(string first, string last) {


name=first+" "+last;
}

public void SetName(string saluation, string first, string last) {


name=saluation+" "+first+" "+last;
}
}

public class Personnel {


public static void Main(){
Employee obj=new Employee();
obj.SetName("Bob", "Jones");

}
}
}

Functions with variable-length parameter lists can be included in the set of overloaded functions. The function
is first evaluated with a fixed-length parameter list. If function resolution does not yield a match, the function
is evaluated with variable-length parameters.

Constructors
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

A constructor is a specialized function for initializing the state of an object. Constructors have the same
name of the class. The main purpose of a constructor is to initialize the fields and guarantee that object is in
a known state for the lifetime of the object. Constructors are invoked with the new operator. Here is the
syntax of a constructor:

Constructor syntax:
 accessibility modifier typename(parameterlist)

The accessibility of a constructor determines where new instances of the reference type can be created. For
example, a public constructor allows an object to be created in the current assembly and a referencing
assembly. A private constructor prevents an instance from being created outside the class. extern is the only
modifier for constructors.

The parameter list of constructors has zero or more parameters.

This is the constructor for the Employee class:

using System;

namespace Donis.CSharpBook{

public class Employee {

public Employee(params string []_name) {


switch(_name.Length) {

case 1:
name=_name[0];
break;
case 2:
name=_name[0]+" "+_name[1];
break;
default:
// Error handler
break;
}

public void GetName() {


Console.WriteLine(name);
}

private string name="";


}

public class Personnel{


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static void Main(){


Employee bob=new Employee("Bob", "Wilson");
bob.GetName();
}
}
}

Classes with no constructors are given a default constructor, which is a parameterless constructor. Default
constructors assign default values to fields. An empty new statement invokes a default constructor. You can
replace a default constructor with a custom parameterless constructor. The following new statement calls
the default constructor of a class:

Employee empl=new Employee();

Constructors can be overloaded. The function resolution of overloaded constructors is determined by the
parameters of the new statement. This Employee class has overloaded constructors:

using System;

namespace Donis.CSharpBook{

public class Employee {

public Employee(string _name) {


name=_name;
}

public Employee(string _first, string _last) {


name=_first+" "+_last;
}

private string name="";


}

public class Personnel {


public static void Main(){
Employee bob=new Employee("Jim", "Wilson"); // 2 arg c'tor
}
}
}

In the preceding code, this would cause a compile error:

Employee jim=new Employee();

This is the error message:


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

overloading.cs(20,26): error CS1501: No overload for method 'Employee' takes


'0' arguments

Why? Although the statement is syntactically correct, the Employee class has lost the default constructor.
Adding a custom constructor to a class removes the default constructor. If desired, also add a custom
parameterless constructor to preserve that behavior.

A constructor can call another constructor using the this reference, which is useful for reducing redundant
code. A constructor cannot call another constructor in the method body. Instead, constructors call other
constructors using the colon syntax, which is affixed to the constructor header. This syntax can be used
only with constructors and not available with normal member functions. In this code, all constructors
delegate to the one argument constructor:

class Employee {

public Employee()
: this(""){
}

public Employee(string _name) {


name=_name;
}

public Employee(string _first, string _last)


: this(_first+" "+_last){
}

public void GetName() {


Console.WriteLine(name);
}

private string name="";


}

Constructors can also be static. Create a static constructor to initialize static fields. The static constructor is
invoked before the class is accessed in any manner. There are limitations to static constructors, as follows:
 Static constructors cannot be called explicitly.
 Accessibility defaults to static, which cannot be set explicitly.
 Static constructors are parameterless.
 Static constructors cannot be overloaded.
 Static constructors are not inheritable.
 The return type cannot set explicitly. Constructors always return void.

As mentioned, static constructors are called before a static member or an instance of the classes is
accessed. Static constructors are not called explicitly with the new statement. In the following code, ZClass
has a static constructor. The static constructor is stubbed to output a message. In Main, the time is
displayed, execution is paused for about five seconds, and then the ZClass is accessed. ZClass.GetField is
called to access the class and trigger the static constructor. The static constructor is called immediately
before the access, which displays the time. It is about five seconds later.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System;
using System.Threading;

namespace Donis.CSharpBook{

public class ZClass{

static private int fielda;


static ZClass() {
Console.WriteLine(DateTime.Now.ToLongTimeString());
fielda=42;
}

static public void GetField() {


Console.WriteLine(fielda);
}
}

public class Starter{


public static void Main(){
Console.WriteLine(DateTime.Now.ToLongTimeString());
Thread.Sleep(5000);
ZClass.GetField();
}
}
}

Singleton Singletons provide an excellent example of private and static constructors. A singleton is an
object that appears once in the problem domain. Singletons are limited to one instance, but that instance is
required. This requirement is enforced in the implementation of the singleton. A complete explanation of the
singleton pattern is found at http://www.microsoft.com/patterns.

The singleton presented in this chapter has two constructors. The private constructor means that an
instance cannot be created outside the class. That would require calling the constructor publicly. However,
an instance can be created inside the class. The single instance of the class is exposed as a static
member, which is initialized in the static constructor. The instance members of the class are accessible
through the static instance. Because the static constructor is called automatically, one instance—the
singleton—always exists.

A chess game is played with a single board—no more or less. This is the singleton for a chess board:

using System;

namespace Donis.CSharpBook{

public class Chessboard {


private Chessboard() {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

static Chessboard() {
board=new Chessboard();
board.start=DateTime.Now.ToShortTimeString();
}

public static Chessboard board=null;


public string player1;
public string player2;
public string start;
}

public class Game{


public static void Main(){
Chessboard game=Chessboard.board;
game.player1="Sally";
game.player2="Bob";
Console.WriteLine("{0} played {1} at {2}",
game.player1, game.player2,
game.start);
}
}
}

In Main, game is an alias for the ChessBoard.board singleton. The local variable is not another instance of
Chessboard. The alias is simply a convenience. I preferred game.player1 to Chess-Board.board.player1.

Destructors
An application can clean up unmanaged resources of an object in the destructor method. Destructors are not
directly callable and called by the run time prior to garbage collection removing the object from the managed
heap. Garbage collection is nondeterministic. A destructor is invoked at an undetermined moment in the
future. Like a constructor, the destructor has the same as the class, except a destructor is prefixed with a
tilde (~). The destructor is called by the Finalize method, which is inherited from System.Object. In C#, the
Finalize method cannot be used directly. You must use a destructor for the cleanup of object resources. For
deterministic garbage collection, inherit the IDisposable interface and implement IDisposable.Dispose. Call
dispose to relinquish managed or unmanaged resources associated with the object. Implementing a
disposable pattern is one of the topics found in Chapter 16.

Destructors differ from other methods in the following ways:


 Destructors cannot be overloaded.
 Destructors are parameterless.
 Destructors are not inherited.
 Accessibility cannot be applied to destructors.
 Extern is the sole destructor modifier.
 The return type cannot be set explicitly. Destructors return void.

Here is the syntax of a destructor.

Destructor syntax:
 modifier ~typename()
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Destructors have performance and efficiency implications. Understand the ramifications of destructors before
inserting a destructor in a class. These topics are also covered in Chapter 16.

The WriteToFile class is a wrapper for a StreamWriter object. The constructor initializes the internal object.
The Dispose method closes the file resource. The destructor delegates to the Dispose method. The Main
method tests the class.

using System;
using System.IO;

namespace Donis.CSharpBook{

public class WriteToFile: IDisposable {

public WriteToFile(string _file, string _text) {


file=new StreamWriter(_file, true);
text=_text;
}

public void WriteText() {


file.WriteLine(text);
}

public void Dispose() {


file.Close();
}

~WriteToFile() {
Dispose();
}

private StreamWriter file;


private string text;
}

public class Writer{


public static void Main(){
WriteToFile sample=new WriteToFile("sample.txt", "My text file");
sample.WriteText();
sample.Dispose();
}
}
}

Properties
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Properties are get and set methods exposed as properties. Public fields do not adhere to encapsulation.
Private fields are good policy where the fields are exposed through accessor methods. A property combines
the convenience of a public field and the safety of access methods. For clients of the public interface of a
class, properties are indistinguishable from fields. The client appears to have direct access to the state of
the class or object. There several benefits of properties:
 Properties are safer than public fields. Use the set method to validate the data.
 Properties can be computed, which adds flexibility. Fields represent a data store and never a
calculation.
 Lazy initialization can be used with properties. Some data is expensive to obtain. A large dataset
is an ideal example. Deferring that cost until necessary is a benefit.
 Write- and read-only properties are supported. Public fields are fully accessible.
 Properties are valid members of an interface. As part of the interface contract, a class can be
required to publish a property. Interfaces do not include fields.

A property is a get and set method. Neither method is called directly. Depending on the context of the
property, the correct method is called implicitly. As a left-value of an assignment, the set method of the
property is called. When used as a right-value, the get method of the property is called. When a property is
the target of an assignment, the set method of the property is invoked. The get method is called if a property
is used within an expression. Here is the syntax of a property:

Property syntax:
 accessibility modifier type propertyname { attributes get {getbody} attributes set {setbody} }

The accessibility and any modifier included in the property header apply to both the get and set method.
However, the set or get method can override the defaults of the property. Type is the underlying type of the
property. Neither the get nor set method has a return type or parameter list. Both are inferred. The get
method returns the property type and has no parameters. The set method returns void and has a single
parameter, which is the same type of the property. In the set method, the value keyword represents the
implied parameter.

In this code, the Person class has an age property:

using System;

namespace Donis.CSharpBook{

public class Person {


private int prop_age;
public int age {
set {
// perform validation
prop_age=value;
}
get {
return prop_age;
}
}
}
class People{

public static void Main(){


Person bob=new Person();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

bob.age=30; // Calls set method


Console.WriteLine(bob.age); // Call gets method
}
}
}

Properties have no inherent data storage. If desired, the data storage must be declared in the class.
Computed properties might not require data storage. As a guideline, the property is public, whereas the data
store is private. There is considerable flexibility available. The data store of a property could consist of
several private fields. Conversely, multiple properties can share the same data store. This is demonstrated in
the following code, where the fullname, firstname, and lastname property share the prop_name data store:

using System;

namespace Donis.CSharpBook{

public class Employee {

private string prop_name;


public string name {
get {
return prop_name;
}
set {
prop_name=value;
}
}

public string first {


get {
return (prop_name.Split(' '))[0];
}
set {
string lastname=name.Split(' ')[1];
prop_name=value+" "+lastname;
}
}
public string last {
get {
return (prop_name.Split(' '))[1];
}
set {
string firstname=name.Split(' ')[0];
prop_name=firstname+" "+value;
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

public class Personnel{


public static void Main(){
Employee bob=new Employee();
bob.name="Lisa Miller";
bob.first="Frank";
Console.WriteLine(bob.name); // Jane Wilson
Console.WriteLine(bob.last); // Wilson
}
}
}

Read-only and write-only properties Read-only properties offer only the get method and omit the set
method. Birth date is an ideal read-only property. Conversely, write-only properties have a set only, which is
common with a password property:

public class SensitiveForm{


private string prop_password;
public string password {
set {
prop_password=value;
}
}
}

Error handling Validating the state of an object is important to avoid the "garbage-in/ garbage out"
syndrome. An object or class is only as useful as the quality of the data it contains. Validation can be
performed in the set method of a property. What is the appropriate action if the validation fails? You cannot
return an error code from a set method. There are two options. First (and preferably), raise an application
exception. Second, if the property type is a reference or nullable type, set the property to null. For the person
class, an age greater than 130 is probably an error. The estimated maximum age of a person is 120. In case
someone is especially hearty, an age greater than 130 is flagged as invalid. Here are both approaches to
handling an error condition in a property:

private int prop_age;


public int age {
set {
if(value<0 || value>120) {
throw new ApplicationException("Not valid age!");
}
prop_age=value;
}
get {
return prop_age;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

public class Person {


private int? prop_age;
public int? age {
set {
if(value<0 || value>120) {
prop_age=null;
return;
}
prop_age=value;
}
get {
return prop_age;
}
}
}

Nested Types
Nested types are classes and structures declared inside a class. Nested classes are advantageous when
modeling systems of interconnecting components. This is an example of a nested class:

public class Outer {

public void FuncA() {


}

public class Inner {

static public void FuncB() {


Console.WriteLine("Outer.Inner.FuncB()");
}
}
}

Nested types can be public, private, or other accessibility. A full complement of modifiers is available. In
addition, the new modifier is available to nested types, which hides a nested class of the base class.

Use the dot syntax to access members of the nested class. This code calls a static method of the inner
class:

Outer.Inner.FuncB();

You can build an instance of the nested class, which is an inner reference. If public, references to the nested
class can be created inside or outside the outer class. A nested class that is private can be instantiated
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

only in the outer class. The this object of the inner reference includes members of the inner class alone.
Instance members of the outer class are not accessible from the this object of the inner reference. Pass a
reference of the outer component into the constructor of the inner component. The back reference is then
available to access the instance members of the outer component from within the inner component. The
static members of the outer class, regardless of accessibility, are available in the inner class.

The Automobile class models a car engine, which is a system. An automobile system contains alternators,
ignition, steering system, and other systems. This is an abbreviated version of the Automobile class:

using System;

namespace Donis.CSharpBook{

public class Automobile {

public Automobile() {
starter=new StarterMotor(this);
}

public void Start() {


starter.Ignition();
}

private bool prop_started=false;


public bool started {
get {
return prop_started;
}
}

private class StarterMotor {


public StarterMotor(Automobile _auto) {
auto=_auto;
}

public void Ignition() {


auto.prop_started=true;
}
Automobile auto;
}

private StarterMotor starter;


}

public class Starter{


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static void Main(){


Automobile car=new Automobile();
car.Start();
if(car.started) {
Console.WriteLine("Car started");
}
}
}
}

Partial Classes
A partial class can span multiple source files. When compiled, the partial class is reassembled in the
assembly. Each source file has a complete class declaration and body. The class declaration is preceded
with the partial keyword. The class body in each source file includes only the members that the partial class
is contributing to the overall type. Code generators will benefit from partial classes. Rely on the code
generator or wizard to generate the core code. The developer can then extend the code without disturbing the
base code. Teams of developers collaborating on an application also benefit from partial classes. The class
can be parceled based on responsibility. The developer works in separate source files, which isolate
changes and focus a developer on code relevant to their responsibility.

Consistency is the key to partial types:


 Each partial type is preceded with the partial keyword.
 The partial types must have the same accessibility.
 If any part is sealed, the entire class is sealed.
 If any part is abstract, the entire class is abstract.
 Inheritance at any partial type applies to the entire class.

Here is the example of a class separated into partial types:

// partial1.cs

using System;

namespace Donis.CSharpBook{

public partial class ZClass {

public void CoreMethodA() {


Console.WriteLine("ZClass.CoreA");
}
}

public class Starter{


public static void Main(){
ZClass obj=new ZClass();
obj.CoreMethodA();
obj.ExtendedMethodA();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
}

// partial2.cs

using System;

namespace Donis.CSharpBook{

public partial class ZClass {

public void ExtendedMethodA() {


Console.WriteLine("ZClass.ExtendedA");
}
}
}

Figure 2-2 shows the ZClass combined in the assembly, which demonstrates that the partial classes are
merged.

Figure 2-2: ZClass depicted in ILDASM


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Structures
Structures are lightweight classes. Similar to classes, structures have behaviors and attributes. As a value
type, structures directly contain their value and are stored on the stack. Because structures reside on the
stack, keep them small. Do not cache large objects on the stack. The implementation of structures in C#
enforces the policy of using a structure as a lightweight class. The following list details the differences
between structures and classes:
 Structures are sealed and cannot be inherited.
 Structures cannot inherit classes and other structures.
 Structure implicitly inherits from System.ValueType.
 The default constructor of a structure cannot be replaced by a custom constructor.
 Custom constructors of a structure must fully initialize the value of the structure.
 Structures do not have destructors.
 Field initialization is not allowed. Const members of a structure can be initialized.

Structure syntax:
 attributes accessibility struct structname: interfacelist { structbody };

There are several attributes that target structures. Structures support the same accessibility of a class.
Structures implicitly inherit System.ValueType and cannot explicitly inherit another type. However, structures
can implement interfaces. Interfacelist is a list of interfaces the structure implements. The structbody
encompasses the member functions and data members of the structure.

The default constructor of a structure initializes each field to a default value. You cannot replace the default
constructor of a structure. Unlike a class, adding custom constructors to a structure does not remove the
default constructor. Invoke a custom constructor with the new operator. The new operator will not place the
structure on the managed heap. It is a call to the parameterized constructor of a structure. Structures are
commonly declared without the new operator. In that circumstance, the default constructor is called.

Fraction is a structure that models naturally a fraction. Fraction has two double members. It is small and
ideal for a structure.

using System;

namespace Donis.CSharpBook{

public struct Fraction {

public Fraction(double _divisor, double _dividend) {


divisor=_divisor;
dividend=_dividend;
}

public double quotient {


get {
return divisor/dividend;
}
}

private double divisor;


private double dividend;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class Calculate{


public static void Main(){
Fraction number=new Fraction(4,5);
Console.WriteLine("{0}", number.quotient);
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Enumeration
An enumeration is a set of discrete and related values. Enumerations expand into a type, whereas the
members of the enumeration are defined as constant. The default underlying type of an enumeration is
integer. An enumeration is never required; integer variables can be used instead. However, enumerations are
safer, more extensible, and enhance readability. The Months.GetMonth method outputs the name of a
month. The method relies on integer values.

public class Months {


static public void GetMonth(int iMonth) {
switch(iMonth) {
case 1:
Console.WriteLine("January");
break;

case 2:
Console.WriteLine("Febuary");
break;
case 3:
Console.WriteLine("March");
break;
// and so on...
default:
Console.WriteLine("Invalid Month");
break;
}
}
}

Here is the Months class rewritten to use an enumeration:

public enum Month {


January=1,
February,
March
}
public class Months{
public static void GetMonth(Month m) {
Console.WriteLine(m.ToString());
}
}

Which version of Months is simpler and more readable?

Here is the syntax of an enumeration:


 accessibility enum enumname: basetype {memberlist};
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Enumerations support public and other accessibility. The default underlying type is integer. The basetype
element changes the underlying type. This can be any integral type, except the character type. For the
Month enumeration, changing the underlying from integer to byte is more efficient. The memberlist includes
all the constants of the enumeration. By default, the constant members are numbered in textual order from
zero to n-1. Each member can be assigned a specific value. Here is the updated enumeration called Month:

public enum Month: byte {


January=1,
February,
March
}

When assigning values to enumeration members, sequential ordering is not required. In addition, duplicate
values are allowed. Some members can be set without initializing others. The value of the preceding member
is incremented and assigned to any unassigned member. ZEnum is a mixture of explicitly and implicitly
initialized members. Optional values are listed in the comments.

public enum ZEnum{


item1=6,
item2=3,
item3, // 4
item4, // 5
item5=8,
item6 // 9
}

Enumerations are derived from the System.ValueType method, which offers important services for
enumeration types. Table 2-5 lists some of those services.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-5:
Important
System.Enum
Methods

Me De
tho scr
d ipti
Na on
me

sta Ret
tic urn
stri s
ng the
Ge stri
tNa ng
me rep
(Ty res
pe ent
en ati
um on
typ of
e, a
obj sp
ect ecif
val ic
ue) ite
m
of
the
en
um
era
tio
n.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-5:
Important
System.Enum
Methods

Me De
tho scr
d ipti
Na on
me

sta Ret
tic urn
stri s
ng[ a
] stri
Ge ng
tNa arr
me ay
s(T co
ype nta
en inin
um g
typ the
e) stri
ng
rep
res
ent
ati
on
of
eve
ry
ite
m
of
the
sp
ecif
ied
en
um
era
tio
n.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-5:
Important
System.Enum
Methods

Me De
tho scr
d ipti
Na on
me

sta Ret
tic urn
Arr s
ay an
Ge arr
tVa ay
lue of
s(T the
ype un
en der
um lyin
typ g
e) typ
e.
Th
e
arr
ay
co
nta
ins
the
nu
me
ric
al
rep
res
ent
ati
on
of
ea
ch
val
ue
of
the
en
um
era
tio
n.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 2-5:
Important
System.Enum
Methods

Me De
tho scr
d ipti
Na on
me

sta Ret
tic urn
Ty s
pe the
Ge un
tUn der
der lyin
lyin g
gT typ
ype e
(Ty of
pe the
en en
um um
Ty era
pe) tio
n.

Bitwise Enumeration

Bitwise enumeration is for mutually inclusive flags. Each member of the enumeration is assigned a unique
bitwise value. Apply the flags attribute to an enumeration to specify bitwise enumeration.

Combine bitwise flags using the or operator (|). Confirm the existence of a flag with the bitwise and operator (
&).

The following code demonstrates the flags attribute of an enumeration:

using System;

namespace Donis.CSharpBook{

[Flags] public enum Contribution {


Pension=0x01,
ProfitSharing=0x02,
CreditBureau=0x04,
SavingsPlan=0x08,

All=Pension|ProfitSharing|CreditBureau|SavingsPlan
}

public class Employee {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

private Contribution prop_contributions;


public Contribution contributions {
get {
return prop_contributions;
}
set {
prop_contributions=value;
}
}
}

public class Starter{


public static void Main(){
Employee bob=new Employee();
bob.contributions=Contribution.ProfitSharing|
Contribution.CreditBureau;
if((bob.contributions&Contribution.ProfitSharing)
== Contribution.ProfitSharing) {
Console.WriteLine("Bob enrolled in profit sharing");
}
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Identity versus Equivalence


Reference and value types support different memory models. References refer to objects created on the
managed heap, whereas value types are created on the stack. Equivalence and identity complement the
memory model. Equivalence is the value or state of an instance. Related instances that have the same value
are equivalent. Identity is the location of an object.

Equivalent values are related types that contain the same value. In the following code, integers locala and
localc are equivalent. However, the variables are not identical because they are stored at different locations
on the stack. The variables locala and localb are neither equivalent no identical. They have differenet values
and are stored at different locations on the stack:

int locala=5;
int localb=10;
int localc=5;

Assigning a value type copies the value. The target and source are equivalent after this assignment, but not
identical:

locala=localb; // locala and localb are equivalent.

For reference types, there is synchronicity of equivalence and identity. Related references containing the
same value are equivalent and identical. Assigning a reference creates an alias, which can create unplanned
side affects. For this reason, be careful when assigning references. The following code has some unplanned
side effects:

using System;

namespace Donis.CSharpBook{

public class XInt {


public int iField=0;
}

public class Starter{


public static void Main(){
XInt obj1=new XInt();
obj1.iField=5;
XInt obj2=new XInt();
obj2.iField=10;

// Alias created and second instance lost


obj2=obj1;
obj1.iField=15; // side affect
Console.WriteLine("{0}", obj2.iField); // 15
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Class Refinement
Classes can be refined through inheritance, which is code reuse. The common members of related classes
can be extracted and placed in a base class. Child classes inherit and refine a base class. A personnel
application might have SalariedEmployee, HourlyEmployee, and CommissionedEmployee classes that inherit
the Employee class. The Employee class holds the common members of all Employee-derived classes.
Each derived class adds members to refine the base class. Optionally, derived classes can override
members of the base class. Sealed classes cannot be inherited. Inheritance and polymorphism are closely
related. Polymorphism calls the correct method at run time from a base reference to a derived object, and it
can add considerable efficiencies to an application.

Inheritance and polymorphism and other strategies to refine class usage are reviewed in Chapter 3.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 3: Inheritance
Overview
Classes are often related to other classes. The two popular methods of relating classes are containment,
also known as composition, and inheritance. Containment is a "has a" relationship, where a class contains
or embeds another class. For example, a timestamp contains time. Inheritance is based on the "is a"
relationship, in which one class is a type of another class. For example, an hourly employee is a kind of
employee.

Inheritance involves a base type and a derived type, where a derived type is a kind of base type. Derived
types inherit the members of the base type. In essence, they are derived from the base type.

A base type represents a generalization, whereas a derived type represents a specialty. Specialties are
derivatives of generalizations. A personnel program might contain different types of employees. Hourly,
salaried, commissioned, temporary, and retired are possible types of employees. Each is a kind of
employee and distinct from any other employee specialization. For example, an hourly employee is different
from a salaried employee. Employee is a generalization of all employees and is therefore a base class.
Conversely, HourlyEmployee, SalariedEmployee, CommissionedEmployee, TemporaryEmployee, and
RetiredEmployee are specializations and are therefore derived classes.

Derived types refine base types. A base type holds the common members of the generalization. Derived
classes inherit those members and add specialty members. These members refine the base class in the
context of the derived class. The Employee class, which is a base class, defines the FullName and EmplID
members. Every employee has a name and employee number. As such, those members belong in the base
type. The SalariedEmployee class adds members for the salary and number of pay periods. This is unique to
the salaried employee specialization. The HourlyEmployee class has additional fields for the hourly rate and
the number of hours worked. Both SalariedEmployee and HourlyEmployee classes refine the Employee class
with these extra members.

Inheritance provides hierarchical clarity. The employee and derived types form a hierarchy. Without this
clarity, you face a greater challenge in programming an application. Classes are analogous to marbles in a
bin. A large bin holds hundreds of marbles. The bin is an indiscriminate jumble of marbles. From this jumble,
you might try to find the one marble that is a clearie and has gray and white stripes. You could be looking for
awhile, as shown in Figure 3-1. The marbles could be organized into separate bins for regular, boulder, and
steelie marblies. Regular marbles are further segmented into cat's eyes and clearies, which are placed in
smaller subcontainers. With this additional organization, finding the clearie with gray and white stripes is
easier. (See Figure 3-2.)

Figure 3-1: A basket of marbles


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 3-2: Organized baskets of marbles

As part of the design phase, scenarios are often employed. The nouns in the scenarios are candidates for
classes. Figure 3-3 shows the nouns found in a scenario for a Personnel application. There is no order or
hierarchy. You should look for relationships. The "is a" or "is a kind of" phrases are excellent for identifying
inheritance and discerning the base to derived class relationships. When the classes are organized by
relationships, clarity blooms, as shown in Figure 3-4.

Figure 3-3: Nouns from the Personnel scenario


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 3-4: Nouns grouped by relationships

Class hierarchy in moderation is helpful. However, excessive hierarchy is as cumbersome as no hierarchy at


all. An overly vertical hierarchy is as incoherent as a flat hierarchy. There are also performance penalties for
extended class hierarchies. The best practice in C++ was to limit class hierarchies to six levels or fewer. For
example, the copious layers of classes in Microsoft Foundation Classes (MFC) contributed to the
complexity of the product. Wading through the extensive class hierarchy of the MFC is sometimes a tedious
task. In addition, understanding the members of a class is harder when dozens of other classes seed that
class with methods, properties, fields, and so on. Hierarchical clarity is lost, which affects your productivity.
The Active Template Library (ATL) is on the opposite end of the spectrum and has a flatter model. It is trivial
to navigate the ATL hierarchy, which is appreciated.

Inheritance also promotes code reuse. Without inheritance, common members would be implemented
repeatedly—once in each derived type. Modifications would require updating several classes. This is a recipe
for problems and is neither efficient nor versionable. Inheritance has a cascade effect, which is better. A
member is implemented once in a base class, and the implementation cascades to all derived classes.
Changes to a base member ripple to all descendants. Insert base members at the highest relevant point in
the hierarchy. This creates the widest cascade and efficient utilization of the member. Inserting a member
too low in the hierarchy forces related types to separately implement that member.

Reference types can inherit classes and interfaces. Inheriting a class exemplifies code reuse. The derived
class inherits the members—including the code—of the base class. Conversely, an interface has no code. It
is a contract. Types that implement the interface contract to implement every member of the interface,
whereas the interface contracts to be immutable. This is important because changes to the interface would
break any type derived from that interface. Value types and primitives are not inheritable; they are sealed.
For example, you cannot inherit an int.

Value types cannot inherit other value types or classes. The exception is the System.ValueType class.
Value types implicitly inherit the System.ValueType class. A struct can inherit interfaces.

Terminology is important. Accurate terminology enhances a conversation, whereas incorrect or unclear


terminology muddles the discussion. Object-oriented analysis and design introduced a plethora of new
terms, some of which are identical or similar. Some terms are intended for design, whereas others are for the
implementation phase. However, this distinction is often lost. Table 3-1 shows a list of terms similar to base
and derived types. In this chapter, the base/derived and parent/child terms are used interchangeably.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 3-1:
Inheritance
Terminology

Inh Inh
eri eri
tab tin
le g
Cl Cl
ass ass

Su Su
per bcl
cla as
ss s

Par Chi
ent ld

As De
ce sc
nd en
ant da
nt

Ba Der
se ive
d

Inheritance is not a mechanism to simply drop members into a class. From a design perspective, those
members should belong in that class. For example, a timestamp has the properties of time and a stamp. A
timestamp is a kind of stamp and has a time piece. However, a timestamp is not a kind of time. A
TimeStamp class should inherit from the Stamp class but not the Time class. The "has a" relationship
between the timestamp and time infers containment. Embedding a Time class in the TimeStamp class is
the preferable implementation.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Inheritance Example
Before introducing the specifics of inheritance, an example that includes all the prerequisite elements of
inheritance might be helpful. In the code, XParent is the base class. XChild is the derived class and inherits
the XParent class. XChild inherits a method, property, and field from the base class. XChild extends XParent
by adding a method and field to this assemblage. XChild has five members: three from the base and two
from itself. In this manner, XChild is a specialty type and refines XParent. In Main, instances of the XParent
and XChild classes are created. Base methods are called on the XParent instance. Both base and derived
methods are called on the XChild instance.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){

XParent parent=new XParent();


parent.MethodA();
XChild child=new XChild();
child.MethodA();
child.MethodB();
child.FieldA=10;
Console.WriteLine(child.FieldA);
}

public class XParent {


public void MethodA() {
Console.WriteLine("XParent.MethodA called from {0}.",
this.GetType().ToString());
}

private int propFieldA;

public int FieldA {


get {
return propFieldA;
}
set {
propFieldA=value;
}
}

}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class XChild: XParent {


public int MethodB() {
Console.WriteLine("XChild.MethodB called from {0}.",

this.GetType().ToString());
return fieldb;
}

private int fieldb=5;


}
}
}
}

Cross-Language Inheritance
Inheritance is language-agnostic. Managed languages can inherit classes written in another managed
language. For library developers, this expands the universe of potential clients. Developers no longer need to
maintain language-specific versions of a library or create complex workarounds. Just as important, a family
of developers is not excluded from using a certain library. Another benefit of cross-language inheritance is
collaboration. Team members collaborating on a software system can develop in the language of their
choice. The entire team is not compelled to select a single source language.

Managed languages compile to Microsoft intermediate language (MSIL) code. The Common Language
Runtime (CLR) does not perceive a Microsoft Visual Basic .NET class inheriting from a C# class. It views
one MSIL class inheriting from another MSIL class. Language independence is easier to achieve when
specific languages dissolve into a shared common language at compilation.

Cross-language inheritance fractures without compliance to the Common Language Specification (CLS)—at
least relative to the base or derived class. Language-specific and noncompliant artifacts must be wrung from
classes when cross-language inheritance is planned or expected. For example, the following class, although
perfectly okay in C#, is unworkable in Visual Basic .NET. Visual Basic .NET is case insensitive, making
MethodA in the following code ambiguous:

public class XBase {


public void MethodA() {
}
public void methoda() {
}
}

The following code is an example of successful cross-language inheritance. The base class is written in C#,
whereas the derived class is Visual Basic .NET.

' VB Code: which includes derived class.

Imports System
Imports Donis.CSharpBook

Namespace Donis.CSharpBook
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Public Class Starter

Public Shared Sub Main


Dim child as New XChild
child.MethodA()
child.MethodB()
End Sub
End Class

Public Class XChild


Inherits XParent

Public Sub MethodB


Console.WriteLine("XChild.MethodB called from {0}.", _
Me.GetType().ToString())
End Sub
End Class
End Namespace
// C# Code: which includes base class

using System;

namespace Donis.CSharpBook{
public class XParent {
public void MethodA() {
Console.WriteLine("XParent.MethodA called from {0}.",
this.GetType().ToString());
}

private int propFieldA;

public int FieldA {


get {
return propFieldA;
}
set {
propFieldA=value;
}
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

System.Object
System.Object is the ubiquitous base type. All managed types inherit from System.Object, either directly or
indirectly. System.Object encompasses the baseline behavior accorded to all managed types. Reference
types without an explicit base class inherit System.Object implicitly. Reference types that inherit another
type explicitly still inherit System.Object, but indirectly. You can inherit System.Object explicitly. However,
that is somewhat redundant and, therefore, is not often done. Value types inherit from System.ValueType,
which then inherits System.Object. System.ValueType overrides System.Object members to implement the
semantics of a value type.

The members of the System.Object class are explained in Table 3-2.


Table 3-2: System.Object Methods

Method Name Description

Constructor public Object()


This is the default constructor of the System.Object. It is called whenever an
instance of an object is created. The object keyword is an alias for the
System.Object type.

Equals public virtual bool Equals(object obj)


public static bool Equals(object obj1, object obj2)
Equals returns true if the value of two objects is equal. For reference types, this is
an object comparison, which compares identity. For value types, this method
compares state, which is an equivalency test. Override this method to perform a
more appropriate equality comparison of a derived type.

Finalize protected override void Finalize().


This method is called when an instance is garbage collected. This method cleans
up unmanaged resources associated with an instance. In C#, the destructor is
called from the Finalize method. Destructors and finalization are discussed in
Chapter 14, "Memory Management."

GetHashCode public virtual int GetHashCode()


This method returns a hash code of an instance. The default hash code is not
guaranteed to be unique or have even distribution. You can override this method to
return a meaningful hash code for a derived type or provide better distribution.

GetType public Type GetType()


This method returns a Type reference, which can be used to inspect the structure of
an instance. A Type reference is often the first ingredient in Reflection. Reference is
discussed in Chapter 10, "Metadata and Reflections."

MemberwiseClone protected object MemberwiseClone()


This method creates and returns a new instance of the current object. It performs a
shallow copy. For this reason, reference members of the original and cloned object
point to the same objects. This method is protected and cannot be overridden in the
derived type.

ReferenceEquals public static bool ReferenceEquals(object obj1, obj2)


This method returns true if the identity, not the state, of two objects is the same.

ToString public virtual string ToString()


This method returns a string representation of the current instance. The default
return is the fully qualified name of the type for the current instance. ToString is
frequently overridden to return more pertinent information
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Object.Equals Method

For reference types, the Object.Equals method compares identity. References are equal when pointing to
the same object. References that point to different objects but have the same state are not equal. You can
override the Equals method to perform a value comparison. For value types, the Equals method is already
overridden to compare values.

In Applied Microsoft .NET Framework Programming (Microsoft Press, 2001), author Jeffrey Richter mentions
four tenets of the Equals method: reflexivity, symmetry, transitivity, and consistency.

 Reflexive An object is always equal to itself. The obj1.Equal (obj1) call should always return true.

 Symmetric If obj1.Equals(obj2) is true, then obj2.Equals(obj1) must also be true.

 Transitive If obj1.Equals(obj2) and obj2.Equals(obj3) are both true, then obj3.Equals(obj1) is true.

 Consistent If obj1.Equals(obj2) is true, then obj1 and obj2 should always be equal. This assumes
that the state of neither object has changed.

The Employee class is a base class. The HourlyEmployee, CommissionedEmployee, and SalariedEmployee
classes derive from the Employee class and represent specific types of employees. This is the override of
the Equals method in the Employee class:

public static bool operator==(Employee obj1, Employee obj2) {


return obj1.Equals(obj2);
}

public static bool operator!=(Employee obj1, Employee obj2) {


return !obj1.Equals(obj2);
}

public override bool Equals(object obj) {


Employee _obj=obj as Employee;

if(obj==null) {
return false;
}
return this.GetHashCode()==_obj.GetHashCode();
}

The preceding code also includes overloads of the operators == and !=. The default implementation of these
operators will not call the overridden Equals method. This can cause inconsistencies, where the comparison
operators behave differently from the Equals method. For this reason, both operators have been overloaded.

When overriding the Equals method, you should also override the GetHashCode method. If not, a compiler
warning occurs. Objects that are equal should have the same hash code. Therefore, equality can be based
on comparing hash codes. In the Equals method, call GetHashCode to retrieve and compare hash codes.

Object.GetHashCode Method

GetHashCode returns a hash code as a 32-bit integer. Override this method when a reference type is used
as a key in a collection. As indicated in the previous section, the Equals and GetHashCode methods should
be implemented in tandem.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The fields associated with a hash code should be immutable. If the fields are not immutable, when the fields
change, the hash code is also modified. This could necessitate updating the key in a collection. If not, the
original key is stale. Stale keys in a collection can cause problems. For this reason, hash codes should not
be transient, and the related fields should not change.

The following code shows the GetHashCode method for the Employee class. The EmplID field used for the
hash is read-only. After the Employee instance is created, EmplID cannot be modified. It is immutable.
There are a variety of algorithms for creating efficient and distributed hash codes—some quite complex. For
simplicity, this implementation of GetHashCode simply returns the EmplID property:

public override int GetHashCode() {


return EmplID;
}

Hash codes are recyclable. When a reference is garbage collected, the hash code is returned to the
available pool. The hash code is then assignable to a future instance. For this reason, you should remove
dead objects from any collections.

Object.GetType Method

The GetType method returns a Type instance, which describes the current object. Type objects are useful in
interrogating the composition of an associated object. Members, such as GetMethods and GetFields, return
the underlying architecture of a type. This process is called Reflection.

The following code demonstrates Reflection. The public methods of System.Object are enumerated and
displayed. As expected, the methods of Table 3-3 are shown. This excludes the Object.MemberwiseClone
method, which is not a public method.
Table 3-3: Member
Accessibility

Me Ou De
mb tsi riv
er de ed
Ac W Cl
ce orl ass
ss d
Mo
difi
er

pu Ye Ye
blic s s

priv No No
ate

pro No Ye
tec s
ted

int Ye Ye
ern s s
al (thi (thi
s s
as as
se se
mb mb
ly) ly)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 3-3: Member


Accessibility

Me Ou De
mb tsi riv
er de ed
Ac W Cl
ce orl ass
ss d
Mo
difi
er

int Ye Ye
ern s s
al (thi
pro s
tec as
ted se
mb
ly)

using System;
using System.Collections;
using System.Reflection;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
Object obj=new Object();
Type t=obj.GetType();
foreach(MethodInfo m in t.GetMethods()) {
Console.WriteLine(m.Name);
}
}
}
}

Object.ToString Method

The ToString method returns a string representation of an instance. The default return is the fully qualified
name of the type. Value types override ToString to return the value of the instance. The following code
displays the default string representation of a value and a reference type:

int locala=10;
Console.WriteLine(locala.ToString()); // 10
Object obj=new Object();
Console.WriteLine(obj.ToString()); // System.Object
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

In the Employee class, ToString is overridden to return the name of the employee:

public override string ToString() {


return FullName;
}

Object.MemberwiseClone Method

MemberwiseClone returns a new instance of an object. A shallow copy is performed. An object is cloned by
performing a bitwise copy of each member. If a member is a value type, the values are copied and there is no
side effect. For a member that is a reference type, the reference—not the object—is copied. The result is
that the reference members of both objects point to the same memory, as shown in Figure 3-5. When this
occurs, any changes in the original object will affect the cloned object, and vice versa.

Figure 3-5: The result of MemberwiseClone

MemberwiseClone is protected and cannot be overridden. The method is typically called from a derived class
when implementing the ICloneable interface. The ICloneable interface defines an interface for cloning
objects. The only member is the ICloneable.Clone method.

The following code shows the implementation of the ICloneable.Clone method in the Employee class. As
expected, the code delegates to the MemberwiseClone method. In the Employee class, emplName is a
member and a reference type. In Main, obj2 is a clone of obj1. The hash of both objects is displayed. This
confirms the separate identities of each object. Nonetheless, changes to the employee name affect both
objects, which is a nasty side effect. Both objects point to the same name in memory.

public class Starter{


public static void Main(){
Employee obj1=new Employee(5678);
Employee obj2=(Employee) obj1.Clone();
obj1.Last="Marshall";
obj2.First="Donis";
Console.WriteLine("Obj1 HC "+
obj1.GetHashCode().ToString());
Console.WriteLine(obj1.EmplID+": "+obj1.FullName);
// 5678: Donis Marshall
Console.WriteLine("Obj2 HC "+
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

obj2.GetHashCode().ToString());
Console.WriteLine(obj2.EmplID+": "+obj2.FullName);
// 5678: Donis Marshall
}
}

class Employee: ICloneable {

public Employee(int id) {


if((id<1000) || (id>9999)) {
throw new Exception(
"Invalid Employee ID");
}

propID=id;
}

public object Clone() {


return MemberwiseClone();
}
// end of partial listing…

Object.ReferenceEquals Method

The ReferenceEquals method compares identity. If the objects are the same, ReferenceEquals returns true.
Otherwise, false is returned. ReferenceEquals is not virtual and cannot be overridden in the derived class.
The following code compares an original object and a cloned object. The objects have the same state but
different identities. Because the identities are distinct, the ReferenceEquals method returns false.

Employee obj1=new Employee(5678);


Employee obj2=(Employee) obj1.Clone();
if(Employee.ReferenceEquals(obj1, obj2)) {
Console.WriteLine("objects identical");
}
else {
Console.WriteLine("objects not identical");
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Employee Class
This is the complete listing of the Employee class, including the overridden methods of the System.Object
class:

using System;
using System.Collections;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
Employee obj1=new Employee(5678);
Employee obj2=new Employee(5678);
if(obj1==obj2) {
Console.WriteLine("equals");
}
else {
Console.WriteLine("not equals");
}
}
}

class Employee {

public Employee(int id) {


if((id<1000) || (id>9999)) {
throw new Exception(
"Invalid Employee ID");
}

propID=id;
}

public static bool operator==(Employee obj1, Employee obj2) {


return obj1.Equals(obj2);
}

public static bool operator!=(Employee obj1, Employee obj2) {


return !obj1.Equals(obj2);

}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public override bool Equals(object obj) {


Employee _obj=obj as Employee;

if(obj==null) {
return false;
}
return this.GetHashCode()==_obj.GetHashCode();
}

public override int GetHashCode() {


return EmplID;
}

public string FullName {


get {
return propFirst+" "+
propLast;
}
}

private string propFirst;


public string First {
get {
return propFirst;
}
set {
propFirst=value;
}
}

private string propLast;


public string Last {
get {
return propLast;
}
set {
propLast=value;
}
}

private readonly int propID;


public int EmplID {
get {
return propID;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

public override string ToString() {


return FullName;
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Implementing Inheritance
Inheritance requires a base class and a derived class, where the derived class inherits from the base class.
The members of the base class are inherited into the derived type. Derived classes can override and extend
the interface inherited from the base type.

This is the syntax for inheritance syntax:

class derivedclass: baseclass, interface 1, interface 2, interface n {


derived body
}

In the class header, the colon stipulates inheritance and prefixes the base list. The base list is a
comma-delimited list that includes at most one base class and any number of interfaces. Classes are
limited to inheriting a single class. However, a class can inherit multiple interfaces. C++ developers are
probably familiar with multiple inheritance. C++ allows multiple inheritance of classes. Excluding multiple
inheritance was an important design decision for C#. Personally, I endorse that decision. First, multiple
inheritance is not used that often. Second, multiple inheritance often causes more problems than are
resolved. Third, multiple inheritance allows for the increased probability of ambiguousness of members.

A base type must have the same or greater accessibility than the derived type. A compiler error occurs in
the following code. The accessibility of the base class is narrower than the derived class, which is an error.

internal class ZClass {


}
public class YClass: ZClass {
}

.NET supports only public inheritance. C++ supported public, protected, and private inheritance. Despite this
flexibility in C++, practically all inheritance was public inheritance. Most C++ developers were not familiar
with or ever used any other kind of inheritance. Thus, protected and private inheritance will probably not be
missed.

Access Modifiers

Access modifiers set the visibility of members to the outside world and the derived type. Table 3-3 describes
member accessibility.

Are private members of the base class inherited? Private members are indeed inherited but are not visible to
the derived type and are not directly accessible in the derived class. These members are accessible through
the public and protected functions of the base class. Therefore, a derived type has two realms of private
variables. One realm includes private members that are defined in a derived class. These members are
visible in the derived type. The other realm includes inherited private members, which are not visible to the
derived type.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Overriding
A derived class can override behaviors in the base class, which allows a derived type to substitute different
implementations where appropriate. The Pay method of the Employee class is overridden in
CommissionedEmployee to include commissions in each paycheck. In the SalariedEmployee class, the Pay
method is overridden to calculate pay by prorating annual income. Methods, properties, and indexers can be
overridden. Fields and static members of the base cannot be overridden in the derived class. However,
derived types can hide fields and static members of the base class.

When is a child class allowed to override the parent? Most parents hope that their children inherit their
sterling behavior. However, the behavior of the parent is merely a suggestion to the child. Children are often
inclined to override the behaviors of the parents. The parent is hopeless in preventing this substitution. In
many object-oriented languages, that is the model. Child or derived classes can override the behavior of the
parent or base class. The derived class might override a behavior inappropriately and destabilize the base
class. This is called the fragile base class problem: a problem that is acute with class libraries where a child
class is more likely to inherit a type and unknowingly or incorrectly override a base member. The model is
different in C#. By default, functions cannot be overridden. Parent classes must tacitly approve the overriding
of a method. In addition, the child class must acknowledge its intent to override the method. This prevents
the child from unknowingly overriding a member of the base class.

Virtual and Override Keywords

The virtual keyword indicates that a member can be overridden in a child class. It can be applied to methods,
properties, indexers, and events. In the derived class, the override keyword indicates the intention to override
a virtual member of the base class. The virtual and override keywords complement each other. The virtual
keyword propagates to descendants. A virtual method is overridable in a derived class and descendants.

Overriding is not an all-or-nothing condition. Using the base keyword, the public and protected members of
the base class are accessible in the derived type. The syntax is base.member. You cannot skip levels with
the base keyword. For example, you cannot access a member in a grandfather class. The base.base.
member syntax is illegal. In the following code, the SalariedEmployee.Pay method calls the Employee.Pay
method to display an employee name on a paycheck:

public class Employee: ICloneable {

public Employee() {
}

public Employee(int id) {


if((id<1000) || (id>9999)) {
throw new Exception(
"Invalid Employee ID");
}

propID=id;
}

public virtual void Pay() {


Console.WriteLine("Employee: "+FullName);
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

// partial listing
}

public class SalariedEmployee: Employee {

public override void Pay() {


base.Pay();
Console.WriteLine("Pay is: {0,6:c}",
propSalary/(decimal)propPeriods);
}

// partial listing

Overload versus Override

Override and overload are different concepts. When a member of a base class is overridden, the signature of
the base and the signature of the derived member are the same. Overloading requires different signatures. In
a derived class, a function can be overloaded, overridden, or both. When a member is overridden with a
different signature, a compiler warning occurs in the derived type. This prevents an accidental overload,
where method overriding was intended. This is shown in the following code, where MethodA is overloaded in
the YClass class but not overridden. In Main, both the base and the derived implementation are called.

using System;

namespace Donis.CSharpBook{

public class Starter{

public static void Main(){


YClass obj=new YClass();
obj.MethodA();
obj.MethodA(10);
}
}

public class ZClass {


public virtual void MethodA() {
Console.WriteLine("ZClass.MethodA");
}
}

public class YClass: ZClass


{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public override void MethodA(int a) {


Console.WriteLine("YClass.MethodA");
}

}
}

Overriding Events

For completeness, the following is sample code for overriding an event. Events are discussed in Chapter 8,
"Delegates and Events."

public class ZClass {

public virtual void MethodA() {


}

public delegate void MyDel();


public virtual event MyDel MyEvent {
add{
}
remove{
}
}
}

public class YClass: ZClass {

public override event MyDel MyEvent{


add{
// different implementation
}
remove{
// different implementation
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

New Modifier
The new modifier hides a member of the base class. New is the default modifier when a member is replicated
in a derived type. However, unless the new keyword is stated explicitly, a compiler warning is presented to
prevent the inadvertent hiding of a member of the base class. Explicit use of the new keyword prevents the
warning. A virtual member and overridden member are related, which is important to polymorphism. The
derived member and hidden member are, however, unrelated.

NET supports hide-by-signature and hide-by-name techniques. C# only supports hide-by-signature, where a
single member is hidden using the new modifier. Hide-by-name hides the entire interface of a member, which
may entail several functions. This option is available in Visual Basic .NET.

In the following code, ZClass is the base class and contains MethodA and MethodB members. Both are
virtual methods, and MethodB calls MethodA.

public virtual void MethodB() {


MethodA();
}

YClass is a derived class and inherits from ZClass. MethodA is overridden in the derived type, but MethodB
is not overridden. Therefore, two versions of MethodA exist: a base version and a derived version. When
YClass.MethodB is called, which version of MethodA is invoked in the method? Because MethodA is virtual,
the most derived method is called. YClass.MethodA is invoked. With a virtual method, the compiler prefers
the most derived method.

Here is the code:

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
YClass obj=new YClass();
obj.MethodB(); // YClass.MethodA
}
}

public class ZClass {


public virtual void MethodA() {
Console.WriteLine("ZClass.MethodA");
}

public virtual void MethodB() {


MethodA();
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class YClass: ZClass


{
public override void MethodA() {
Console.WriteLine("YClass.MethodA");
}
}
}

The following code is almost identical to the previous code. However, ZClass.MethodA is not overridden in
the derived class. Instead, YClass hides the base class implementation of MethodA with the new modifier.
ZClass.MethodA and YClass.MethodA are now unrelated. Therefore, the compiler will not delegate to
YClass.MethodA for an implementation inherited from the parent. For this reason, YClass.MethodB calls
ZClass.MethodA. This prevents functions inherited from the base class in calling unrelated functions, which
could cause the fragile base class problem.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
YClass obj=new YClass();
obj.MethodB(); // ZClass.MethodA
}
}

class ZClass {
public virtual void MethodA() {
Console.WriteLine("ZClass.MethodA");
}

public virtual void MethodB() {


MethodA();
}
}

class YClass: ZClass


{
public new void MethodA() {
Console.WriteLine("YClass.MethodA");
}
}
}

Interestingly, although the new modifier hides the base class member, you can still access the base class
implementation with the base keyword. This is demonstrated in the following code:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class ZClass {

public virtual void MethodA() {


Console.WriteLine("ZClass.MethodA");
}
}

public class YClass: ZClass


{
public new void MethodA() {
base.MethodA();
Console.WriteLine("YClass.MethodA");
}
}

Virtual methods are overridable in all descendants. The new modifier ends the propagation of this
characteristic. The new modifier changes virtual methods to nonvirtual. The method cannot be overridden in
further descendants. A function can be declared as both new and virtual. In that circumstance, the function
hides the base method and is overridable to descendants.

The following code demonstrates that a member with the new modifier cannot be overridden:

public class ZClass {


public virtual void MethodA() {
}

public virtual void MethodB() {


}
}

public class YClass: ZClass


{

public new virtual void MethodA() {


}

public new void MethodB() {


}

public class XClass: YClass


{
public override void MethodA() {
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

/* ERROR

public override void MethodB() {


}
*/
}

Base fields and static members cannot be overridden in a derived class. However, both can be hidden with
the new modifier. Hiding field and static members can cause confusion. When you use this feature, I
recommend thorough supporting documentation in your code.

In the following code, ZClass has a static method and field. Their purpose is to count ZClass instances.
YClass inherits ZClass and hides the two static members of the base type. The new members count the
instances of the YClass. Therefore, there are simultaneous counts—the base class and derived class
counters. In Main, multiple instances of the ZClass and YClass are created. Both counters are then
displayed.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
ZClass obj1=new ZClass();
YClass obj2=new YClass();
YClass obj3=new YClass();
ZClass.DisplayCounter();
YClass.DisplayCounter();
}
}

public class ZClass {


public ZClass() {
++count;
}

public static int count=0;


public static void DisplayCounter() {
Console.WriteLine("ZClass.Count:");
Console.WriteLine(count);
}

/* ERROR - static methods cannot be virtual

public static virtual void DisplayCounter() {


Console.WriteLine("ZClass count:");
Console.WriteLine(count);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
*/
}

public class YClass: ZClass


{
public YClass() {
++count;
}

private new static int count=0;

public new static void DisplayCounter() {


Console.WriteLine("YClass count:");
Console.WriteLine(count);
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Abstract
Abstract classes are concepts. Object-oriented applications model the real world, which is replete with
concepts. For developers of a graphics program, a geometric shape is a concept. Have you even seen a
geometric shape? No. Rather, you have seen types of geometric shapes, such as triangles, ellipses,
rectangles, and lines. Geometric shape is a description of a category—a kind of shape. Conversely, a
rectangle is tangible: A television, a box, and this book are actual rectangles.

The Employee class is an abstract class. Why? In the personnel domain, employee is a categorization of
employees. Each employee is specifically an hourly, salary, or commissioned employee. How an employee
is paid is determined by the type of employee. Payroll calculations are conducted into the derived type, such
as HourlyEmployee. The Employee base type is a container of general information such as the employee
name. However, without pay specifics, the Employee class is incomplete. Most employees value getting
paid. For that reason, Employee is a concept and abstract.

The abstract keyword makes a class abstract. Abstract classes exist extensively for inheritance. You
cannot create an instance of an abstract class. Nonabstract classes are concrete classes. You can create
an instance of a concrete class. Static classes, value types, and interfaces do not support the abstract
modifier.

In the next example, Employee is the base class and is abstract. HourlyEmployee is the derived class and is
concrete.

public class Starter{


public static void Main(){
Employee obj1=new Employee(); // Not valid
HourlyEmployee obj2=new HourlyEmployee(); // Valid
}
}

public abstract class Employee { // abstract


}

public class HourlyEmployee: Employee { // concrete


}

Members can also be abstract. Methods, properties, indexers, and event members can be abstract.
However, static members cannot be abstract. In addition, classes with abstract members must also be
abstract. An abstract member has a signature but no function body. Virtual is implied with abstract
functions. Abstract members must be implemented in the derived type.

In the real world, a parent can ask a child to do something with or without instructions. The parent can
provide instruction to the child to complete the request. Alternatively, a parent might provide no directions.
The child must accomplish the task. However, the parent does not care about the details of the
implementation. An abstract function is an example of the latter. Abstract methods are a means of assuring
that derived types implement required methods. The derived type inherits no implementation (instructions)
from the base type. Derived types must override all abstract functions. If not, the derived type is incomplete
and in error.

In the following code, Employee mandates that derived types implement the CalculatePay method. Because
the class has an abstract method, the Employee class is also abstract:

public abstract class Employee {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public virtual void Pay() {


}

public abstract void CalculatePay();


}

public class HourlyEmployee: Employee {


public override void Pay() {
CalculatePay();
}

public override void CalculatePay() {


}
}

For completeness, here is an example of an abstract property:

public abstract class ZClass {


public abstract int PropA {
get;
set;
}
}

public class YClass: ZClass {


public override int PropA {
get {
return 0;
}
set {
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Sealed
Sealed classes are the reverse of abstract classes. Abstract types must be inherited. You cannot create an
instance of an abstract type. Conversely, sealed types cannot be inherited and are concrete. Sealed classes
cannot be refined by a derived type. Sealed classes are terminating nodes in the class hierarchy.

The sealed modifier can also be applied to instance methods, properties, events, and indexers. It cannot be
applied to static members. Sealed members are allowed in sealed and nonsealed classes. A sealed
member must override a virtual or implied virtual member, such as an abstract member. However, a sealed
member itself cannot be overridden. It is sealed. The sealed modifier must be combined with the override
modifier. Although sealed members cannot be overridden, a sealed member in a base class can be hidden in
a derived type with the new modifier. As a bonus, the CLR can perform optimizations on sealed members.

The following code demonstrates both a sealed class and a sealed member. In this example, the
HourlyEmployee class cannot be further refined. In addition, the HourlyEmployee.Pay method cannot be
overridden.

public abstract class Employee {


public virtual void Pay() {
}

public abstract void CalculatePay();


}

public sealed class HourlyEmployee: Employee {


public sealed override void Pay() {
CalculatePay();
}

public override void CalculatePay() {


}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Constructors and Destructors


Constructors and destructors are not inherited. However, both the bases and derived components of an
object require initialization. The base component of an object is responsible for initializing base members,
whereas the derived component is responsible for initializing derived members. Constructors of both the
derived and base components are called for this reason. Because constructors are not inheritable, derived
types must implement local constructors to initialize derived members.

During the instantiation of a derived type, the default or parameterless instance constructor of the based type
is called by default. If the base class does not have a default constructor, a compile error occurs unless the
derived class calls a constructor in the base class that has a parameter. In the following code, ZClass does
not have a default constructor and will not compile:

public class ZClass {


public ZClass(int param) {
}
}

public class YClass: ZClass {


}

Constructors in a derived class can explicitly call constructors in the base class. This is particularly useful
for calling parameterized constructors in the base class. Base class constructors are called from the derived
class using a constructor initializer list. The initializer list can only be affixed to instance constructors in the
derived type. The derived constructor is responsible for initializing the derived type and possibly calling the
base class constructor.

This is the constructor initializer syntax:


 accessibility modifier typename(parameterlist 1) : base(parameterlist 2)
 {constructorbody}

The constructor initializer list follows the derived constructor name and colon. The base keyword refers to the
base class constructor. The parameterlist 2 determines which base class constructor is called. Parameters of
the derived constructor can be used in the parameter list of the base class constructor.

In the following example, the YClass constructor explicitly calls the one-argument constructor of the base
class:

public class ZClass {


public ZClass(int param) {
}
}

public class YClass: ZClass {


public YClass(int param) : base(param) {
}
}

Instances of a derived type are created inside out. The base element is created first, and then the derived
elements. In support of this model, the constructors are walked bottom-up. This facilitates passing
parameters from derived constructors to base constructors. After the parameters are passed up the class
hierarchy, the constructors are executed top-down, beginning with the constructor in the root class.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The following code confirms that constructor initializers are called bottom-up but the constructors are invoked
top-down starting with the constructor in the base class:

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
XClass obj=new XClass();
}
}

public class ZClass {


public ZClass(int param) {
Console.WriteLine("ZClass constructor");
}
}

public class YClass: ZClass {


public YClass(int param) : base(YClass.MethodA()) {
Console.WriteLine("YClass constructor");
}

public static int MethodA() {


Console.WriteLine("YClass constructor initializer");
return 0;
}
}

public class XClass: YClass {


public XClass() : base(XClass.MethodA()) {
Console.WriteLine("XClass constructor");
}

public static new int MethodA() {


Console.WriteLine("XClass constructor initializer");
return 0;
}
}
}

This is the output from the code, which confirms the sequencing of base constructor initializers and the
actual invocation of constructors:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

C:\>insideout
XClass constructor initializer
YClass constructor initializer
ZClass constructor
YClass constructor
XClass constructor

Objects are not fully created until the constructor has finished completely. Therefore, the this reference of the
derived type cannot be used as a parameter in the base class constructor initializer list:

public class ZClass {


public ZClass(YClass obj) {
}
}

public class YClass: ZClass {


public YClass() : base(this) { // Illegal
}
}

Destructors are called in reverse order of constructors. Derived objects are destroyed outside-in, where the
most-derived component is destroyed first. Correspondingly, destructors are called bottom-up. Because
destructors are parameterless, there is no information to pass between them. In C#, base class destructors
are called automatically. Do not attempt to call the base class destructor explicitly.

The following code has three classes—each with a destructor—which form a class hierarchy. At the end of
the program, the destructors are called bottom-up, which confirms the sequencing of destructors.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
XClass obj=new XClass();
}
}

public class ZClass {


~ZClass() {
Console.WriteLine("ZClass destructor");
}
}

public class YClass: ZClass {


~YClass() {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("YClass destructor");
}
}

public class XClass: YClass {


~XClass() {
Console.WriteLine("XClass destructor");
}
}
}

This is the output from the program:

C:\>destructors
XClass destructor
YClass destructor
ZClass destructor
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Interfaces
An interface is a contract and defines the requisite behavior of generalization of types. For example, vehicle
behavior includes ignition on, ignition off, turn left, turn right, accelerate, and decelerate. A car, truck, bus,
and motorcycle are included in the vehicle category. As such, they must encapsulate baseline behavior
representative of all vehicles. The vehicle interface defines that baseline. Specific vehicle types implement
that baseline behavior differently than others. A car accelerates differently from a motorcycle. A motorcycle
turns differently from a bus. An interface mandates a set of behaviors, but not the implementation. The
derived type is free to implement the interface in an appropriate manner. Interfaces must be inherited. You
cannot create an instance of an interface.

Any class or structure that inherits an interface commits to implementing the members of that interface. An
interface is an array of related functions that must be implemented in a derived type. Members of an interface
are implicitly public and abstract.

An interface is similar to an abstract class. Both types must be inherited. You cannot create an instance of
either. Abstract members require implementation in the derived type. Interface members require
implementation in a derived type. Although abstract and interface members are similar, there are several
differences:
 An abstract class can contain some implementation. Interfaces have no implementation.
 Abstract classes can inherit other classes and interfaces. Interfaces can only inherit other
interfaces.
 Abstract classes can contain fields. Interfaces cannot have state.
 Abstract classes have constructors and destructors. Interfaces have neither.
 Interfaces can be inherited by structures. Abstract classes are not inheritable by structures.
 Interfaces support multiple inheritance. Abstract classes support single inheritance.

When choosing between defining an interface versus an abstract class that has all abstract members, select
the interface. With an interface, you can still inherit other types. Further-more, interfaces are clearer. The
ZClass in the following code is simply not as clear as a comparable interface:

public abstract class ZClass {


abstract public void MethodA (int a);
abstract public void MethodB (int a);
abstract public void MethodC (int a);
abstract public void MethodD (int a);
}

public interface IZ {
void MethodA (int a);
void MethodB (int a);
void MethodC (int a);
void MethodD (int a);
}

This is the syntax of an interface:

attributes accessibility modifiers interface interfacename :baselist


{interface body }

An interface can begin with an attribute. Use attributes to further describe an interface, such as the
ObsoleteAttribute. For accessibility, independent interfaces can be public or internal. Nested interfaces can
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

also be protected or private. Interfaces can be nested in classes and structs, but not in other interfaces.
Interfaces support the unsafe modifier. For nested interfaces, the new modifier is also applicable. Baselist is
a list of zero or more interfaces that this interface inherits. The interface body contains the members of the
interface, which consists of methods, properties, indexers, and events. As mentioned, interface members
are implicitly public and abstract.

Interfaces can inherit from other interfaces. The inherited members are added to the members of the current
interface. The inherited interface essentially extends the current interface. A type inheriting the interface
must implement the aggregate interface, which includes the members of the current interface and members
that interface inherited from other interfaces. If a member appears in both the current interface and an
inherited interface, there is no ambiguity. An identical member in a current interface hides the same member
in an inherited interface. However, a compiler warning is generated. Add the new modifier to the member in
the current interface to avoid the warning.

In the following code, IZ and IY are interfaces. The IY interface inherits IZ. MethodB is a member of both
interfaces. For that reason, IY.MethodB hides IZ.MethodB with the new modifier. Types implementing the IY
have to implement the MethodA, MethodB, and MethodC methods. These are members of both interfaces.

public interface IZ {
void MethodB();
void MethodC();
}

public interface IY: IZ{


void MethodA();
new void MethodB();
}

A type can inherit multiple interfaces. The type must implement the members of each interface that is
inherited. Those interfaces may have identical members. For example, assume that IZ and IY interfaces
contain a MethodA method. The single implementation in the derived type satisfies the requirements for both
IZ.MethodA and IY.MethodA. Therefore, the same method in multiple interfaces is not ambiguous. The
implementation in the type consolidates all requirements for the interface member.

Implementing Interfaces

Members of an interface are implicitly public. The implementation in the type must also be public.

In the following code, the Car class inherits the IVehicle interface. As required, the members of the IVehicle
interface are implemented in the Car class.

public interface IVehicle {


void IgnitionOn();
void IgnitionOff();
void TurnLeft();

void TurnRight();
}

public class Car: IVehicle{


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void IgnitionOn(){


}

public void IgnitionOff(){


}

public virtual void TurnLeft() {


}

public virtual void TurnRight(){


}
}

A class that inherits multiple interfaces probably falls into multiple categorizations. An amphibious vehicle is
a combination of a vehicle and a boat. In the following code, the Amphibious class inherits both the IVehicle
and IBoat interfaces. The members of both interfaces are implemented in the Amphibious class. As
discussed, duplicate interface members are implemented only once.

using System;

namespace Donis.CSharpBook {

public interface IVehicle {


void IgnitionOn();
void IgnitionOff();
void TurnLeft();
void TurnRight();
}

public interface IBoat {


void IgnitionOn();
void IgnitionOff();
void TurnLeft();
void TurnRight();
void FishFinder();
void Rudder();
}

public class Amphibious: IVehicle, IBoat {


public void IgnitionOn(){
}
public void IgnitionOff(){
}
public void TurnLeft() {
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void TurnRight() {


}

public void FishFinder() {


}
public void Rudder(){
}
}
}

Explicit Interface Member Implementation

You can associate the implementation of an interface member with a specific interface. This is called explicit
interface member implementation. Explicit interface member implementation binds an interface member to a
particular interface, which requires prefixing the member with the interface name. Members implemented in
this manner are not accessible through the derived type. For this reason, the accessibility modifier is omitted
from explicitly implemented interface member. These members are available only via an interface cast. The
modifiers abstract, virtual, override, or static are also not allowed.

In the following code, the ZClass inherits the IA interface. The IA.MethodA is an explicitly implemented
interface member, whereas IA.MethodB is implemented regularly. Because it is explicitly implemented,
MethodA is prefixed with the interface name. Because the implementation of MethodA is hidden, it cannot be
called from a ZClass instance type. However, you can cast the instance to the underlying interface, which is
interface IA. The method can then be called on that interface.

public class Starter{


public static void Main(){
ZClass obj=new ZClass();
obj.MethodA(); // Error
obj.MethodB();
IA i=obj;
i.MethodA();
}
}

public interface IA {
void MethodA();
void MethodB();
}

public class ZClass: IA {

void IA.MethodA() {
Console.WriteLine("IA.MethodA");
}

public void MethodB() {


Console.WriteLine("IA.MethodB");
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

Explicit interface implementation is most helpful when duplicate members require separate implementations.
Members inherited from multiple interfaces might require separate implementation. Normally, they are
consolidated with a single implementation. Another possibility is duplicate members between the interface
and derived type. You can implement duplicate members separately with explicit interface implementation.
Explicit interface implementation provides separate implementation without ambiguity.

The following code is for the amphibious vehicle. Steering a boat is different from steering a car. Therefore,
TurnLeft and TurnRight are explicitly implemented for the IBoat interface. TurnLeft and TurnRight are also
implemented explicitly for the IVehicle interface. To assign defaults, Amphibious delegates to
IVehicle.TurnLeft and IVehicle.TurnRight from identical functions in the class.

using System;

namespace Donis.CSharpBook {

public class Starter{


public static void Main(){

Amphibious marinevehicle=new
Amphibious();
marinevehicle.IgnitionOn();
marinevehicle.TurnLeft();
IBoat boatmaneuvers=marinevehicle;
boatmaneuvers.TurnLeft();
marinevehicle.IgnitionOff();
}
}

public interface IVehicle {


void IgnitionOn();
void IgnitionOff();
void TurnLeft();
void TurnRight();
}

public interface IBoat {


void IgnitionOn();
void IgnitionOff();
void TurnLeft();
void TurnRight();
void FishFinder();
void Rudder();
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class Amphibious: IVehicle, IBoat {

public void IgnitionOn(){


Console.WriteLine("Ignition on.");
}

public void IgnitionOff(){


Console.WriteLine("Ignition off.");
}

public void TurnLeft() {


IVehicle vehicle=this;
vehicle.TurnLeft();
}

public void TurnRight() {


IVehicle vehicle=this;
vehicle.TurnRight();
}

void IVehicle.TurnLeft() {
Console.WriteLine("Turn vehicle left.");
}

void IVehicle.TurnRight() {
Console.WriteLine("Turn vehicle right.");
}

void IBoat.TurnLeft() {
Console.WriteLine("Turn boat left.");
}

void IBoat.TurnRight() {
Console.WriteLine("Turn boat right.");
}

public void FishFinder() {


Console.WriteLine("Fish finder in use.");
}

public void Rudder(){


Console.WriteLine("Adjust rudder."); }
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Another reason to use explicit interface implementation is to hide some portion of a class or struct. The
explicitly implemented members are hidden from clients of the class. You must cast the type to the interface
to access the hidden interface members.

In the following code, the Car class inherits and implements the IVehicle and IEngine interface. The two
interfaces have no overlapping members. A driver doesn't usually interface with the engine directly. That is
usually left to the mechanic. Therefore, the IEngine interface is hidden in the Car class.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
Car auto=new Car();

auto.IgnitionOn();
auto.IgnitionOff();

// Access engine.

IEngine e=auto.AccessEngine();

// Inspect engine.
}
}

public interface IVehicle {


void IgnitionOn();
void IgnitionOff();
void TurnLeft();
void TurnRight();
}

public interface IEngine {


void Alternator();
void Ignition();
void Transmission();
}

public class Car: IVehicle, IEngine{

public void IgnitionOn(){


Console.WriteLine("Ignition on.");
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

AccessEngine().Ignition();
}

public void IgnitionOff(){


Console.WriteLine("Ignition off.");
}

public void TurnLeft() {


Console.WriteLine("Turn left.");
}

public void TurnRight(){


Console.WriteLine("Turn right.");
}

public IEngine AccessEngine() {


return this;
}

void IEngine.Alternator(){
Console.WriteLine("Alternator.");
}

void IEngine.Ignition() {
Console.WriteLine("Ignition");
}

void IEngine.Transmission(){

Console.WriteLine("Transmission");
}

}
}

Reimplementation of Interfaces

A child class can reimplement an interface that was implemented in a base class. In the following code,
ZClass inherits interface IZ. YClass inherits ZClass and reimplements the IZ interface. This interface
reimplementation in the derived class hides the implementation of the base class. Unless the new modifier is
specified, warnings will occur in the derived class.

public interface IZ {
void MethodA();
void MethodB();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class ZClass: IZ {


public void MethodA(){
}
public void MethodB(){
}
}

public class YClass: ZClass, IZ {


public new void MethodA(){
}
public new void MethodB(){
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Polymorphism
Polymorphism is one of the major goals of inheritance. With polymorphism, related types can be treated in a
generic manner. In a graphics program, instead of calling separate algorithms or operations for rectangle,
ellipse, and triangle shapes, you leverage their commonality and call a generic algorithm or operation. This is
more extensible and maintainable than handling each type of geometric shape differently.

The following program draws rectangles, ellipses, and triangles:

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
Rectangle shape1=new Rectangle();
Rectangle shape2=new Rectangle();
Ellipse shape3=new Ellipse();

shape1.Draw();

shape2.Draw();
shape3.Draw();
}
}

public abstract class Geoshape {


public Geoshape() {
++count;
ID=count;
}

private static int count=0;


protected int ID=0;

public virtual void Draw() {


}
}

public class Rectangle: Geoshape {


public override void Draw() {
Console.WriteLine("Drawing Shape {0} : rectangle",
ID.ToString());
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class Triangle: Geoshape {


public override void Draw() {
Console.WriteLine("Drawing Shape {0} : triangle",
ID.ToString());
}
}

public class Ellipse: Geoshape {


public override void Draw() {
Console.WriteLine("Drawing Shape {0} : ellipse",
ID.ToString());
}
}

The two primary advantages to polymorphism are late binding and extensibility:
 Late binding is when a specific function call is decided at run time. Early binding sets the function
call at compile time, which is not always feasible. For example, in a competent graphics program,
users decide the objects to draw at run time. The previous program does not accommodate this.
The same objects are drawn every time.
 Extensible code adapts easily to future changes. In the preceding code, the Draw method is
called separately for each kind of geometric type. A rectangle is drawn differently from an ellipse.
As the program evolves into the future, more geometric shapes are likely to be added. It could
eventually support 50 types of shapes. An extensible process for drawing a variety of shapes is
needed. Do you want to call Draw 50 different times—once for each type of shape?

Polymorphism starts with a base class reference to an instance of a derived type. Assign an instance of a
derived type to a base class reference. When a virtual function is called on the base class reference, the
compiler automatically delegates to the overridden method in the derived instance. Virtual and overridden
methods have a special relationship. Virtual methods delegate to overridden methods when possible.
BaseReference.VirtualMethod delegates to different implementations depending on the derived object
assigned to the base class reference.

In the following code, Geoshape is the base class reference, and Draw is the virtual method. At run time, two
derived instances are created and assigned to the base class reference. Geoshape references shape[0] and
shape[1] are assigned an Ellipse and Rectangle object, respectively. The Draw method is invoked on the
Geoshape base class reference. At that time, the compiler delegates to the Draw methods overridden in the
derived types (base.virtualfunc-> derived. overriddenfunc). Therefore, a virtual function has different behavior
depending on the kind of object assigned to the reference.

Geoshape [] shapes={ new Ellipse(),


new Rectangle() };

shapes[0].Draw(); // Geoshape.Draw()->Ellipse.Draw()
shapes[1].Draw(); // Geoshape.Draw()->Rectangle.Draw()

In the following code, the DrawShape method draws a geometric shape. Can you predict which type.Draw is
called? The method has one parameter, which is the Geoshape base class. This is a reference to a base
class. When a Rectangle instance is passed as a parameter, it is a derived instance to a base reference.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

This is one of the requirements of polymorphism. The base reference points to Rectangle instance, which
means Rectangle.Draw is called. When the Triangle instance is passed as a parameter, Triangle.Draw is
called. Therefore, one statement, shape.Draw, calls different implementations for related types. The
shape.Draw statement is extensible.

public static void Main(){


DrawShape(new Ellipse());
DrawShape(new Rectangle());
}

public static void DrawShape(Geoshape shape) {


shape.Draw(); // which Draw is called?
}

Polymorphism requires three things:


 Related classes
 Common method
 Different behavior

The following code demonstrates polymorphism. There are related types: Triangle, Ellipse, and Rectangle.
The common method is Draw. Each Draw method is implemented differently in the derived class. At the
command line, clients indicate which shapes to draw. This command draws a rectangle, ellipse, triangle,
and another rectangle. Therefore, the decision about what to draw is deferred to run time:

shapes r e t r

The program defines a collection of base references. At compile time, we know that clients will draw shapes
but we don't know the specific shape. Therefore, a collection of Geoshape base class references is defined,
which is a generalization of all shape types. Plus, polymorphism begins with base references to derived
instances. In the first loop, derived instances are created and added to the collection of base class
references. In the second loop, the array of Geoshape base class references is iterated. Rectangle.Draw,
Ellipse.Draw, or Triangle.Draw is called based on the type of derived object assigned to the base reference.
Therefore, each call to the Geoshape.Draw could initiate a different operation. This is the polymorphic
behavior.

using System;
using System.Collections.Generic;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(string [] shapeArray){
List<Geoshape> shapes=new List<Geoshape>();
Geoshape obj=null;
foreach(string shape in shapeArray) {
if(shape.ToUpper()=="R") {
obj=new Rectangle();
}
else if(shape.ToUpper()=="E") {
obj=new Ellipse();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
else if(shape.ToUpper()=="T") {
obj=new Triangle();
}
else {
continue;
}
shapes.Add(obj);
}

foreach(Geoshape shape in shapes) {


shape.Draw(); // polymorphic behavior
}
}
}

public abstract class Geoshape {


public Geoshape() {
++count;
ID=count;
}

private static int count=0;


protected int ID=0;

public abstract void Draw() {


}
}

public class Rectangle: Geoshape {


public override void Draw() {
Console.WriteLine("Drawing Shape {0} : rectangle",
ID.ToString());
}
}

public class Triangle: Geoshape {


public override void Draw() {
Console.WriteLine("Drawing Shape {0} : triangle",
ID.ToString());
}
}

public class Ellipse: Geoshape {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public override void Draw() {


Console.WriteLine("Drawing Shape {0} : ellipse",
ID.ToString());
}
}

Geoshape is an abstraction and not concrete. You cannot draw a generic geometric shape. For that reason,
in the Geoshape class, the Draw method should also be abstract. There is an added benefit of an abstract
Draw in the base class. Derived types are forced to implement a specific Draw method. They are not
inheriting the Draw method of the base class, which does nothing:

public abstract void Draw();

Interface Polymorphism

Interface polymorphism employs base interfaces instead of base classes. The result is the same. Because it
has some implementation, the Geoshape class cannot be entirely replaced with an interface. However, the
Draw abstract method can be lifted from the class and placed in an IDraw interface:

using System;
using System.Collections.Generic;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(string [] shapeArray){
List<Geoshape> shapes=new List<Geoshape>();
Geoshape obj=null;
// partial listing

foreach(IDraw shape in shapes) {


shape.Draw();
}
}
}

public interface IDraw {


void Draw();
}

public abstract class Geoshape: IDraw {


public Geoshape() {
++count;
ID=count;
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

private static int count=0;


protected int ID=0;

public abstract void Draw();


}
// partial listing

New Modifier and Polymorphism

The new modifier interrupts normal polymorphism and can cause unexpected results. Unlike an overridden
member, the compiler will not delegate from a virtual member to a member that has the new modifier. They
are considered unrelated.

The following code demonstrates the potential problem. ZClass.MethodA method is virtual and polymorphic.
YClass.MethodA overrides ZClass.MethodA. XClass derives from YClass. In the XClass, the new modifier
defines an unrelated MethodA. XClass.MethodA is also marked avirtual. WClass.MethodA overrides
XClass.MethodA. ZClass.MethodA and YClass.MethodA define a group of related methods. XClass.MethodA
and WClass.MethodA define a second group. In Main, several related objects are instantiated. The derived
instances are cached in an array of ZClass references, which is an array of base class references. In the
loop, MethodA is called through the derived objects.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
ZClass [] zArray={
new ZClass(),
new YClass(),
new XClass(),
new WClass(),
new YClass(),
new ZClass() };
foreach(ZClass obj in zArray) {

obj.MethodA(); // polymorphic behavior


}
}
}

public class ZClass {


public virtual void MethodA(){
Console.WriteLine("ZClass.MethodA");
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class YClass: ZClass {


public override void MethodA(){
Console.WriteLine("YClass.MethodA");
}
}

public class XClass: YClass {


public new virtual void MethodA(){
Console.WriteLine("XClass.MethodA");
}
}

public class WClass: XClass {


public override void MethodA(){
Console.WriteLine("WClass.MethodA");
}
}
}

The following code shows the result of running the application. Notice that XClass.MethodA and
WClass.MethodA are not called. The new modifier on the XClass.MethodA method interrupts the
polymorphic hierarchy.

C:\ >newapp
ZClass.MethodA
YClass.MethodA
YClass.MethodA
YClass.MethodA
YClass.MethodA
ZClass.MethodA
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Casting
Casting a derived object to a base type is always safe. As shown in the previous section, this is the
common cast for polymorphism and is legitimate in all circumstances. Derived types extend base types.
Because derived types encompass everything about the base type, a derived-to-base-type cast is
guaranteed to be safe. You can even cast a derived instance to an abstract base class. This was
demonstrated earlier. Casting from a derived object to a base reference provides a base view of the instance.
You are limited to members of the base type. The refinements of the derived type are not visible through a
base reference to a derived instance, although the derived class implementation of an abstract base class
method will be visible. After the cast, the base reference is an alias to the original derived object.

Casting a value type to a base interface has different semantics. The result of casting a reference type to an
interface is an alias. However, when casting a value type to an interface, a separate entity is created.
Interfaces are reference types. Boxing always occurs when casting a value type to a reference type. This
includes casting a value type to an interface. Boxing creates a copy of the value type, which is placed on the
managed heap. The original and copy are unrelated. Changes to one will not affect the other.

In the following code, the ZStruct structure implements the IAdd interface. Structures are value types. The
IAdd.Increment method increments a counter. In Main, a ZStruct local variable is cast to an IAdd interface,
which is legitimate. Boxing happens, and a copy of the ZStruct is placed on the managed heap. Changes to
one will not affect the other. When the counts are displayed, the variables have different counts that confirm
their separate identities.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
XStruct val=new XStruct();
val.Increment();
IAdd obj=val;
val.Increment();
Console.WriteLine("Val: {0}",
val.Count);
Console.WriteLine("Obj: {0}",
obj.Count);
}
}

public interface IAdd {


void Increment();
int Count {
get;
}
}

public struct XStruct: IAdd {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void Increment() {


++propCount;
}

private int propCount;


public int Count {
get {
return propCount;

}
}
}
}

A base class or interface can be used as a function parameter or return value. In this circumstance, you can
substitute any related type for the function parameter or return value. There are three major reasons to use a
base class or interface as a parameter or return value:
 It generalizes a function call or return. The function parameter or return can be used with different
types.
 A specific parameter or return type may not be known at compile time. A base reference supports
late binding, where the type is selected at run time.
 Returning a base class or interface restricts access to an object. This is especially useful for
class libraries that want to hide internal implementation.

The following code is an example of a class library—albeit a rather small library. The library contains a single
class, which is the ZClass. It is marked as internal and visible solely within the class library. IExposed
defines the public face of the ZClass type and clients of the library. LibraryClass.Method returns a ZClass
instance through the IExposed public interface. This prevents clients from accessing the other methods of
the ZClass. Those methods are internal and reserved for use in the class library.

using System;
namespace Donis.CSharpBook{

public class LibraryClass{


public IExposed GetSomething() {
ZClass obj=new ZClass();
// do something
obj.InternalA();
obj.InternalB();
obj.MethodA();
return obj;
}
}

public interface IExposed {


void MethodA();
void MethodB();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

internal class ZClass: IExposed {


public void MethodA() {
}

public void MethodB() {


}

public void InternalA() {


}

public void InternalB() {


}

}
}

As shown several times in this chapter, casting a derived object to a base reference is safe. However, you
cannot implicitly cast a base object to a derived reference. The derived type might have members not defined
in the base type. Therefore, the derived reference might access members not available to the base object.
For this reason, the cast is unsafe. An explicit cast can force the compiler to accept the unsafe cast of a
base object to a derived reference. Because the cast remains unsafe, an exception is raised at run time at
the cast. You have simply deferred the problem from compile time to run time.

This code raises an exception at run time because of an invalid cast:

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
ZClass obj=new ZClass();

// Fails at compile time


// YClass alias=obj;

// Fails at run time


YClass alias=(YClass) obj;

obj.MethodA();
obj.MethodB();

}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class ZClass {


public virtual void MethodA() {
}
public virtual void MethodB() {
}
}

public class YClass: ZClass {


public override void MethodA() {
}
}
}

Inheritance Operators

The is and as operators are convenient tools for testing the pedigree of an instance. These operators confirm
the presence of a class or interface somewhere in the hierarchy of an instance. This confirmation is useful for
promoting type-safe function calls. You can also develop algorithms that vary based on class types, for
example, to display extra menu items for managers.

This is the syntax of the is operator:


 bool result=expression is type;

The is operator returns true if the expression type and target type are related. If the expression type and
target type are unrelated, false is returned.

The following code displays a menu. If employee is a manager, additional menu items are displayed. The is
operator confirms that the employee is a manager.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
Manager person=new Manager("Accounting");
Console.WriteLine("[Menu]\n");
Console.WriteLine("Task 1");
Console.WriteLine("Task 2");
if(person is IManager) {
IManager mgr=person;
Console.WriteLine("\n[{0} Menu]\n",
mgr.Department);
Console.WriteLine("Task 3");
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public interface IManager {


string Department {
get;
}
}

public class Employee {


}

public class SalariedEmployee: Employee {


}

public class Manager: SalariedEmployee, IManager {

public Manager(string dept) {


propDepartment=dept;
}

private string propDepartment;


public string Department {

get {
return propDepartment;
}
}
}
}

This is the syntax of the as operator:


 typeinstance=expression as type

The as operator evaluates an expression in the context of the target type. If the expression type and target
type are related, an instance of the target type is returned. If the expression type and target type are
unrelated, null is returned.

Here is the previous code rewritten with the as operator (this is a partial listing):

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
Manager person=new Manager("Accounting");
Console.WriteLine("[Menu]\n");
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("Task 1");
Console.WriteLine("Task 2");
IManager mgr=person as IManager;
if(mgr != null) {
Console.WriteLine("\n[{0} Menu]\n",
mgr.Department);
Console.WriteLine("Task 3");
}
}
}

// Partial listing
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Attribute Inheritance
By default, custom attributes are not inheritable. The AttributeUsage attribute can make an attribute
inheritable. For the AttributeUsage attribute, set the Inherited option to true to enable inheritance.

Inheriting classes with attributes sometimes can cause interesting behavior. In the following code, ZClass is
the base class, and YClass is the derived class. Both classes are adorned with the PrincipalPermission
attribute, which identifies the users or roles that can call functions in a particular class. In the example, the
ZClass function can be called by managers; YClass function calls are limited to accountants. The YClass
inherits MethodA from the ZClass. Who can call YClass.MethodA? Because MethodA is not overridden in
the derived class, YClass is relying on the implementation of MethodA in the base class, which includes any
applicable attributes. Therefore, only managers can call the YClass.MethodA, whereas YClass.MethodB is
available to accountants and not managers, as demonstrated in the following code:

using System;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
using System.Threading;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
GenericIdentity g=new GenericIdentity("Person1");
GenericPrincipal p=new GenericPrincipal(g,
new string [] {"Manager"});
Thread.CurrentPrincipal=p;
ZClass.MethodA();
YClass.MethodA();
// YClass.MethodB(); // Security exception.
}
}

[PrincipalPermission(SecurityAction.Demand,
Role="Manager")]
public class ZClass {

static public void MethodA() {


Console.WriteLine("ZClass.MethodA");
}
}

[PrincipalPermission(SecurityAction.Demand,
Role="Accountant")]
public class YClass: ZClass {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

static public void MethodB() {


Console.WriteLine("ZClass.MethodB");
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Visual Studio .NET 2005


The next chapter introduces Visual Studio .NET 2005, including an overview and walk-through. Visual Studio
is an integrated development environment for developing managed code in a variety of languages. It is an
environment for creating secure, robust, and scalable applications. In addition, Visual Studio hosts a variety
of rapid application development tools that facilitate the quick and painless development of managed
applications.

Visual Studio .NET 2005 includes several enhancements. Improved editing capabilities have been added,
such as Code Expansion and Auto IntelliSense. Code snippets have also been improved. Refactoring is an
exciting new feature and the friend of every developer. New build alternatives such as MSBuild are available
for professional developers. Microsoft has also added a pantheon of new project and template types, such as
Smart Devices, to Visual Studio. These new Visual Studio 2005 options provide developers with additional
choices for managed development.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Part II: Core Skills


Chapter List

Chapter 4: Introduction to Visual Studio 2005

Chapter 5: Arrays and Collections

Chapter 6: Generics

Chapter 7: Iterators
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 4: Introduction to Visual Studio 2005


Overview
Microsoft Visual Studio 2005 is the centerpiece of a suite of products for developing, debugging, and
deploying managed applications from Microsoft. Visual Studio 2005 is the latest evolution of Visual Studio
and includes several enhancements that improve developer productivity, effectiveness, and collaboration.
Code snippets, class diagrams, IDE Navigator, MSBuild, and ClickOnce are some of the noteworthy
additions to Visual Studio. Visual Class 2005 also has several new debugging features, which are discussed
in Chapter 12, "Debugging with Visual Studio 2005." Tools for developers collaborating on software systems
have been enriched with introduction of Visual Studio Team System. Working with Microsoft Visual Studio
2005 Team System from Microsoft Press and authored by Richard Hundhausen is a great resource on
Visual 2005 Team System. Visual Studio 2005 is a worthy successor to a strong legacy of Visual Studio
products.

Visual Studio 2005 has additional build and deployment options. The Microsoft Build Engine (MSBuild) is a
new build environment, which is integrated into Visual Studio 2005, but also available separately. MSBuild
projects are XML files that choreograph the build process of an application. ClickOnce Deployment deploys a
desktop application from a centralized server and has several benefits when compared with traditional
Windows Installer technology, such as self-updating. It is the perfect merger of desktop and Web
technology, which provides hands-free distribution of desktop applications. Finally, Windows Installer
technology remains available and is improved with the introduction of Microsoft Installer 2.0.

Visual Studio 2005 is more online-enabled than before. Developers can easily participate in the developer
community, submit questions to Microsoft, and visit a variety of online resources. In addition, Help is now
online-enabled.

With the exception of debugging, this chapter demonstrates many of the new features of Visual Studio 2005.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Integrated Development Environment


Visual Studio 2005 is an integrated development environment (IDE) for developing and maintaining managed,
native, and mixed-mode applications. A variety of project templates are available to create a diverse
assortment of applications. There are templates for Microsoft Windows Forms, Console, ASP.NET Web
Site, ASP.NET Web Service, SmartPhone2003, Windows CE 5.0, and other types of applications. There are
templates that target specific devices, including mobile devices. In addition, developers can choose the
language of their choice, including C#, Microsoft Visual Basic .NET, and Managed C++.

The Visual Studio 2005 IDE has many rapid application development (RAD) tools. The Visual Studio Code
Editor, Microsoft IntelliSense, Solution Explorer, Class View, Object Browser, and the class diagram are
essential components of the user interface and contribute to improved developer productivity, accuracy, and
efficiency. Many of the tools have been updated, such as IntelliSense and the Object Browser. Other tools,
including the class diagram, are new.

Start Page

Start Page is the gateway screen into Visual Studio. For many developers, the Start Page is the first window
presented in Visual Studio. The Start Page, shown in Figure 4-1, is completely redesigned in Visual Studio
2005. Visual Studio normally starts with the Start Page. If the page is not visible, open the Start Page from
the View Menu. Select the Other Windows submenu and then the Start Page menu command.

Figure 4-1: Visual Studio 2005 Start Page

The redesigned Start Page has four panes:

 Recent Projects This pane lists the recently opened projects. Select an item in the project list to
open that project. The Open and Create buttons at the bottom of this pane open or create a new
project.

 MSDN: Visual C# This pane contains links to recent news on Visual Studio and C#. Each topic
is previewed. Click the related link to view the complete article.

 Getting Started This pane contains helpful links for new Visual Studio developers.

 Visual Studio Headlines This pane allows developers to submit feedback directly to Microsoft.

Community Integration

The Visual Studio community is an important resource for both novice and experienced developers of
managed and unmanaged code. The availability of the aggregate knowledge of developers is of great benefit
to everyone. Visual Studio 2005 has a menu dedicated to the developer community. The Community menu
provides convenient access to the developer community, which makes participation easier. The Community
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

menu offers the following command choices:

 Ask a Question This command redirects developers to the Microsoft Community Forum, where
questions are posted to Microsoft. You can also view previous posts and responses.

 Check Question Status This command redirects developers to the Microsoft Community Forum,
where the status of previous posts can be checked.

 Send Feedback This command redirects developers to the MSDN Product Feedback Center.

 Developer Center This command redirects developers to the Microsoft Visual C# Development
Center, where C#-related topics are discussed.

 Codezone Community This command redirects users to the Microsoft Codezone page, which
features a Web site each month that makes substantial technological contributions to the
developer community. It also lists number of online communities.

 Partner Products Catalog This command redirects users to the Microsoft Visual Studio Industry
Partner program. You can search for a particular Microsoft partner, product, or solution from this
page.

 Community Search This command searches online for downloadable project templates, code
snippets, macros, and other helpful resources.

Creating Projects

Developing an application in Visual Studio typically starts with the creation of a project. Projects are the
basic organization component of Visual Studio, in which files, resources, reference, and other constituents of
an application are grouped. Related projects are sometimes grouped into solutions, which can contain
projects of different types and languages. For example, during the development cycle, it is common to group
applications and related libraries in the same solution. The option to add a new project to an open solution or
creating the project in a new solution has changed. Figure 4-2 shows the New Project dialog box. Toward the
bottom of the dialog box is a drop-down list box containing the choices Create New Solution and Add To
Solution. This option is not available unless a solution is already open. If desired, select the Create Directory
For Solution option box to create a separate directory for the solution.

Figure 4-2: New Project dialog box

Solution Explorer

You can configure both solutions and projects from the Solution Explorer window. If not visible, display the
Solution Explorer window from the View menu. Solution Explorer is shown in Figure 4-3. In this example, the
solution is Airline Seats, which has two projects: Airline Seats and Person. Developers can change the
properties of a solution or any project. From Solution Explorer, open the shortcut menu on the solution or
project icon and then select the Properties menu item. In the Project properties, configure the application
settings, configure the build environment, configure debug settings, resources, define default application
settings, view or add references to the project, publish the ClickOnce manifests, or sign assemblies. The
user interface of Project properties has changed and been renamed as the Project Designer window, shown
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

in Figure 4-4.

Figure 4-3: Solution Explorer window

Figure 4-4: Project Designer window

In the Solution Explorer window, the AssemblyInfo.cs file has been moved to the Properties folder. The
AssemblyInfo.cs file contains assembly attributes that define assembly level metadata, such as the version
number and culture.

The location of Solution Explorer and some other Visual Studio windows default to a docking window. In
Visual Studio 2005, these windows can be tabbed or set to auto hide, which is an improvement. Figure 4-5
shows Solution Explorer in a tabbed window. Display the shortcut menu on the window header to change the
alignment to Tabbed Document.

Figure 4-5: Solution Explorer as a tabbed window

Project Types
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

In Visual Studio 2005, a wide assortment of projects are available. Common projects, such as a Windows
Application and Class Library, are still available. However, new project types have also been introduced. Table
4-1 lists the standard project types available.
Table 4-1:
Project Types

Te De
mp scr
lat ipti
e on
Na
me

Wi Cre
nd ate
ow a
s Wi
Ap nd
plic ow
ati s
on For
ms
de
skt
op
ap
plic
ati
on
usi
ng
thi
s
te
mp
lat
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-1:
Project Types

Te De
mp scr
lat ipti
e on
Na
me

Cla Cre
ss ate
Lib a
rar ma
y na
ge
d
dy
na
mi
c-li
nk
libr
ary
(DL
L)
usi
ng
thi
s
te
mp
lat
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-1:
Project Types

Te De
mp scr
lat ipti
e on
Na
me

Wi Cre
nd ate
ow cu
s sto
Co m
ntr co
ol ntr
Lib ols
rar for
y Wi
nd
ow
s
For
ms
ap
plic
ati
on
s
usi
ng
thi
s
te
mp
lat
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-1:
Project Types

Te De
mp scr
lat ipti
e on
Na
me

We Cre
b ate
Co cu
ntr sto
ol m
Lib We
rar b
y ser
ver
co
ntr
ols
for
AS
P.
NE
T
ap
plic
ati
on
s
usi
ng
thi
s
te
mp
lat
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-1:
Project Types

Te De
mp scr
lat ipti
e on
Na
me

Co Cre
ns ate
ole a
Ap co
plic ns
ati ole
on ap
plic
ati
on
usi
ng
thi
s
te
mp
lat
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-1:
Project Types

Te De
mp scr
lat ipti
e on
Na
me

Wi Cre
nd ate
ow a
s Wi
Ser nd
vic ow
e s
Ser
vic
e
ap
plic
ati
on,
whi
ch
is
a
da
em
on
pro
ce
ss
tha
t
ca
n
run
acr
os
s
log
on
se
ssi
on
s,
usi
ng
thi
s
te
mp
lat
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-1:
Project Types

Te De
mp scr
lat ipti
e on
Na
me

Em Cre
pty ate
Pro a
jec cu
t sto
m
pro
jec
t,
whi
ch
is
dev
oid
of
the
nor
ma
l
file
s,
wit
h
thi
s
te
mp
lat
e.
Th
e
dev
elo
per
is
res
po
nsi
ble
for
buil
din
g
the
pro
jec
t
fro
m
es
se
nti
ally
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-1:
Project Types

Te De
mp scr
lat ipti
e on
Na
me

Cry Cre
sta ate
l a
Re Wi
por nd
ts ow
Ap s
plic For
ati ms
on ap
plic
ati
on
tha
t
co
nta
ins
a
Cry
sta
l
Re
por
t
usi
ng
thi
s
te
mp
lat
e.

Web applications are no longer included with the standard templates detailed in Table 4-1. Web applications
are created from the File menu. Select the New submenu and the Web Site menu command. The New Web
Site dialog box appears, displaying Web application templates. Table 4-2 lists the available Web templates.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-2:
Web Project
Types
Open table as
spreadsheet

Te De
mp scr
lat ipti
e on

AS Cre
P. ate
NE an
T AS
We P.
b NE
Sit T
e We
b
ap
plic
ati
on
usi
ng
thi
s
te
mp
lat
e.

AS Cre
P. ate
NE an
T AS
We P.
b NE
Ser T
vic We
e b
Ser
vic
e
usi
ng
thi
s
te
mp
lat
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-2:
Web Project
Types
Open table as
spreadsheet

Te De
mp scr
lat ipti
e on

Per Cre
so ate
nal an
We AS
b P.
Sit NE
e T
Sta 2.0
rter sta
Kit rter
We
b
sit
e,
incl
udi
ng
an
initi
al
ho
me
pa
ge,
usi
ng
thi
s
te
mp
lat
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-2:
Web Project
Types
Open table as
spreadsheet

Te De
mp scr
lat ipti
e on

Em Cre
pty ate
We a
b cu
Sit sto
e m
We
b
pro
jec
t,
whi
ch
is
dev
oid
of
the
nor
ma
l
file
s,
usi
ng
thi
s
te
mp
lat
e.
Th
e
dev
elo
per
is
res
po
nsi
ble
for
buil
din
g
the
We
b
sit
e
fro
m
es
se
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-2:
Web Project
Types
Open table as
spreadsheet

Te De
mp scr
lat ipti
e on

AS Cre
P. ate
NE a
T ne
Cry w
sta We
l b
Re sit
por e
ts tha
We t
b incl
Sit ud
e es
a
sa
mp
le
Cry
sta
l
Re
por
t
usi
ng
thi
s
te
mp
lat
e.

Visual Studio 2005 also includes a variety of special-purpose project templates. Some of these templates
are detailed in Table 4-3.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-3:
Special-Purp
ose Project
Templates

Te De
mp scr
lat ipti
e on

Sm Thi
art s
De pro
vic jec
e t
Pro typ
jec e
t incl
Ty ud
pe es
the
Po
ck
et
PC
20
03,
Sm
art
ph
on
e
20
03,
an
d
Wi
nd
ow
s
CE
5.0
cat
eg
ory
of
te
mp
lat
es,
whi
ch
tar
get
mo
bile
an
d
em
be
dd
ed
dev
ice
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-3:
Special-Purp
ose Project
Templates

Te De
mp scr
lat ipti
e on

SQ Cre
L ate
Ser a
ver dat
Pro ab
jec as
t e
pro
jec
t
tar
get
ing
a
Mi
cro
sof
t
SQ
L
Ser
ver
20
05
dat
ab
as
e
usi
ng
thi
s
te
mp
lat
e.
In
thi
s
pro
jec
t,
dev
elo
per
s
ca
n
cre
ate
a
vari
ety
of
cla
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-3:
Special-Purp
ose Project
Templates

Te De
mp scr
lat ipti
e on

Sta Thi
rter s
Kit pro
Pro jec
jec t
t typ
Ty e
pe incl
s ud
es
the
Scr
ee
n
Sa
ver
Sta
rter
Kit
an
d
Mo
vie
Col
lec
tio
n
Sta
rter
Kit
te
mp
lat
es.
Th
e
Scr
ee
n
Sa
ver
Sta
rter
Kit
is
a
sa
mp
le
scr
ee
n
sav
er
tha
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-3:
Special-Purp
ose Project
Templates

Te De
mp scr
lat ipti
e on

Set Thi
up s
An typ
d e
De incl
vel ud
op es
me the
nt Set
Pro up,
jec We
t b
Ty Set
pe up,
Me
rge
Mo
dul
e,
Set
up
Wi
zar
d,
CA
B,
an
d
Sm
art
De
vic
e
CA
B
pro
jec
t
te
mp
lat
es.
Th
es
e
are
te
mp
lat
es
for
cre
ati
ng
set
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-3:
Special-Purp
ose Project
Templates

Te De
mp scr
lat ipti
e on

Ext Ext
en en
sibi sibi
lity lity
te
mp
lat
es
incl
ud
e
the
Vis
ual
Stu
dio
Ad
d-I
n
an
d
Sh
are
d
Ad
d-I
n
te
mp
lat
es.
Th
es
e
are
te
mp
lat
es
for
cre
ati
ng
ad
d-i
ns,
whi
ch
are
ma
na
ge
d
DL
Ls
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Adding References

Developers add application references to projects to access foreign types contained in those applications.
The Add Reference dialog box in Visual Studio 2005 has some new windows. To add a reference from the
Project menu, choose the Add Reference menu command. Add Web Reference adds a reference to a Web
service application. References can also be added from Solution Explorer. Open a shortcut menu on the
Reference folder. From the menu, choose the Add Reference or Add Web Reference menu command. The
Add Reference command now has five windows. References can be added from any of the windows.
 The .NET window lists system libraries of the Common Language Runtime (CLR) and .NET
Framework Class Library.
 The COM window lists registered COM servers, which contain unmanaged code.
 The Projects window lists references to other projects in the current solution.
 The Browse Window allows developers to browse for references.
 The Recent window lists recent references that have been added to this solution.

Data Menu

In Visual Studio 2005, the Data menu has been added to the menu system. From this menu, developers can
add a new data source to the project or show available data sources. When adding new data sources, you
are presented with the Data Source Configuration Wizard, shown in Figure 4-6.

Figure 4-6: Data Source Configuration Wizard

The Data Source Configuration Wizard works with three types of data sources:
 A Database data source is a connection to a database, which returns a dataset to the application.
A dataset is a disconnected client-side representation of data at the data source.
 A Web Service data source retrieves data from a Web service. This option adds a Web reference
to the specified Web service application.
 An Object data source retrieves data from a managed object.

Managing Windows in Visual Studio

Visual Studio offers an array of windows for a variety of purposes. The potential windows include Code Editor
windows, a variety of toolboxes, Server Explorer, Solution Explorer, Property windows, and much more. Most
of these windows are movable, but can also be docked. In Visual Studio, it has been easy to misplace
windows or muddle the interface while attempting to dock a window. Visual Studio 2005 provides visual clues
to aid in moving and docking windows, including a guide diamond with docking arrows to help dock windows
correctly.

Switching between project files and windows is also improved. Visual Studio 2005 has the IDE Navigator to
help toggle between open files and windows. Pressing Ctrl+Tab opens the IDE Navigator. Once there, you
can navigate between open files and windows. This IDE Navigator dialog box is shown in Figure 4-7. When
the window is open, use Ctrl+arrow keys or Ctrl+Tab to navigate the items in the window.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-7: IDE Navigator

AutoRecover

AutoRecover is another feature that is added to Visual Studio 2005. This option periodically saves a project
and prevents the loss of data when Visual Studio is exited abnormally. Figure 4-8 shows the AutoRecover
window of the Options dialog box. Open this window from the Tools menu and Options menu command.
AutoRecover is found in the Environment settings. In the AutoRecover window, set the frequency of auto
saves and the length of time backups are retained.

Figure 4-8: AutoRecover window

When re-entering Visual Studio after an abnormal termination, the Microsoft Visual Studio Recovered Files
dialog box automatically displays. (See Figure 4-9.) In the dialog box, confirm the files to recover.

Figure 4-9: Microsoft Visual Studio Recovered Files dialog box


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Class Hierarchies
Visual Studio 2005 offers several visual tools that depict class hierarchies. These tools also depict individual
types, such as classes, structures, and interfaces. This includes showing relationships between types,
including inheritance. The Class View and Object Browser have been updated with new features. The class
diagram is new and adds a capable object-modeling tool to Visual Studio 2005.

Class View Window

The Class View window provides a visual representation of the types included in projects of the current
solution. Expand the project and then expand class nodes to display the class hierarchy. Each item in the
class hierarchy has a shortcut menu with helpful commands. For example, the shortcut menu can display
classes in a class diagram. The Class View window can now show classes in referenced applications. Open
the Project References folder to find references and view their classes. Figure 4-10 shows the Class View
window, including the Project Reference folder. If the Class View window is closed, open it from the View
menu.

Figure 4-10: Class View window

The Class View window has two panes: The top pane contains the hierarchy, whereas the bottom pane
displays the details of whatever item is selected in the class hierarchy. Across the top of the class view
window are four icons: New Folder, Forward, Back, and Class View Settings. Beneath the icons is the
search combo box, which is used to search the hierarchy for a symbol. This is especially helpful for
extensive class hierarchies. Type the search text and press Enter to initiate a search. All symbols—such as
classes, methods, fields, and properties, which contain some part of the search text—are returned in the
Class View window.

Object Browser

The Object Browser is an alternative to the Class View window. The Object Browser displays the class
hierarchy of the current project, referenced applications, and system libraries. If the Object Browser is not
visible, open it from the View menu. Figure 4-11 shows the Object Browser window.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-11: Object Browser window

The Object Browser window contains three panes. The left pane contains the class hierarchy. The two right
panes list the members and a description of the selected type, respectively. The Object Browser toolbar has
the Browser Scope, Edit Custom Component Set, Back, Forward, Add Reference, and Object Browser
Settings buttons. The Browser Scope button filters the class hierarchy. You can display classes from the
current solution, custom component set, .NET Framework, or all classes. Browse a class in a foreign
assembly using the Edit Custom Component Set button. The Add Reference button adds a reference to the
project for the application of the selected type. Above the class hierarchy is a combo box for searching. Use
the search box to find specific types in the class hierarchy.

Class Diagram

Visual Studio 2005 introduces the class diagram. Class diagrams are created by the Class Designer, which
is an internal component of Visual Studio 2005. Developers can model object-oriented applications using
class diagrams. This tool will assuredly continue to evolve in the future and is destined to be a developer
favorite. For me, it has already become one of the most frequently used tools in Visual Studio. Class
diagrams present a visual representation of a type and type hierarchy. It's important to note that class
diagrams are not static. Developers can add new types, create new relationships, insert members, delete
members, and much more. The class diagram is synchronized with the source code of the application.
Changes to types modeled in the class diagram are immediately reflected in code. Conversely, changes in
the source code immediately appear in a relevant class diagram. Therefore, the application and diagram
consistently remain in sync. Updated design documents are one of the seminal benefits of the class
diagram. Where do design documents vanish to after the project implementation has begun? This is a
common problem that plagues developers of object-oriented applications. For many applications, original
design documents are not available or have not been updated as the software evolved. Often, design
documents quickly become stale and sometimes vanish shortly after the implementation phase. Class
diagrams help update these important documents, including changes to the original design. Conversely,
class diagrams can be saved as images preserving a snapshot of the design. With the class design, the
design and implementation phase is truly iterative, which translates into better-developed applications. It also
makes maintaining applications exponentially easier.

Class diagrams provide a high-level perspective of an application, which is beneficial throughout the life cycle
of the application. This is particularly useful with complex systems that entail hundreds of classes and
dozens of relationships. Reviewing code in this circumstance is a tedious, time-consuming process. It also
does not transfer the clarity of understanding that only a synoptic view of an application affords. Class
diagrams present a general overview, in which introspection is available as needed. This information is
particularly invaluable to programmers maintaining an application. The class diagram represents a new
starting point for anyone who has to maintain a product with Visual Studio.

The entire class hierarchy can be presented in the class diagram. However, developers control how much
information is presented in the class diagram. You can view one class, a dozen types, or everything in the
class diagram. It depends on developer discretion. In addition, multiple class diagrams can be added to
group-related types or simply to reduce the amount of information presented in any particular diagram. In the
diagram, you can view all types: classes, structures, and interfaces. Relationships between types, such as
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

inheritance and association, are also available.

In Visual Studio 2005, there are several ways to create a class diagram. One way is to select the Add New
Item command on the Project menu. From the Add New Item dialog box, choose Class Diagram. In the edit
box, name the class diagram. (Class diagram files are automatically given the .cd file extension.) You can
also open a new class diagram from the Solution Explorer or Class View window. In Solution Explorer, open
a shortcut menu for the project name or source file and then choose View Class Diagram. This creates a
new class diagram that contains all the classes found in the project or source file. In Class View, open a
shortcut menu for the project name or class and choose View Class Diagram.

Class diagrams have a surface. There are several ways to add existing or new types to this surface, as listed
here. Types added to the class diagram surface are represented by shapes.
 Drag a type from the Class View window or the Object Browser to the class diagram surface.
 Drag a file from Solution Explorer to the class diagram surface.
 Add a new type from the Class Designer toolbox.

Figure 4-12 shows a class diagram with a single class on the surface. The single class is contained in a
shape. Shapes have a header and a details pane. Click once on the class label in the shape header to
change the name of the class. Double-click the class label to view the related source code. There is also an
expand button or collapse button. The expand button is the double-down arrow and shows the details of the
type. The collapse button is the double-up arrow and hides the details of the type. The expand and collapse
buttons toggle, depending on whether the details are expanded or collapsed.

Figure 4-12: Class diagram that contains a single class

Types can be removed from a class diagram. Select the shape for the type and open the shortcut menu from
the class header. Choose Remove From Diagram. The type is removed from the diagram, but remains in the
program. The Delete Code option is not the same. This option not only removes the class from the class
diagram but also deletes it from the project. An easier method of removing a class from the diagram is
simply to select the type and then press Delete.

The class detail shows the members of the class. Members are grouped by type, where fields, methods,
properties, and other member types are grouped. Each group can be collapsed or expanded. From the
shortcut menu, members can be refactored, deleted, copied, pasted, and more. Members can also be
viewed and maintained in the Class Details window, as shown in Figure 4-13. If the Class Details window is
not visible, display it from the shortcut menu of any shape in the class diagram.

Figure 4-13: Class Details window

In the Class Details window, you can view, change, or add new members to the class. You can change the
name, type, or accessibility of a type. The Hide option hides or displays a member in the class diagram. The
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

shortcut menu of the class header has the Show All Members command, which shows all members,
including any hidden members.

The Class Details toolbox has four buttons. The New Member button adds a Method, Property, Field, Event,
Constructor, Destructor or constant to a class. The Navigate To Methods button selects that method
category in the Class Details window. This is helpful for large classes with dozens of members. The final
three buttons navigate to properties, fields, and events, respectively.

Class Diagram Toolbox


Class diagrams have a specific toolbox, as shown in Figure 4-14. The top buttons of the toolbox add new
types to the application and the class diagram. You can add a new class, enumeration, interface, abstract
class, structure, and delegate. Double-clicking the associated button adds the new type to the application,
which is then displayed in the class diagram. Alternatively, you can drag the related button from the toolbox
onto the class diagram surface to add the new type. The New Type dialog box is displayed when a new type
is added. (See Figure 4-15.) The type name, accessibility, and file name can be entered into the dialog box.

Figure 4-14: Class Diagram toolbox

Figure 4-15: Add New Interface Dialog box

After the buttons for adding new types, the inheritance and association buttons appear next on the toolbox.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The inheritance button creates an inheritance line, which links a base class and a derived class. The
association button creates an association line that defines the relationship between an embedded class and
the owning class. The comment button is the last item on the toolbox and adds comments to the class
diagram.

Inheritance

Inheritance is visualized in the class diagram. Inheritance lines depict the base-to-derived-type relationship.
Implicit inheritance of System.Object and System.ValueType are not shown in the class diagram. Figure 4-16
shows class inheritance in the class diagram. In the figure, XClass1 inherits the ZClass class. The
inheritance line is the arrow that starts at the base class and ends at the derived class. Delete the
inheritance line to remove the inheritance relationship. Alternatively, you can remove the inheritance line from
the shortcut menu. Open a shortcut menu on the inheritance line and then select Delete Code.

Figure 4-16: Class inheritance in the class diagram

You can define new base and derived classes in the class diagram. Select the inheritance line in the
toolbox. Drag the inheritance line from the base class to the derived class. This assumes that both the base
and derived classes are already on the class diagram. If the base class is not on the class diagram, drag the
class from the Class View window onto the derived class shape in the class diagram. This both creates the
inheritance relationship and adds the derived class to the class diagram.

Interface inheritance and class inheritance are similarly shown in the class diagram. Add interface
inheritance to a type using the inheritance line. To fully implement the interface, the class diagram adds
stubs for each member of the interface in the derived type. In the Code Editor, developers can replace the
stubs with the appropriate implementation. Interface inheritance is not depicted as an inheritance line.
Instead, interface inheritance is displayed as a lollipop atop the derived type. This is displayed in Figure 4-17,
in which the ZClass class inherits the IA interface. You can change how the interface is implemented using
the shortcut menu of the interface label. This includes whether to implement the interface implicitly or
explicitly.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-17: Interface inheritance in the class diagram

Relationship lines, which are the inheritance and association lines, can be rerouted. Simply click the line
and drag the mouse to reroute. Lines can be rerouted multiple times. Figure 4-18 shows a rerouted
inheritance line. Dragging the endpoints of the line repositions the relationship line on the class shape. The
mouse cursor looks like a cross when positioned over the endpoint of a relationship line. The shortcut menu
of a relationship line can hide, reroute, delete, or display the properties of the relationship.

Figure 4-18: Rerouted inheritance line

Class diagrams can find the base or derived class of a type. Open the shortcut menu on the class shape
header. The Show Base Class command finds the base class of the type in the class diagram. If not already
present, the base class is added to the class diagram. The Show Derived Classes command selects the
derived type.

Association

Association lines define a "has-a" relationship, in which a class owns another class. The class is embedded
as a property. Figure 4-19 shows an association relationship in the class diagram. In the figure, the XClass
class owns the YClass class, which is embedded as a property. The association line looks slightly different
from the inheritance line.

Figure 4-19: Association relationship

Select the association line in the class diagram toolbox to create a new relationship. Both classes and
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

interfaces can be embedded. Drag the association line from the owning type to the embedded type. A
property is created in the owning class for the embedded class. You can then switch to the Code Editor and
implement the property, which should return an instance of the embedded type. When the association line is
visible, the embedded member is not shown in the class details pane of the shape. If desired, you can show
the embedded member and hide the association line. Open the shortcut menu of the association line and
select the Show As Property command. To reverse that decision, open the shortcut menu and select Show
As Association.

Class Diagram Walkthrough

This walkthrough demonstrates the class diagram—particularly creating new types and relationships.
1. Create a new class library. In Visual Studio 2005, from the File menu, choose the New submenu
to create a new project. You can also accomplish this by clicking New Project on the Standard
toolbar. The Class Library template is selected from a C# project. The project is named Personnel.
2. Add a class diagram to the project. Open the Project menu and select the Add New Item menu
item. From the Add New Item dialog box, add a class diagram. The class diagram is named
Employee.
3. Add a new interface using the class diagram toolbox. Name the interface IEmployee. Other
defaults are accepted.
4. Add a new abstract class using the class diagram toolbox. Name the class IEmployee.
5. Add another class using the class diagram toolbox. Name this class HourlyEmployee.
6. Add a new struct using the class diagram toolbox. Name the struct Name. Structs are depicted in
the class diagram as rectangles with square corners.

From the Class Details window, add three members to the IEmployee interface. (See Figure 4-20.) The
EmployeeInfo method returns a string. The Age property is an integer and gets and sets the age of an
employee. Finally, the Fullname property is of the Name type and gets the Employee name.

Figure 4-20: IEmployee interface details

The Employee class should inherit and implement the IEmployee interface. Select the inheritance line in the
class diagram toolbox. Drag the inheritance line from the Employee class to the IEmployee interface. The
interface members now appear in the class details of the Employee class. In addition, Employee is given the
stubbed implementations of the interface members:

public abstract class Employee : IEmployee


{
#region IEmployee Members

public int Age


{
get
{
throw new Exception(
"The method or operation is not implemented.");
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

set
{

throw new Exception(


"The method or operation is not implemented.");
}
}

// Partial listing

Derived types of the Employee class must have a calculate pay operation. Add an abstract CalculatePay
method to the Employee class. The method returns a decimal. In the header of the Employee class, open a
shortcut menu. Select the Add submenu and the Method menu command. Name the new method
CalculatePay. In the Class Details window, set decimal as the return type. The method should be abstract.
Open the shortcut menu for the CalculatePay method and change the Inheritance Modifier to abstract. A
message box is displayed asking you to confirm this decision. Click Yes.

The HourlyEmployee class should inherit the Employee class. This relationship is created with the
inheritance line. Drag the inheritance line from the HourlyEmployee class to the Employee class.

Finally, add a Pay method to the HourlyEmployee class. The Pay method has a single parameter, which is
the hours worked. In the Class Details window, expand the row for the Pay method to expose the Add
Parameter item. Select the Add Parameter row and enter Hours as the parameter name. Change the type to
decimal. To complete the class, add a HourlyRate property to the class. It is a decimal type.

The Name struct has two string properties: FirstName and LastName. Both properties can be added in the
Class Details window.

The final class diagram for the Personnel application is shown in Figure 4-21.

Figure 4-21: Class diagram of the Personnel library

This is code created per the class diagram. The functions are stubbed. Implementing the stubbed methods
is the only remaining step:

public interface IEmployee


{
int Age
{
get;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

set;
}

Name Fullname
{
get;
set;
}

string EmployeeInfo();
}

public struct Name


{
public string FirstName
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}

public string LastName


{
get
{
throw new System.NotImplementedException();
}
set
{
}
}
}

public abstract class Employee : IEmployee


{
#region IEmployee Members

public int Age


{
get
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

{
throw new Exception(
"The method or operation is not implemented.");

}
set
{
throw new Exception(
"The method or operation is not implemented.");
}
}

public Name Fullname


{
get
{
throw new Exception(
"The method or operation is not implemented.");
}
set
{
throw new Exception(
"The method or operation is not implemented.");
}
}

public string EmployeeInfo()


{
throw new Exception(
"The method or operation is not implemented.");
}

#endregion

public abstract decimal CalculatePay();


}

public class HourlyEmployee : Employee


{
public decimal HourlyRate
{
get
{
throw new System.NotImplementedException();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
set
{
}
}

public override decimal CalculatePay()


{
throw new Exception(
"The method or operation is not implemented.");
}

public void Pay(decimal Hours)


{
throw new System.NotImplementedException();
}
}

Error List Window

The Error List window is new to Visual Studio 2005. It displays edit and compile errors, warnings, and
general messages. Unique icons are assigned to each type of message. For example, error messages are
decorated with a red circle that contains an x. If there are compile errors, compiling a program automatically
displays the Error List window. (See Figure 4-22.) You can also display the Error List window from the View
menu.

Figure 4-22: Error List window

The Error List window displays different categories of messages. The Error, Warning, and General buttons
hide or show a particular category of messages. The Error List buttons also indicate the number of
messages in each category. For each error, the error number, description, and location are shown.
Double-clicking an error message in the error list will jump to the related source code. In addition, you can
use the column headers to sort the error list. Column headers can be dragged to change column order.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Code Editor
In Visual Studio 2005, the Code Editor has been enhanced. Developers can add, format, and edit code with
the Code Editor. Code is often organized by file, region, and color. Some of the improvements to the Code
Editor include better IntelliSense, code snippets, smart tags, and additional formatting options.

IntelliSense

IntelliSense helps developers enter code correctly and efficiently. It minimizes the keystrokes required to
enter code while improving developer accuracy. IntelliSense is available in both the Code Editor and the
immediate mode command window. IntelliSense is actually a group of related features that includes the
completion list, parameter information, quick info, and complete word.

IntelliSense is a dynamic drop-down list called the completion list and appears as developers type new
commands or words. The completion list automatically appears after a space separator or dot for a member
is typed. You can also force a completion list at a dot or the Ctrl+spacebar shortcut key. The completion list
contains items for namespaces, types, type members, language keywords, and code snippets. As text is
entered, the first matching item in the list is selected. As more text is entered, the match is refined. When
the desired item is selected, press Tab to insert. Assuming that the IntelliSense For Most Recently Used
Members option is enabled, recently used items that match the input text are selected first. Function
overloads are not shown in the completion list. For example, there are 19 overloads of the Console.WriteLine
method. However, WriteLine appears in the member list just once. The overload versions of a function, if any,
are displayed with the IntelliSense for parameter info.

Parameter Info, a form of IntelliSense, displays the parameters of a function, including the overloaded
versions of the function, which have different signatures. Use the arrows to cycle through the available
overloads (shown in Figure 4-23). Parameter Info is prompted at the open parentheses of a function. Within
function parentheses, the Ctrl+Shift+spacebar key-stroke prompts Parameter Info.

Figure 4-23: Parameter info for Console.WriteLine

IntelliSense in Visual Studio 2005 auto detects generics types and arguments. (See Figure 4-24.) A generic
dictionary is defined that has string keys and integer values. When creating a new instance of the generic
type, IntelliSense filters the completion list. The completion list automatically highlights the correct generic,
key, and value types.

Figure 4-24: IntelliSense for a generic type

There are other circumstances in which IntelliSense filters the completion list:
 Interfaces
 Base classes
 Attributes
 As and is operators
 Catch clauses
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Add using Have you ever attempted to use a type without the proper using statement? It requires stopping,
determining the correct namespace, and then explicitly entering the namespace before the type or adding a
using statement. The Add Using feature of IntelliSense avoids the distraction of resolving unbound types.
This is yet another way IntelliSense improves developer productivity.

When an unbound type is entered, a smart tag, which appears as a narrow red box, is placed beneath the
last character. The smart tag is shown when the cursor is in or immediately adjacent to the unbound type.
From the smart tag menu, you have two choices: Either insert the using statement or prefix the unbound
type with the required namespace. Figure 4-25 shows the smart tag menu. Alternatively, open a shortcut
menu on the unbound type, choose the Resolve submenu, and then choose from the two menu choices.

Figure 4-25: Add Using smart tag menu

Surround With

Visual Studio allows developers to surround code with an item on the completion list. You can surround a
block of code with a region. A block of statements can be surrounded with a for loop. The Surround With
feature surrounds selected text with something from the completion list. First select the text to be
surrounded. Open a shortcut menu on the selected text and choose the Surround With command. The
Surround With command will display the completion list. Select the item that should surround the text.

Font and Color Formatting

Visual Studio has always allowed developers to customize the color scheme of the user interface. Visual
Studio 2005 .NET extends custom formatting to user types, user keywords, and other information. This is
done in the Options dialog box, which is opened from the Tools menu. In the dialog box, switch to the
Environment window and select Fonts and Colors. Figure 4-26 shows the Fonts and Colors window.

Figure 4-26: Fonts and Colors window

Source Code Formatting

Visual Studio 2005 provides developers additional control over code formatting. Developers control code
indentation, new line spacing, code spacing, and the wrapping of blocks. This is done in the Options dialog
box on the Tools menu. In the dialog box, open the Formatting window in the Text Editor section under the
C# node. (See Figure 4-27.) Except for the General node, the bottom-right pane is the code preview area, in
which options can be reviewed before accepting.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-27: Source Formatting window

Change Tracking

Change tracking distinguishes saved from unsaved code. Visual Studio 2005 colorizes the far left pane to
indicate the status of code. Saved code is highlighted in green. Unsaved code is marked in yellow. Original
code, which is code unchanged since the source file was opened, is not highlighted. This is demonstrated in
Figure 4-28.

Figure 4-28: Change tracking of code

Profile

Almost every aspect of the Visual Studio 2005 user interface is customizable. Some developers spend
considerable time creating the ideal look and feel. They might want to preserve these settings to reapply
when necessary. User interface settings are saved in a profile, which includes window and text settings. The
profile is particularly useful when reinstalling Visual Studio because the user interface settings are lost at
that time. The profile is a convenient tool for reasserting preferred user preferences. The profile is helpful
when you want to configure the Visual Studio user interface similarly on different machines. Developers can
share profiles with other developers to identically configure their machines. This is helpful when developers
are working together on a project.

Profiles can be exported or imported in the Import And Export Settings Wizard dialog box on the Tools
menu. In the dialog box, you can import, export, or reapply the defaults of the user interface. (See Figure 4-29
.) Exporting the user interface settings creates a profile, whereas importing reads a profile that is applied to
the user interface. The Import And Export Settings Wizard dialog box guides the user through the process.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-29: Import And Export Settings Wizard dialog box


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Code Snippets
Developers are connoisseurs of code and tend to collect useful code in a variety of places. While other
people collect coins, books, or PEZ dispensers, developers collect code snippets. Why? Developers do not
like typing. There is some irony considering how much typing is involved in programming. If you want to
improve developer productivity, reduce the amount of typing. This also reduces the number of typos and
resulting compiler errors, which require an inordinate amount of developer attention. Code reuse is another
reason why developers collect code. Even unique applications are largely composed of small but common
code snippets. These are the same code elements enlisted in almost every program: loops, classes,
exception handling, and so on. Developers traditionally cut and paste code to prevent repetitive typing.
However, this has considerable limitations, including limited persistence. There should be a more viable
solution.

That solution is code snippets, introduced in Visual Studio 2005, which are capsules of reusable source
code. A code snippet is an alias for code. Insert a code snippet to insert the aliased code into the source file
at the cursor or selection. Code snippets improve developer efficiency and accuracy.

There are multiple sources for snippets. Visual Studio 2005 has a set of default snippets for common tasks,
such as the for, try, and while snippets. Snippets are available online to be downloaded, and developers can
create custom snippets.

There are three kinds of snippets, described as follows:

 Expansion An Expansion snippet inserts code at the cursor.

 Surround With A Surround With snippet envelops selected code.

 Refactoring A Refactoring snippet is used with refactoring.

Snippet types are not mutually exclusive. For example, the while snippet is both an Expansion and Surround
With template.

Copy and Paste

Of course, copying and pasting code remains available. The main disadvantages are that the Clipboard is a
shared resource—the contents of the Clipboard can be altered by another application. Clipboard data is not
retained across logon sessions. Visual Studio lets developers copy source code directly to the toolbox. The
code is then preserved on the toolbox for future placement. This is not as elegant as a snippet but
sometimes quicker and more convenient—especially when a custom snippet is required. Code placed on the
toolbox is preserved between Visual Studio and logon sessions. Unlike the Clipboard, the toolbox is not a
shared resource and is available only to Visual Studio.

There are two methodologies for placing code on the toolbox. Select the code and copy to the Clipboard.
Next click on the toolbox and paste the code. You can also drag the code onto the toolbox. A button is then
created on the toolbox for the code. Multiple passages of code can be added to the toolbox. Moving the
mouse over a code button in the toolbox displays the saved code. Click a code button to insert the code at
the cursor. As a best practice, create a separate tab on the toolbox to group code. Intermingling code with
nonrelated buttons can be confusing. A toolbox populated with source code is shown in Figure 4-30. A tab
called Code was added to the toolbox to group the source code.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-30: Toolbox with code

Insert a Code Snippet

There are several ways to insert code snippets into source code. IntelliSense is probably the simplest
method. Code snippets appear in the completion list as a torn page. Use a complete word to select the code
snippet and then press Tab to insert. Alternatively, double-click the snippet in the completion list.

Use the following techniques to select and insert code snippets. Inserting a snippet is called code expansion.
 Insert a code snippet using IntelliSense. The completion list includes snippets.
 Insert a code snippet from a menu using the Insert Snippet menu command. Insert Snippet is also
available from the shortcut menu in the Code Editor. You will be prompted to insert the name of
the snippet. Find the Insert Snippet menu command on the Edit menu and the IntelliSense
submenu. The resulting completion list includes only code snippets. This is called the snippet
picker.
 Ctrl+K and then Ctrl+X is the keyboard shortcut for the Insert Snippet menu command.
 Insert a code snippet using Auto IntelliSense. Position the cursor where the snippet should be
inserted, type the name of snippet, and then press Tab twice.

Some code snippets are templates and contain editable fields. After inserting the code snippet, a developer
customizes the template by assigning values to each field. The first field is selected automatically when the
code snippet is inserted. Other fields in the code template are color-highlighted. There can be multiple
instances of a field in the same code snippet. For example, there are several instances of the i field in the
code snippet of the for keyword. The first instance of a field is color-highlighted and editable. Remaining
instances are notated with a dotted border. Tab moves to the next field, whereas Shift-Tab moves to the
previous file. You can double-click to select a field. Fields with tooltips display the tip when the field is
selected. Figure 4-31 shows the code snippet of the for keyword. It has the ‘i' and length fields. Figure 4-32
presents the snippet with the fields customized.

Figure 4-31: Code snippet of the for keyword


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-32: Customized code snippet

When using a Surround With template, select the target code first and then insert the snippet. The snippet
will surround the code. For example, the following code increments a counter:

int count = 0;
Console.WriteLine(++count);
if (count == 10)
{
break;
}

This is the result of selecting the code and inserting the code snippet for the while keyword:

while (true)
{
int count = 0;
Console.WriteLine(++count);
if (count == 10)
{
break;
}
}

Default Snippets

Visual Studio 2005 has default snippets for tasks that are routine for developers. The default is a mixture of
expansion and surround with code snippets. Default snippets appear in the IntelliSense completion list and
the code snippet picker. Table 4-4 lists some of the default code snippets.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

#if Thi
s
co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
#if
an
d
#e
ndi
f
dir
ect
ive.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

#re Thi
gio s
n co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
#re
gio
n
an
d
#e
ndr
egi
on
dir
ect
ive.

~ Thi
s
co
de
sni
pp
et
ins
ert
s
a
de
str
uct
or.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

attr Thi
ibu s
te co
de
sni
pp
et
ins
ert
s
a
de
cla
rati
on
for
a
cu
sto
mi
ze
d
attr
ibu
te,
whi
ch
is
a
cla
ss
der
ive
d
fro
m
Sy
ste
m.
Att
rib
ut
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

ch Thi
ec s
ke co
d de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
ch
ec
ke
d
blo
ck.

cla Thi
ss s
co
de
sni
pp
et
ins
ert
s
a
cla
ss
de
cla
rati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

cto Thi
r s
co
de
sni
pp
et
ins
ert
s
a
co
nst
ruc
tor.

cw Thi
s
co
de
sni
pp
et
ins
ert
s
a
Co
ns
ole
.W
rite
Lin
e
sta
te
me
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

do Thi
s
co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
do
whi
le
blo
ck.

els Thi
e s
co
de
sni
pp
et
ins
ert
s
an
els
e
blo
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

en Thi
um s
co
de
sni
pp
et
ins
ert
s
an
en
um
de
cla
rati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

eq Thi
ual s
s co
de
sni
pp
et
ove
rrid
es
the
Eq
ual
s
me
tho
d
inh
erit
ed
fro
m
the
Sy
ste
m.
Ob
jec
t
typ
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

exc Thi
ept s
ion co
de
sni
pp
et
ins
ert
s
the
de
cla
rati
on
of
an
ap
plic
ati
on
ex
ce
pti
on,
whi
ch
is
der
ive
d
fro
m
Sy
ste
m.
Ex
ce
pti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

for Thi
s
co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
for
loo
p.

for Thi
ea s
ch co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
for
ea
ch
loo
p.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

forr Thi
s
co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
de
cre
me
nti
ng
for
loo
p.

if Thi
s
co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
an
if
blo
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

ind Thi
exe s
r co
de
sni
pp
et
ins
ert
s
an
ind
ex
er
fun
cti
on.

int Thi
erf s
ac co
e de
sni
pp
et
ins
ert
s
an
int
erf
ac
e
de
cla
rati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

iter Thi
ato s
r co
de
sni
pp
et
ins
ert
s
an
iter
ato
r.

int Thi
eri s
nd co
ex de
sni
pp
et
ins
ert
s
a
na
me
d
iter
ato
r
an
d
ind
ex
er.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

inv Thi
ok s
e co
de
sni
pp
et
ins
ert
s
an
d
inv
ok
es
an
eve
nt.

loc Thi
k s
co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
loc
k
blo
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

mb Thi
ox s
co
de
sni
pp
et
ins
ert
s
the
Me
ss
ag
eB
ox.
Sh
ow
sta
te
me
nt.

na Thi
me s
sp co
ac de
e sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
na
me
sp
ac
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

pro Thi
p s
co
de
sni
pp
et
ins
ert
s
a
pro
per
ty
an
d
ba
cki
ng
fiel
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

pro Thi
pg s
co
de
sni
pp
et
ins
ert
s
a
rea
d-o
nly
pro
per
ty.
Re
ad-
onl
y
pro
per
tie
s
hav
e
onl
y
a
get
me
tho
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

si Thi
m s
co
de
sni
pp
et
ins
ert
s
an
ent
ry
poi
nt
me
tho
d
tha
t
is
sta
tic
an
d
ret
urn
s
an
int
eg
er.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

str Thi
uct s
co
de
sni
pp
et
ins
ert
s
a
str
uct
de
cla
rati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

sv Thi
m s
co
de
sni
pp
et
ins
ert
s
an
ent
ry
poi
nt
me
tho
d
tha
t
is
sta
tic
an
d
ret
urn
s
voi
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

swi Thi
tch s
co
de
sni
pp
et
ins
ert
s
a
swi
tch
sta
te
me
nt.

try Thi
s
co
de
sni
pp
et
ins
ert
s
a
try-
cat
ch
blo
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

tryf Thi
s
co
de
sni
pp
et
ins
ert
s
a
try-
fin
ally
blo
ck.

un Thi
ch s
ec co
ke de
d sni
pp
et
sur
rou
nd
s
co
de
wit
h
an
un
ch
ec
ke
d
blo
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

un Thi
saf s
e co
de
sni
pp
et
ins
ert
s
an
un
saf
e
blo
ck.

usi Thi
ng s
co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
usi
ng
blo
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-4:
Default Code
Snippets

Co De
de scr
Sn ipti
ipp on
et
Na
me

whi Thi
le s
co
de
sni
pp
et
sur
rou
nd
s
co
de
wit
h
a
whi
le
loo
p.

Code Snippets Manager

Use the Code Snippets Manager to manage snippets, including adding, removing, importing, and searching
for snippets.

The Code Snippets Manager is available on the Tools menu. (See Figure 4-33.) The folders shown in the
Code Snippets Manager are snippet directories. Open a folder to view individual snippets. For each snippet,
the follow information is provided:
 Description of the code snippet
 Alias or shortcut of the code snippet
 Snippet type
 Author of the snippet
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-33: Code Snippets Manager

The Add button in the dialog box adds another directory to the list of code snippet directories. A code
snippets directory contains code snippet files, which are XML files with the .snippet suffix. For C#, the
default snippets directories are My Code Snippets, Refactoring, and Visual C#. The Remove button removes
a snippet directory from the list. The Import button imports a code snippet file. Use the Search Online button
to browse for code snippets. This button opens a general search window, in which developers can search for
the code snippets. When you find the code snippet you're searching for, you can download it to the local
machine.

Downloading snippets found online can pose security problems. A snippet is not guaranteed to have
innocuous XML. In addition, the snippet might hide malicious scripts. The Help URL element defined in the
snippet might stealthily launch a script. Also, code snippets can silently add references. Malicious calls are
then possible to functions in the reference. Long snippets can hide potentially harmful code. Be careful when
downloading code snippets with database access, code-access security, role-base security, or validation
code. As a best practice, carefully review the source code of code snippets that are downloaded before using
in an application.

Creating Snippets

You can create custom code snippets to encapsulate reusable code not found in a default snippet, which
allows you to maintain private libraries of reusable code. Different industries might benefit from specialized
code snippets. For example, a developer of medical software may have a need for medical code snippets.
Developers of legal software could benefit from legal code snippets. I am confident that vendors will publish
industry-specific code snippets in the future.

Custom code snippets are created in XML files. Microsoft publishes an XML schema for code snippets. Code
snippet files should have the .snippet extension. When the schema is set, Visual Studio 2005 offers
IntelliSense on the XML elements and attributes, which helps considerably in creating properly formed code
snippet files. You can group custom snippets in directories. Add these directories to the Code Snippets
Manager to make using the custom snippets more convenient.

The XML schema for code snippets defines the structure of a code snippets file. For a complete explanation
of the schema, visit the Code Snippet Schema Reference at
http://msdn2.microsoft.com/en-us/library/ms171418(en-us,vs.80).aspx. Some parts of the schema are
discussed in the next few pages.

CodeSnippets and CodeSnippet Elements


The CodeSnippets element is the root element of the code snippet file. The xlmns attribute names the code
snippet schema:

<CodeSnippets xmlns="
http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

An individual code snippet is described inside CodeSnippet elements:

<CodeSnippet>
<!-Insert code snippet here. -->
</CodeSnippet>

Header Element
The Header element has child elements, which together provide the basic information about the code
snippet. The title, author, description, shortcut, and snippet type are some of the details that can be
provided. The title is the name of the code snippet as it appears in the Code Snippet Picker, whereas the
shortcut name appears in the IntelliSense completion list. The description of the snippet found in the Code
Snippets Manager is read from this element.

This is the Header element for an example snippet for StringBuilder types:

<Header>
<Title>StringBuilder</Title>
<Shortcut>sb</Shortcut>
<Description>Creates a new String Builder</Description>
<Author>Donis Marshall</Author>
</Header>

Snippet, References, and Imports Elements


The Snippet element encapsulates the actual code of the code snippet. References and Imports are child
elements of the Snippet element. The References element identifies references required for the code snippet.
Within the References element, there are Reference child elements for each individual reference. The Imports
element names implicit namespaces. Within the Imports element, there are Import child elements that
identify each namespace to import. Importing a namespace allows implicit access of members in a
namespace without explicitly mentioning that namespace. An Import element is identical to the using
namespace statement of C#.

This is an example of the References and Import elements. The System.Text namespace contains the
StringBuilder type:

<Snippet>
<References>
<Reference>
<Assembly>System.Text.Dll</Assembly>
</Reference>
</References>
<Imports>
<Import>
<Namespace>System.Text</Namespace>
</Import>
</Imports>

Declarations, Literal, and Object Elements


The Declarations element describes the fields used in the code snippet. It is also a child element of the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Snippet element. There are literal and object fields. The Literal element declares a literal field, which is a field
that is fully contained in the code snippet. This would include string and numeric literals. The Object element
also declares a field, which is a field defined outside the snippet. This usually describes a type.

The Literal and Object elements can contain ID, Default, Tooltip, Type, and Function child elements:
 The ID element is the name of the field.
 The Default element is the default value of the field.
 The Tooltip element is the tooltip of the field.
 The Type element sets the type of the field.
 The Function element names a function. This is a function to call whenever the field is selected.

This is the Declarations element of the StringBuilder code snippet:

<Declarations>
<Literal>
<ID>Name</ID>
<Default>mytext</Default>
<ToolTip>Name of new StringBuilder</ToolTip>
</Literal>
<Literal>
<ID>Size</ID>
<ToolTip>Capacity of String</ToolTip>
</Literal>
</Declarations>

Code and <![CDATA ]> Elements


The Code element contains individual lines of code. It also selects the language of the code snippet. Code is
a child element of the Snippet element. The target language is set in the Language attribute. Valid languages
are CSharp, VB, VJSHARP, and XML.

Each line of code is placed in a <![CDATA]> element. The code must be written in the syntax of the chosen
language.

CDATA syntax:

<![CDATA[ snippetcode ]]>

In snippet code, fields are bounded with dollar signs ($field$). This is the snippet code for the StringBuilder
snippet:

<Code Language="CSharp">
<![CDATA[StringBuilder $Name$=]]>
<![CDATA[ new StringBuilder($Size$);]]>
</Code>

String Builder Code Snippet


The following code is the complete listing of the sample code snippet, which creates a new StringBuilder
type. The StringBuilder type is found in the System.Text.Dll library and the System.Text namespace. Fields
are defined for the name and size of the StringBuilder type.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

<?xml version="1.0" encoding="utf-8"?>


<CodeSnippets xmlns="
http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>StringBuilder</Title>
<Shortcut>sb</Shortcut>
<Description>Creates a new String Builder</Description>
<Author>Donis Marshall</Author>

</Header>
<Snippet>
<References>
<Reference>
<Assembly>System.Text.Dll</Assembly>
</Reference>
</References>
<Imports>
<Import>
<Namespace>System.Text</Namespace>
</Import>
</Imports>
<Declarations>
<Literal>
<ID>Name</ID>
<Default>mytext</Default>
<ToolTip>Name of new StringBuilder</ToolTip>
</Literal>
<Literal>
<ID>Size</ID>
<ToolTip>Capacity of String</ToolTip>
</Literal>
</Declarations>
<Code Language="CSharp">
<![CDATA[StringBuilder $Name$=]]>
<![CDATA[new StringBuilder($Size$);]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>

Create a Code Snippet Walkthrough


The section provides a walkthrough for creating a code snippet. Before creating a snippet, it is best to write
and test the code. Convert the code into a code snippet only after a successful code compilation. Custom
code snippets should be placed in dedicated directories reserved for custom snippets. Make sure that the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

directory is eventually added as a code snippet directory using the Code Snippets Manager.

This walkthrough creates a code snippet that reflects the methods of a type. This code tests the proposed
snippet:

// Snippet starts
Type t = typeof(Object);
string typename = t.Name;
string typenamespace = t.Namespace;
MethodInfo [] methods = t.GetMethods();
// Snippet ends
Console.WriteLine("Type Name:"+typename);
Console.WriteLine("Namespace Name:"+typenamespace);
foreach (MethodInfo method in methods)
{
Console.WriteLine(method.Name);
}

These are the steps for creating the preceding snippet:


1. Create an XML file in Visual Studio. The filename of the code snippet is reflectmethod.snippet.
2. All snippet files begin with the CodeSnippets, CodeSnippet, and Header elements, which name
the file schema and describe the basic attributes of the code snippet:
3.
4. <?xml version="1.0" encoding="utf-8"?>
5. <CodeSnippets xmlns="
http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
6. <CodeSnippet Format="1.0.0">
7. <Header>
8. <Title>ReflectMethod</Title>
9. <Shortcut>rm</Shortcut>
10. <Description>Reflects methods of a type.</Description>
11. <Author>Donis Marshall</Author>
12. </Header>
13. </CodeSnippet>
14. </CodeSnippets>
15. Reflection requires the Reflection namespace. Import the System.Reflection namespace with an
Import element, which is defined within the Imports element. The System.Reflection namespace
is declared in the System.DLL, which is automatically referenced from managed code. For that
reason, a Reference element is not needed.
16.
17. <Snippet>
18. <Imports>
19. <Import>
20. <Namespace>System.Text</Namespace>
21. </Import>
22. </Imports>
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

23. </Snippet>
24. The code snippet has four fields, which name the type, type instance, namespace, and MethodInfo
array. The type instance is an object field. The other fields are literals and contained within the
code snippet. Defaults for the fields are gleaned from the code used to test the code snippet.
Fields are defined within the Declarations element with literal and object elements:
25.
26. <Declarations>
27. <Literal>
28. <ID>Instance</ID>
29. <Default>t</Default>
30. <ToolTip>Name of instance.</ToolTip>
31. </Literal>
32. <Literal>
33. <ID>TypeName</ID>
34. <Default>typename</Default>
35. <ToolTip>Name of type.</ToolTip>
36. </Literal>
37. <Literal>
38. <ID>TypeNamespace</ID>
39. <Default>typenamespace</Default>
40. <ToolTip>Namespace of type.</ToolTip>
41. </Literal>
42. <Literal>
43.
44. <ID>Methods</ID>
45. <Default>Methods</Default>
46. <ToolTip>Type methods</ToolTip>
47. </Literal>
48. <Object>
49. <ID>Type</ID>
50. <Default>Object</Default>
51. <ToolTip>object type</ToolTip>
52. <Type>System.Object</Type>
53. </Object>
54. </Declarations>
55. Paste the code for the snippet into <![CDATA]> elements, which are placed within the Code
element. Add extra line feeds to separate lines of source code. After pasting the code, substitute
the field names into the code:
56.
57. <Code Language="CSharp">
58. <![CDATA[Type $Instance$ = typeof($Type$);
59. ]]>
60. <![CDATA[string $TypeName$ = $Instance$.Name;
61. ]]>
62. <![CDATA[string $TypeNamespace$ = $Instance$.Namespace;
63. ]]>
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

64. <![CDATA[MethodInfo [] $Methods$ = $Instance$.GetMethods();


65. ]]>
66. </Code>
67. Save the file for the code snippet in the directory reserved for custom code snippets.
68. Test the snippet in Visual Studio 2005. Open a source file and insert the code snippet using the
code snippet picker. Figure 4-34 shows the snippet.

Figure 4-34: Reflect Method snippet


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Refactoring
Refactoring helps developers re-engineer their code and removes much of the tedium of maintaining an
application. Considerable time is spent re-engineering during the lifetime of an application. This sometimes
starts as early as the development phase and accelerates as the application matures. This includes—but is
not limited to—renaming variables, moving methods, changing method signatures, and redesigning classes.
The objective is to improve the application. The process is tedious. Finding and changing a variable in a
software system that spans dozens of source files can be challenging. Another example is changing the
signature of a commonly used method. Method calls throughout the application must be located and
corrected. These changes are made to improve an application. However, if executed poorly, these changes
have the opposite effect. Worst-case scenario: Maintenance might introduce bugs into otherwise pristine
applications. Visual Studio 2005 introduces refactoring as a tool to help developers re-engineer code quickly
and accurately. Refactoring is a multifaceted tool. It assists in the renaming of variables, changing of method
signatures, extrapolating of interfaces, converting fields to properties, and much more.

A Refactoring menu is available in the Visual Studio 2005 user interface that shows the refactoring
operations. Table 4-5 list the various refactoring operations. The refactoring menu is also available in the
Code Editor using a shortcut menu.
Table 4-5: Refactoring Operations

Operations Description

Rename The Rename operation renames a symbol, such as a variable or method


name, throughout an application.

Extract Method The Extract Method operation creates a new method that encapsulates the
selected code.

Encapsulate Field The Encapsulate Field operation creates a property that abstracts the selected
field.

Extract Interface The Extract Interface operation extracts an interface from a type.

Promote Local The Promote Local Variables To Parameters operation promotes a local
Variables To Parameters variable to a parameter of the current method.

Remove Parameters The Remove Parameters operation removes a parameter from the parameter
list of a function. Call sites for the function are updated to reflect the removed
parameter.

Reorder Parameters The Reorder Parameters operation reorders the parameters of a function. Call
sites for the function are updated for the new sequence of parameters.

The Preview Changes dialog box is invaluable because it provides you with an opportunity to preview
refactoring changes before applying them. Figure 4-35 displays the Preview Changes dialog box.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-35: Preview Changes dialog box

Refactoring can span multiple projects in the same solution, which occurs with project-to-project references.
A project-to-project reference is a reference in which both the referencing and referenced assemblies are built
in projects of the same solution. The Projects window in the Add Reference dialog box inserts a
project-to-project reference.

Refactoring Walkthrough

This walkthrough demonstrates some of the features of refactoring, including the renaming of variables and
extracting of interfaces. The walkthrough refactors the Airline Seats application. This application manages
the first class and coach standby lists of an airline flight. This is the user interface (shown in Figure 4-36)
presented to flyers on overhead monitors at the airport gate.

Figure 4-36: Airline Seats application

The following steps outline the walkthrough.


1. The application defines a Node class, which is a generic collection class in the node.cs file. The
value of the node is returned from the Info property. The property should be renamed Value, which
is probably more intuitive. Select the Info name in the source file. From the shortcut menu,
choose the Refactor submenu and the Rename menu command.
2. The Rename dialog box appears. The selected text is displayed with its location. Three option
buttons are presented. The Preview Reference Changes option requests a preview window before
the changes are applied. This option is selected by default. The Search In Comments option
searches comments for the renamed text. The Search In String option extends the search to
literals, such as string literals. Change the text to Value and proceed with the renaming operation.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

(See Figure 4-37.)


3. The Preview Changes—Rename dialog box appears. (See Figure 4-38.) You can review the
pending changes in this window. Specific changes can be selected or unselected. When
acceptable, click Apply, and the specified changes are enacted. If necessary, you can undo
refactoring changes using the Undo (Ctrl+Z) feature of Visual Studio.
4. The capability to extrapolate interfaces from classes is another great feature of refactoring.
Manually extracting interfaces from types is a time-consuming process for developers. The Airline
Seats application has a Person class that represents the flyer. In the future, other types of people
may be added to the application. For that reason, the Person interface is extrapolated for future
use. Position the cursor within the class and open the shortcut menu. From the Refactor menu,
select the Extract interface menu command. The Extract Interface dialog box appears, as shown
in Figure 4-39. Enter the interface name and file name. A list of potential members is presented.
You can select which members to include in the interface. As a convenience, Select All and
Deselect All buttons are provided.
5. The Passenger class, which is a form, has two public fields. A tenet of object-oriented
programming is that fields should be private. Exposing fields as public properties is more secure.
6.
7. public Node<Flyer.Person> coachlist=null;
8. public Node<Flyer.Person> fflist= null;
9.
10. Select the first field. From the shortcut menu, select the Refactoring menu and Encapsulate Field
menu command. The Encapsulate Field dialog box appears. (See Figure 4-40.) Enter the property
name and accept.
11. After accepting the Encapsulate Field dialog box, the Preview Reference Changes dialog box
appears. This dialog box shows the potential changes. You can accept or reject individual
changes.
12. Repeat steps 6 and 7 to convert the second field to a property. Despite the numerous changes in
various parts of the application, you can now compile and run the program successfully.

Figure 4-37: Rename dialog box


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-38: Preview Changes—Rename dialog box

Figure 4-39: Extract Interface dialog box

Figure 4-40: Encapsulate Field dialog box

This is the interface created from the Extract Interface refactoring operation. It is saved to a separate file. In
the file, change the namespace containing the interface appropriately. For the sample application, the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

namespace is changed to Flyer.

interface IPerson
{
string FirstName { get; }

bool FrequentFlyer { get; }


string ID { get; }
string LastName { get; }
}

Refactoring also updated the Person class to inherit the IPerson interface:

public class Person : IPerson


{
// partial listing
}

This is one property created from refactoring a field:

private Node<Flyer.Person> coachlist = null;

public Node<Flyer.Person> Coachlist


{
get { return coachlist; }
set { coachlist = value; }
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Building and Deployment


The Microsoft Build Engine (MSBuild) is a new build environment. The build process is orchestrated in an
XML-based project file. MSBuild replaces traditional .mak files. The project file describes the build process,
build configuration, and input and output files.

Visual Studio 2005 supports conventional deployment based on Windows Installer technology. With
Windows Installer technology, an application is packaged in a Setup.exe file and then deployed to the local
machine or a public share. The Setup.exe program installs the application on the local machine. ClickOnce
deployment is introduced in Visual Studio 2005 as an alternate deployment strategy. ClickOnce deploys an
application from a central location and combines a desktop application with Web-based delivery system.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

MSBuild
MSBuild does not require Visual Studio. This is ideal for lab environments in which Visual Studio is not
installed. Individual builds are organized in project files. Build project files are XML files and have a .proj
extension. As an XML file, the build project is platform-independent and extensible. For a complete
explanation of MSBuild, consult the MSBuild Reference at the Microsoft Developer Network (MSDN) at
http://winfx.msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_fxgenref/html/.asp.

Build projects consist of items, properties, and tasks, as described in the following sections.

Items

Items are the input of the build process. Items are created as child elements of the ItemGroup element.
Items sharing the same name are considered a collection. Item collections are addressable in the build
project as @(ItemCollectionName). Item collections are primarily used as parameters in build tasks.

For example, the Compile element is a standard item. It defines the source files that are included or
excluded from the build. The Include attribute specifies a file to be included in the build. The Exclude
attribute, naturally, excludes files. The following code defines a Compile collection, which includes two items:

<ItemGroup>
<Compile Include="source1.cs"/>
<Compile Include="source3.cs" Exclude="source2.cs"/>
</ItemGroup>

Properties

Properties are configuration data used during the build process. Properties represent individual values and
cannot be grouped into collections. Properties are defined as child elements of the PropertyGroup element.
Refer to properties in the project using the $(property) syntax:

<PropertyGroup>
<ApplicationVersion>1.2.3.4</ApplicationVersion>
</PropertyGroup>

There are several reserved properties in the MSBuild environment. Table 4-6 lists the reserved properties.
Table 4-6: Reserved Properties

Property Description

MSBuildProjectDirectory This property is the absolute path to the MSBuild project file.

MSBuildProjectFile This property is the name and extension of the MSBuild project file.

MSBuildProjectExtension This is the file extension of the MSBuild project file. It should include the
. prefix.

MSBuildProjectFullPath This property is the fully qualified name of the MSBuild project file.

MSBuildProjectName This property is the name of the MSBuild project file without the
extension.

MSBuildBinPath This property is the path to the MSBuild binaries.

MSBuildProjectDefaultTargets This property is the list of targets specified in the project element of the
MSBuild project file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-6: Reserved Properties

Property Description

MSBuildExtensionsPath This property is the supplemental directory for custom target files, which
is found under the Program Files directory.

Tasks

Tasks are the build operations of the MSBuild project and child elements of the Target element. Tasks can
accept parameters, which are the attributes of the Task element. Item collections and properties are valid
parameters to tasks. Create multiple targets to batch groups of build operations. The MSBuild tool can
invoke different targets. For example, you can create targets for release versus debug builds.

Tasks are written in a managed language and are available to any MSBuild project. Developers can author
specialty tasks in managed code. Build tasks are classes that implement the ITask interface.

Table 4-7 list the defaults tasks available in the MSBuild environment.
Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

AL Thi
s
tas
k
inv
ok
es
the
As
se
mb
ly
Lin
ker
(AL
)
too
l.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

As Thi
pN s
etC tas
om k
pile inv
r ok
es
as
pn
et_
co
mp
iler
.ex
e,
whi
ch
pre
co
mp
iles
AS
P.
NE
T
ap
plic
ati
on
s.

As Thi
sig s
nC tas
ult k
ure cre
ate
s
an
ite
m
for
a
cul
tur
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Co Thi
py s
tas
k
co
pie
s
file
s
to
a
sp
ecif
ied
dir
ect
ory
.

Cre Thi
ate s
Ite tas
m k
co
pie
s
ite
ms
bet
we
en
coll
ect
ion
s.

Cre Thi
ate s
Pro tas
per k
ty co
pie
s
pro
per
tie
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Cs Thi
c s
tas
k
inv
ok
es
cs
c.e
xe,
whi
ch
is
the
C#
co
mp
iler
.

Del Thi
ete s
tas
k
del
ete
s
file
s.

Ex Thi
ec s
tas
k
ex
ec
ute
s
an
ap
plic
ati
on
or
co
m
ma
nd.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Fin Thi
dU s
nd tas
erP k
ath det
er
mi
ne
s
whi
ch
ite
ms
are
fou
nd
wit
hin
a
sp
ecif
ied
dir
ect
ory
an
d
its
su
bdi
rec
tori
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Ge Thi
ner s
ate tas
Ap k
plic cre
ati ate
on s
Ma an
nif ap
est plic
ati
on
ma
nife
st
or
nat
ive
ma
nife
st
for
a
Cli
ck
On
ce
ap
plic
ati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Ge Thi
ner s
ate tas
Bo k
ots loc
tra ate
pp s,
er do
wnl
oa
ds,
an
d
ins
tall
s
an
ap
plic
ati
on.

Ge Thi
ner s
ate tas
De k
plo cre
ym ate
ent s
Ma a
nif de
est plo
ym
ent
ma
nife
st
for
a
Cli
ck
On
ce
ap
plic
ati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Ge Thi
ner s
ate tas
Re k
so cre
urc ate
e s.
res
our
ce
s
file
s
fro
m.
txt
an
d.
res
x
file
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Ge Thi
tAs s
se tas
mb k
lyId ret
ent urn
ity s
as
se
mb
ly
me
tad
ata
an
d
sto
res
the
res
ult
s
in
an
ite
m
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Ge Thi
tFr s
am tas
ew k
ork obt
Pat ain
h s
the
pat
h
of
the
.N
ET
Fra
me
wor
k
as
se
mb
lies
.

Ge Thi
tFr s
am tas
ew k
ork obt
SD ain
KP s
ath the
pat
h
of
the
.N
ET
Fra
me
wor
k
SD
K.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

LC Thi
s
tas
k
co
nve
rts
a.
licx
to
a.
lice
ns
e
file.

Ma Thi
ke s
dir tas
k
ma
ke
s
a
dir
ect
ory
.

MS Thi
Bui s
ld tas
k
buil
ds
an
MS
Bui
ld
pro
jec
t
fro
m
an
oth
er
buil
d
pro
jec
t.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Re Thi
ad s
Lin tas
es k
Fro rea
mF ds
ile MS
Bui
ld
ite
ms
fro
m
a
file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Re Thi
gis s
ter tas
As k
se rea
mb ds
ly the
me
tad
ata
of
an
as
se
mb
ly
an
d
reg
ist
ers
the
as
se
mb
ly
as
a
CO
M
ser
ver,
whi
ch
allo
ws
CO
M
clie
nts
to
ac
ce
ss
the
as
se
mb
ly.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Re Thi
mo s
ve tas
Dir k
del
ete
s
a
dir
ect
ory
.

Re Thi
sol s
ve tas
As k
se det
mb er
lyR mi
efe ne
ren s
ce whi
ch
as
se
mb
lies
de
pe
nd
on
an
oth
er
as
se
mb
ly.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Re Thi
sol s
ve tas
Co k
mR res
efe olv
ren es
ce the
loc
ati
on
of
typ
e
libr
ary
(TL
B)
file
s.

Re Thi
sol s
ve tas
Ke k
yS det
our er
ce mi
ne
s
the
str
on
g
na
me
of
a
ke
y
so
urc
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Sg Thi
en s
tas
k
is
a
wra
pp
er
for
the
XM
L
Ser
iali
zat
ion
Ge
ner
ato
r
To
ol (
sg
en.
exe
).

Sig Thi
nFi s
le tas
k
sig
ns
a
file
wit
h
a
cer
tific
ate
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

To Thi
uc s
h tas
k
set
s
the
ac
ce
ss
an
d
mo
difi
cat
ion
tim
e
of
a
file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Unr Thi
egi s
ste tas
rAs k
se unr
mb egi
ly ste
rs
an
as
se
mb
ly
fro
m
the
reg
istr
y.
Aft
erw
ard
,
the
as
se
mb
ly
is
no
lon
ger
ava
ilab
le
to
CO
M
clie
nts
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Vb Thi
c s
tas
k
inv
ok
es
vb
c.e
xe,
whi
ch
is
the
Vis
ual
Ba
sic
.N
ET
co
mp
iler
.

Vc Thi
Bui s
ld tas
k
wra
ps
vc
bui
ld.
exe
,
whi
ch
buil
ds
a
Vis
ual
C+
+
pro
jec
t.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-7:
Default Tasks

Ta De
sk scr
ipti
on

Wri Thi
teL s
ine tas
sT k
oFi writ
les es
the
pat
hs
of
the
sp
ecif
ied
ite
ms
to
a
file.

Project File

A project file is a generalized skeleton of an MSBuild project. An MSBuild project can have any number of
tasks, item collections, and properties. This is entirely dependent on the requirements of the actual project.

<?xml version="1.0" encoding="utf-8"?>


<!-- MSBuild Schema -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<!-- Item Collection -->
</ItemGroup>
<Target Name="Task1">
<!-- Task(s) -->
</Target>
<PropertyGroup>
<!-- Properties -->
</PropertyGroup>
<ItemGroup>
<!-- Item Collection -->
</ItemGroup>
<Target Name="Task2">
<!-- Task(s) -->
</Target>
</Project>
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

This is the syntax of the MSBuild command line:

Msbuild switches projectfile

MSBuild command-line switches are listed in Table 4-8.


Table 4-8: MSBuild
Switches

Ta Description
sk

/he This switch


lp displays help
information on
the MSBuild
command. /?
and /h are
also help
switches.

/no This switch


co disabled the
ns default
olel console
og logger. Events
ger should not be
logged to the
console
window.

/no This switch


log suppresses
o the startup
banner and
copyright
information.

/ve This switch


rsi displays the
on version of the
MSBuild tool.

@fi This switch


le reads
command-line
instructions
from a batch
file.

/no This switch


aut disables the
ore automatic
sp include of the
on MSBuild.rsp
se file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-8: MSBuild


Switches

Ta Description
sk

/tar This switch


get identifies the
: targets to
tar execute. The
get targets are
na delimited by
me commas or
s semicolons.

/pr This switch


op sets the value
ert of a property.
y: Multiple
na properties are
me delimited by
=va commas or
lue semicolons.

/lo This switch


gg logs MSBuild
er: events to a
log logger.
ger

/co This switch


ns sets the
olel parameters of
og the console
ger logger.
par
am
ete
rs:
par
am
ete
rs
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-8: MSBuild


Switches

Ta Description
sk

/ve This switch


rbo sets the
sity amount of
: information
lev written to the
el event log. The
levels are as
follows:
 q—
quiet
 m—
minima
l
 n—
normal
 d—
detaile
d
 diag—
diagno
stic

/val This switch


ida validates the
te: project file. If
sc no schema is
he provided, the
ma default
schema is
used to
perform the
validation.

MSBuild Walkthrough

This section provides a walkthrough of a normal MSBuild project. The project contains two tasks: The first
task compiles an assembly from the available source files, and the second task creates a DLL from a source
file. The project then compiles the remaining sources files. This requires a reference to the DLL. The
walkthrough MSBuild project is documented with steps. Here is the project, followed by a description of each
step:

<?xml version="1.0" encoding="utf-8"?>


<!-- Step One-->

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Step Two -->
<ItemGroup>
<Compile Include="source1.cs"/>
<Compile Include="source2.cs"/>
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

</ItemGroup>
<!-- Step Three -->
<PropertyGroup>
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup>
<AssemblyName>sample.exe</AssemblyName>
</PropertyGroup>
<!-- Step Four -->
<Target Name="Application1">
<Csc Sources="*.cs" OutputAssembly="$(AssemblyName)"
DebugType="$(DebugType)"/>
</Target>
<!-- Step Five-->
<Target Name="Application2">
<Csc Sources="source3.cs" TargetType="library"/>
<Csc Sources="@(compile)" References="source3.dll"
OutputAssembly="$(AssemblyName)" DebugType="$(DebugType)"/>
</Target>
</Project>
 Step 1 establishes the schema for the MSBuild schema.
 Step 2 creates an item collection for the Compile element. The source files source1.cs and
source2.cs are named in the collection.
 Step 3 sets the defaults for the DebugType and AssemblyName properties.
 Step 4 creates target Application1, which has a single task. The task compiles the source files in
the current directory. It uses both the AssemblyName and DebugType properties.
 Step 5 creates target Application2, which contains two tasks: The first task compiles source3.cs
and places the results in a library assembly; the second task compiles the item collection and
references the library assembly.

This MSBuild command line reads the sample.proj project file. The output is the donis.exe assembly. The
debugtype property is assigned full, whereas the assemblyname property is assigned donis.exe. This
overwrites the default values of those properties. Finally, MSBuild invokes the Application1 target:

C:\>msbuild /p:debugtype=full,assemblyname=donis.exe
sample.proj /target:application1

The following MSBuild command executes the tasks of the Application2 target:

C:\ >msbuild /p:debugtype=full,assemblyname=donis.exe


sample.proj /target:application2
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Click Once Deployment


With ClickOnce deployment, developers browse to Window applications published on an ASP.NET Web
server. Setup and deployment of desktop and non-Web applications have recently become increasingly
complex. In addition, installation must be repeated for updates and future versions of the product. There is
also the productivity problem of having to physically install the product on multiple machines. Conversely,
deployment of Web applications is hands-free. You simply browse to the application using the proper URL.
No installation required. Web applications are also self-updating. Users automatically obtain the latest
version of the Web application whenever the Web site is browsed. Productivity is improved because
per-machine installations are avoided. The benefits of a Web distribution extend to ClickOnce deployment.

ClickOnce deployment is nonintrusive. Windows Installer technology is intrusive as the application is


installed to the local machine. ClickOnce deployment downloads an application into the download cache, in
which there is limited impact to the local machine. There are security considerations because these
applications execute in the download cache with potentially limited security privileges. These security
considerations must be addressed in the application or on the local machine. Because the deployment is
hands-free, user experience is improved.

ClickOnce applications are self-updating, which is particularly useful for applications that require frequent
updates. Deploying applications that require frequent updates within the Windows Installer technology model
was a time-consuming process. ClickOnce applications are deployed once and updated online
automatically. Updates require online connectivity.

Another benefit includes the security privileges required to perform an installation. Windows Installer
technology sometimes required administrative permissions, but ClickOnce deployment does not require
administrative permissions to deploy the application.

ClickOnce deployment publishes an application at a Web site on an ASP.NET server. The client machine
must support the .NET Framework. This is more likely in an intranet deployment, in which the desktops are
controlled. It is also feasible in an extranet environment, in which requirements can be published and a
reasonable level of compliance can be expected. ClickOnce applications can be deployed in a traditional
manner, but require online connectivity for self-updating.

ClickOnce deployment has two modes of deployment. The online-only mode executes the application from
the Web, which requires the client to be connected to the server computer whenever the application is
executed. The full installation mode executes the installation on the client computer. This is similar to a
traditional installation from an .msi or .cab file. Updates still require online connectivity.

ClickOnce deployment uses an application manifest (which is an XML file) to define dependent assemblies,
files, and security permissions required for the application. ClickOnce deployment also uses a deployment
manifest. This manifest contains deployment configuration information, such as the current version, the
location of required files, deployment mode, and update policies.

Create application and deployment manifests with the Manifest Generation and Editing (MageUI) tool, which
is distributed in the .NET Framework. To create a new application manifest, choose the File menu and then
choose the New submenu. From the submenu, select Application Manifest The Name window of the
application manifest appears first. This window contains the general information on the deployment. The
Airline Seats application is published as a ClickOnce application. Figure 4-41 shows a view of the Name
window in the MageUI tool for the Airline Seats application.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-41: Application manifest—Name window

The Files window lists the files included in the deployment. (See Figure 4-42.)

Figure 4-42: Application manifest—Files window

The Permissions Required window sets the security required to execute the deployed application.(See Figure
4-43.)

You can also open the deployment manifest using the MageUI tool. The Names windows for both the
deployment and application manifests are the same. For the deployment manifest, the two most important
windows are the Deployment and Update Options windows.

Figure 4-43: Application manifest—Permissions Required window

The Deployment Options window sets the ClickOnce deployment mode and the URL of the published
application. (See Figure 4-44.)

The Update Options window configures how updates are managed for an application deployed with
ClickOnce technology. Figure 4-45 shows the Update Options window.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-44: Deployment manifest—Deployment Options window

Figure 4-45: Deployment manifest—Update Options window

Publish a ClickOnce Application

Fortunately, ClickOnce deployment is automated in Visual Studio 2005. This includes the creation of both
manifest files and Web server configuration. In Visual Studio 2005, developers use the Publish Wizard to set
up an application for ClickOnce deployment. Open the project shortcut menu and choose Publish to launch
the Publish Wizard.

The Publish Wizard has several steps. The first step provides the URL in which the application is published.
Figure 4-46 shows the first window of the Publish Wizard.

Figure 4-46: Publish Wizard—step 1

Step 2 of the Publish Wizard sets the online connectivity requirements of the deployed application. (See
Figure 4-47.)

Step 3 (shown in Figure 4-48) is the confirmation window, in which a developer can review the ClickOnce
settings and confirm the deployment.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-47: Publish Wizard—step 2

Figure 4-48: Publish Wizard—step 3


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Arrays and Collections


The next chapter reviews arrays and collections. Arrays are collections of related types, and they are the
only native collection. C# supports one-and multidimensional arrays. Jagged arrays are also supported,
which are arrays of arrays. System.Array is the underlying type of all arrays, which defines the baseline
behavior of all arrays. You learn a lot about arrays in examining the System.Array class. For example, the
Array.SyncRoot property is used to synchronize access to an array. Arrays implement a myriad of
interfaces, such as ICloneable, ICollection, and IEnumerable. The next chapter discusses the merits of
each of these interfaces.

More sophisticated collections are sometimes needed. The .NET Framework offers ArrayList, Queue, Stack,
HashTable, and other useful collections. Specialty collections are also available, including BitVector32,
HybridDictionary, and NameValueCollection.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 5: Arrays and Collections


Overview
An array is a collection of related instances, either value or reference types. Arrays possess an immutable
structure, in which the number of dimensions and size of the array are fixed at instantiation. C# supports
single-dimensional, multidimensional, and jagged arrays. Single-dimensional arrays, sometimes called
vectors, consist of a single row. Multidimensional arrays are rectangular and consist of rows and columns. A
jagged array also consists of rows and columns, but is irregularly shaped.

Arrays are represented in most programming languages. Most developers have some familiarity with the
concept of arrays. Arrays are employed in a variety of ways. A personnel program would contain an array of
employees. Graphic programs might have one array for each type of geometric object, such as ellipses,
rectangles, or triangles. An accounting and scheduling application for automobile repair likely would have an
array of automobile repair tickets. The Space Shuttle program would have an array of astronauts.

Arrays are intrinsic to the language. Other collections, such as Stack, Queue, and Hashtable, are not native
to the language. As such, ease of use is one of the benefits of arrays. Another benefit is familiarity. Arrays
are available and functionally similar in almost every programming language. Few developers have not worked
with arrays.

An array is a container, which is an abstraction of a data structure. As a container, an array holds data
items called elements. Elements of an array are always related, such as an array of apples or an array of
oranges. An array might consist of SalariedEmployee, HourlyEmployee, and CommissionedEmployee
instances. However, an array of apples and employees is probably invalid because those objects are
probably unrelated. In addition, an array is a data structure that is a composite of elements that reside in
contiguous memory.

Arrays are reference types, and the memory for the array is allocated on the managed heap. Even an array
of value types is allocated on the managed heap and not on the stack. An array of 30 integer values would
have the same number of 32-bit slots allocated in contiguous memory for the array elements. With arrays of
reference types, the objects are not stored in contiguous memory; the references are stored in contiguous
memory. However, the objects themselves are stored in noncontiguous memory, which is pointed to by the
reference. Figure 5-1 shows the difference in memory allocation between arrays of reference versus value
types.

Figure 5-1: Array of reference types versus value types

Elements are relative to the beginning of the array and are identified with indexes, which are either integer or
long types. Indexes are also commonly called indices or subscripts, and placed inside the indexing operator
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

([ ]). Arrays are zero-based where the index is actually an offset. Array indexes are offsets from the
beginning of the array to a particular element. Therefore, the first element is at the start of the array, which is
an offset of zero. For an array of five elements, a proper index is from zero to four. Therefore, the last element
of the array is at index n -- 1. This is a common cause of fencepost errors. Fencepost errors occur when
referring to array elements with indexes outside the bounds of an array. If an array has five elements,
accessing element six is a fencepost error.

As mentioned, arrays are immutable. This means that an array is statically sized, and the dimensions
cannot be changed at run time. The System.Array.Resize method, which is a generic method, seemingly
resizes an array. However, appearances can be deceiving. Array.Resize creates an entirely new array that is
the new size. The new array is initialized with the elements of the source array. Afterward, the original array
is discarded.

Single-dimensional arrays are indigenous to the run time. There are specific MSIL instructions for vectors,
including newarr, ldelem, ldlen, and stelem. There are no built-in instructions for multidimensional arrays.
This direct manipulation of single-dimensional arrays makes them more efficient. In addition, some of the
members of the System.Array type, which is the underlying type for all arrays, cannot be applied to
multidimensional arrays. Conversely, all the methods and properties of the System.Array type are applicable
to single-dimensional arrays.

The System.Array type is the underpinning of all arrays. It is an abstraction of an array. Instances of arrays
are instances of the System.Array type. Thus, arrays are implicitly reference types. Arrays can access
many of the instance methods and properties of the System.Array type. System.Array is a combination of
original methods and the implementation of a series of interfaces. Table 5-1 lists the interfaces that
System.Array implements.
Table 5-1:
Interfaces
Implemented
at
System.Array

Int De
erf scr
ac ipti
e on

ICl Thi
on s
ea int
ble erf
ac
e
defi
ne
s
a
me
tho
d
to
clo
ne
an
ins
tan
ce
of
an
arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-1:
Interfaces
Implemented
at
System.Array

Int De
erf scr
ac ipti
e on

ICo Thi
llec s
tio int
n erf
ac
e
defi
ne
s
me
tho
ds
to
co
unt
the
nu
mb
er
of
ele
me
nts
of
an
arr
ay
an
d
for
thr
ea
d
sy
nc
hro
niz
ati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-1:
Interfaces
Implemented
at
System.Array

Int De
erf scr
ac ipti
e on

IEn Thi
um s
era int
ble erf
ac
e
defi
ne
s
a
me
tho
d
tha
t
en
um
era
tes
the
ele
me
nts
of
a
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-1:
Interfaces
Implemented
at
System.Array

Int De
erf scr
ac ipti
e on

ILi Th
st e
int
erf
ac
e
defi
ne
s
me
tho
ds
to
ac
ce
ss
an
ind
ex-
ba
se
d
coll
ect
ion
.
So
me
me
mb
ers
of
thi
s
int
erf
ac
e
are
not
pu
blic
ly
im
ple
me
nte
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Create arrays as local variables or fields. Use arrays also as method parameters and return types. The
rationale of using an array as a local variable, field, method parameter, or return type is the same as any
type. Arrays are passable into or out of a method as a parameter. The semantics of an array parameter are
the same as any parameter. Because an array is a reference type, it is passed by reference. Therefore, the
content of the array can be changed in the called method. Parameter modifiers, such as the ref modifier, are
assignable to array parameters.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Arrays
Following is the syntax for declaring a one-dimensional array. A vector has a single index. When declaring
an array, the indexing operator on the right-hand side sets the size of the array.

type [] arrayname 1;
typea [] arrayname 2=new typeb[n];
typea [] arrayname 3=new typeb[n] {ilist};
typea[] arrayname 4=new typeb[] {ilist};
typea[] arrayname 5={ilist};

The first syntax declares a reference to an array that is not initialized. You can later initialize the array
reference using the right hand side (RHS) syntax of declaring an array. This is sample code of the first
syntax of declaring an array. It declares an integer array named zArray. The array is then assigned an array
of 10 integers that initializes the references. However, the array elements of 10 integers are not initialized.
Array elements default to zero or null: zero for value types and null for reference type elements. In this code,
the array elements are set to zeroes:

int [] zArray;
zArray=new int[10];

The second syntax declares and initializes a reference to an array. The array reference is assigned a
reference to the new instance. An array of a value types must be initialized to an array of the same value
type. Otherwise, typea and typeb must be identical. Even if typea and typeb are convertible, the declaration
is not allowed. Bytes are convertible to integers. However, an array of bytes is not convertible to an array of
integers. The size of the array is n. The elements are indexed from zero to n -- 1.

This is sample code of the second syntax:

byte aValue=10;
int bValue= aValue; // convertible
int [] zArray=new byte[5]; // not convertible
int [] yArray=new int[5]; // convertible

Unlike value types, an array of reference types can be initialized to an array of the same or derived types. In
the declaration, typeb must be the same or a derivation of typea, which is demonstrated in the following code:

public class Starter{


public static void Main(){
XBase [] obj=new XDerived[5]; // base <- derived
XDerived [] obj2=new XBase[5]; // derived <- base [invalid]
}
}

public class XDerived: XBase {


}

public class XBase {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The third syntax declares, initializes, and assigns values to the array elements. The initialization list (ilist)
contains the initial value for the elements of the array, where the values are comma-delimited. The number of
values in the list should match the number of elements in the array exactly—no more and no less.

This is an example of the third syntax for declaring an array:

int [] zArray=new int[3] {1,2,3}; // valid


int [] yArray=new int[3] {1,2}; // invalid
ZClass [] xArray=new ZClass[3] { // valid
new ZClass(5), new ZClass(10),
new ZClass(15) };

The fourth syntax also declares, initializes, and assigns values to array elements. However, in this
circumstance, the initialization list sets the number of elements. The array size is not stipulated in this
syntax. The compiler counts the number of items in the initialization list to set the length of the array.

This is an example of the fourth syntax:

int [] zArray=new int[] {1,2,3,4,5}; // 5 elements

The fifth syntax is an abbreviation of the fourth syntax, where the array type and number of elements are
inferred from the initialization list.

This is an example of the fifth syntax:

int [] yArray={1,2,3,4,5};

As in a local variable or field definition, multiple declarations can be combined:

public class ZClass{


private int [] first={1,2,3},
second={4,5,6},
third={7,8,9};

// Remainder of class...
}

Array Elements

Indexing operators refer to elements of an array. With an index, the indexing operator returns a specific
element of the array. When an indexing operator is used on the left hand side (LHS), the element value is
changed. On the RHS, the indexing operator returns the value of the element.

The following for loop lists the elements of an array. The element and indexing operator appear as an l-value
to total the array. It is used as an r-value to display each element:

int [] zArray={1,2,3,4,5};
int total=0;
for(int count=0;count<zArray.Length;++count) {
total+=zArray[count]; // l-value
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

int number=zArray[count]; // r-value


Console.WriteLine(number);
}
Console.WriteLine("\nThe total is {0}.",
total);

Multidimensional Arrays

You are not limited to one-dimensional arrays. Multidimensional arrays are rectangular arrays and have
multiple dimensions and indices. Two-dimensional arrays, which consist of rows and columns, are the most
prevalent kind of multidimensional array. Each row contains the same number of columns, thus making the
array rectangular. From a geometric perspective, the x-axis consists of rows and the y-axis consists of
columns. Multidimensional arrays are stored in row-major order and are processed in row-major order.

The total number of elements in a multidimensional array is the product of the indices. For example, an array
of 5 rows and 6 columns has 30 elements. The Array.Length property returns the total number of elements in
the array. The Array.GetLength method returns the number of elements per index. The indices are numbered
from zero. For a two-dimensional array, row is the zero dimension, whereas column is the one dimension.
GetLength(0) would then return the number of rows in the multidimensional array.

This is the syntax to declare a two-dimensional array. Notice the indexing operator. Row and column
indexes in the indexing operator are delimited with a comma.

type [,] arrayname 1;


typea [,] arrayname 2=new typeb[r,c];
typea [,] arrayname 3=new typeb[r,c] {ilist};
typea[,] arrayname 4=new typeb[,] {ilist};
typea[,] arrayname 5={ilist};

The following code shows various declarations of multidimensional arrays. The initialization list of a
multidimensional array includes nested initialization lists for each row. If an array has two rows, the
initialization list includes two nested initialization lists. This is the syntax of a nested initialization list:
 { {nlist}, {nlist}, {nlist} …}

The following code shows the various declaration syntaxes, including nested initialization lists:

int [,] array1; // syntax 1


array1=new int[1,2];
int [,] array2=new int[2,3]; // syntax 2
int [,] array3=new int[2,3] { // syntax 3
{1,2,3}, {4,5,6} };
int [,] array4=new int[,] { // syntax 4
{1,2,3}, {4,5,6} };
int [,] array5= { // syntax 5
{1,2,3}, {4,5,6} };

To access an element of a multidimensional array, specify a row and column index in the indexing operator.
It can be used on the LHS and RHS to set or get the value of an element, respectively. The following code
calculates the total of the elements. This requires enumerating all the elements of a multidimensional array.

int [,] zArray=new int[2,3] {


{1,2,3}, {4,5,6} };
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

int total=0;

for(int row=0;row<zArray.GetLength(0);++row) {
for(int col=0;col<zArray.GetLength(1);++col) {
total+=zArray[row, col]; // LHS
int number=zArray[row, col]; // RHS
Console.WriteLine(number);
}
}
Console.WriteLine("\nThe total is {0}.",
total);

We have been focusing on two-dimensional arrays. However, arrays can have more than two dimensions. In
fact, there is no limit to the number of dimensions. Three- and four-dimensional arrays are less common than
two-dimensional arrays, but are seen nonetheless. More dimensions are rarely enunciated. Most developers
find multidimensional arrays beyond two indices mind-numbing to manage and manipulate. Additional
dimensions require added comma-delimited indexes when the array is, declared, defined, and used.

This is an example of a four-dimensional array:

int [,,,] array=new int[1,2,3,2]


{{{{1,2}, {1,2},{1,2}},{{1,2},{1,2},{1,2}}}};

How is the preceding code interpreted? A multidimensional array can be viewed as a hierarchical array that
consists of layers. Each layer represents a different level of array nesting. The previous example defines a
single-dimensional array, which aggregates two nested arrays. The nested arrays each contain three other
arrays. Each of these lower nested arrays contains two elements.

This is a diagram of the array hierarchy:

{ 1 }; // layer 1
{{ 1 },{ 2 }}; // layer 2
{{{ 1 }, { 2 },{ 3 }},{{{ 1 }, { 2 },{ 3 }}; // layer 3
{{{{1,2}, {1,2},{1,2}} , {{1,2},{1,2},{1,2}}}}; // layer 4

The following code demonstrates a practical use of a multidimensional array. The program maintains the
grades of students. Each student attends two classes. Each class has a class name and grade. Object
elements are defined to make the array generic. Strings, integers, reference types, or anything else can be
placed in an object array. Everything is derived from System.Object in managed code. The downside is
boxing and unboxing of grades, which are value types.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){

string [] names={"Bob", "Ted", "Alice"};


object [,,] grades=new object[3,2,2]
{{{"Algebra",85}, { "English",75}},
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

{{"Algebra",95}, { "History",70}},
{{"Biology",100}, { "English",92}}};

for(int iName=0;iName<names.Length;++iName) {
Console.WriteLine("\n{0}\n", names[iName]);
for(int iCourse=0;iCourse<2;++iCourse) {
Console.WriteLine("{0} {1}",
grades[iName, iCourse, 0],
grades[iName, iCourse, 1]);
}
}
}
}
}

Jagged Arrays

The most frequently found definition of a jagged array is an array of arrays. More specifically, a jagged array
is an array of vectors. Although other arrays are rectangular, a jagged array, as the name implies, is jagged
as each vector in the array can be of different length. With jagged arrays, first define the number of rows or
vectors in the jagged array. Second, declare the number of elements in each row.

The syntax for declaring a jagged array is similar to a multidimensional array. Instead of a single bracket ([r,c
]), jagged arrays have two brackets ([r][]). When declaring a jagged array, the number of columns is not
specified and is omitted. The number of elements in each row is set individually. This is the syntax of a
jagged array:

type [][] arrayname 1;


typea [][] arrayname 2=new typeb[r][];
typea [][] arrayname 3=new typeb[r][] {ilist};
typea[][] arrayname 4=new typeb[][] {ilist};
typea[][] arrayname 5={ilist};

This is sample code for declaring a jagged array:

int [][] zArray; // syntax 1


int [][] yArray=new int[3][]; // syntax 2
int [][] xArray=new int[3][] // syntax 3
{new int [] {1,2,3},
new int[] {1,2},
new int[] {1,2,3,4}};
int [][] wArray=new int[][]{ // syntax 4
new int [] {1,2,3},
new int[] {1,2},

new int[] {1,2,3,4}};


int [][] wArray={ // syntax 5
new int [] {1,2,3},
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

new int[] {1,2},


new int[] {1,2,3,4}};

The rows of the jagged array are initialized to one-dimensional arrays. Because the rows are assigned
distinct arrays, the length of each row may vary. Therefore, a jagged array is essentially an array of vectors:

jarray[row]=new type[elements];

Here is sample code that employs a jagged array. Each row of the jagged array has an increasing number of
elements. The first nested loop creates and initializes each row of the jagged array. At the end, the values of
each row are totaled and displayed.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
int [][] jagged=new int [7][];
int count=0;
for(int row=0;row<jagged.GetLength(0);++row) {
Console.Write("\nRow {0}:", row);
jagged[row]=new int[row+1];
for(int index=0; index<row+1; ++index) {
++count;
jagged[row][index]=count;
Console.Write(" {0}", count);
}
}
Console.WriteLine("\n\nTotals");
for(int row=0;row<jagged.GetLength(0);++row) {
int total=0;
for(int index=0; index<jagged[row].GetLength(0);
++index) {
total+=jagged[row][index];
}
Console.Write("\nRow {0}: {1}",
row, total);
}

}
}
}

Vectors and multidimensional arrays are both collections. As such, arrays implement a combination of an
array and some collection-specific interfaces, which are encapsulated in the System.Array type.
System.Array implements the ICollection, IEnumerable, IList, and ICloneable interfaces. System.Array also
implements array-specific behaviors, such as the Array.GetLength method.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

System.Array

The System.Array type houses the fundamental methods and properties that are essential to an array. This
includes sorting, reversing, element count, synchronization, and much more. Table 5-2 lists the methods of
the System.Array type. Many of the methods are static, which is noted in the syntax. In addition, some
methods are for single-dimensional arrays and are not usable with multidimensional arrays. This fact is noted
in the method description in Table 5-2.
Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

As
Re stati
ad c
Onl ReadO
y nlyCo
Thi llect
s ion<T
is >
a
ge AsRea
ner dOnly
ic <T>(
me
tho
d T[]
tha sourc
t eArra
ret y)
urn
s
a
rea
d-o
nly
wra
pp
er
for
an
arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Bin
ary stati
Se c
arc int
h Binar
Thi ySear
s ch(
me
tho Array
d sourc
co eArra
nd y,
uct
s
a objec
bin t
ary searc
se hValu
arc e)
h
for
stati
a
c
sp
int
ecif
Binar
ic
ySear
val
ch<T>
ue
(
in
a
sor T[]
ted sourc
on eArra
e-d y,
im
en T
sio value
nal )
arr
ay.
Th
ere
are
sev
era
l
ove
rlo
ad
s
for
thi
s
me
tho
d.
Th
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Cle
ar stati
Thi c
s void
me Clear
tho (Arra
d y
set sourc
s eArra
a y,
ran
ge int
of index
ele ,
me int
nts lengt
to h)
zer
o,
null
,
or
fals
e.

Clo
ne seale
Thi d
s objec
me t
tho Clone
d ()
clo
ne
s
the
cur
ren
t
arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Co
nst stati
rai c
ne void
dC Const
opy raine
dCopy
Thi {
s
me Array
tho sourc
d eArra
co y,
pie
s
a int
ran sourc
ge eInde
of x
ele
me Array
nts desti
fro natio
m nArra
the y,
so
urc
int
e
desti
arr
natio
ay
nInde
int
x,
o
a
de int
sti lengt
nat h)
ion
arr
ay.
Yo
u
set
the
so
urc
e
ind
ex
an
d
de
sti
nat
ion
ind
ex,
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Co
nve stati
rtAl c
l <dest
Thi inati
s onTyp
is e>
a
ge Conve
ner rtAll
ic <sour
me ceTyp
tho e,
d
tha
t desti
co natio
nve nType
rts >(
the
typ sourc
e eType
of sourc
an eArra
arr y,
ay.
Conve
rter<
sourc
eType
,

desti
natio
nType
>
conve
rter)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Co
py stati
Thi c
s void
me Copy(
tho
d Array
co sourc
pie eArra
s y,
ele
me
nts Array
fro desti
m natio
the nArra
so y,
urc
e int
arr lengt
ay h)
to
the
de stati
sti c
nat void
ion Copy(
arr
ay. Array
Th sourc
e eArra
sp y,
ecif
ied
nu int
mb sourc
er eInde
of x,
ele
me Array
nts desti
is natio
co nArra
pie y,
d.
Th int
ere desti
are natio
fou nInde
r x,
ove
rlo int
ad lengt
s h)
to
thi
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Co
py void
To CopyT
Thi o(Arr
s ay
me desti
tho natio
d nArra
co y,
pie
s int
the index
cur )
ren
t void
on CopyT
e-d o(Arr
im ay
en desti
sio natio
nal nArra
arr y,
ay
to long
the index
de )
sti
nat
ion
arr
ay
sta
rtin
g
at
the
sp
ecif
ied
ind
ex.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Cre
ate stati
Ins c
tan Array
ce Creat
Thi eInst
s ance(
me
tho Type
d array
cre Type,
ate
s
an int
ins lengt
tan h)
ce
of
stati
an
c
arr
Array
ay
Creat
at
eInst
run
ance(
tim
e.
Type
Thi
array
s
Type,
me
tho
d int
ha rows,
s
sev int
era cols)
l
ove
rlo
ad
s.
On
e-d
im
en
sio
nal
an
d
two
-di
me
nsi
on
al
ver
sio
ns
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Exi
sts stati
c
Thi bool
s Exist
is <T> {
a
ge T []
ner sourc
ic eArra
me y,
tho
d
tha Predi
t cate<
co T>
nfir match
ms )
tha
t
an
ele
me
nt
ma
tch
es
the
co
ndi
tio
ns
set
in
the
pre
dic
ate
fun
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Fin
d stati
Thi c T
s Find<
is T>(
a
ge T[]
ner sourc
ic eArra
me y,
tho
d
tha Predi
t cate<
find T>
s match
the )
firs
t
ele
me
nt
tha
t
ma
tch
es
the
co
ndi
tio
ns
set
in
the
pre
dic
ate
fun
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Fin
dAl stati
l c
Thi T[]
s FindA
is ll<T>
a (
ge
ner T[]
ic sourc
me eArra
tho y,
d
tha
t Predi
ret cate<
urn T>
s match
all )
the
ele
me
nts
tha
t
ma
tch
the
co
ndi
tio
ns
set
in
the
pre
dic
ate
fun
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Fin
dIn stati
dex c
int
Thi FindI
s ndex<
is T>(
a
ge T[]
ner sourc
ic eArra
me y,
tho
d
tha Predi
t cate<
ret T>
urn match
s )
the
ind
stati
ex
c
to
int
the
FindI
firs
ndex<
t
T>(
ele
me
nt T[]
tha sourc
t eArra
ma y,
tch
es int
the start
co ingIn
ndi dex,
tio
ns
set Predi
in cate<
the T>
pre match
dic )
ate
fun stati
cti c
on. int
FindI
ndex(

T[]
sourc
eArra
y,
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Fin
dL stati
ast c T
FindL
Thi ast<T
s >{
is
a T[]
ge sourc
ner eArra
ic y,
me
tho
d Predi
tha cate<
t T>
ret match
urn )
s
the
las
t
ele
me
nt
tha
t
ma
tch
es
the
co
ndi
tio
ns
set
in
the
pre
dic
ate
fun
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Fin
dL stati
ast c
Ind int
ex FindL
Thi astIn
s dex(T
is []
a sourc
ge eArra
ner y,
ic
me Predi
tho cate<
d T>
tha match
t )
ret
urn
s stati
the c
ind int
ex FindL
to astIn
the dex(T
las []
t sourc
ele eArra
me y,
nt
tha
int
t
start
ma
ingIn
tch
dex,
es
the
co Predi
ndi cate<
tio T>
ns match
set )
in
the
pre stati
dic c
ate int
fun FindL
cti astIn
on. dex(T
[]
sourc
eArra
y,

int
start
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

For
Ea publi
ch c
Thi stati
s c
is void
a ForEa
ge ch<T>
ner (
ic
me T[]
tho array
d ,
tha
t
per Actio
for n<T>
ms actio
an n)
act
ion
on
ea
ch
ele
me
nt
of
the
arr
ay,
wh
ere
act
ion
ref
ers
to
a
fun
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Ge
tEn seale
um d
era IEnum
tor erato
Thi r
s GetEn
me umera
tho tor()
d
ret
urn
s
an
en
um
era
tor
tha
t
im
ple
me
nts
the
en
um
era
tor
pat
ter
n
for
coll
ect
ion
s.
Yo
u
ca
n
en
um
era
te
the
ele
me
nts
of
the
arr
ay
wit
h
the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Ge
tLe int
ngt GetLe
h ngth(
Thi int
s dimen
me sion)
tho
d
ret
urn
s
the
nu
mb
er
of
ele
me
nts
for
a
di
me
nsi
on
of
an
arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Ge
tLo long
ng GetLo
Le ngLen
ngt gth(i
h nt
Thi dimen
s sion)
me
tho
d
ret
urn
s
the
nu
mb
er
of
ele
me
nts
as
a
64-
bit
int
eg
er
for
a
di
me
nsi
on
of
an
arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Ge
tLo int
wer GetLo
Bo werBo
un und(i
d nt
Thi dimen
s sion)
me
tho
d
ret
urn
s
the
low
er
bo
un
d
of
a
di
me
nsi
on,
whi
ch
is
us
uall
y
zer
o.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Ge
tUp int
per GetUp
Bo perBo
un und(i
d nt
Thi dimen
s sion)
me
tho
d
ret
urn
s
the
up
per
bo
un
d
of
a
di
me
nsi
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Ge
tVa objec
lue t
GetVa
Thi lue(i
s nt
me index
tho )
d
ret
urn objec
s t
the GetVa
val lue(p
ue arams
of int[]
an indic
ele es)
me
nt
at
the
sp
ecif
ied
ind
ex.
Thi
s
me
tho
d
ha
s
sev
era
l
ove
rlo
ad
s.
A
on
e-d
im
en
sio
nal
ver
sio
n
an
d
a
mu
ltidi
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Ind
ex stati
Of c
Thi int
s Index
me Of(Ar
tho ray
d sourc
ret eArra
urn y,
s
the objec
ind t
ex find)
of
the Ge
firs ner
t ic
ele ver
me sio
nt n:
in
a
stati
on
c
e-d
int
im
Index
en
Of<T>
sio
(T[]
nal
sourc
arr
eArra
ay
y,
tha
t
ha T
s value
the )
sp
ecif
ied
val
ue.
Thi
s
me
tho
d
ha
s
sev
era
l
ove
rlo
ad
s.
A
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Init
iali void
ze Initi
Thi alize
s ()
me
tho
d
initi
aliz
es
eve
ry
ele
me
nt
of
the
arr
ay.
Th
e
def
aul
t
co
nst
ruc
tor
of
ea
ch
ele
me
nt
is
call
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

La
stI stati
nd c
ex int
Of LastI
Thi ndexO
s f(Arr
me ay
tho sourc
d eArra
ret y,
urn
s objec
the t
ind value
ex )
of
the Ge
las ner
t ic
ele ver
me sio
nt n:
tha
t
stati
ma
c
tch
int
es
LastI
the
ndexO
sp
f<T>(
ecif
T[]
ied
sourc
val
eArra
ue
y,
in
a
on T
e-d value
im )
en
sio
nal
arr
ay.
Thi
s
me
tho
d
ha
s
sev
era
l
ove
rlo
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Re
siz stati
e c
Thi void
s Resiz
is e<T>(
a
ge ref
ner T[]
ic sourc
me eArra
tho y,
d
tha
t int
ch newSi
an ze)
ge
s
the
siz
e
of
a
on
e-d
im
en
sio
nal
arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Re
ver stati
se c
Thi void
s Rever
me se(Ar
tho ray
d sourc
rev eArra
ers y)
es
the
ord stati
er c
of void
ele Rever
me se(Ar
nts ray
in sourc
a eArra
on y,
e-d
im int
en index
sio ,
nal int
arr lengt
ay. h)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Set
Val void
ue SetVa
Thi lue(o
s bject
me value
tho ,
d int
set index
s )
the
val
ue void
of SetVa
a lue(o
sp bject
ecif value
ic ,
ele
me param
nt s
of int[]
the indic
cur es)
ren
t
on
e-d
im
en
sio
nal
arr
ay.
Thi
s
me
tho
d
ha
s
sev
era
l
ove
rlo
ad
s.
Tw
o
of
the
ove
rlo
ad
s
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Sor
t stati
Thi c
s void
me Sort(
tho Array
d sourc
sor eArra
ts y)
the
ele
me stati
nts c
of void
a Sort<
on T>(
e-d
im T[]
en sourc
sio eArra
nal y)
arr
ay.
Thi
s
me
tho
d
ha
s
sev
era
l
ove
rlo
ad
s.
A
no
ng
en
eri
c
ver
sio
n
an
d
a
ge
ner
ic
ver
sio
n
of
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-2:
System.Array
Members

De Sy
scr nta
ipti x
on

Tru
eF stati
orA c
ll bool
Thi TrueF
s orAll
is <T>(
a
ge T[]
ner array
ic ,
me
tho
d Predi
tha cate<
t T>
ret match
urn )
s
tru
e
if
all
ele
me
nts
of
an
arr
ay
ma
tch
the
co
ndi
tio
ns
set
in
the
pre
dic
ate
fun
cti
on.

The following sections offer sample code and additional descriptions for some of the System.Array methods.

Array.AsReadOnly Method
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The following code creates and initializes an integer array. The second element of the array is then modified,
which demonstrates the read-write capability of the collection. Array .AsReadOnly is called to wrap the array
in a read-only collection. The ReadOnlyCollection type is found in the System.Collections.ObjectModel
namespace. After displaying the elements of the read-only collection, the code attempts to modify an
element. Since the collection is read-only, a compile error occurs at this line:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
int [] zArray={1,2,3,4};
zArray[1]=10;

ReadOnlyCollection<int> roArray=Array.AsReadOnly(zArray);
foreach(int number in roArray) {
Console.WriteLine(number);
}
roArray[1]=2; // compile error
}
}
}

Array.Clone Method
In the following code, the CommissionedEmployee type inherits from the Employee type. An array of
commissioned employees is defined and then cloned with the Clone method. The clone type is an array of
Employees. Because Clone returns an object array, which is unspecific, you should cast to a specific array
type. The cast from System.Object is not type-safe, and an incorrect cast would cause an exception.
Polymorphism is employed in the foreach loop to call the Pay method of the derived class.

using System;
using System.Collections.Generic;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
CommissionedEmployee [] salespeople=
{new CommissionedEmployee("Bob"),
new CommissionedEmployee("Ted"),
new CommissionedEmployee("Sally")};

Employee [] employees=
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

(Employee [])salespeople.Clone();

foreach(Employee person in
employees) {
person.Pay();
}
}
}

public class Employee {


public Employee(string name) {
m_Name=name;
}

public virtual void Pay() {


Console.WriteLine("Paying {0}", m_Name);
}

private string m_Name;


}

public class CommissionedEmployee: Employee {


public CommissionedEmployee(string name) :
base(name) {
}

public override void Pay() {


base.Pay();
Console.WriteLine("Paying commissions");
}

Array.CreateInstance Method
The following code demonstrates both the CreateInstance and SetValue methods. CreateInstance creates a
new array at run time. This requires some degree of reflection, which will be discussed in Chapter 10,
"Metadata and Reflection." This code reads the array type, method to call, and initial values for each element
from the command line. CreateInstance creates a new array using the type name read from the command
line. In the for loop, Activator.CreateInstance creates instances of the element type, where values from the
command line are used to initialize the object. In the foreach loop, the elements of the array are enumerated
while calling the method stipulated in the command-line arguments as the second parameter.

using System;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System.Reflection;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(string [] argv){
Assembly executing=Assembly.GetExecutingAssembly();
Type t=executing.GetType(argv[0]);
Array zArray=Array.CreateInstance(
t, argv.Length-2);
for(int count=2;count<argv.Length;++count) {
System.Object obj=Activator.CreateInstance(t, new object[] {
argv[count]});
zArray.SetValue(obj, count-2);
}
foreach(object item in zArray) {
MethodInfo m=t.GetMethod(argv[1]);
m.Invoke(item, null);
}
}
}

public class ZClass {


public ZClass(string info) {
m_Info="ZClass "+info;
}

public void ShowInfo() {

Console.WriteLine(m_Info);
}

private string m_Info;


}

public class YClass {


public YClass(string info) {
m_Info="YClass "+info;
}

public void ShowInfo() {


Console.WriteLine(m_Info);
}

private string m_Info;


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class XClass {


public XClass(string info) {
m_Info="XClass "+info;
}

public void ShowInfo() {


Console.WriteLine(m_Info);
}

private string m_Info;


}
}

A typical command line and results of the application are shown in Figure 5-2.

Figure 5-2: A command line and the results from running the application

Array.FindAll Method
Several System.Array methods use predicates, such as the Exists, Find, FindAll, and FindLastIndex
methods. Predicates are delegates initialized with functions that find matching elements. The predicate
function is called for each element of the array. A conditional test is performed in the function to isolate
matching elements; true or false is returned from the predicate indicating that a match has or has not been
found, respectively.

This is the syntax of the Predicate delegate:

delegate bool Predicate<T>(T obj)

Predicate methods are generic methods. The type parameter indicates the element type. The return value is
the result of the comparison.

The following code finds all elements equal to three. MethodA is the predicate method, which compares each
value to three.

public static void Main(){


int [] zArray={1,2,3,1,2,3,1,2,3};
Predicate<int> match=new Predicate<int>(MethodA<int>);
int [] answers=Array.FindAll(zArray, match);
foreach(int answer in answers) {
Console.WriteLine(answer);
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static bool MethodA<T>(T number) where T:IComparable {


int result=number.CompareTo(3);
return result==0;
}

Array.Resize Method
The Resize method resizes a one-dimensional array.

Here is sample code for resizing an array. The elements added to the array are initialized to a default value.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
int [] zArray={1,2,3,4};
Array.Resize<int>(ref zArray, 8);
foreach(int number in zArray) {
Console.WriteLine(number);
}
}
}
}

System.Array Properties

System.Array has several properties that are useful when working with arrays. Table 5-3 lists the various
properties.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-3:
System.Array
Properties
Open table as
spreadsheet

De Sy
scr nta
ipti x
on

IsF
ixe virtu
dSi al
ze bool
Thi IsFix
s edSiz
pro e{
per
ty get;}
ret
urn
s
tru
e
if
the
arr
ay
is
a
fixe
d
siz
e.
Ot
her
wis
e,
fal
se
is
ret
urn
ed.
Al
wa
ys
tru
e
for
arr
ay
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-3:
System.Array
Properties
Open table as
spreadsheet

De Sy
scr nta
ipti x
on

IsR
ea virtu
dO al
nly bool
Thi IsRea
s dOnly
pro {
per
ty get;}
ret
urn
s
tru
e
if
the
arr
ay
is
rea
d-o
nly
.
Ot
her
wis
e,
fal
se
is
ret
urn
ed.
Al
wa
ys
fal
se
for
arr
ay
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-3:
System.Array
Properties
Open table as
spreadsheet

De Sy
scr nta
ipti x
on

IsS
ync virtu
hro al
niz bool
ed IsSyn
Thi chron
s ized{
pro
per get;}
ty
ret
urn
s
tru
e
if
the
arr
ay
is
thr
ea
d-s
afe
.
Ot
her
wis
e,
fal
se
is
ret
urn
ed.
Al
wa
ys
fal
se
for
arr
ay
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-3:
System.Array
Properties
Open table as
spreadsheet

De Sy
scr nta
ipti x
on

Le
ngt int
h Lengt
Thi h{
s
pro get;}
per
ty
ret
urn
s
the
nu
mb
er
of
ele
me
nts
in
the
arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-3:
System.Array
Properties
Open table as
spreadsheet

De Sy
scr nta
ipti x
on

Lo
ng Long
Le LongL
ngt ength
h {
Thi
s get;}
pro
per
ty
ret
urn
s
the
nu
mb
er
of
ele
me
nts
in
the
arr
ay
as
a
64-
bit
val
ue.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-3:
System.Array
Properties
Open table as
spreadsheet

De Sy
scr nta
ipti x
on

Ra
nk int
Thi Rank{
s
pro get;}
per
ty
ret
urn
s
the
ran
k
of
the
arr
ay,
whi
ch
is
the
nu
mb
er
of
di
me
nsi
on
s.
For
ex
am
ple
,a
two
-di
me
nsi
on
al
arr
ay
ha
s
a
ran
k
of
two
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-3:
System.Array
Properties
Open table as
spreadsheet

De Sy
scr nta
ipti x
on

Sy
nc virtu
Ro al
ot objec
Thi t
s SyncR
pro oot{
per
ty get;}
ret
urn
s
a
sy
nc
hro
niz
ati
on
obj
ect
for
the
cur
ren
t
arr
ay.
Arr
ay
s
are
not
inh
ere
ntl
y
thr
ea
d-s
afe
.
Sy
nc
hro
niz
e
ac
ce
ss
to
the
arr
ay
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Many of the preceding properties are used in sample code. The SyncRoot property is particularly important
and not included in previous sample code.

Array.SyncRoot Property
The purpose of the SyncRoot object is to synchronize access to an array. Arrays are unsafe data structures.
As documented, the IsSynchronized property always returns false for an array. Accesses to arrays are
easily synchronized with the lock statement, where the SyncRoot object is the parameter.

In the following code, the array is a field in the Starter class. The DisplayForward and DisplayReverse
methods list array elements in forward and reverse order correspondingly. The functions are invocated at
threads, in which the SyncLock property prevents simultaneous access in the concurrent threads.

using System;
using System.Threading;

namespace Donis.CSharpBook{
public class Starter{

public static void Main(){


Array.Sort(zArray);
Thread t1=new Thread(
new ThreadStart(DisplayForward));
Thread t2=new Thread(
new ThreadStart(DisplayReverse));
t1.Start();
t2.Start();
}

private static int [] zArray={1,5,4,2,4,2,9,10};


public static void DisplayForward() {
lock(zArray.SyncRoot) {
Console.Write("\nForward: ");
foreach(int number in zArray) {
Console.Write(number);
}
}
}

public static void DisplayReverse() {


lock(zArray.SyncRoot) {
Array.Reverse(zArray);
Console.Write("\nReverse: ");
foreach(int number in zArray) {
Console.Write(number);
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Array.Reverse(zArray);
}
}
}
}

Comparable Elements
System.Array methods require elements to be instances of comparable types.
 Array.IndexOf
 Array.LastIndexOf
 Array.Sort
 Array.Reverse
 Array.BinarySearch

Comparable types implement the IComparable interface, which requires the implementation of the
CompareTo method. The CompareTo method returns zero when the current and target instances are equal. If
the current instance is less than the target, a negative value is returned. A positive value is returned if the
current instance is greater than the target. The preceding methods call IComparable.CompareTo to perform
the required comparisons to sort, reverse, and otherwise access the array in an ordered manner.

A run-time error occurs in the following code when Array.Sort is called. Why? The XClass does not
implement the IComparable interface.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
XClass [] objs={new XClass(5), new XClass(10),
new XClass(1)};
Array.Sort(objs);
}
}

public class XClass {


public XClass(int data) {
propNumber=data;
}

private int propNumber;


public int Number {
get {
return propNumber;
}
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Here is the proper code, where the XClass implements the IComparable interface. This program runs
successfully.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
XClass [] objs={new XClass(5), new XClass(10),
new XClass(1)};
Array.Sort(objs);
foreach(XClass obj in objs) {
Console.WriteLine(obj.Number);
}
}
}

public class XClass: IComparer {


public XClass(int data) {
propNumber=data;
}

private int propNumber;


public int Number {
get {
return propNumber;
}

public int CompareTo(object obj) {


XClass comp=(XClass) obj;
if(this.Number==comp.Number){
return 0;
}
if(this.Number<comp.Number){
return -1;
}
return 1;
}
}
}

Many of the methods and properties of System.Array are mandated in interfaces that the type implements.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The following section lists those interfaces and methods.

ICollection Interface
The ICollection interface is one of the interfaces implemented in System.Array type; it returns the count of
elements and supports synchronization of collections. The members of the ICollection interface are as
follows:
 CopyTo method
 Count property
 IsSynchronized property
 SyncRoot property

ICloneable Interface
System.Array implements the ICloneable interface. This is the interface for duplicating an object, such as an
array. The only member of this interface is the Clone method.

IEnumerable
System.Array type implements the IEnumerable interface. IEnumerable.GetEnumerator is the sole member
of this interface. GetEnumerator returns an enumerator object that implements the IEnumerator interface.
The enumerator provides a consistent interface for enumerating any collection. The benefit is the ability to
write a generic algorithm, which requires enumerating the elements of a collection in a consistent manner.
For example, the foreach statement uses an enumerator object to consistently iterate all collection types.

Chapter 7, "Iterators," will focus more on enumerators.

Here is sample code that enumerates an array using an enumerator object:

using System;
using System.Collections;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
int [] numbers={1,2,3,4,5};
IEnumerator e=numbers.GetEnumerator();
while(e.MoveNext()) {
Console.WriteLine(e.Current);
}
}
}
}

IList Interface
System.Array type implements the IList interface. However, only part of this implementation is publicly
available. The private implementation of some IList members effectively removes those members from the
public interface. These are members contrary to the array paradigm, such as the RemoveAt method. Arrays
are immutable. You cannot remove elements from the middle of an array.

Table 5-4 lists the IList interface and indicates the public versus private implementation in System.Array.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-4: List


Members

Me Pu
mb bli
er c
Na or
me Pri
vat
e

Ad Pri
d vat
e

Cle Pu
ar blic

Co Pri
nta vat
ins e

Ind Pu
ex blic
Of

Ins Pri
ert vat
e

Re Pri
mo vat
ve e

Re Pri
mo vat
ve e
At

Indexers
You can treat instances as arrays by using indexers. Indexers are ideal for types that wrap collections, in
which additional functionality is added to the type that augments the collection. Access the object with the
indexing operator to get or set the underlying collection. Indexers are a combination of an array and a
property. The underlying data of an indexer is often an array or a collection. The indexer defines a set and get
method for the this reference. Indexers are considered a default property because the indexer is a nameless
property. Internally, the compiler inserts the get_Item and set_Item method in support of indexers.

Indexers are fairly typical properties. However, there are some exceptions. Here are some of the similarities
and differences between indexers and properties:
 Indexers can be overloaded.
 Indexers can be overridden.
 Indexers can be added to interfaces.
 Indexers support the standard access modifiers.
 Indexers cannot be a static member.
 Indexers are nameless and associated with the this reference.
 Indexers parameters are indices. Properties do not have indices.
 Indexers in the base class are accessed as base[indices], while a similar property is accessed
base.Property.

Indexers are also similar to arrays:


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 Indexers are accessed using indices.


 Indexers support non-numeric indices. Arrays support only integral indices.
 Indexers use a separate data store, whereas an array is the data store.
 Indexers can perform data validation, which is not possible with an array.

This is the syntax of an indexer:


 accessibility modifier type this[parameters]
 { attributes get {getbody} attributes set {setbody} }

Except for static accessibility, indexers have the same accessibility and modifiers of a normal property.
Indexers cannot be static. The parameters are a comma-delimited list of indexes. The list includes the type
and name of each parameter. Indexer indices can be nonintegral types, such as string and even Employee
types.

The following is example code for indexers. The Names type is a wrapper of an array of names and ages.
The indexer is read-only in this example and provides access to the array field. Per the parameters of the
indexer, the indexer manipulates object elements and has a single index. However, the _names array is
two-dimensional, which requires two indexes. Flexibility is one of the benefits of indexers versus standard
arrays. In the sample code, the parameter of the indexer represents the row, whereas the column is a
constant.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Names obj=new Names();
Console.WriteLine(obj[1]);
}
}

public class Names {


object [,] _names={
{"Valerie", 27},

{"Ben", 35},
{"Donis", 29}};

public object this[int index] {


get {
return _names[index,0]+" "+_names[index,1];
}
}
}
}

Indexers can be overloaded based on the parameter list. Overloaded indexers should have a varying number
of parameters or parameter types. The following code overloads the indexer property twice. The first property
is read-only and returns the name and age information. The second overload is a read-write property that
sets and gets the age of a person. This property, which uses a string parameter, also demonstrates
non-numerical indexes.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Names obj=new Names();
obj["Donis"]=42;
Console.WriteLine(obj["Donis"]);
}
}

public class Names {


object [,] _names={
{"Valerie", 27},
{"Ben", 35},
{"Donis", 29}};

public object this[int index] {


get {
return _names[index,0]+" "+_names[index,1];
}
}

public object this[string sIndex] {

get {
int index=FindName(sIndex);
return _names[index, 1];
}
set {
int index=FindName(sIndex);
_names[index, 1]=value;
}
}

private int FindName(string sIndex) {


for(int index=0; index<_names.GetLength(0);

++index) {
if((string)(_names[index,0])==sIndex) {
return index;
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

throw new Exception("Name not found");


}
}
}

params Keyword

The params keyword is a parameter modifier, which indicates that a parameter is a one-dimensional array of
any length. This defines a variable-length parameter list. The params modifier can be applied to only one
parameter in the parameter list, which must be the final parameter. The ref and out modifiers cannot be
applied to the params modified parameter. You have probably used methods of the Microsoft .NET
Framework class library (FCL) that have variable-length parameter lists, such as Console.WriteLine.
Console.WriteLine accepts a variable number of arguments. It has a param parameter.

Initialize the params-modified argument with an implicit or explicit array. This is done at the call site. For
implicit initialization, the C# compiler consumes the optional parameters that follow the fixed parameter list.
The fixed parameters are the parameters that precede the params-modified parameter in the function
signature. The optional arguments are consolidated into an array. If there are six optional arguments after the
fixed arguments, an array of six elements is created and initialized with the values of the optional arguments.
Alternatively, an explicit array can be used. Finally, the params argument can be omitted. When omitted, the
params parameter is assigned an empty array. An empty array is different from a null array. Empty arrays
have no elements but are valid instances.

In the following code, Names is a static method, where the params modifier is applied to the second
parameter. Therefore, the employees argument is a single-dimensional string array, and the Names method
offers a variable-length parameter list.

public static void Names(string company,


params string [] employees) {
Console.WriteLine("{0} employees: ",
company);
foreach(string employee in employees) {
Console.WriteLine(" {0}", employee);
}
}

For a variable-length parameter list, the number of parameters, which includes the parameter array, is set at
the called site. The following code shows the Names method being called with varying numbers of
parameters. In both calls, the first parameter is consumed by the company parameter. The remaining
parameters are used to create an array, which is assigned to the params parameter. A three-argument array
is created for the first method call, whereas the second method creates a six-argument array that is
assigned to the params parameter.

Names("Fabrikam","Fred", "Bob", "Alice");


Names("Contoso", "Sally", "Al", "Julia",
"Will", "Sarah", "Terri");

The following code calls the Names method with an explicit array. This is identical to calling the method with
three optional arguments.

Names("Fabrikam", new string [] {"Fred", "Bob",


"Alice"});
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

In this statement, the Names method is called without a params argument. For the omitted parameter, the
compiler creates an array with no elements, which is subsequently passed to the method.

Names("Fabrikam");

Variable-length methods can be overloaded similar to any method. You can even overload a method with a
fixed number of parameters with a method with a variable number of parameters. Where there is ambiguity,
the method with the fixed number of parameters is preferred and called.

In the following code, the Names method is overloaded with three methods. The first two overloads have a
variable-length parameter list, whereas the final method has a fixed-length parameter list. In Main, the first
two calls of the Names method are not ambiguous. The final call is ambiguous and can resolve to either the
first or third overload. Because the third overload has a fixed-length parameter list, it is called instead of the
first overloaded method.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Names("Fabrikam","Fred", "Bob", "Alice");
Names("Fabrikam",1234, 5678, 9876, 4561);
Names("Fabrikam","Carter", "Deborah");
}

public static void Names(string company,


params string [] employees) {
Console.WriteLine("{0} employees: ",
company);
foreach(string employee in employees) {
Console.WriteLine(" {0}", employee);
}
}

public static void Names(string company,


params int [] emplid) {

Console.WriteLine("{0} employees: ",


company);
foreach(int employee in emplid) {
Console.WriteLine(" {0}", employee);
}
}

public static void Names(string company,


string empl1, string empl2) {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("{0} employees: ",


company);
Console.WriteLine(" {0}",empl1);
Console.WriteLine(" {0}",empl2);
}
}
}

Array Conversion

You can cast between arrays. Arrays are implicit System.Array types. For that reason, regardless of type or
the number of dimensions, any array can be cast to System.Array. All arrays are compatible with that type.

When casting or converting between arrays, the source and destination array are required to have the same
dimensions. In addition, an array of value types is convertible only to arrays of the same dimension and type.
Arrays of reference types are somewhat more flexible. Arrays of reference types can be converted to arrays
of the same or ascendant type. This is called array covariance. Array reference types are covariant, whereas
arrays of value types are not.

Arrays can be inserted as function parameters and returns. In these roles, proper conversion is important.

Arrays as Function Returns and Parameters


Arrays provided as function arguments are passed by reference. This is more efficient than caching
potentially a large number of elements on the stack. As a reference type, the array state can be changed in
the called method. Array parameters are normal parameters and support the regular assortment of modifiers.
Of course, the array argument must be convertible to the array parameter.

In the following code, the ZClass has two static methods, which both have an array parameter. The ListArray
method has a System.Array parameter, which accepts any array argument. For this reason, the ListArray
method is called in Main with different types of array arguments. The Total method limits array arguments to
one-dimensional integer arrays.

using System;

namespace Donis.CSharpBook{
public class Starter{

public static void Main(){


int [] zArray={10,9,8,7,6,5,4,3,2,1};
string [] xArray={"a", "b", "c", "d"};
Console.WriteLine("List Numbers");
ZClass.ListArray(zArray);
Console.WriteLine("List Letters");
ZClass.ListArray(xArray);
Console.WriteLine("Total Numbers");
ZClass.Total(zArray);
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class ZClass {

public static void ListArray(Array a) {


foreach(object element in a) {
Console.WriteLine(element);
}
}

public static void Total(int [] iArray) {


int total=0;
foreach(int number in iArray) {
total+=number;
}
Console.WriteLine(total);
}
}
}

Arrays can also be returned from functions, which is one means of returning more than a single value. You
can return multiple values as elements of an array. Returning an array gives the calling function a reference
to the array, which provides direct access to the array. Arrays are not returned on the stack.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Collections
Arrays are the most popular collection. However, the .NET FCL offers a variety of other collections with
different semantics. Collections are abstractions of data algorithms. ArrayList is an abstraction of a dynamic
array, the Stack collection abstracts a stack data structure, the Queue collection abstracts queues, the
Hashtable collection abstracts a lookup table, and so on. Each collection exposes both unique and standard
interfaces. The unique interface is specific to the collection type. For example, the Stack type has pop and
push methods, whereas the Queue type has Dequeue and Enqueue methods. Collections minimally
implement the ICollection, IEnumerable, and ICloneable interfaces. (These interfaces were described earlier
in this chapter.) The nongeneric collection classes are implemented in the System.Collections namespace.
Generic collections are reviewed in Chapter 6, "Generics."

Table 5-5 lists the nongeneric collections in the .NET FCL.


Table 5-5: Collection Types

Class Name Description

ArrayList Dynamic array

BitArray Bit array

Hashtable Lookup table of keys and values

Queue First-in/first-out (FIFO) collection of elements

SortedList Sorted list of elements

Stack Last-in/first-out (LIFO) collection of elements

What follows is a detailed explanation of each collection found in the Collections namespace. The
explanations are complemented with sample code, which demonstrates the uniqueness of each collection.

ArrayList Collection

An array list is a dynamic array. Although indigenous arrays are static, elements can be added or removed
from an ArrayList at run time. Elements of the ArrayList are not automatically sorted. Similar to
single-dimensional arrays, the elements of an ArrayList are accessible using the indexing operator and
indices.

In addition to the standard collection interfaces, ArrayList implements the IList interface.

Table 5-6 lists the ArrayList-specific methods and properties. The static members of ArrayList are
thread-safe, whereas instance members are not. The common collection interfaces—ICollection,
IEnumerable, and ICloneable—are not discussed in detail. (These interfaces and their members were
reviewed earlier in the chapter.)
Table 5-6: ArrayList Members

Member Name Syntax

Constructors
ArrayList()
ArrayList(

ICollection
sourceCollection)

ArrayList(int capacity)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-6: ArrayList Members

Member Name Syntax

Adapter
This method creates a wrapper for an IList collection. static ArrayList
Adapter(
IList list)

Add
This method adds an element to the end of the ArrayList collection. virtual int Add(object
value)

AddRange
This method adds a range of elements to the ArrayList collection. The virtual void
elements are input from an ICollection type, such as a regular array. AddRange(
ICollection
elements)

BinarySearch
This method performs a binary search for a specific value in a sorted array. virtual int
BinarySearch(
object value)

virtual int
BinarySearch(
object value,
IComparer
comparer)

virtual int
BinarySearch(
int index,
int count,
object value,
IComparer
comparer)

Capacity
This property gets or sets the number of properties allowed in the collection. virtual int Capacity
The default capacity is 16 elements. Capacity is different from the number of {
elements. The capacity is automatically increased as elements are added. get; set}
When the number of elements exceeds the current capacity, the capacity
doubles. Capacity is for better memory management of elements in the
collection.

Clear
This method removes all the elements of the collection. virtual void Clear()

Contains
This method returns true if the specified item is found in a collection. If the virtual bool
item is not found, false is returned. Contains(object item)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-6: ArrayList Members

Member Name Syntax

Count
This property returns the number of elements in the collection. virtual int Count{
get; }

FixedSize
This method creates a wrapper for an ArrayList or IList collection, in which static ArrayList
elements cannot be added or removed. FixedSize(
ArrayList
sourceArray)

static IList
FixedSize(
IList sourceList)

GetRange
This method returns a span of elements from the current array. The result is virtual ArrayList
stored in a destination ArrayList. GetRange(
int index, int
count)

IndexOf
This method returns the index of the first matching element in the collection. virtual int IndexOf(
object value)

virtual int
IndexOf(object value,
int startIndex)

virtual int
IndexOf(object value,
int startIndex,
int count)

Insert
This method inserts an element into the collection at the specified index. virtual void
Insert(int index,
object value)

InsertRange
This method inserts multiple elements into the collection at the specified virtual void
index. InsertRange(
int index,
ICollection
sourceCollection)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-6: ArrayList Members

Member Name Syntax

IsFixedSize
This property returns true if the collection is fixed-length. Otherwise, the virtual bool
property returns false. IsFixedSize{
get;}

IsReadOnly
This property returns true if the collection is read-only. Otherwise, the virtual bool
property returns false. IsReadOnly{
get;}

Item
This property gets or sets the element at the index. virtual object
this[int index] {
get;set;}

LastIndexOf
This method returns the index of the last matching element in the collection. virtual int
LastIndex(
object value)

virtual int
LastIndexOf(object
value,
int startIndex)

virtual int
LastIndexOf(object
value,
int startIndex,
int count)

ReadOnly
This method creates a read-only wrapper for an IList object. static ArrayList
ReadOnly(
ArrayList
sourceArray)

static IList
ReadOnly(
IList sourceList)

Remove
This method removes the first element in the collection that matches the virtual void Remove(
value. object value)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-6: ArrayList Members

Member Name Syntax

RemoveAt
This method removes the element at the index from the collection. virtual void
RemoveAt(
int index)

RemoveRange
This method removes a range of elements from a collection. virtual void
RemoveRange(
int index,
int count)

Repeat
This method returns an ArrayList with each element initialized to the same static ArrayList
value. Count is the number of times to replicate the value. Repeat(
object value,
int count)

Reverse
This method reverses the order of elements in the collection. virtual void
Reverse()

virtual void Reverse(


int beginIndex,
int endingIndex)

SetRange
This method copies elements from a collection into the same elements in virtual void
the ArrayList collection. SetRange(
int index,
ICollection
sourceCollection)

Sort
This method sorts an ArrayList. virtual void Sort()

virtual void Sort(


IComparer
comparer}

virtual void
Sort(int index,
int count,
IComparer
comparer)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-6: ArrayList Members

Member Name Syntax

Synchronized
This method returns a thread-safe wrapper of an ArrayList or IList object. static ArrayList
Synchronized(
ArrayList
sourceArray)

static IList
Synchronized(
IList sourceList)

ToArray
This method copies elements from the current array into a new collection. virtual object []
ToArray()

virtual Array
ToArray(Type type)

TrimToSize
This method sets the capacity to the number of elements in the collection. virtual void
TrimToSize()

IEnumerable members GetEnumerator

ICloneable members Clone

ICollection members CopyTo, Count,


IsSynchronized, and
SyncRoot

The following code uses various ArrayList methods and properties. It creates a new ArrayList, which is then
initialized with command-line parameters. The Add method is called to add elements to the ArrayList. The
ArrayList is then sorted and cloned. Then the values at the elements of the cloned ArrayList are doubled.
Afterward, the cloned ArrayList is enumerated and every element is displayed.

using System;
using System.Collections;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(string [] argv){

ArrayList al1=new ArrayList();


foreach(string arg in argv) {
al1.Add(int.Parse(arg));
}
al1.Sort();
ArrayList al2=(ArrayList)al1.Clone();
for(int count=0;count<al2.Count;++count) {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

al2[count]=((int)al2[count])*2;
}
foreach(int number in al2) {
Console.WriteLine(number);

}
}
}
}

BitArray Collection

The BitArray collection is a composite of bit values. Bit values are 1 and 0, where 1 is true and 0 false. This
collection provides an efficient means of storing and retrieving bit values.

Table 5-7 list the BitArray-specific methods and properties. The static members of the BitArray are
thread-safe, whereas instance members are not.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

Co
nst BitAr
ruc ray(b
tor ool
Th []
e bits)
Bit
Arr
ay BitAr
co ray(i
nst nt
ruc []
tor bits)
is
ove
BitAr
rlo
ray(i
ad
nt
ed.
count
Th
,
es
e
are bool
so defau
me lt)
of
the
ove
rlo
ad
ed
co
nst
ruc
tor
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

An
d BitAr
Thi ray
s And(B
me itArr
tho ay
d value
per )
for
ms
a
bit
wis
e
An
d
on
the
cur
ren
t
an
d
Bit
Arr
ay
par
am
ete
r.
Th
e
res
ult
is
pla
ce
d
in
the
ret
urn
ed
Bit
Arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

Ge
t bool
Thi Get(i
s nt
me index
tho )
d
ret
urn
s
a
sp
ecif
ic
bit
in
the
Bit
Arr
ay
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

IsR
ea virtu
dO al
nly bool
Thi IsRea
s dOnly
pro {
per
ty get;}
ret
urn
s
tru
e
if
the
coll
ect
ion
is
rea
d-o
nly
.
Ot
her
wis
e,
the
pro
per
ty
ret
urn
s
fal
se.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

Ite
m virtu
Thi al
s objec
pro t
per this[
ty int
get index
s ] {
or
set get;s
s et;}
the
bit
at
the
ind
ex.

Le
ngt publi
h c
Thi int
s Lengt
pro h{
per
ty get;
get set;
s }
or
set
s
the
nu
mb
er
of
bit
s
in
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

Not
BitAr
Thi ray
s Not()
me
tho
d
ne
gat
es
the
bit
s
of
the
Bit
Arr
ay
coll
ect
ion
.
Th
e
res
ult
is
pla
ce
d
in
the
ret
urn
ed
Bit
Arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

Or
Thi BitAr
s ray
me Or(Bi
tho tArra
d y
per value
for )
ms
a
bit
wis
e
Or
on
the
cur
ren
t
an
d
Bit
Arr
ay
par
am
ete
r.
Th
e
res
ult
is
pla
ce
d
in
the
ret
urn
ed
Bit
Arr
ay.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

Set
Void
Thi Set(i
s nt
me index
tho ,
d bool
set value
s )
a
sp
ecif
ic
bit
in
the
coll
ect
ion
.

Set
All void
Thi SetAl
s l(boo
me l
tho value
d )
set
s
all
the
bit
s
of
the
coll
ect
ion
to
tru
e
or
fal
se.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

Xor
BitAr
Thi ray
s Xor(
me
tho BitAr
d ray
per value
for )
ms
an
ex
clu
siv
e
OR
on
the
cur
ren
t
coll
ect
ion
an
d
the
Bit
Arr
ay
par
am
ete
r.

IEn Ge
um tEn
era um
ble era
me tor
mb
ers
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-7:
BitArray
Members

Me Sy
mb nta
er x
Na
me

ICl Clo
on ne
ea
ble
me
mb
ers

ICo Co
llec py
tio To,
n Co
me unt
mb ,
ers IsS
ync
hro
niz
ed
,
an
d
Sy
nc
Ro
ot

The following code demonstrates the BitArray collection. The Employee class contains a BitArray collection
that tracks employee enrollment in various programs, such as the health plan and credit union. This is
convenient because enrollment is either true or false and never maybe. In the Employee class, properties are
provided to set and get enrollment in various programs.

using System;
using System.Collections;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Employee ben=new Employee();
ben.InProfitSharing=false;

ben.InHealthPlan=false;
Employee valerie=new Employee();
valerie.InProfitSharing=false;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Participation("Ben", ben);
Participation("Valerie", valerie);
}

public static void Participation(string name, Employee person) {


Console.WriteLine(name+":");
if(person.InProfitSharing) {
Console.WriteLine(" Participating in"+
" Profit Sharing");
}
if(person.InHealthPlan) {
Console.WriteLine(" Participating in"+
" Health Plan");
}
if(person.InCreditUnion) {
Console.WriteLine(" Participating in"+
" Credit Union");
}
}
}

public class Employee {

public Employee() {
eflags.SetAll(true);
}

private BitArray eflags=new BitArray(3);

public bool InProfitSharing{


set {
eflags.Set(0, value);
}
get {
return eflags.Get(0);
}
}

public bool InHealthPlan{


set {
eflags.Set(1, value);
}
get {
return eflags.Get(1);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

public bool InCreditUnion{


set {
eflags.Set(2, value);
}
get {

return eflags.Get(2);
}
}
}
}

Hashtable Collection

The Hashtable collection is a collection of key/value pairs. Entries in this collection are instances of the
DictionaryEntry type. DictionaryEntry types have a Key and Value property to get and set keys and values.

In addition to the standard collection interfaces, the Hashtable collection implements the IDictionary,
ISerializable, and IDeserializationCallback interfaces.

The entries are stored and retrieved in order based on a hash code of the key.

Table 5-8 lists the members of the Hashtable collection.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Co
nst Hasht
ruc able(
tor )
Th Hasht
e able(
Ha int
sht capac
abl ity)
e
co
nst Hasht
ruc able(
tor int
is capac
ove ity,
rlo
ad
float
ed.
loadF
Th
actor
es
)
e
sy
nta
xe
s
are
so
me
of
the
ove
rlo
ad
ed
co
nst
ruc
tor
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Ad
d virtu
Thi al
s void
me Add(o
tho bject
d key,
ad
ds objec
an t
ele value
me )
nt
to
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Co
nta virtu
ins al
bool
Thi Conta
s ins(
me
tho objec
d t
ret key)
urn
s
tru
e
if
the
ke
y
is
fou
nd
in
the
coll
ect
ion
. If
the
ke
y
is
not
pre
se
nt,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Co
nta virtu
ins al
Ke bool
y Conta
Thi insKe
s y(
me
tho objec
d t
ret key)
urn
s
tru
e
if
the
ke
y
is
fou
nd
in
the
coll
ect
ion
. If
the
ke
y
is
not
pre
se
nt,
fal
se
is
ret
urn
ed.
Ide
nti
cal
to
the
Co
nta
ins
me
tho
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Co
nta virtu
ins al
Val bool
ue Conta
Thi insVa
s lue(
me
tho objec
d t
ret value
urn )
s
tru
e
if
the
val
ue
is
fou
nd
in
the
coll
ect
ion
. If
the
val
ue
is
not
pre
se
nt,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Eq
uali IEqua
tyC lityC
om ompar
par er
er Equal
ityCo
mpare
r {

get;}
.

Ge
tHa virtu
sh al
Thi int
s GetHa
me sh(
tho
d objec
ret t
urn key)
s
the
ha
sh
co
de
for
the
sp
ecif
ied
ke
y.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Ge
tO virtu
bje al
ctD void
ata GetOb
jectD
Thi ata(
s
is Seria
the lizat
me ionIn
tho fo
d info,
im
ple
me Strea
nte mingC
d ontex
to t
ser conte
iali xt)
ze
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

IsF
ixe virtu
dSi al
ze bool
Thi IsFix
s edSiz
pro e{
per
ty get;}
ret
urn
s
tru
e
if
the
coll
ect
ion
is
fixe
d
siz
e.
Ot
her
wis
e,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

IsR
ea virtu
dO al
nly bool
Thi IsRea
s dOnly
pro {
per
ty get;}
ret
urn
s
tru
e
if
the
coll
ect
ion
is
rea
d-o
nly
.
Ot
her
wis
e,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

IsS
ync virtu
hro al
niz bool
ed IsSyn
Thi chron
s ized{
pro
per get;}
ty
ret
urn
s
tru
e
if
the
coll
ect
ion
is
sy
nc
hro
niz
ed.

Ite
m virtu
Thi al
s objec
pro t
per this[
ty objec
get t
s key]{
or
set get;
s set;}
a
val
ue
rel
ate
d
to
a
ke
y.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Ke
yE virtu
qu al
als bool
KeyEq
Thi uals(
s
me objec
tho t
d item,
co
mp
are objec
s t
a key)
ke
y
to
a
val
ue.
If
eq
ual
,
tru
e
is
ret
urn
ed.
Ot
her
wis
e,
fal
se
is
ret
urn
ed.
Thi
s
me
tho
d
is
pri
ma
rily
us
ed
to
co
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Ke
ys virtu
Ret al
urn IColl
s ectio
a n
coll Keys{
ect
ion get;}
tha
t
co
nta
ins
the
ke
ys
of
the
Ha
sht
abl
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

On
De virtu
ser al
iali void
zat OnDes
ion erial
izati
Thi on(
s
me objec
tho t
d sende
is r)
call
ed
wh
en
de
ser
iali
zat
ion
is
co
mp
let
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Re
mo virtu
ve al
Thi void
s Remov
me e(
tho
d objec
re t
mo key)
ves
an
ele
me
nt
wit
h
the
sp
ecif
ied
ke
y
fro
m
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Sy
nc stati
hro c
niz Hasht
ed able
Thi Synch
s roniz
me ed(
tho
d Hasht
ret able
urn sourc
s eTabl
a e)
thr
ea
d-s
afe
wra
pp
er
of
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

Val
ue virtu
s al
Ret IColl
urn ectio
s n
a value
coll s{
ect
ion get;}
tha
t
ha
s
the
val
ue
s
of
the
Ha
sht
abl
e.

IEn Ge
um tEn
era um
ble era
me tor
mb
ers

ICl Clo
on ne
ea
ble
me
mb
ers
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-8:
Hashtable
Members

Me Sy
mb nta
er x
Na
me

ICo Co
llec py
tio To,
n Co
me unt
mb ,
ers IsS
ync
hro
niz
ed,
an
d
Sy
nc
Ro
ot

Hashtable.GetEnumerator implements IDictionary.GetEnumerator, which returns an IDictionary Enumeator.


IDictionaryEnumerator implements the IEnumerator interface. It also adds three properties: Entry, Key, and
Value.

The following code extends the previous sample code for the BitArray collection. The program creates a
Hashtable, in which employee identifiers are the keys. The values associated with the keys are instances of
the Employee type.

using System;
using System.Collections;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Hashtable employees=new Hashtable();
employees.Add("A100", new Employee(
"Ben", true, false, true));
employees.Add("V100", new Employee(
"Valerie", false, false, true));
Participation((Employee) employees["A100"]);
Participation((Employee) employees["V100"]);
}

public static void Participation(Employee person) {


Console.WriteLine(person.Name+":");
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

if(person.InProfitSharing) {
Console.WriteLine(" Participating in"+
" Profit Sharing");
}
if(person.InHealthPlan) {
Console.WriteLine(" Participating in"+
" Health Plan");
}
if(person.InCreditUnion) {
Console.WriteLine(" Participating in"+
" Credit Union");
}
}
}

public class Employee {

public Employee(string emplName) {


propName=emplName;
eflags.SetAll(true);
}

public Employee(string emplName,


bool profitSharing,
bool healthPlan,
bool creditUnion) {
propName=emplName;
InProfitSharing=profitSharing;
InHealthPlan=healthPlan;

InCreditUnion=creditUnion;
}

private BitArray eflags=new BitArray(3);

public bool InProfitSharing{


set {
eflags.Set(0, value);
}
get {
return eflags.Get(0);
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public bool InHealthPlan{


set {
eflags.Set(1, value);
}
get {
return eflags.Get(1);
}
}

public bool InCreditUnion{


set {
eflags.Set(2, value);
}
get {
return eflags.Get(2);
}
}

private string propName;


public string Name {
get {
return propName;
}
}
}
}

This is sample code of the IDictionaryEnumerator enumerator:

using System;
using System.Collections;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Hashtable zHash=new Hashtable();
zHash.Add("one", 1);
zHash.Add("two", 2);
zHash.Add("three", 3);
zHash.Add("four", 4);
IDictionaryEnumerator e=

zHash.GetEnumerator();
while(e.MoveNext()){
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine(
"{0} {1}",
e.Key, e.Value);
}
}
}
}

Queue Collection

Queue collections abstract FIFO data structures. The initial capacity is 32 elements. Queue collections are
ideal for messaging components.

Table 5-9 lists the member of the Queue collection.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-9:
Queue
Members

Me Sy
mb nta
er x
Na
me

Co
nst publi
ruc c
tor Queue
()
publi
c
Queue
(

IColl
ectio
n
sourc
eColl
ectio
n)

publi
c
Queue
(int
capac
ity)

publi
c
Queue
(int
capac
ity,

float
facto
r)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-9:
Queue
Members

Me Sy
mb nta
er x
Na
me

Cle
ar virtu
Thi al
s void
me Clear
tho ()
d
re
mo
ves
all
the
ele
me
nts
of
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-9:
Queue
Members

Me Sy
mb nta
er x
Na
me

Co
nta virtu
ins al
bool
Thi Conta
s ins(o
me bject
tho value
d )
ret
urn
s
tru
e
if
the
sp
ecif
ied
val
ue
is
fou
nd
in
the
coll
ect
ion
. If
the
val
ue
is
not
fou
nd,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-9:
Queue
Members

Me Sy
mb nta
er x
Na
me

De
qu virtu
eu al
e objec
Thi t
s Deque
me ue()
tho
d
re
mo
ves
an
d
ret
urn
s
the
firs
t
ele
me
nt
of
the
qu
eu
e.

En
qu virtu
eu al
e void
Thi Enque
s ue(
me
tho objec
d t
ad eleme
ds nt)
an
ele
me
nt
to
the
qu
eu
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-9:
Queue
Members

Me Sy
mb nta
er x
Na
me

Pe
ek virtu
Thi al
s objec
me t
tho Peek(
d )
ret
urn
s
the
firs
t
ele
me
nt
of
the
qu
eu
e
wit
ho
ut
re
mo
vin
g
it.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-9:
Queue
Members

Me Sy
mb nta
er x
Na
me

Sy
nc stati
hro c
niz Queue
ed Synch
Thi roniz
s ed(
me
tho Queue
d sourc
ret eQueu
urn e)
s
a
thr
ea
d-s
afe
wra
pp
er
for
a
qu
eu
e
obj
ect
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-9:
Queue
Members

Me Sy
mb nta
er x
Na
me

To
Arr virtu
ay al
Thi objec
s t[]
me ToArr
tho ay()
d
cre
ate
s
a
ne
w
arr
ay
initi
aliz
ed
wit
h
the
ele
me
nts
of
the
qu
eu
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-9:
Queue
Members

Me Sy
mb nta
er x
Na
me

Tri
mT virtu
oSi al
ze void
Thi TrimT
s oSize
me ()
tho
d
set
s
the
ca
pa
cit
y
to
the
nu
mb
er
of
ele
me
nts
in
the
coll
ect
ion
.

IEn Ge
um tEn
era um
ble era
me tor
mb
ers

ICl Clo
on ne
ea
ble
me
mb
ers
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-9:
Queue
Members

Me Sy
mb nta
er x
Na
me

ICo Co
llec py
tio To,
n Co
me unt
mb ,
ers IsS
ync
hro
niz
ed,
an
d
Sy
nc
Ro
ot

This is sample code of the Queue collection. Customers are added to the queue and then displayed.

using System;
using System.Collections;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Queue waiting=new Queue();
waiting.Enqueue(new Customer("Bob"));
waiting.Enqueue(new Customer("Ted"));
waiting.Enqueue(new Customer("Kim"));
waiting.Enqueue(new Customer("Sam"));

while(waiting.Count!= 0) {
Customer cust=
(Customer) waiting.Dequeue();
Console.WriteLine(cust.Name);
}
}

public class Customer{


public Customer(string cName) {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

propName=cName;
}

private string propName;


public string Name {
get {
return propName;
}
}
}
}
}

SortedList
The SortedList collection is a combination of key/value entries and an ArrayList collection, where the
collection is sorted by the key. The collection is accessible per the key or an index.

Table 5-10 include the members of the SortedList collection.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Co
nst Sorte
ruc dList
tor ()
Th
e
Sor Sorte
ted dList
Lis (ICom
t parer
co compa
nst rer)
ruc
tor
Sorte
is
dList
ove
(
rlo
ad
ed. IDict
Th ionar
es y
e sourc
are eColl
so ectio
me n)
of
the
ove
rlo
ad
ed
co
nst
ruc
tor
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Ad
d virtu
Thi al
s void
me Add(o
tho bject
d key,
ad
ds objec
an t
ele value
me )
nt
to
the
coll
ect
ion
.

Ca
pa virtu
city al
int
Thi Capac
s ity{
pro
per get;
ty set;}
get
s
or
set
s
the
ca
pa
cit
y
of
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Cle
ar virtu
Thi al
s void
me Clear
tho ()
d
re
mo
ves
all
the
ele
me
nts
of
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Co
nta virtu
ins al
bool
Thi Conta
s ins(o
me bject
tho value
d )
ret
urn
s
tru
e
if
the
sp
ecif
ied
val
ue
is
fou
nd
in
the
coll
ect
ion
. If
the
val
ue
is
not
fou
nd,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Co
nta virtu
ins al
Ke bool
y Conta
Thi insKe
s y(
me
tho objec
d t
ret key)
urn
s
tru
e
if
the
ke
y
is
fou
nd
in
the
coll
ect
ion
. If
the
ke
y
is
not
pre
se
nt,
fal
se
is
ret
urn
ed.
Ide
nti
cal
to
the
Co
nta
ins
me
tho
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Co
nta virtu
ins al
Val bool
ue Conta
Thi insVa
s lue(
me
tho objec
d t
ret value
urn )
s
tru
e
if
the
val
ue
is
fou
nd
in
the
coll
ect
ion
. If
the
val
ue
is
not
pre
se
nt,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Ge
tBy virtu
Ind al
ex objec
Thi t
s GetBy
me Index
tho (
d
ret int
urn index
s )
the
val
ue
at
the
ind
ex.

Ge
tKe virtu
y al
Thi objec
s t
me GetKe
tho y(
d
ret int
urn index
s )
the
ke
y
at
the
sp
ecif
ied
ind
ex.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Ge
tKe virtu
yLi al
st IList
Thi GetKe
s yList
me ()
tho
d
ret
urn
s
all
the
ke
ys
in
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Ge
tVa virtu
lue al
Lis IList
t GetVa
Thi lueLi
s st()
me
tho
d
ret
urn
s
all
the
val
ue
s
of
the
Sor
ted
Lis
t
in
a
ne
w
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Ind
ex virtu
Of al
Ke int
y Index
Thi OfKey
s (
me
tho objec
d t
ret key)
urn
s
the
ind
ex
of
a
ke
y
fou
nd
in
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Ind
ex virtu
Of al
Val int
ue Index
Thi OfVal
s ue(
me
tho objec
d t
ret value
urn )
s
the
ind
ex
to
the
firs
t
ins
tan
ce
of
thi
s
val
ue
in
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

IsF
ixe virtu
dSi al
ze bool
Thi IsFix
s edSiz
pro e{
per
ty get;}
ret
urn
s
tru
e
if
the
coll
ect
ion
is
fixe
d
siz
e.
Ot
her
wis
e,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

IsR
ea virtu
dO al
nly bool
Thi IsRea
s dOnly
pro {
per
ty get;}
ret
urn
s
tru
e
if
the
coll
ect
ion
is
rea
d-o
nly
.
Ot
her
wis
e,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Ite
m virtu
Thi al
s objec
pro t
per this[
ty objec
get t
s key]
or
set {get;
s set;}
the
val
ue
of
thi
s
ke
y.

Ke
ys publi
Thi c
s virtu
pro al
per IColl
ty ectio
ret n
urn Keys{
s
the get;}
ke
ys
of
the
Sor
ted
Lis
t
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Re
mo virtu
ve al
Thi void
s Remov
me e(
tho
d objec
re t
mo key)
ves
an
ele
me
nt,
whi
ch
is
ide
ntifi
ed
by
the
ke
y,
fro
m
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Re
mo virtu
ve al
At void
Thi Remov
s eAt(
me
tho int
d index
re )
mo
ves
an
ele
me
nt
at
the
sp
ecif
ic
ind
ex.

Set
ByI virtu
nd al
ex void
Thi SetBy
s Index
me (
tho
d int
set index
the ,
val objec
ue t
of value
the )
ele
me
nt
at
the
sp
ecif
ied
ind
ex.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Sy
nc stati
hro c
niz Sorte
ed dList
Thi Synch
s roniz
me ed(
tho
d Sorte
ret dList
urn sourc
s eList
a )
thr
ea
d-s
afe
wra
pp
er
for
a
qu
eu
e
obj
ect
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Tri
mT virtu
oSi al
ze void
Thi TrimT
s oSize
me ()
tho
d
tri
ms
the
ca
pa
cit
y
to
the
act
ual
nu
mb
er
of
ele
me
nts
in
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

Val
ue virtu
s al
Thi IColl
s ectio
pro n
per Value
ty s{
ret
urn get;}
s
the
val
ue
s
of
the
coll
ect
ion
.

IEn Ge
um tEn
era um
ble era
me tor
mb
ers

ICl Clo
on ne
ea
ble
me
mb
ers
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-10:
SortedList
Members

Me Sy
mb nta
er x
Na
me

ICo Co
llec py
tio To,
n Co
me unt
mb ,
ers IsS
ync
hro
niz
ed,
an
d
Sy
nc
Ro
ot

This following program is an application that tracks auto repair tickets. Each ticket, which is an instance of
the AutoRepairTicket, is added to a sorted list. The key is the customer name. The value is the actual
ticket. After populating the SortedList type, the CustomerReport method lists the open tickets.

using System;
using System.Collections;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
SortedList tickets=new SortedList();
AutoRepairTicket ticket=NewTicket("Ben");
tickets.Add(ticket.Name, ticket);
ticket=NewTicket("Donis");
tickets.Add(ticket.Name, ticket);
ticket=NewTicket("Adam");
tickets.Add(ticket.Name, ticket);
CustomerReport(tickets);
}

public static AutoRepairTicket NewTicket(


string customerName) {
return new AutoRepairTicket(customerName,
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

DateTime.Now);
}

public static void CustomerReport(SortedList list) {


foreach(DictionaryEntry entry in list) {
int nextTag=((AutoRepairTicket) entry.Value).Tag;
string nextTime=((AutoRepairTicket)
entry.Value).Time.ToShortTimeString();
Console.WriteLine("Customer: {0} Ticket: {1} Time: {2}",
entry.Key, nextTag, nextTime);
}
}
}

public class AutoRepairTicket{


public AutoRepairTicket(string customerName,
DateTime ticketTime) {
propName=customerName;
propTime=ticketTime;
propTag=++count;
}

private string propName;


public string Name {
get {
return propName;
}
}

private DateTime propTime;


public DateTime Time {
get {
return propTime;
}
}

private int propTag;


public int Tag {
get {
return propTag;
}
}

private static int count=1000;


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

Stack Collection

Stack collections abstract LIFO data structures in which the initial capacity is 32 elements.

Table 5-11 lists the member of the Stack collection.


Table 5-11:
Stack
Members

Me Sy
mb nta
er x
Na
me

Cle
ar virtu
Thi al
s void
me Clear
tho ()
d
re
mo
ves
all
the
ele
me
nts
of
the
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-11:
Stack
Members

Me Sy
mb nta
er x
Na
me

Co
nta virtu
ins al
bool
Thi Conta
s ins(o
me bject
tho value
d )
ret
urn
s
tru
e
if
the
sp
ecif
ied
val
ue
is
fou
nd
in
the
coll
ect
ion
. If
the
val
ue
is
not
fou
nd,
fal
se
is
ret
urn
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-11:
Stack
Members

Me Sy
mb nta
er x
Na
me

Pe
ek virtu
Th al
e objec
Pe t
ek Peek(
me )
tho
d
pre
vie
ws
the
las
t
ele
me
nt
on
the
sta
ck.
Th
e
ele
me
nt
is
ret
urn
ed
wit
ho
ut
re
mo
val
fro
m
the
sta
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-11:
Stack
Members

Me Sy
mb nta
er x
Na
me

Po
p virtu
Thi al
s objec
me t
tho Pop()
d
ret
urn
s
an
d
re
mo
ves
the
top
ele
me
nt
of
the
sta
ck.

Pu
sh virtu
Thi al
s void
me Push(
tho objec
d t
pu obj)
sh
es
an
oth
er
ele
me
nt
on
the
sta
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-11:
Stack
Members

Me Sy
mb nta
er x
Na
me

Sy
nc stati
hro c
niz Stack
ed Synch
Thi roniz
s ed(
me
tho Stack
d sourc
ret eStac
urn k)
s
a
thr
ea
d-s
afe
wra
pp
er
for
the
Sta
ck
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-11:
Stack
Members

Me Sy
mb nta
er x
Na
me

To
Arr virtu
ay al
Thi objec
s t[]
me ToArr
tho ay()
d
ret
urn
s
the
Sta
ck
coll
ect
ion
as
a
reg
ula
r
arr
ay.

The following code adds numbers to a Stack collection. The values of the collection are then enumerated
and displayed.

using System;
using System.Collections;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Stack numbers=new Stack(
new int [] {1,2,3,4,5,6});
int total=numbers.Count;
for(int count=0;count<total;++count) {
Console.WriteLine(numbers.Pop());
}
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Specialized Collections

In addition to the common collections that most developers use, the .NET FCL offers specialized collections.
These collections are found in the System.Collections.Specialized namespace. Although these collections
are used infrequently, they are valuable in certain circumstances.

Table 5-12 lists the specialized collections.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-12:
Specialized
Collections

Me De
mb scr
er ipti
Na on
me

Bit Thi
Ve s
cto is
r32 an
arr
ay
of
32
bit
s.
It
is
si
mil
ar
to
a
Bit
Arr
ay,
but
limi
ted
to
32
bit
s.
Be
ca
us
e
of
thi
s
arr
ay'
s
refi
ne
d
us
e,
Bit
Ve
cto
r32
str
uct
ure
s
are
mo
re
effi
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-12:
Specialized
Collections

Me De
mb scr
er ipti
Na on
me

Hy Thi
bri s
dDi coll
cti ect
on ion
ary is
a
co
mb
ina
tio
n
of
a
Lis
tDi
cti
on
ary
an
d
Ha
sht
abl
e.
It
op
era
tes
as
a
Lis
tDi
cti
on
ary
wh
en
co
nta
inin
g
a
sm
all
nu
mb
er
of
ele
me
nts
.
For
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-12:
Specialized
Collections

Me De
mb scr
er ipti
Na on
me

Na Thi
me s
Val is
ue a
Col coll
lec ect
tio ion
n of
ke
ys
an
d
val
ue
s,
in
whi
ch
bot
h
the
ke
y
an
d
val
ue
are
stri
ng
s.
Th
e
coll
ect
ion
is
ac
ce
ssi
ble
via
an
ind
ex
or
ke
y.
A
ke
y
ca
n
ref
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-12:
Specialized
Collections

Me De
mb scr
er ipti
Na on
me

Or Not
der do
ed cu
Dic me
tio nte
nar d
y at
the
tim
e
of
thi
s
bo
ok.

Stri Thi
ng s
Col is
lec a
tio coll
n ect
ion
of
stri
ng
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 5-12:
Specialized
Collections

Me De
mb scr
er ipti
Na on
me

Stri Thi
ng s
Dic is
tio a
nar co
y mb
ina
tio
n
of
the
Ha
sht
abl
e
an
d
Stri
ng
Col
lec
tio
n
coll
ect
ion
s,
in
whi
ch
bot
h
the
ke
y
an
d
val
ue
are
stri
ng
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Generics
The next chapter is about Generics, which improves upon the performance and other factors related to
nongeneric collections. The collections reviewed in this chapter manipulate object types. For this reason,
when populating collections with value types, boxing is required. Excessive boxing is both a performance
and memory issue. Another problem is type-safeness. You often cast elements that are object types to a
specific type. The cast is not type-safe and can cause run-time errors when done incorrectly.

Generics types are classes with type parameters. The type parameter acts as a placeholder for a future
type. When a generic type is declared, type arguments are substituted for the type parameters. The type
argument is the actual type. At that time, the generic is type-specific, which resolves many of the problems
of a nongeneric type. Generic methods, like generic types, have type parameters. However, the type
argument can be inferred from the way the method is called.

A complete explanation of generic types and methods follows in Chapter 6.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 6: Generics
Overview
The definition of generic, as found in the Merriam-Webster's Collegiate Dictionary, is "adj. of a whole genus,
kind, class, etc.; general; inclusive." Based on this definition, a person is generic, whereas Donis Marshall is
quite specific. A city is generic, whereas Seattle is specific. For developers, a data algorithm is generic,
whereas the implementation is specific. A stack is generic, whereas a stack of integers is specific. A
spreadsheet is generic, whereas a spreadsheet of strings is specific. To lesser extent, general abstractions
can use generic implementation. An arithmetic class is generic, whereas integer calculations are specific.

In .NET, a type is specific, such as a class or structure. A StackInt class is a specific type and represents
a specialization of the stack pattern, which targets integers. A stack of strings or floats would require
additional implementations of the same algorithm, such as StackString and StackFloat.

Here is an implementation of the StackInt class:

"using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
StackInt stack=new StackInt(5);
stack.Push(10);
stack.Push(15);
Console.WriteLine("Pushed 3 values");
stack.ListItems();
stack.Pop();
Console.WriteLine("Popped 1 value");
stack.ListItems();
}
}

public class StackInt {

public StackInt(int firstItem) {


list=new int[1] {firstItem};
top++;
}

public int Pop() {


if(top!=(-1)) {
return list[top--]; //was list[--top]
}
throw new Exception("Stack empty");
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void Push(int topitem) {


++top;
if(top==list.Length) {
int [] temp=new int[top+1];
Array.Copy(list, temp, top);
list=temp ;
}
list[top]=topitem;
}

public void ListItems () {


for(int item=0;item<=top;++item) {
Console.WriteLine(list[item]);
}
}

private int [] list;


private int top=(-1);
}

The implementation works, but not without some issues:


 Replicating the algorithm is time-consuming and is the antithesis of code reuse.
 This approach is not maintainable. What if the core algorithm is refashioned for better
performance? It requires updating and testing multiple sets of nearly identical source code.
 Specific types are not extensible. As an application matures, the number of implementations
could become unwieldy. In a graphics program, as additional geometric shapes are supported, the
list of stack classes could expand to include StackEllipse, StackOval, StackLine, StackTriangle,
StackCurve, StackText, ad infinitum.

Inheritance polymorphism, which is polymorphism using inheritance and virtual functions, is an alternate
solution to type specialty. In a personnel application, ExemptEmployee, HourlyEmployee, and
TempEmployee are specific classes that are related through inheritance, where Employee is the generic
base class. Using it solves some of the aforementioned problems, such as code reuse. This is a potential
solution to generic abstraction but not a generic data algorithm. Abstracting the stack algorithm based on
inheritance encourages bad design. Is a stack a kind of integer? Is an integer a kind of stack? Neither
statement is true. For a stack solution, inheritance polymorphism is a contrived solution at best.

A simple solution is generic implementation, which is single implementation for all types—a stack of anything
, versus a stack of integers. This is the function of collections in the .NET Framework class library (FCL),
which are general-purpose containers. All types—value or reference—are derived directly or indirectly from
System.Object, making it the ubiquitous type. System.Object can be anything. General-purpose collections
are containers of System.Object instances. These collections are discussed in Chapter 5, "Arrays and
Collections."

In the following code, a stack of integers is implemented using the stack collection class from the .NET FCL.
The stack collection is reused as a stack of strings, which demonstrates the amorphous nature of the stack
collection class.

using System;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System.Collections;

namespace Donis.CSharpBook{
public class Starter{

public static void Main(){


Console.WriteLine("Integer stack");
Integers();
Console.WriteLine("String stack");
Strings();
}

public static void Integers() {


Stack list=new Stack();
list.Push(5);
list.Push(10);
list.Push(15);
foreach(int item in list) {
Console.WriteLine(item);
}
}

public static void Strings() {


Stack list=new Stack();
list.Push("a");
list.Push("b");
list.Push("c");
foreach(string item in list) {
Console.WriteLine(item);
}
}

}
}

General-purpose collections (described in the previous chapter) are valuable, but there are some drawbacks.
Performance is the first problem. These collections manage instances of System.Object. Casting is required
to access, remove, and insert items into a collection. For integers, boxing occurs as items are added to the
collection. Unboxing happens when items are accessed in the collection. Boxing occurs if a collection
contains value types—integers are value types. Frequent boxing can prompt earlier garbage collection, which
is especially expensive. The incremental penalty for boxing and unboxing can be substantial for a collection
of value types. For a collection of reference types, there is the cost of down-casting, which is lighter. The
second problem is type-safeness. Although the StackInt type is type-safe, the general-purpose collection of
integers is not. The stack collection stores elements in memory as System.Object. As a System.Object
type, the behavior of each element is limited to ToString, GetHashCode, Equals, and GetType. Casting is
required for expanded behavior. However, you can cast to anything, which is inherently type-unsafe. Incorrect
casts cause run-time exceptions. The third problem is clarity. Frequent casting, as required with collection
classes, obfuscates the source code. Generics are the solution.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Generics are parameterized types and methods. Each parameter is a placeholder of a yet unspecified type.
The polymorphic behavior of the generic type or method is conveyed through parameters, which is called
parametric polymorphism. There is a single implementation of the algorithm, which is abstracted through
parameters. Many developers were introduced to this concept in C++ as parameterized templates. Other
languages also support this feature. However, generics in .NET avoid some of the problems emblematic of
parametric polymorphism in these other languages.

Generics address the shortcomings of generic collections. Generics perform better because needless boxing
and unboxing are eliminated. At run time, generic types with value type arguments expand to type-specific
instances. For example, a generic stack with an integer type parameter becomes an actual stack of
integers, which make generics inherently type-safe. Generic types become specific types, which avoids the
necessity of casting. Because casting is avoided, clarity is enhanced.

Generic types and methods are not suitable in all circumstances:


 The entry point method cannot be a member of an generic type.
 Unmanaged types cannot be generic.
 Constructors cannot be generic.
 Operator member functions cannot be generic methods.
 Properties cannot be generic.
 Indexers cannot be generic.
 Attributes cannot be generic.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Generic Types
Generics are types with parameters, and parameters are placeholders for future types. Generic types include
classes, structures, and interfaces. The essence of the type remains. The persona of a class, even a generic
class, remains a class—it is simply a class with type parameters.

Type Parameters

Parameters appear after the class header and are placed in anchor brackets (< and >). The type parameters
are accessible to the class declaration, header, body, and constraints. Because collections are typically
general-purpose, generics are ideal for implementing collections. .NET provides generic collections for
arrays, stacks, queues, and other common data structures. However, there is no predefined spreadsheet
collection, which is a collection of rows and columns. Sounds like an opportunity to me.

Here is sample code for a sheet collection:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
int count=1;
Sheet<int> asheet=new Sheet<int>(2);
for(byte row=1; row<3; ++row) {
for(byte col=1; col<3; ++col) {
asheet[row,col]=count++;
}
}
for(byte row=1; row<3; ++row) {
for(byte col=1; col<3; ++col) {
Console.WriteLine("R{0} C{1}= {2}",
row, col, asheet[row,col]);
}
}

Console.WriteLine("Current[{0},{1}] = {2}",
asheet.R, asheet.C, asheet.Current);
asheet.MoveDown();
asheet.MoveRight();
Console.WriteLine("Current[{0},{1}] = {2}",
asheet.R, asheet.C, asheet.Current);
}
}

class Sheet<T> {
public Sheet(byte dimension) {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

if(dimension<0) {
throw new Exception("Invalid dimensions");
}
m_Dimension=dimension;
m_Sheet=new T[dimension, dimension];
for(byte row=0; row<dimension; ++row) {
for(byte col=0; col<dimension; ++col) {
m_Sheet[row,col]=default(T);
}
}

public T this[byte row, byte col] {


get {
ValidateCell(row, col);
return m_Sheet[row-1, col-1];
}
set {
m_Sheet[row-1, col-1]=value;
}
}

public void ValidateCell(byte row, byte col) {


if((row < 0) || (row > m_Dimension)) {
throw new Exception("Invalid Row");
}
if((col < 0) || (col > m_Dimension)) {
throw new Exception("Invalid Col");
}
}

public T Current {
get {
return m_Sheet[curRow-1, curCol-1];
}
set {
m_Sheet[curRow-1, curCol-1]=value;
}
}

public void MoveLeft() {


curCol=Math.Max((byte) (curCol-1), (byte) 1);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void MoveRight() {


curCol=Math.Min((byte) (curCol+1), (byte) m_Dimension);
}

public void MoveUp() {


curRow=Math.Max((byte) (curRow-1), (byte) 1);
}

public void MoveDown() {


curRow=Math.Min((byte) (curRow+1), (byte) m_Dimension);
}

private byte curRow=1;


public byte R {
get {
return curRow;
}
}

private byte curCol=1;


public byte C {
get {
return curCol;

}
}

private byte m_Dimension;


private T [,] m_Sheet;
}
}

Sheet is a generic type and collection, with a single parameter. For generics with a single parameter, by
convention, T is the name of the parameter. (T is for type.) In the sheet generic type, the type parameter is
used as a function return, field type, and local variable. When the sheet is instantiated, the specific type is
specified. This defines a spreadsheet of strings, which has two rows and columns:

Sheet<string> asheet=new Sheet<string>(2);

Review the constructor of the sheet generic type. Notice the use of the default keyword:

for(byte row=0; row<dimension; ++row) {


for(byte col=0; col<dimension; ++col) {
m_Sheet[row,col]=default(T);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

The preceding for loop initializes the internal collection of the Sheet generic type. However, the
implementation is not based on a specific type. A generic type implementation has placeholders instead of
specific types. The challenge is initializing a nonspecific type, which could be a reference or value type. The
default expression returns null for a reference type and bitwise zero for a value type. This is the syntax of the
default expression:
 zerovalue default(type)

The Sheet generic type has a single parameter. Generics can have multiple parameters. The type parameter
list is contained within the anchor brackets. Parameters in the type parameter list are comma-delimited. If a
generic has two parameters, the parameters are normally named K and V, for key and value. Here is sample
code of a generic type that has two parameters:

public class ZClass<K, V> {


static void Method(K key, V data) {

}
}

This code creates an instance of the ZClass, which has two parameters:

ZClass<string, float> obj=new ZClass<string, float>();

Generic types have parameters. Those parameters can themselves be generic types. In the following code,
XClass is generic and is also inserted as a nested parameter:

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
ZClass<XParameter<string>, float> obj=
new ZClass<XParameter<string>, float>();
}
}

public class XParameter<P> {


public static void MethodA(P data) {
}
}

public class ZClass<K, V> {


public static void MethodB(K key, V data) {
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The syntax of nested parameters can be somewhat complicated. What if the type parameter was
extrapolated even further? You could have a type parameter that is a generic, which has a type parameter
that is also generic, and so on, which could become somewhat labyrinthine. If the declaration is repeated, it
would be particularly problematic. An alias is a good solution. Alias the declaration containing a nested
parameter and rely on the alias in the code. The following alias is used for this purpose:

using ZClass2=ZClass<XParameter<string>, int>;

public class Starter{


public static void Main(){
ZClass2 obj=new ZClass2();
}
}

public class XParameter<P> {


public static void MethodA(P data) {
}
}

public class ZClass<K, V> {


public static void MethodB(K key, V data) {
}
}

This is the syntax of a generic type:

attributes accessibility modifiers class classname : baselist


<parameterlist> where parameter:constraintlist:
{ class body };

Constructed Types

Generic types are also called constructed types. There are open constructed and closed constructed types.
An open constructed type has at least one type parameter. The type parameter is a placeholder, which is
unbound to a specific type. The implementation of a generic type is an example of an open constructed type.
This is an open constructed type:

public class ZClass<K, V> {


static void Method(K key, V data) {

}
}

For a closed constructed type, all type parameters are bound. Bound parameters are called type arguments
and are assigned a specific type. Closed constructed types are used in several circumstances: to create an
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

instance of a generic type, inherit a generic type, and more. In the following code, ZClass<int, decimal> is a
closed constructed type. The first parameter is bound to an integer, whereas the second is a decimal. The
type arguments are int and decimal.

ZClass<int, decimal> obj=new ZClass<int, decimal>();


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Generic Methods
A generic method can declare method-specific generic parameters. These parameters can be used in the
method header or body. An open method has type parameters, which are nonspecific. A closed method has
type arguments, whereas specific types are substituted for type parameters. For a generic method, the type
parameters are listed after the function header. The type parameter list is enclosed in anchor brackets,
whereas each parameter is delimited with commas.

This is a prototypical generic method:

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
ZClass.MethodA<int>(20);
}
}

public class ZClass{


public static void MethodA<T>(T param) {
Console.WriteLine(param.GetType().ToString());
}
}
}

When calling a generic method, provide the type arguments as a substitute for type parameters. There is an
alternate syntax to calling a generic method, called type inference, in which the type argument is inferred
from the actual method parameters. The type argument can then be omitted. Basically, the generic method
is called similarly to any method. The benefit is ease of use. However, type inference disguises the true
nature of the call, which could be relevant when debugging an application.

In the previous code, ZClass.MethodA is a generic method. The following statement calls MethodA using
type inference:

ZClass.MethodA(20);

This is the syntax of a generic method:


 attributes accessibility modifiers returntype methodname <parameterlist>
 (argumentlist) where parameter:constraintlist
 { method body }

Overloaded Methods

Generic methods can be overloaded, which creates an interesting dilemma. Is a method ambiguous based
on extrapolation alone? In the following code, MethodA is overloaded:

public void MethodA(T arg) {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
public void MethodA(U arg) {
}

Both functions have a single type parameter. The type parameters are different, but each parameter could be
anything, including both parameters being identical. This makes certain renditions of MethodA ambiguous.
For example, they both could have a single integer parameter. However, the C# compiler is concerned with
actual ambiguity and does not highlight, as an error or warning, potential ambiguousness related to
overloading generic methods. A compile error is manifested when MethodA is called, if ever, in an ambiguous
manner. This is a potential land mine for developers of libraries. Test every permutation of type parameters to
predict and avoid potential ambiguousness for clients of a library.

In the following code, MethodA is called ambiguously. Interestingly, MethodA is known to be ambiguous at
the generic type instantiation. However, the compiler error occurs on the next statement at the call site.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){

ZClass<int, int> obj=new ZClass<int, int>();


obj.MethodA(5); // ambiguous error
}
}

public class ZClass<T, U> {


public void MethodA(T arg) {
Console.WriteLine("ZClass.MethodA(T arg)");
}

public void MethodA(U arg) {


Console.WriteLine("ZClass.MethodA(U arg)");
}

public void MethodA() {


Console.WriteLine("ZClass.MethodA()");
}
}
}

Generic methods can overload nongeneric methods. If the combination of a generic and nongeneric method
is ambiguous, the nongeneric method is called. The compiler prefers nongeneric methods over generic
methods of the same signature.

The following code contains a generic and nongeneric MethodA. When MethodA is called with an integer
parameter, the call would otherwise be ambiguous. Because the ambiguous methods are generic and
nongeneric methods, the nongeneric MethodA is simply called. Then MethodA is called with a double, which
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

is not ambiguous, and the generic MethodA is called appropriately.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
ZClass<int> obj1=new ZClass<int>();
obj1.MethodA(5);
ZClass<double> obj2=new ZClass<double>();
obj2.MethodA(5.0);
}
}

public class ZClass<T> {


public void MethodA(T arg) {
Console.WriteLine("ZClass.MethodA(T arg)");
}

public void MethodA(int arg) {


Console.WriteLine("ZClass.MethodA(int arg)");
}

public void MethodA() {

Console.WriteLine("ZClass.MethodA()");
}
}
}

This Reference for Generic Types

Generic types, similar to any type, have a this reference, which is a reference to the current object and the
same type of that object. If the object is an XClass instance, the this reference is also of the XClass type.
The this reference is used implicitly to refer to instance members and explicitly as function returns and
parameters. The this reference of a generic type is associated with the closed constructed type, which is
normally defined at generic type instantiation.

The following code displays the type of a this reference. The following is a this reference of a generic type,
which is Donis.CSharpBook.ZClass`1[System.Int32]. From the type, you know that the closed constructed
type has a single parameter that is a 32-bit integer.

using System;

namespace Donis.CSharpBook{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class Starter{


public static void Main(){
ZClass<int> obj=new ZClass<int>();
obj.MethodA();
}
}

class ZClass<T> {
public T MethodA() {
T var=default(T);
Console.WriteLine(this.GetType().ToString());
return var;
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Constraints
When a generic type is implemented, the deferred specialty of the type parameter is unknown. Managed
code has plenty of cool features, but they do not include foretelling the future. Therefore, within the
implementation of a generic type, a type parameter could eventually be anything. We are assured that the
type parameter inherits from System.Object—nothing else. .NET guarantees that all types are a derivation of
System.Object. For this reason, type parameters are implied System.Object types and must behave
accordingly. This limits type parameters to the public interface of the System.Object, which assures type
safeness.

In the following code, ZClass has a single parameter, which is T. My intention is that T is an array of some
type. ZClass.MethodA will enumerate that array while displaying each value. System.Array is the underlying
type of an array and implements the IEnumerable interface. This is the required interface for enumeration
and an essential ingredient of a foreach loop. Unfortunately, the C# compiler does not know my intention.
Regardless of my future intention, T is an implied System.Object, which does not implement the
IEnumerable interface. Therefore this code does not compile.

class ZClass<T> {

public void Iterate(T data) {


foreach(object item in data) {
Console.WriteLine(item);
}
}
}

This problem is resolved with a generic constraint. Constraints define the future intention of a type parameter.
The following program uses a constraint, which is a where clause, to indicate the intention of the T
parameter. It is intended that the T parameter is an IEnumerable type. With this understanding, the program
compiles and executes successfully:

using System;
using System.Collections;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
ZClass<int[]> obj=new ZClass<int[]>();
obj.Iterate(new int[] {1,2,3,4});
}
}

public class ZClass<T> where T: IEnumerable {

public void Iterate(T data) {


foreach(object item in data) {
Console.WriteLine(item);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
}
}

There are five types of constraints:


 Derivation constraints state the ascendancy of a type parameter.
 Interface constraints are interfaces that are implemented by the type parameter.
 Value type constraints restrict a type parameter to a value type.
 Reference type constraints restrict a type parameter to a reference type.
 Constructor constraints stipulate that the type parameter has a default or parameterless
constructor.

Constraints can be applied to both generic types and methods.

Derivation Constraint

The derivation constraint states the derivation of a type parameter. The type parameter must be derived from
that constraint, which is enforced by the C# compiler. This allows the compiler to relax the restriction that
access to type parameters is limited to the System.Object. The public interface of the constrained type
parameter is expanded to include the derivation type. A type can inherit from a single class because multiple
inheritance is not available in C#. For this reason, a type parameter can optionally have a single constraint.
However, each parameter can have separate derivation constraints, in which each constraint is
space-delimited.

Because the constraint is enforced by the compiler, the type parameter can only be used accordingly. This
avoids an unsafe usage of the type parameter. The compiler assures that all access to the type parameter is
type-safe as defined in the constraint. This is different in C++, in which the compiler performs no such
type-checking on type parameters. In C++, you can basically do anything with a type parameter. Errors are
uncovered when the parameter template is expanded at compile time, deep in the bowels of the expansion
code. This can lead to cryptic error messages that are hard to debug. Anyone that has used the Active
Template Library (ATL) and had expansion errors can attest to this. The C# compiler also updates Microsoft
IntelliSense per the derivation constraint. A type parameter reflects the IntelliSense of any constraints on
that parameter.

ZClass is a generic type and is defined in the following code. It has a K and V type parameter, each with a
separate constraint. Per the constraints, the K parameter must be derived from XClass, while the V
parameter should be derived from YClass. Main has three generic type instantiations. The first two are okay,
but the third causes compile errors. The problem is the first type argument. WClass is not derived from
XClass, which is a requirement of the first parameter per the constraint.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){

// good
ZClass<XClass, YClass> obj=
new ZClass<XClass, YClass>();

// good
ZClass<XClass, WClass> obj2=
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

new ZClass<XClass, WClass>();

// bad
ZClass<WClass, YClass> obj3=
new ZClass<WClass, YClass>();

}
}

public class ZClass<K, V> where K:XClass


where V:YClass {
}

public class XClass {

public class YClass {


}

public class WClass: YClass {


}
}

The following code shows a generic method with a derivation constraint:

class ZClass {
public T MethodA<T>() where T:XClass {
return default(T);
}
}

Generic types can function as constraints, which include both open and closed constructed types. This is
demonstrated in the following code. XClass is a nongeneric type. YClass is a generic type with a single
parameter. ZClass is also a generic type, also with a single parameter, where YClass<XClass> is the
constraint on that parameter. YClass<XClass> is a closed constructed type. In Main, an instance of the
YClass is created, where XClass is the type parameter. Next, an instance of the ZClass is created, and the
parameter type is YClass<XClass>, which is required by the constraint mentioned earlier. ZClass.MethodA
is then called, where the YClass instance is passed as a parameter.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
YClass<XClass> param=new YClass<XClass>();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

ZClass <YClass<XClass>> obj=new ZClass <YClass<XClass>>();


obj.MethodA(param);
}
}

public class ZClass<T> where T: YClass<XClass> {


public void MethodA(T obj) {
Console.WriteLine("ZClass::MethodA");
obj.MethodB();
}
}

public class YClass<T> {


public void MethodB() {

Console.WriteLine("YClass::MethodB");
}
}

public class XClass {


public void MethodC() {
Console.WriteLine("XClass::MethodA");
}
}

A type parameter can be used as a constraint. In this circumstance, one type of parameter is constraining
another. You are stating that a parameter is derived from another parameter. In this code, the T1 parameter
must be derived from the eventual T2 type argument:

using System;
using System.Collections;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
XClass<YClass, ZClass> obj=new XClass<YClass, ZClass>();
}
}

public class ZClass {


public void MethodA() {
Console.WriteLine("YClass::MethodA");
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

public class YClass: ZClass {


}

public class XClass<T1, T2> where T1:T2 {


public void MethodB(T1 arg) {

}
}

Nodes are the ideal generic type. You can have nodes of integers, floats, employees, or even football teams.
When creating a link list, each node has reference to the next and previous node. The node should reference
nodes of the same type. For an employee node, the next and previous node must also be an employee. This
relationship between nodes is enforced with a recursive constraint:

public class Node<T> where T: Node<T> {

// partial implementation

public T Previous {
get {
return default(T);
}
set {
}
}

public T Next {
get {
return default(T);
}
set {
}
}
}

The type parameter cannot exceed the visibility of the constraint. In the following code, XClass has internal
accessibility and is visible in the current assembly alone. The T parameter is public and is visible outside the
current assembly. The accessibility of the T parameter exceeds XClass. For this reason, it is an error to use
XClass as a constraint on the type parameter.

public class ZClass<T> where T: XClass{


}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

internal class XClass {


}

In addition, value types cannot be used as constraints, which is a good introduction to a limitation with
generics. Look at the following code, which will not compile. Why not?

public class Arithmetic<T> {


public T Cubed (T number) {
return number*number*number;
}
}

As with any parameter, the T parameter is an inferred System.Object type. System.Object does not have an
operator *. Therefore, "number*number*number" will not compile. An integer constraint should resolve the
problem, which would confirm that the type parameter is an integer. Integers have an operator *. However,
value types and primitives are not valid constraints. The following code will not compile:

class Arithmetic<T> where T: System.Int32 {


public T Cubed (T number) {
return number*number*number;
}
}

The inability to use standard operators with value types is a major limitation to generics. The workaround is
implementing named operators, such as Add, Multiply, and Divide, as members of the generic type.

In addition to value types, there are other restrictions on constraints. The following types cannot be used as
constraints:
 Sealed classes
 Open constructed types
 Primitive types
 System.Array
 System.Delegate
 System.Enum
 System.ValueType

Interface Constraints

Interfaces can also be constraints, which requires that the type argument implement the interface. Although
a type parameter can have at most one derivation constraint, it can have multiple interface constraints. This
is logical because a class can inherit a single base class but can implement many interfaces. The syntax for
an interface constraint is identical to a derivation constraint. Class and interface constraints can be
combined in a list of constraints. However, a class constraint should precede interface constraints in the list.

Interface and derivation constraints share many of the same rules and restrictions, such as the visibility of
the interface constraint exceeding that of the type parameter.

In the following code, the find capability has been added to the Sheet collection. The Find method returns an
array of cells that contain a certain value. A comparison is made between the cell and value, where both are
the type indicated in the type argument. Types that implement the IComparable interface support
comparisons. If a comparison is equal, IComparable .CompareTo returns 0. To support this behavior, an
interface constraint for IComparable is added to the type parameter. This is a partial implementation of the
Sheet collection that shows Find and related methods. (Some of the code shown previously is omitted.)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Sheet<int> asheet=new Sheet<int>(5);
for(byte row=1; row<6; ++row) {
for(byte col=1; col<6; ++col) {
asheet[row,col]=row*col;
}
}

Cell [] found=asheet.Find(6);
foreach(Cell answer in found) {

Console.WriteLine("R{0} C{1}",
answer.row, answer.col);
}
}
}

public struct Cell {


public byte row;
public byte col;
}

public class Sheet<T> where T: IComparable {


public Cell[] Find(T searchValue) {


int total=Count(searchValue);
int counter=0;
Cell [] cells=new Cell[total];
for(byte row=1; row<=m_Dimension; ++row) {
for(byte col=1; col<=m_Dimension; ++col) {
if(m_Sheet[row-1,col-1].CompareTo(searchValue)==0) {
cells[counter].row=row;
cells[counter].col=col;
++counter;
}
}
}
return cells;
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public int Count(T searchValue) {


int counter=0;
for(byte row=1; row<=m_Dimension; ++row) {
for(byte col=1; col<=m_Dimension; ++col) {
if(m_Sheet[row-1,col-1].CompareTo(searchValue)==0) {
++counter;
}
}
}
return counter;
}

}
}

This code works, but there is a subtle problem. The IComparable interface manipulates objects, which
causes boxing and unboxing when working with value types. This could become expensive in a large
collection of value types. In the preceding code, the type argument is an integer, which is a value type. This
causes boxing with the IComparable interface. Generic interfaces obfuscate this problem. .NET Framework
2.0 includes several general-purpose generic interfaces for developers. This is the class header updated for
the IComparable generic interface:

public class Sheet<T> where T: IComparable<T>

Value Type Constraint

A value type constraint restricts a type parameter to a value type. Value types are derived from the
System.ValueType type. Primitives and structures are examples of value types. The exception is the Nullable
type. The Nullable type is a value type, but it is not allowed with a value type constraint. A value type
constraint is a constraint using the struct keyword.

The following code demonstrates the value type constraint. The commented source line uses a reference
type, which would cause compile errors because of the value type constraint.

using System;
using System.Collections;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
ZClass<int> obj1=new ZClass<int>();
// ZClass<XClass> obj2=new ZClass<XClass>(); [illegal]
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class ZClass<T> where T: struct {

public void Iterate(T data) {


}
}

public class XClass{


}
}

Reference Type Constraint

A reference type constraint restricts a type parameter to a reference type. Reference types are generally
user-defined types, including classes, interfaces, delegates, and array types. A reference type constraint
uses the class keyword.

The following code has a reference type constraint. Although this code is similar to the code presented in the
previous section, a reference type constraint is used instead of a value type constraint. For this reason, the
illegal line has moved. You cannot use an integer type with a reference type parameter.

using System;
using System.Collections;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
// ZClass<int> obj1=new ZClass<int>(); [illegal]
ZClass<XClass> obj2=new ZClass<XClass>();

}
}

public class ZClass<T> where T: class {

public void Iterate(T data) {


}
}

public class XClass{


}
}

Default Constructor Constraint

Will this code compile? It looks fairly innocuous:


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

class ZClass<T> {
public void MethodA() {
T obj=new T();
}
}

This code does not compile. The problem is the default constructor. Although prevalent, not every type has a
default constructor. A default constructor, or a constructor with no arguments, assigns a default state to an
object. The default constructor is called with a parameterless new operator. However, because a default
constructor is not guaranteed, the new operator is not universally applicable. Therefore, the new operator is
disallowed on type parameters.

The solution is the constructor constraint. The derivation constraint does not help with constructors because
derived types do not inherit constructors for the base class. Constructor constraints mandate that a type
parameter have a default constructor, which is confirmed at compile time. This allows the new operator to be
used with the type parameter. The constructor constraint is added to the where clause and is a new
operator. When combined with other constraints, the default constructor constraint must be the last item in
the constraint list. The constructor constraint applies only to the default constructor. You are still prevented
from using constructors with arguments.

Here is sample code of the constructor constraint. The constructor constraint is used on the ZClass.

using System;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(){
ZClass obj=new ZClass();
obj.MethodA<XClass>();
}
}

public class ZClass {


public void MethodA<T>()
where T:XClass, new() {
Console.WriteLine("ZClass.MethodA");
T obj=new T();
obj.MethodB();
}
}

public class XClass{


public void MethodB() {
Console.WriteLine("XClass.MethodB");
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Casting
You may need to a cast a generic type. Since generic types are implicit System.Object types, they can
always be cast to that type. In addition, generic types can be cast to the derivation constraint, which is also
a type. The derivation constraint assures that the generic type is a descendant of the constraint. This
assures a safe cast. Finally, generics can be cast to any interface even if the interface is not included in an
interface constraint. Since there is no restriction on casting to interfaces, it is not type-safe. For that reason,
care should be taken to cast to an implemented interface.

In the following code, ZClass is a generic type. It has a single type parameter (T) that has three constraints:
YClass type derivation, IA interface derivation, and the constructor constraint. An instance of the T
parameter is created in the method called Cast. The instance is then cast in succession to the YClass, IA,
and IB interface. The first two casts work as expected. The third cast fails spectacularly. The type parameter
is not related to IB. However, the compiler does not notice. Therefore, an exception is raised at run time,
which is the worst possible time and underscores the type-unsafe nature of interface cast of generic types.

public class ZClass<T> where T:YClass, IA, new() {


static public void Cast() {
T obj=new T();
((YClass) obj).MethodA();
((IA) obj).MethodA();
((IB) obj).MethodB(); // kaboom
}
}

public class YClass : IA {


public void MethodA() {
Console.WriteLine("YClass.MethodA");
}
}

Generic type parameters cannot be assigned a null or zero. There is no assurance that a type parameter is
either a reference or value type, which prevents safely assigning a null or zero value to a type parameter.
However, you can test a type parameter against null but not zero. If the comparison succeeds, the type
parameter is a reference type. Otherwise, the type parameter is a value type.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Inheritance
Generic and nongeneric classes can inherit a generic type. In addition, a generic type can be the base class
to a generic or nongeneric type. Some basic rules apply. For example, the derived class cannot be a closed
constructed type. Table 6-1 lists all the possible permutations.
Table 6-1: Inheritance Table for Generic Types

Base Class Derived Class Comments

Generic (open) Generic (open) Permitted when the derived class consumes the type parameters of
the base class

Generic (open) Generic Not permitted


(closed)

Generic (open) Nongeneric Permitted

Generic Generic (open) Permitted


(closed)

Generic Generic Not permitted


(closed) (closed)

Generic Nongeneric Not permitted


(closed)

Nongeneric Generic Permitted


(closed)

Nongeneric Generic (open) Not permitted

This sample code shows some of the permitted and not permitted combinations:

public class ZClass<T> {


}

public class XClass<T> : ZClass<T> {


}

public class BClass<Y> {


}

public class AClass<Z> : BClass<int> {


}

public class YClass: ZClass<int> {


}

/*
public class AClass<Z> : BClass<Y> { [ illegal ]
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class YClass: ZClass<T> { [ illegal ]


}
*/

When inheriting an open constructed type, the constraints of the base class must be repeated in the derived
type. Furthermore, the derived type can provide additional constraints on type parameters declared at the
base type. This is not applicable to closed constructed types because closed constructed types do not have
type parameters or constraints.

Here is sample code combining inheritance of generic types and constraints:

public class ZClass<T> where T: IComparable {


}

public class YClass<T> : ZClass<T> where T: IComparable {


}

public class XClass<T> : ZClass<T> where T: IComparable, IDisposable {


}

public class BClass<Y> where Y: IEnumerable {


}

public class AClass<Z> : BClass<int[]> where Z:IDisposable {


}

Overriding Methods

Methods that have a type parameter can be overridden, regardless of where the type parameter is declared.
These methods can also override other methods. Table 6-2 lists the various combinations of overriding
generic and nongeneric methods. If a base class is nongeneric or closed, overriding methods cannot have
type parameters. Conversely, if the base class is open, overriding methods can employ type parameters.
Table 6-2:
Combination of
Overriding Generic
Methods

Ba De Co
se riv m
Me ed me
tho Me nts
d tho
d

No Ge Per
ng ner mit
en ic ted
eri (op
c en)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 6-2:
Combination of
Overriding Generic
Methods

Ba De Co
se riv m
Me ed me
tho Me nts
d tho
d

No Ge Per
ng ner mit
en ic ted
eri (cl
c os
ed)

Ge No Not
ner ng per
ic en mit
(op eri ted
en) c

Ge Ge Per
ner ner mit
ic ic ted
(op (op ;
en) en) mu
st
us
e
the
sa
me
typ
e
par
am
ete
rs

Ge Ge Not
ner ner per
ic ic mit
(op (cl ted
en) os
ed)

Ge No Per
ner ng mit
ic en ted
(cl eri
os c
ed)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 6-2:
Combination of
Overriding Generic
Methods

Ba De Co
se riv m
Me ed me
tho Me nts
d tho
d

Ge Ge Per
ner ner mit
ic ic ted
(cl (cl
os os
ed) ed)

Ge Ge Not
ner ner per
ic ic mit
(cl (op ted
os en)
ed)

Here is some example code:

using System;

namespace Donis.CSharpBook{

public class Starter{

public static void Main(){


}
}

public class ZClass<T> {


public virtual void MethodA(T arg) {
}
}

public class YClass<T> : ZClass<T>{


public override void MethodA(T arg) {
}

// public override void MethodA(int arg) { [ illegal ]


// }

}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class XClass<X> : ZClass<int>{


public override void MethodA(int arg) {
}

// public override void MethodA(X arg) { [ illegal ]


// }

public class WClass: ZClass<int> {


public override void MethodA(int arg) {
}
}
}

When a generic method overrides another generic method, it inherits the constraints of that method. The
overriding method cannot change the inherited constraints.

The following code correctly overrides a generic method:

public class ZClass {


public virtual void MethodA<T>(T arg)
where T: new() {
}
}

public class YClass : ZClass {


public override void MethodA<T>(T arg) {
T obj=new T();
}
}

Nested Types

You can nest a generic type inside a nongeneric type. Conversely, a nongeneric type can be nested in a
generic type. More intriguing is nesting generic types inside of generic types. The nested generic type can
consume the type parameters of the surrounding type. A type parameter of the surrounding type cannot be
redefined as a new type parameter in the nested type. However, the nested generic type can declare entirely
new type parameters.

This is sample code of nested generic types:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

ZClass<int>.Nested<double> obj=
new ZClass<int>.Nested<double>();
obj.MethodA(10, 12.34);
}
}

public class ZClass<T> {


public void MethodA(T arg) {

public class Nested<S> {


public void MethodA(T arg1, S arg2) {
Console.WriteLine("arg1: {0}",
arg1.GetType().ToString());
Console.WriteLine("arg2: {0}",
arg2.GetType().ToString());
}
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Static Members
Generic types can have static members. If present, a closed constructed type owns a set of any static
members. Therefore, there are possibly multiple instances of the static members—one for each closed
constructed type. Static members are not referable from the open constructed type. Static members are
usually accessed through the class name. With generic types, static members are accessible using the
closed constructed type notation. Static constructors, which are called implicitly, initialize the static fields in
the context of the current closed constructed type.

This is the constructed type notation:


 classname<argumentlist>.staticmember

classname is the name of the generic type; argumentlist is a comma-delimited list of type arguments;
staticmember is the name of the static member.

Static members are frequently used as counters. The following code counts the instances of generic types.
There are several generic type instantiations—each using a closed constructed type. The static count is
specific to each closed constructed type. The count counts the number of instances of a closed constructed
type.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ZClass<int> obj1=new ZClass<int>();
ZClass<double> obj2=new ZClass<double>();
ZClass<double> obj3=new ZClass<double>();
ZClass<int>.Count(obj1);
ZClass<double>.Count(obj2);
}
}

public class ZClass<T> {

public ZClass() {
++counter;
}

public static void Count(ZClass<T> _this) {


Console.WriteLine("{0} : {1}",
_this.GetType().ToString(),
counter.ToString());
}

private static int counter=0;


}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Several articles describing generics bemoan the extra cost of static fields in generic types. This is a
misplaced concern. A generic type often supplants the explicit implementation of separate classes:
StackCircle, StackTriangle, and so on. As separate classes, static members would also be replicated.
Alternatively, a general-purpose collection would have a single set of static members but incur other costs,
such as boxing and unboxing. From every perspective, the overhead from extra sets of static members from
generic types is comparable to or better than any alternate solution.

Operator Functions

You can implement operator functions for generic types. Operator member functions are static members.
Therefore, the rules of static members also apply to operator member functions. An operator member
function cannot be a generic method. However, the operator member function can use type parameters of the
generic type.

An operator+ has been added to the Sheet generic type. It adds two Sheet collections. The results of the
calculations are placed in a third sheet. Only integral sheets can be added. Because type parameters
cannot be constrained by a value type, a helper function called Add is provided:

public abstract class AddClass<T> {


public abstract T Add(T op1, T op2);
}

public class Sheet<T> : AddClass<int> where T: IComparable{


public Sheet(byte dimension) {
if(dimension<0) {
throw new Exception("Invalid dimensions");
}
m_Dimension=dimension;
m_Sheet=new T[dimension, dimension];
for(byte row=1; row<=dimension; ++row) {
for(byte col=1; col<=dimension; ++col) {
m_Sheet[row-1,col-1]=default(T);
}
}

public static Sheet<int> operator+(Sheet<int> sheet1,


Sheet<T> sheet2)
{
byte dimension=Math.Max(sheet1.m_Dimension,
sheet2.m_Dimension);
Sheet<int> total=new Sheet<int>(dimension);

for(byte row=1; row<=dimension; ++row) {


for(byte col=1; col<=dimension; ++col) {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

total[(byte) row,(byte)col]=
sheet1.Add(sheet1[(byte) row,(byte)col],(int)
(object) (sheet2[(byte) row,(byte)col]));
}
}
return total;
}

public override int Add(int op1, int op2) {


return op1+op2;
}

This is the signature of the operator+ function in the Sheet generic type:

public static Sheet<int> operator+(Sheet<int> sheet1,


Sheet<T> sheet2)

An operator+ is a binary operator with two operands. Notice that one operand is a closed constructed type,
whereas the other is an open constructed type. Why? The operator+ requires that one of the operands be
the containing class, which is the open constructed type, so there is a chance of adding incompatible
sheets. This explains the cast:

(int) (object) (sheet2[(byte) row,(byte)col])

sheet2 is the right-hand parameter of the operator+ function. The unknown type in sheet2 is being cast back
to an integer. If the type is incompatible, an exception is raised at that moment. Exception handling could
mitigate this problem. However, to keep the code simple, the problem is left unresolved. This code is meant
as demonstration only.

Serialization

Serialization persists the state of an object to a stream. Serializing the instance of a generic type is similar
to a regular type. This book does not provide a detailed overview of serialization. This section presents
targeted information on serializing generic types.

Serialization is done mostly with the SerializationInfo object. For generic types, there are additional
overloads of the SerializationInfo.AddValue and SerializationInfo.GetValue methods for object types. This
requires casting to and from object types.

For serialization, the generic type must be adorned with the Serializable attribute.

The GetObjectData method implements the serialization of an object. This includes serializing both the
metadata and instance data of the type. GetObjectData has a SerializationInfo and StreamingContext
parameter. The SerializationInfo.AddValue method is called to serialize generic type content:

public void GetObjectData(SerializationInfo info,


StreamingContext ctx) {
info.AddValue("fielda", fielda, typeof(T));
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

To deserialize, add a two-argument constructor to the generic type. The arguments are a SerializationInfo
and StreamingContext parameter. Call the SerializationInfo.GetValue method to rehydrate the instance:

private ZClass(SerializationInfo info,


StreamingContext ctx) {
fielda=(T) info.GetValue("fielda", typeof(T));
}

Objects can be serialized in different formats, which is accomplished with formatters, such as the
BinaryFormatter type. The SoapFormatter type cannot be used with generic types. Serialization also
requires creating an appropriate stream, such as a FileStream. The stream is where the instance is
serialized or deserialized. Call BinaryFormatter.Serialize to serialize a generic type instance. Conversely,
call BinaryFormatter.Deserialize to deserialize.

The following program accepts a command-line argument. The Set command instructs the program to
serialize an instance of the ZClass generic type to a file. A Get command asks the program to deserialize
the ZClass generic type.

using System;
using System.Runtime.Serialization;

using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace Donis.CSharpBook{

public class Starter{


public static void Main(string [] args){
BinaryFormatter binary=new BinaryFormatter();
FileStream file=
new FileStream("data.bin", FileMode.OpenOrCreate);

if(args[0].ToLower()=="set") {
ZClass<int> obj=new ZClass<int>(5);
binary.Serialize(file, obj);
return;
}

if(args[0].ToLower()=="get") {
ZClass<int> obj=(ZClass<int>)
binary.Deserialize(file);
Console.WriteLine(obj.GetValue());
return;
}

}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

[Serializable] public class ZClass<T> {

public ZClass(T init) {


fielda=init;
}

public void GetObjectData(SerializationInfo info,


StreamingContext ctx) {
info.AddValue("fielda", fielda, typeof(T));
}

private ZClass(SerializationInfo info,


StreamingContext ctx) {
fielda=(T) info.GetValue("fielda", typeof(T));
}

public void SetValue(T data) {


fielda=data;
}

public T GetValue() {
return fielda;
}

private T fielda=default(T);
}

Generics Internals

Generics are economical and expeditious, especially when compared with past implementations of
parametric polymorphism. The disparity is found in the compile-time and run-time semantics of code
expansion in generics. This section focuses on improvement in this area as compared with parameterized
types in C++, which has a widely-recognized implementation of parametric polymorphism.

Although an inspection of parameterized templates in C++ might uncover cursory similarities with generics,
there are considerable differences between them. These differences make generics more efficient and
better-performing than parameterized templates. The exact implementation of templates is specific to each
C++ compiler. However, the concepts of parameterized templates are similar in all implementations.

The major difference between generics and parameterized templates is that the latter is purely compile-time
based. Instances of parameterized templates expand into separate classes and are inlined at compile time.
The Standard Template Library (STL) of C++ offers a stack collection. If ellipse, rectangle, triangle, and curve
instances of the stack are defined, the stack template expands into separate classes—one for each type.
The expansion occurs at compile time. What happens when two stacks of circles are defined separately? Is
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

there a consolidation of the code? The answer is no, which can lead to significant code bloating.

The compile-time expansion has some shortcomings. This makes the parameterized templates specific to
C++. In .NET, generic types expand at run time and are not language-specific. Therefore, generics are
available to any managed language. The Sheet generic type presented in this chapter is usable in Microsoft
Visual Basic .NET. With C++, the particulars of the template, such as the parameterized types, are lost at
compile time and not available for later inspection. Managed code, including generics, undergoes two
compilations. The first compilation, administered by the language compiler, emits metadata and Microsoft
intermediate language (MSIL) code specific to generic types. Because the specifics of the generic type are
preserved, it is available for later inspection, such as reflection. There are new metadata and MSIL
instructions that target generic types. The second compilation, performed by the just-in-time compiler (jitter),
performs the code expansion. The jitter is part of the Common Language Runtime (CLR).

Figure 6-1 shows the MSIL-specific code for a generic type.

Figure 6-1: MSIL view of a generic type

The CLR performs an intelligent expansion of generic types, unlike C++, which blindly expands
parameterized types. Intelligent expansion is conducted differently for value type versus reference type
arguments.

When a generic type with a value argument is defined, it is expanded into a class at run time, where the
specific type is substituted for the parameter throughout the class. The resulting class is cached in memory.
Future instances of the generic type with the same type argument reference the existing class. In this
circumstance, there is code sharing between the separate generic type instantiations. Additional class
expansion is prevented and unnecessary code bloating is avoided.

If the type argument is a reference type, the CLR conducts intelligent expansion differently. The run time
creates a specialized class for the reference type, where System.Object is substituted for the parameter.
The new class is cached in memory. Future instances of the generic type with any reference type parameter
references this same class. Generic type instantiations that have a reference type parameter share the
same code.

Look at the following code. How many specialized classes are created at run time?

Sheet<int> asheet=new Sheet<int>(2);


Sheet<double> bsheet=new Sheet<double>(5);
Sheet<XClass> csheet=new Sheet<XClass>(2);
Sheet<YClass> dsheet=new Sheet<YClass>(5);
Sheet<int> esheet=new Sheet<int>(3);

The preceding code results in three specialized classes. The Sheet<int> instantiations share a class.
Sheet<double> is a separate class. Sheet<XClass> and Sheet<YClass> also share a class.

Generic Collections

As discussed in the previous chapter, the .NET Framework Class Library includes general-purpose collection
classes for commonplace data algorithms, such as a stack, queue, dynamic array, and dictionary. These
collections are object-based, which affects performance, hinders type-safeness, and potentially consumes
the available memory. The .NET FCL includes parameterized versions of most of the collections.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The parameterized data algorithms are found in the System.Collections.Generic namespace. Generic
interfaces are also included in the namespace. Table 6-3 lists some of the types and interfaces members of
this namespace.
Table 6-3:
Generic
Types and
Interfaces

De Ty
scr pe
ipti
on

Dy Lis
na t<T
mi >
c
arr
ay

LIF Sta
O ck
list <T
>

FIF Qu
O eu
list e<
T>

Col Dic
lec tio
tio nar
n y<
of K,
ke V>
y/v
alu
e
pai
rs

Co ICo
mp mp
are ara
s ble
a <T
cur >
ren
t
an
d
oth
er
obj
ect
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 6-3:
Generic
Types and
Interfaces

De Ty
scr pe
ipti
on

Co ICo
mp mp
are are
s r<T
two >
obj
ect
s

Ret IEn
urn um
s era
an ble
en <T
um >
era
tor

Def IEn
ine um
s era
an tor
en <T
um >
era
tor
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Enumerators
The next chapter pertains to enumerators, a topic that is a natural extension of this chapter. Enumerators
are typically used to iterate collections, which have been the focus of the last two chapters. Enumerators are
implemented and typically exposed from an enumerable object. Enumerable objects implement the
IEnumerable interface. The IEnumerable.GetEnumerator method returns an enumerator object.

The foreach statement is the most visible expression of enumeration in a C# program. The target of the
foreach statement is not any object—it has to be an enumerable object.

The next chapter documents the enumerator pattern, including how to implement an enumerator and
enumerable object.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 7: Iterators
Overview
Stacks, queues, dictionaries, dynamic arrays, normal arrays, and various other collections were introduced
in previous chapters. Collections are assemblages of related types. There could be a dynamic array of
Employee types, which would include HourlyEmployee, ExemptEmployee, and CommissionedEmployee
instances. There could be a queue of bank requests, such as DepositTransaction, WithdrawalTransaction,
and InterestTransaction types. Inheritance relates these types at compile time, whereas polymorphism
binds them at run time. Collections are also assemblages of similar items. Enumerating the elements of a
collection is a recurrent and valuable behavior. Enumeration iterates the items in a collection. A report that
lists new employees would need to enumerate the employee collection. Bank statements require
enumerating transactions of a particular bank client.

Enumeration is a valuable tool to almost every developer, encouraging some standardization. Enumerable
nongeneric types implement the IEnumerator and IEnumerable interfaces, whereas generic types implement
the IEnumerator<T> and IEnumerable<T> generic interfaces. IEnumerable interfaces return unique
enumerator objects to clients. An enumerator object implements the IEnumerator interface, which defines
the behavior of enumeration. Collections are enumerable objects, which implement one of the IEnumerable
interfaces and adhere to the enumeration pattern.

Collections are usually enumerated in a loop. Most collections offer collection-specific interfaces to
enumerate elements. The ArrayList type has indexes. The Stack has the Pop method. Hashtables have the
Keys and Values properties. Collections also offer a standardized approach to enumeration with the
IEnumerator interface. Loops are often harbingers of subtle bugs. The foreach statement is a
compiler-generated loop that uses IEnumerator objects to iterate error-free enumerable collections. This
reduces the code required to iterate a collection and makes developer code more robust.

The following is a straightforward foreach loop. The colors array is an array of strings. Arrays are collections
and are therefore enumerable. Instead of writing a for loop, with indexes and a counter to manage, the
foreach loop keeps everything simple. No indexes. No counters. The foreach loop automatically enumerates
each element of the collection.

string [] colors={"red", "green", "blue"};


foreach(string color in colors) {
Console.WriteLine(color);
}

Here is another example of a foreach loop. This code manipulates a Stack collection—a more complex
structure than a simple array. However, stacks are also collections, meaning that the foreach statement is
available.

Stack<int> collection=new Stack<int>();


collection.Push(10);
collection.Push(15);
collection.Push(20);
foreach(int number in collection) {
Console.WriteLine(number);
}

Implementing the IEnumerator interface in an enumerable object can be challenging—especially for complex
data structures. Iterators have been introduced for this reason. Iterators provide a standardized
implementation of the enumerator pattern and prevent individual developers from re-creating the same wheel.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Enumerable Objects
Enumerable objects implement the IEnumerable interface. The GetEnumerator method is the only member
of this interface. It returns an enumerator, which is used to enumerate nongeneric collections.

This is the IEnumerable interface:

public interface IEnumerable {


IEnumerator GetEnumerator();
}

Each invocation of the GetEnumerator method returns a unique enumerator. The enumerator is a state
machine that minimally maintains a snapshot of the target collection and a cursor. The cursor points to the
current item of the collection. The snapshot is a static copy of the collection. What happens if a collection is
modified while being enumerated? An exception occurs. You could lock the collection during enumeration,
but it might cause substantial performance degradation. As a best practice, an enumerator should capture
the collection as a snapshot. This isolates the enumerator from changes to the original collection. In
addition, the snapshot collection is read-only. The GetEnumerator method should be thread-safe,
guaranteeing that a unique enumerator is returned, which references an isolated collection regardless of the
thread context.

Enumerators
Enumerators are part of the enumeration pattern and normally implemented as a nested class within the
collection type. The primary benefit of nested classes is access to the private members of the outer class.
This access allows you to avoid breaking the rules of encapsulation to allow the enumerator class to access
the data store of the collection. The data store is undoubtedly a private member of the collection class.

Enumerators implement the IEnumerator interface, which has three members. This is the IEnumerator
interface:

public interface IEnumerator {


object Current {get;}
bool MoveNext();
void Reset();
}

The Current property returns the current element of the collection. MoveNext moves the Current property to
the next element. If the iteration has completed, MoveNext returns false. Otherwise, MoveNext returns true.
Notice that there is not a MovePrevious method; enumeration is forward only. The Reset method returns the
enumeration to the beginning of the collection.

The enumerator is the state machine representing the enumeration. Part of the state machine is the cursor,
which is the collection index or locator. The cursor is not necessarily an integral value, but normally it is. For
a link list, the cursor may be a node, which is an object. When the enumerator is created, the cursor initially
points before the first element of the collection. Do not access the Current property while the cursor is in this
initial state. Call MoveNext first, which positions the cursor at the first element of the collection.

The following is a typical constructor of an enumerator. In this example, the constructor makes a snapshot of
the collection. For reasons of simplicity, the collection is a basic array. The cursor is then set to –1, which is
before the first element of the collection.

public Enumerator(object [] items) {


elements=new object[items.Length];
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Array.Copy(items, elements, items.Length);


cursor=-1;
}

The MoveNext method increments the value of the cursor. This action moves the Current property to the next
element of the collection. If the list has been fully iterated, MoveNext returns false. Collections are not
circular, where MoveNext might cycle through a collection. Circular collections are not within the enumerator
pattern. The Current property is not valid after the collection has been fully enumerated. For this reason, do
not use the Current property after MoveNext returns false.

Here is one possible implementation of the MoveNext method:

public bool MoveNext() {


++cursor;
if(cursor>(elements.Length-1)) {
return false;
}
return true;
}

The Reset method resets the enumeration. The cursor is updated to point to before the collection again.
Resetting the cursor also automatically resets the Current property.

Here is a Reset method:

public void Reset() {


cursor=-1;
}

With the cursor as a reference to the current item, the Current property provides access to the current
element of the collection. The Current property must be read-only. Implement the get method of the property
but not the set method. The implementation should check for fence-post errors. If the index is before or after
the collection, the appropriate exception should be thrown.

Here is an implementation of the Current property:

public object Current {


get {
if(cursor>(elements.Length-1)) {
throw new InvalidOperationException(
"Enumeration already finished");
}
if(cursor == -1) {
throw new InvalidOperationException(
"Enumeration not started");
}
return elements[cursor];
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Enumerator states Enumerators can be in one of four possible states. Table 7-1 lists the enumerator states.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 7-1:
Enumerator
States

St De
ate scr
ipti
on

Bef Thi
ore s
is
the
sta
te
of
the
en
um
era
tor
bef
ore
en
um
era
tio
n
ha
s
sta
rte
d
or
aft
er
it
ha
s
be
en
res
et.
Th
e
firs
t
call
to
Mo
ve
Ne
xt
ch
an
ge
s
the
sta
te
fro
m
Bef
ore
to
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 7-1:
Enumerator
States

St De
ate scr
ipti
on

Ru Thi
nni s
ng is
the
sta
te
wh
en
Mo
ve
Ne
xt
is
cal
cul
ati
ng
the
ne
xt
ele
me
nt (
Cur
ren
t)
of
the
iter
ati
on.
Wh
en
Mo
ve
Ne
xt
ret
urn
s
tru
e,
the
ne
xt
ele
me
nt
ha
s
be
en
en
um
era
ted
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 7-1:
Enumerator
States

St De
ate scr
ipti
on

Su Th
sp e
en sta
de te
d of
the
en
um
era
tor
bet
we
en
en
um
era
tio
ns.
Cal
ling
Mo
ve
Ne
xt
ch
an
ge
s
the
sta
te
fro
m
Su
sp
en
de
d
to
Ru
nni
ng
whi
le
cal
cul
ati
ng
the
ne
xt
Cur
ren
t
pro
per
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 7-1:
Enumerator
States

St De
ate scr
ipti
on

Aft Thi
er s
is
the
sta
te
aft
er
en
um
era
tio
n
ha
s
co
mp
let
ed.
Re
set
ret
urn
s
the
en
um
era
tio
n
to
Bef
ore
,
an
d
en
um
era
tio
n
ca
n
be
res
tart
ed.

Enumerator Example
Sample code for an enumerator class and client are provided as follows. This is also the complete listing for
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

some of the partial code presented earlier in this segment. The SimpleCollection is a thin wrapper for a basic
array. Actually, it is somewhat redundant because arrays are already fully functional collections, including
exposing an enumerator. However, this simple example is ideal for demonstrating the enumerator pattern.

The enumerator pattern recommends isolation of the underlying collection. In this code, the enumerator is
created as a nested class, in which a snapshot of the collection is made in the constructor. The isolated
collection is created from a copy of the array. In addition, the Current property is read-only, which prevents
changes to the collection data.

In Main, an instance of the SimpleCollection is created. It is initialized with an integer array. The collection is
then iterated using the IEnumerator interface.

using System;
using System.Collections;

namespace Donis.CSharpBook{

public class Starter{

public static void Main(){


SimpleCollection simple=new SimpleCollection(
new object[] {1,2,3,4,5,6,7});

IEnumerator enumerator=simple.GetEnumerator();
while(enumerator.MoveNext()) {
Console.WriteLine(enumerator.Current);
}
}
}

public class SimpleCollection: IEnumerable {

public SimpleCollection(object [] array) {


items=array;
}

public IEnumerator GetEnumerator() {


return new Enumerator(items);
}

private class Enumerator: IEnumerator {

public Enumerator(object [] items) {


elements=new object[items.Length];
Array.Copy(items, elements, items.Length);
cursor=-1;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public bool MoveNext() {


++cursor;
if(cursor>(elements.Length-1)) {
return false;
}
return true;
}

public void Reset() {


cursor=-1;
}

public object Current {


get {
if(cursor>(elements.Length-1)) {
throw new InvalidOperationException(
"Enumeration already finished");
}
if(cursor == -1) {
throw new InvalidOperationException(
"Enumeration not started");
}
return elements[cursor];
}
}

private int cursor;


private object [] elements=null;
}

private object [] items=null;


}
}

As mentioned, the SimpleCollection class makes a copy of the collection in the enumerator. This isolates
the collection from contamination caused by modifications. This is the recommended approach for volatile
collections. SimpleCollection is volatile because the elements of the underlying collection can be modified. If
the collection is static, a copy may not be necessary. Isolation protects a collection against changes. If the
collection is static, this is not an issue, and isolation is not required.

Enumerator Example (Static Collection)


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Here is the SimpleCollection class rewritten for a static collection. The underlying collection is read-only,
which makes it static. When the enumerator is created, the this reference of the enumerable object is
passed to the constructor. Future and unique enumerators share this reference to access the same
collection—maybe simultaneously. The state machine encapsulates the back reference and a cursor. The
back reference is the this reference to the outer object. With the back reference, the enumerator gains
access to members of the outer class, including the collection, which allows the enumerator to iterate the
collection directly.

public class SimpleCollection: IEnumerable {

public SimpleCollection(object [] array) {


items=array;
}

public IEnumerator GetEnumerator() {


return new Enumerator(this);
}

private class Enumerator: IEnumerator {

public Enumerator(SimpleCollection obj) {


oThis=obj;
cursor=-1;
}

public bool MoveNext() {


++cursor;
if(cursor>(oThis.items.Length-1)) {
return false;
}
return true;
}

public void Reset() {


cursor=-1;
}

public object Current {


get {
if(cursor>(oThis.items.Length-1)) {
throw new InvalidOperationException(

"Enumeration already finished");


}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

if(cursor == -1) {
throw new InvalidOperationException(
"Enumeration not started");
}
return oThis.items[cursor];
}
}

private int cursor;


private SimpleCollection oThis;
}

private object [] items=null;


}

Collections that have inconstant changes are not ideal for either of the enumerator models presented:
contentious or static. Copying the collection per each enumerator is costly when changes are infrequent.
The static model is inappropriate because the collection may indeed change, albeit not regularly. A
versioned collection is the solution and combines traits of the contentious and static models for
implementing enumerators.

Enumerator Example (Versioned Collection)


The following code contains an implementation for a versioned collection. A private field called version has
been added to the collection class. An indexer has been added to allow clients to modify the collection. The
version is incremented whenever the collection is modified. A version number has also been added to the
enumerator, which is the nested class. In the constructor, the version is initialized to the version of the outer
collection. When the Current property is accessed, the version number inside the enumerator is compared to
that of the collection. If unequal, the collection has been modified since the enumerator was created and an
exception is raised. This is the implementation model of the collections in the .NET Framework class library
(FCL), such as the ArrayList, Stack, Queue, and other collection classes.

The Main method is changed to test the versioning. The collection is modified in the method after the
enumerator has been obtained. After the modification, the Current property is used, which causes the
expected exception:

using System;
using System.Collections;

namespace Donis.CSharpBook{

public class Starter{

public static void Main(){


SimpleCollection simple=new SimpleCollection(
new object[] {1,2,3,4,5,6,7});

IEnumerator enumerator=simple.GetEnumerator();
enumerator.MoveNext();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine(enumerator.Current);
enumerator.MoveNext();
simple[4]=10;
Console.WriteLine(enumerator.Current); // Exception raised
enumerator.MoveNext();
}
}

public class SimpleCollection: IEnumerable {

public SimpleCollection(object [] array) {


items=array;
version=1;
}

public object this[int index] {


get {
return items[index];
}
set {
++version;
items[index]=value;
}
}

public IEnumerator GetEnumerator() {


return new Enumerator(this);
}

private class Enumerator: IEnumerator {

public Enumerator(SimpleCollection obj) {


oThis=obj;
cursor=-1;
version=oThis.version;
}

public bool MoveNext() {


++cursor;
if(cursor>(oThis.items.Length-1)) {
return false;
}
return true;
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void Reset() {


cursor=-1;
}

public object Current {


get {
if(oThis.version != version) {

throw new InvalidOperationException(


"Collection was modified");
}

if(cursor>(oThis.items.Length-1)) {
throw new InvalidOperationException(
"Enumeration already finished");
}
if(cursor == -1) {
throw new InvalidOperationException(
"Enumeration not started");
}
return oThis.items[cursor];
}
}

private int version;


private int cursor;
private SimpleCollection oThis;
}

private object [] items=null;


private int version;
}
}

IEnumerator Problem
Several techniques to implement the enumerator pattern have been shown. The varied strategies share
common problems. Enumerators, which implement the IEnumerator interface, manipulate System.Object
types. This is the heart of the problem.
 There is a performance penalty from boxing and unboxing value types.
 Alternatively, there is a performance cost to downcasting to reference types.
 Frequent boxing stresses the managed heap.
 Casting to and from System.Object is required, which is not type-safe.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

These problems were identified in the previous chapter. The solution was generic types. That is the solution
here also. The .NET Framework offers generic versions of the IEnumerable and IEnumerator interfaces.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Generic Enumerators
Nongeneric enumerable objects and enumerators are oblique. There is a lack of type specialty, which leads
to performance problems and other issues. You can implement enumerable objects and enumerators using
generic interfaces, which avoid some of the problems mentioned earlier. Implement the IEnumerable<T>
interface for generic enumerable objects. For generic enumerator objects, implement the IEnumerator<T>
interface. Both IEnumerable<T> and IEnumerator<T> are generic interfaces found in the .NET FCL in the
System.Collections .Generic namespace. IEnumerable<T> and IEnumerator<T> inherit their nongeneric
counterparts IEnumerable and IEnumerator, respectively. This means that generic enumerable objects and
enumerators are available generically or nongenerically.

IEnumerable<T> Interface
Generic enumerable objects implement the IEnumerable<T> interface. This is the IEnumerable<T> interface:

public interface IEnumerable<T> : IEnumerable {


IEnumerator<T> GetEnumerator();
}

As shown, IEnumerable<T> inherits IEnumerable, which is the nongeneric version of the same interface.
This includes a nongeneric version of the GetEnumerator method. Enumerators inheriting IEnumerable<T>
must therefore implement a generic and nongeneric GetEnumerator method. The two GetEnumerator
methods differ in return type only. As you know, the return type alone is insufficient for overloading a method.
To prevent ambiguousness, one of the GetEnumerator methods must have explicit interface member
implementation.

This is sample code of the GetEnumerator methods for a generic enumerable object. (The nongeneric version
of GetEnumerator is implemented explicitly.)

public IEnumerator<T> GetEnumerator() {


return new Enumerator<T>(this);
}

IEnumerator IEnumerable.GetEnumerator() {
return new Enumerator<T>(this);
}

The generic version of GetEnumerator naturally returns a generic enumerator, which implements the
IEnumerator<T> interface.

IEnumerator<T> Interface
Generic enumerators implement the IEnumerator<T> interface, shown here:

public interface IEnumerator<T>: IDisposable, IEnumerator {


T Current {get;}
}

Current is a read-only property and is the only direct member of the IEnumerator<T> generic interface. The
remaining members are inherited from the IDisposable and IEnumerator interfaces. The IDisposable
interface defines generic enumerators as disposable. This requires implementing the IDisposable.Dispose
method. The IEnumerator interface adds the nongeneric enumerator interface. The MoveNext and Reset
methods do not require a generic implementation and are therefore not defined in the generic portion of the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

interface. A second Current property, a nongeneric version, is inherited from the IEnumerable interface.
Therefore, IEnumerator has overloaded Current properties, where both should be implemented in the
enumerator.

This is sample code of a generic and nongeneric implementation of the Current property. The nongeneric
Current property delegates to the generic version.

public __T Current {


get {
if(oThis.version != version) {
throw new InvalidOperationException(
"Collection was modified");
}

if(cursor>(oThis.items.Length-1)) {
throw new InvalidOperationException(
"Enumeration already finished");
}
if(cursor == -1) {
throw new InvalidOperationException(
"Enumeration not started");
}
return oThis.items[cursor];
}
}

object IEnumerator.Current {
get {
return Current;
}
}

The Dispose method supports deterministic garbage collection. This method is called explicitly to clean up
for an object. In this circumstance, the method is called to clean up resources assigned to an enumerator.
Dispose methods of enumerators are most frequently called by iterators, which is the next topic of this
chapter. In the Dispose method, set the state of the enumeration to After and perform any necessary
cleanup. Some enumerators track the state using a flag (an enumeration type), where the flag is updated in
the Dispose method and elsewhere in the enumerator. The code presented earlier does not employ a state
flag. If the cursor is beyond the collection, the After state is assumed. Conversely, a cursor of -1 indicates
the Before state. Based on these assumptions, this is one implementation of a Dispose method for an
enumerator:

public void Dispose() {


cursor=oThis.items.Length+1;
}

Generic Enumerator Example (Versioned Collection)


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Earlier in the chapter, a version collection model of enumeration was presented. Here is the versioned
collection example redone with generic interfaces. The following code also completes some of the partial
code presented earlier in this section. In Main, the collection is enumerated in a generic and nongeneric
manner. In the second foreach loop, the simple collection is cast to the nongeneric IEnumerable interface.
This instructs the foreach statement to call the nongeneric GetEnumerator method, which returns a
nongeneric enumerator. The nongeneric enumerator is then used to iterate the simple collection.

Here is the sample code:

using System;
using System.Collections;
using System.Collections.Generic;

namespace Donis.CSharpBook{

public class Starter{

public static void Main(){


SimpleCollection<int> simple=
new SimpleCollection<int>(
new int [] {1,2,3,4,5,6,7});

foreach(int number in simple) {


Console.WriteLine(number);
}

foreach(int number in
(IEnumerable) simple) {
Console.WriteLine(number);
}
}
}

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

public SimpleCollection(T[] array) {


items=array;
version=1;
}

public T this[int index] {


get {
return items[index];
}
set {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

++version;
items[index]=value;
}
}

public IEnumerator<T> GetEnumerator() {


Console.WriteLine(
"IEnumerator<T> GetEnumerator()");
return new Enumerator<T>(this);
}

IEnumerator IEnumerable.GetEnumerator() {
Console.WriteLine(
"IEnumerator GetEnumerator()");
return new Enumerator<T>(this);
}

private class Enumerator<__T>: IEnumerator<__T>

public Enumerator(SimpleCollection<__T> obj) {


oThis=obj;
cursor=-1;
version=oThis.version;
}

public __T Current {


get {
if(oThis.version != version) {
throw new InvalidOperationException(
"Collection was modified");
}

if(cursor>(oThis.items.Length-1)) {
throw new InvalidOperationException(
"Enumeration already finished");
}
if(cursor == -1) {
throw new InvalidOperationException(
"Enumeration not started");
}
return oThis.items[cursor];
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void Dispose() {


cursor=oThis.items.Length+1;
}

public bool MoveNext() {


++cursor;
if(cursor>(oThis.items.Length-1)) {
return false;
}
return true;
}

public void Reset() {


cursor=-1;
}

object IEnumerator.Current {
get {
return Current;
}
}

private int version;


private int cursor;
private SimpleCollection<__T> oThis;
}

private T [] items=null;
private int version;
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Iterators
Iterators implement the enumerator pattern. This chapter has demonstrated different implementation
strategies for enumerators. The chosen implementation depends on the answer to relevant questions. Should
the enumerator be implemented as a nested class? Should a version collection be used? Should the
implementation be generic or nongeneric? Having every developer answer these questions and author a
proprietary enumerator is not a productive use of their collective mental prowess. Almost assuredly, the
various implementations of the enumerator pattern are within an acceptable delta in performance and
memory requirements. Anyway, a certain number of developers simply visit the MSDN Web site, from which
they copy and paste the enumerator implementation. Therefore, the various implementations are undoubtedly
quite similar. Iterators standardize the enumerator pattern for developers.

When implementing enumerators ourselves, the real challenge is complex enumerations. As shown, forward
iterations are usually straightforward. Reverse iterations are more complex, however. Coding an enumerator
to iterate a sparse collection, nodal list, or binary tree can also be daunting. What about enumerating a
temporary collection? This often requires maintaining multiple enumerators, such as a forward and reverse
enumerator. Does this sound like fun? Actually, I would gladly pass the baton to the compiler.

.NET 2.0 introduced the iterator, which is a compiler-manifested enumerator. When the enumerable object
calls GetEnumerator, either directly or indirectly, the compiler generates and returns an appropriate iterator
object. Optionally, the iterator can be a combined enumerable and enumerator object. You are not
completely excluded from the process. Developers can affect the enumeration in an iterator block. The
essential ingredient of an iterator block is the yield statement.

Yield Statement
The following code demonstrates one of the obvious benefits of the yield statement and an iterator block:
brevity. The previous sample code of a generic enumerator required more than 50 lines of code. The following
example implements a similar enumerator using the yield statement, which requires three lines of code:

public IEnumerator<T> GetEnumerator() {


foreach(T item in items) {
yield return item;
}
}

In the previous code, the C# compiler implements the enumerator. You are still coding the IEnumerable
interface. Optionally, the compiler can implement both the enumerable and enumerator object in the iterator.
If the iterator block returns IEnumerable, the compiler responds by creating an enumerable and enumerator
object. Iterator blocks are explained soon. This removes even having to implement the GetEnumerator
method.

public IEnumerable<T> MethodA() {


foreach(T item in items) {
yield return item;
}
}

For clients, iterators are similar to enumerators. Clients call GetEnumerator or other iterator methods to
obtain an iterator object. You then use the IEnumerator or IEnumerator<T> interface to enumerate the
collection. There is one big difference between iterators and enumerators: Iterators do not implement the
Reset method. Calling the Reset method on an iterator causes an exception.

The pivotal statement of an iterator is yield. This is the syntax of the yield statement:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 yield return expression;


 yield break;

The yield return statements iterate the next element of a collection. The statement expression is assigned to
the Current property. Enumerators start in the Before state. The initial MoveNext method calls the first yield
statement. After the Current property is set, the enumerator is suspended. The next MoveNext calls the next
yield. This pattern continues until the enumeration is finished. The iterator block is not called anew for each
MoveNext. Between yield statements of the same iterator block, enumeration is suspended. The iterator is a
state machine that maintains the state of the enumeration between calls to the MoveNext method.

The yield break statements finish an enumeration, which ultimately changes the enumerator state to after.
The Dispose method is then called to clean up the enumerator. This is sample code of the yield break
statement. The yield break statement stops the enumeration after the fourth element.

public IEnumerator<T> GetEnumerator() {


int count=0;
foreach(T item in items) {
++count;
yield return item;
if(count==4) {
yield break;
}
}
}

Iterator Blocks
Iterator blocks contain the logic to enumerate a collection. This includes one or more yield statements.
Methods, properties, and operator functions can be iterator blocks. Iterator blocks are not executed
continuously and are sometimes suspended. The function is suspended between successive yield
statements, which are controlled by the MoveNext method. As mentioned, the iterator block maintains the
state machine of the enumerator between iterations.

There are restrictions on iterator blocks. For example, iterator blocks cannot have a return statement. Only
yield return statements are allowed:

public IEnumerator<T> GetEnumerator() {


foreach(T item in items) {
yield return item;
return; // not allowed
}
}

There are several other restrictions on iterator blocks:


 Iterator blocks can be contained only in method, operator, or property functions.
 Iterator blocks cannot be in anonymous methods.
 Iterator blocks cannot be contained in a try with a catch handler.
 Iterator blocks cannot be placed in a finally block.

Functions with iterators or iterator methods also have certain restrictions:


 Iterator methods must return a generic or nongeneric IEnumerable or IEnumerator interface.
 Iterator methods cannot have ref parameters.
 Iterator methods cannot have out parameters.
 Iterator methods cannot be unsafe.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

When an iterator block is exited, the Dispose method of the enumerator is called. Internally, the iterator
creates the enumerator in a using block. This provides an opportunity to clean up for the enumerator when
the enumeration is completed.

Iterator Internals
Iterators are implemented as nested classes, which are created by the C# compiler. The nested class
maintains the state of the current enumeration. It persists the enumeration state between yield statements.
Iterators are created by the language compiler, not by the Common Language Runtime (CLR). Neither
Microsoft intermediate language (MSIL) nor metadata has changed to especially accommodate iterators. The
nested class for an enumerator is a normal class, which is created for a method that contains an iterator
block. If three methods within a class have enumerator blocks, the compiler adds three nested classes to
that class.

This is how the nested class is named:


 <membername>uniqueid<T>
 <membername>uniqueid

If the iterator method returns either the IEnumerator<T> or IEnumerable<T> interfaces, the name of the
nested class has the <T> suffix.

In this code, ZClass has multiple iterator methods:

public class ZClass {

public IEnumerator GetEnumerator() {


int [] array=new int [] {1,2,3,4};
int count=0;
for(count=0;count<4;++count){
yield return array[count];
}
}
public IEnumerator MethodA() {
int [] array=new int [] {1,2,3,4};
int count=0;
for(count=0;count<4;++count){
yield return array[count];
}
}

public IEnumerable<T> MethodB<T>() {


T local=default(T);
yield return local;
}

The compiler adds three nested classes, one for each enumerator method, to the ZClass type. The various
nested classes represent the state machine for different enumerators. Figure 7-1 shows ZClass and the
nested classes.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 7-1: A view of the ZClass type, which includes the nested enumerator classes

The nested enumerator class has several private fields. The local variables of the iterator method are lifted to
fields of the nested class. The fields maintain the state of these local variables throughout the enumeration.
The nested class also has three special purpose fields. The state of the enumeration, such as running or
after, is in the <>1__state field. The <>2__current field is the result of the last iteration. It is the current item.
The <4>__field is a back pointer to the outer class. If the iterator method is static, the back pointer is not
initialized; it is initialized only for instance methods. Combined, the lifted and specialty fields are the state of
the enumeration.

Figure 7-2 shows the fields of a typical nested class for an enumerator.

Figure 7-2: A view of a nested class and fields

Iterator Examples
This section presents several examples of iterators to demonstrate the flexibility of iterators and provide
techniques for using them.

Dual iteration The first example iterates two collections simultaneously:

using System;
using System.Collections.Generic;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ZClass obj=new ZClass();
foreach(int item in obj) {
Console.Write(item);
}
}
}

public class ZClass {

private int [] list1=new int [] {0,2,4,6,8};


private int [] list2=new int [] {1,3,5,7,9};
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public IEnumerator<int> GetEnumerator() {


for(int index=0; index<4; ++index) {
yield return list1[index];
yield return list2[index];
}
}

}
}

The preceding code alternates between yielding list1 and list2. As the iteration moves between collections,
the even and odd numbers are intermixed. The result is 0123456789. ZClass does not inherit the
IEnumerable interface. However, it adheres to the enumerator pattern by implementing the GetEnumerator
method. This is sufficient for defining enumerable objects. The following examples implement the iteration
pattern but not explicitly the interfaces.

Reverse iteration The following example iterates a collection forward and reverse. Two iterators are
exposed for this reason. GetEnumerator exposes the standard forward iterator. The reverse iterator is
implemented in the Reverse property. Because the property returns IEnumerable, the Reverse property is
both an enumerable and enumerator object. When an iterator method returns IEnumerable, the nested class
generated by the compiler is implemented as both an enumerable and enumerator object. In Main, there are
two foreach loops: The first foreach loop uses the forward iterator, whereas the reverse iterator is requested
in the second loop:

using System;
using System.Collections.Generic;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
Console.WriteLine("Forward List");
ZClass obj=new ZClass();
foreach(int item in obj) {
Console.Write(item);
}

Console.WriteLine("\nReverse List");
foreach(int item in obj.Reverse) {
Console.Write(item);
}
}
}

public class ZClass {

private int [] list1=new int [] {0,2,4,6,8};

public IEnumerator<int> GetEnumerator() {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

for(int index=0; index<5; ++index) {


yield return list1[index];
}
}

public IEnumerable<int> Reverse {


get {
for(int index=4; index>=0; --index) {
yield return list1[index];
}
}

}
}
}

Temporary collections Temporary collections are calculated at run time and are useful in a variety of
circumstances. The list of prime numbers, the records of a file, and fields in a dataset are examples of
collections that can be calculated. Temporary collections can be populated lazily. You can read a flat file or
dataset on demand at run time to hydrate a temporary collection.

The following code enumerates days from the current date until the end of the month, which is calculated
using DateTime structure. The method ToEndOfMonth is enumerable by virtue of returning the IEnumerable
interface and possessing a yield statement. Each repeat of the while loop extrapolates the next day until the
end of the month is reached. The yield statement iterates the days as they are calculated.

using System;
using System.Collections;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
foreach(string day in ToEndOfMonth()) {
Console.WriteLine(day);
}
}

public static IEnumerable ToEndOfMonth() {


DateTime date=DateTime.Now;

int currMonth=date.Month;
while(currMonth==date.Month) {
string temp=currMonth.ToString()+
"/"+date.Day.ToString();
date=date.AddDays(1);
yield return temp;
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
}

Complex iteration Link lists are complex data structures. Iterators are particularly useful when iterating
complex data structures, such as a link list. Each item in the list is considered a node. Nodes maintain a
reference to the previous and next node. From any node, you can walk the link list either forward or
backward. For several reasons, the iteration is more complex. First, data structure must be iterated forward
and backward during the same iteration. Second, fence posts are not as definable. Fence posts in arrays,
stacks, queues, and other sequenced containers are easily found, which helps avoid fence post error
exceptions. Finally, the iteration can start from any node in the link list, not necessarily just the beginning or
end of the list.

Below is a partial listing of the Node class. The key code is in the GetEnumerator method. In the first while
loop, the link list is iterating in reverse—from the current node to the beginning of list. This is accomplished
by walking the prevNode member of the node class. The current node is enumerated next. Finally, the
second while loop iterates the link list going forward from the current note to the end of the list. The nextNode
members are walked.

public class Node<T> {

public Node(Node<T> node, T data) {


m_Info=data;
if(node==null) {
if(firstNode != null) {
Node<T> temp=firstNode;
this.nextNode=temp;
temp.prevNode=this;
firstNode=this;
return;
}
prevNode=null;
nextNode=null;
firstNode=this;
return;
}

this.prevNode=node;
this.nextNode=node.nextNode;
node.nextNode=this;
if(node.nextNode==null) {
lastNode=null;
}
}

public void AddNode(T data) {


this.nextNode=new Node<T>(this, data);
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public IEnumerator<T> GetEnumerator () {


Node<T> temp=prevNode;
while(temp!=null) {
yield return temp.m_Info;
temp=temp.prevNode;
}
yield return m_Info;
temp=nextNode;
while(temp!=null) {
yield return temp.m_Info;
temp=temp.nextNode;
}
}

private T m_Info;
private static Node<T> lastNode=null;
private static Node<T> firstNode=null;
private Node<T> prevNode=null;
private Node<T> nextNode=null;

}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Delegates and Events


The next chapter pertains to delegates and events, which are related topics. Function pointers are prevalent
in unmanaged programming languages and helpful in streamlining algorithms. As function pointers, functions
can be treated as local variables, function parameters, or even function returns—which adds considerable
flexibility in the way functions are managed and called. Because pointers are simply pointers into raw
memory, function pointers can be unsafe. .NET offers a type-safe version of function pointers called
delegates. Delegates provide the same flexibility as function pointers but in a type-safe manner.

Delegates are frequently used as callbacks, in which a function is called upon something happening. The
Event model promotes an effective paradigm for callbacks, where there are publishers and subscribers.
Publishers expose something that happens—better known as an event. Subscribers subscribe to an event
with a delegate. The delegates of the subscriber are called when the event occurs.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Part III: More C# Language


Chapter List

Chapter 8: Delegates and Events

Chapter 9: Exception Handling


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 8: Delegates and Events


Overview
Function pointers are indirect references to functions and support calling functions through variables. With
function pointers, you can pass a function as a parameter to a function or as a return type. Function pointers
are an important ingredient of many programming languages, including C, C++, and Microsoft Visual Basic.
Function pointers can make applications more flexible, extensible, and scalable. Function pointers have
been the source of many application bugs, however, because function pointers point to raw bytes of memory.
Function pointers are not type-safe, and calling an incompatible method through a function pointer is an
infrequent error. .NET has delegates that are essentially type-safe function pointers. Unlike function pointers
in other languages, particularly C and C++, delegates are type-safe, object-oriented, and secure. This
reduces common problems associated with using function pointers.

A delegate is an abstraction of one or more function pointers. Delegates are derived from
System.MulticastDelegate, which is a reference type. System.MulticastDelegate is derived from
System.Delegate. The delegate classes offer a public interface for initializing, adding, removing, and invoking
delegates. An instance of a delegate is an object that abstracts the semantics of a function pointer. The
object encapsulates a function pointer and a target object. When a delegate is invoked, the delegate calls
the function on that object.

Delegates have a signature and a return type. A function pointer dropped into the delegate must have a
compatible signature, which makes the function pointer type-safe. The return type should also match.
Delegate covariance, which is discussed later in the chapter, provides some flexibility with the signature.
You assign function pointers to delegates based on signature, not type. Regardless of the object or type that
binds the function, it is assignable to a delegate of the same signature.

Functions called with a delegate are given the security context of the caller, which prevents a delegate from
performing a task not available to a lower-privilege caller. Delegates can be initialized with pointers to
functions that are implemented anywhere. The only limitation is the signature. Callers need to be careful
when invoking delegates containing function pointers to unknown sources, where there could be unexpected
implementation. Use code access security to protect delegates.

Delegates are useful as general function pointers, callbacks, events, and threads. As a general function
pointer, a delegate can be a method parameter, function return, class member, or local variable. Callbacks
are valuable in many scenarios, including promoting peer-to-peer relationships, in which objects swap
function pointers to send bilateral messages. Events support a publisher/subscriber model. The publisher
notifies subscribers of events, whereas the subscriber registers functions to be called when the event occurs.
Finally, a delegate is a path of execution for a thread, which is an asynchronous function call. This chapter
focuses on general function pointers, callbacks, and events. Threads are discussed only in this context.

Many .NET applications are event-driven. Event-driven architecture is common in the .NET environment with
Microsoft Windows Forms, ASP.NET, and XML Web Service applications. The lifetime of an event-driven
application is spent waiting for events to handle, such as a paint event for Windows Forms, a page load
event in an ASP.NET application, or a session event in an XML Web Service application. Although
procedural applications execute linearly, event-driven code runs disjointedly. The sequence of code in an
event-driven application is determined at run time from the user interface and other input sources. Poorly
designed or implemented procedural code is commonly referred to as spaghetti code. Poorly implemented
code for an event-driven application is called ravioli code and it can literally run in circles. The randomness of
an event-driven application makes poorly written code harder to maintain and debug.

Events are the most practical application of delegates. Events mark an occurrence as defined by an
application. For proper application design, events in an application should mirror events in the problem
domain. Events represent a wide variety of actions and include predefined and custom events. Predefined
events include button click, page load, timer, unhandled exception, and so on. Custom events include events
for monitoring hardware devices, starting and stopping communications, overdrawing a checking account,
setting alarms, and so on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The event model includes subscribers and publishers: A publisher is an object or type that exposes an
event; a subscriber registers for an event with a delegate. The delegate contains the response to the event.
When an event is raised, publishers invoke the delegates of any subscribers. The Observer pattern, which
includes the event patterns, documents the best practices of an event-driven environment. Use the following
link to view the Observer pattern on the Microsoft Developer Network (MSDN):
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/observerpattern.asp.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Delegates
The common blueprint for using delegates includes steps to define, create, and invoke a delegate.
1. Define a classification of a delegate using the delegate keyword:
2.
3. public delegate int DelegateClass(string info);
4.
5. Create an instance of a delegate using the new keyword. In the constructor, initialize the delegate
with a function pointer. You can also create and initialize a delegate implicitly without the new
keyword:
6.
7. DelegateClass obj=new DelegateClass(MethodA);
8. DelegateClass obj2=MethodA; // implicit
9. Invoke the delegate with the call operator "()". The call operator is convenient, but makes it harder
to discern a delegate invocation from a regular function call. Alternatively, invoke the delegate with
the Invoke method, which clearly distinguishes invoking a delegate from a normal function call:
10.
11. obj("1");
12. obj.Invoke("2"); // Alternative.
13. As with any object, when the delegate is no longer needed, set the delegate to null:
14.
15. obj=null;

The complete list of the example application follows:

using System;

namespace Donis.CSharpBook{

public delegate int DelegateClass(string info);

public class Steps{

public static void Main(){


DelegateClass obj=new DelegateClass(MethodA);
DelegateClass obj2=MethodA; // implicit
obj("1");
obj.Invoke("2"); // Alternative
obj=null;
obj2=null;
}

public static int MethodA(string info) {


Console.WriteLine("Steps.MethodA");
return int.Parse(info);
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

Define a Delegate

The delegate keyword is for defining new delegates. The delegate statement looks like a function signature.
Rather, it defines a new delegate type. Function pointers matching the delegate signature and return type
can be stored into the delegate. Therefore, only functions with similar signatures can be called through the
delegate. This code defines a new delegate, which internally becomes a class named DelegateClass:

public delegate int DelegateClass(string info);

This is the syntax for defining a new delegate class:


 accessibility delegate return delegatename(parameterslist)

Accessibility is limited to the valid accessibility of classes, such as public or private. The remainder of the
syntax defines the signature and return type of the delegate. delegatename is the name of the delegate
classification.

Because defining a delegate creates a new class, delegates can be defined anywhere a class is appropriate.
A delegate can be defined in a namespace as a namespace member and within a class as a nested class,
but not as a class field or a local variable within a method.

Create a Delegate

As a class, use the new keyword to create an instance of a delegate. As mentioned, delegates are derived
from the System.MulticastDelegate reference type. Multicast delegates are repositories of zero or more
function pointers. The list of pointers in a multicast delegate is called the invocation list. When a delegate
hosts multiple function pointers, the functions are called on a first-in, first-out (FIFO) basis.

The delegate constructor is not overloaded and has a single parameter, which is the target method. For an
instance method, use the object.method format. If static, use the class.method format. If the method and
delegate are contained in the same class, neither the object nor class name is required. The following code
initializes a delegate in a variety of ways:

using System;

namespace Donis.CSharpBook{

public delegate void DelegateClass();

public class Constructors{

public static void Main(){


DelegateClass del1=new
DelegateClass(Constructors.MethodA);
DelegateClass del2=new DelegateClass(MethodA);

ZClass obj=new ZClass();


DelegateClass del3=new DelegateClass(obj.MethodB);
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static void MethodA() {


}
}

public class ZClass {

public void MethodB() {


}
}
}

You can assign a function pointer directly to a delegate and omit the new operator, which is called delegate
inference. Delegate inference infers a delegate signature from the function pointer, creates a new delegate,
initializes the source delegate with the function pointer in the constructor, and assigns the source delegate
to the target delegate. The source delegate and the target delegate should have compatible signatures.
Although the code is more concise, the intent is not as obvious. Here is the previous code, changed for
delegate inference:

DelegateClass del1=Constructors.MethodA;
DelegateClass del2=MethodA;

ZClass obj=new ZClass();


DelegateClass del3=obj.MethodB;

The signatures of delegates are not entirely rigid. Through contravariance and covariance, there is some
flexibility. The signature of the function pointer does not have to match the delegate signature exactly.

Contravariance and Covariance


When are delegates compatible or similar? The parameters of the function pointer can be derivations of the
parameters indicated in the delegate signature—this is called contravariance. Because the delegate
parameters refine that of the function pointer, any input from the target method is acceptable to the delegate.
Conversely, the return type of the delegate must be a derivation of the return type of the function pointer. The
return of the function pointer can refine the return of the delegate. Therefore, any return from the delegate is
compatible with that of the function pointer—this is called covariance. Contravariance and covariance expand
the set of methods assignable to a delegate while maintaining type-safeness. Here is an example of both
contravariance and covariance:

using System;

namespace Donis.CSharpBook{
delegate ZClass DelegateClass(BClass obj);
public class Starter{
public static void Main(){
DelegateClass del=MethodA;
}

public static YClass MethodA(AClass obj) {


return null;
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class ZClass {


}

public class YClass: ZClass {


}

public class AClass {


}

public class BClass: AClass {


}
}

In the preceding code, this is the signature of the delegate:

delegate ZClass DelegateClass(BClass obj);

This is the signature of the function pointer:

public static YClass MethodA(AClass obj)

The signature of the delegate and function pointer are not exactly the same. This is okay because the
parameter of the delegate (BClass) refines the parameter of the function (AClass), which is contravariance. In
addition, the return type of the function (YClass) refines the return type of the delegate (ZClass). This is
covariance.

Invoking a Delegate

Delegates are invoked through the call operator or the Invoke method. The C# compiler translates the call
operator into an invocation of the Invoke method, which has the same signature as the delegate and calls
the function pointers contained in the delegate. The parameters of the delegate become the parameters and
input to the function calls. If the delegate contains a function pointer, the return from that function becomes
the return of the delegate. When multiple function pointers are stored in the delegate, the return of the last
function becomes the return of the delegate.

Arrays of Delegates

Arrays of delegates can be the impetus of elegant solutions that would otherwise be unavailable. Creating an
array of delegates is the same as creating an array of any type. Selecting from a set of tasks at run time is
an example of when an array of delegates is essential to an elegant solution. The switch statement is one
solution, in which each case of the switch statement is assigned to a task. Suppose that there are about
three lines of code associated with each task. In the next revision of the application, 30 additional tasks are
added, which results in an additional 90 lines of code. This solution provides linear growth and is not
particularly scalable. With an array of delegates, regardless of the number of tasks, the solution is one line
of code. Now and in the future, this solution remains one line of code. This solution is more scalable than the
switch statement approach. In the following code, an array of delegates facilitates invoking a task from a
menu of choices:

using System;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

namespace Donis.CSharpBook{

public delegate void Task();

public class Starter{

public static void Main(){


// array of delegates
Task [] tasks={MethodA, MethodB, MethodC};
string resp;
do {
Console.WriteLine("TaskA - 1");
Console.WriteLine("TaskB - 2");
Console.WriteLine("TaskC - 3");
Console.WriteLine("Exit - x");
resp=Console.ReadLine();
if(resp.ToUpper()=="X") {
break;
}
try {
int choice=int.Parse(resp)-1;
// as promised, one line of code to invoke
// the correct method.
tasks[choice]();
}
catch {
Console.WriteLine("Invalid choice");
}
} while(true);
}

public static void MethodA() {


Console.WriteLine("Doing TaskA");
}

public static void MethodB() {


Console.WriteLine("Doing TaskB");
}

public static void MethodC() {


Console.WriteLine("Doing TaskC");
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

System.MulticastDelegate Class
Delegates default to multicast delegates, which inherit from the System.MulticastDelegate class. A multicast
delegate is similar to a basket. Multiple function pointers or delegates can be dropped into the basket. The
list of delegates is stored in an invocation list, which can even include multiple instances of the same
delegate. When you execute the contents of the basket, the function pointers of the delegates are called
FIFO. Multicast delegates are useful for invoking a chain of functions.

Combining delegates Multiple delegates are combined using the Combine method, the plus operator (+),
or the += assignment operator. Combine is a static method. In C#, the Combine method is called with two
delegate parameters or an array of delegates. The method returns a reference to the combined delegate.

The following code combines two delegates separately wrapping functions MethodA and MethodB. When the
Combine delegate is invoked, MethodA is run first and MethodB second. This is the order in which the
function pointers are added to the multicast delegate. Both the Combine method and the += assignment
operators are shown, with the Combine statement commented to avoid duplication.

using System;

namespace Donis.CSharpBook{
public delegate void DelegateClass();
public class Starter{
public static void Main(){
DelegateClass del=MethodA;
del+=MethodB;
// del=(DelegateClass) DelegateClass.Combine(
// new DelegateClass [] {MethodA, MethodB});
del();
}
public static void MethodA() {
Console.WriteLine("MethodA...");
}

public static void MethodB() {


Console.WriteLine("MethodB...");
}
}
}

Removing delegates To remove delegates from a multicast delegate, use the Remove method, the minus
operator (-), or the -= assignment operator. Remove is a static method that accepts the source delegate as
the first parameter and the delegate to remove as the second parameter. Be careful not to inadvertently
remove all delegates from a multicast delegate, which causes a run-time error when invoked. The following
code removes MethodB from a multicast delegate. When the delegate is invoked, MethodA is invoked, but
not MethodB. The three methodologies are shown, with the Combine statement and operator minus
commented to avoid duplication.

using System;

namespace Donis.CSharpBook{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public delegate void DelegateClass();

public class Starter{


public static void Main(){
DelegateClass del=MethodA;
del+=MethodB;
del+=MethodC;
del=del-MethodB;

// del=(DelegateClass) DelegateClass.Remove(del,
(DelegateClass) MethodB);
// del-=MethodB;
del();
}
public static void MethodA() {
Console.WriteLine("MethodA...");
}

public static void MethodB() {


Console.WriteLine("MethodB...");
}

public static void MethodC() {


Console.WriteLine("MethodC...");
}
}
}

Invocation List
Multicast delegates maintain an invocation list, which has an entry for each delegate of the multicast
delegate. Entries are added to the invocation list in the same order in which delegates are added.
GetInvocationList returns the invocation list as an array of delegates.

This is the syntax of the GetInvocationList method:


 delegate [] GetInvocationList()

This code retrieves the list of delegates in a multicast delegate, in which each delegate is a wrapper of a
function. The name of each function is displayed. The Delegate.Method property returns a MethodInfo type,
which encapsulates the function abstracted by the delegate.

using System;

namespace Donis.CSharpBook{
public delegate void DelegateClass();
public class Starter{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static void Main(){


DelegateClass del=(DelegateClass)
DelegateClass.Combine(new DelegateClass []
{ MethodA, MethodB, MethodA, MethodB } );
del();
foreach(DelegateClass item in
del.GetInvocationList()) {
Console.WriteLine(item.Method.Name+
" in invocation list.");
}

}
public static void MethodA() {
Console.WriteLine("MethodA...");
}

public static void MethodB() {


Console.WriteLine("MethodB...");
}
}
}

The delegate signature can contain reference parameters. When invoked, the reference is passed to the
called functions. Reference parameters are a way for functions on an invocation list to share state. Value
parameters are not shareable across the functions. Because the invocation list is called in sequence,
beginning with the first delegate and function, each successive entry in the chain can view changes in the
reference parameter. The next item in the chain can view those changes and possibly change the state
again. In this way, when the multicast delegate is invoked, the state information is propagated along the
invocation list. Furthermore, functions in invocation lists that have the same target object or class share the
state of the object or class. The following code uses the reference parameter of a multicast delegate as a
counter. The delegate has a value and reference parameter. The value parameter is lost between function
calls in the invocation list. However, the reference parameter persists.

using System;

namespace Donis.CSharpBook{

public delegate void DelegateClass(int valCount,


ref int refCount);

public class Counter{


public static void Main(){
DelegateClass del=(DelegateClass) AddOne+
(DelegateClass) AddTwo+ (DelegateClass) AddOne;
int valCount=0;
int refCount=0;
del(valCount, ref refCount);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("Value count = {0}",


valCount); // 0
Console.WriteLine("Reference count = {0}",
refCount); // 4
}

public static void AddOne(int valCount,


ref int refCount){
++valCount;
++refCount;
}

public static void AddTwo(int valCount,


ref int refCount) {

valCount+=2;
refCount+=2;
}
}
}

You can access the invocation list to execute each delegate and function therein directly. There are two
reasons to invoke the invocation list directly. First, invoke the delegates explicitly to obtain the return of each
delegate. When the invocation list is invoked implicitly, only the return of the last function is garnered.
Second, invoke the invocation list directly in special circumstances (for example, to modify how exceptions
are handled in a multicast delegate, which is described later).

The following code uses the invocation list to calculate a factorial. The Incrementer method increments a
number, which is a reference parameter. The incremented value is returned from the method. Five delegates
are created and initialized with the Increment method and combined into a multicast delegate. The foreach
loop iterates the invocation list, multiplying the results of each function to calculate a factorial.

using System;

namespace Donis.CSharpBook{

public delegate int IncrementDelegate(


ref short refCount);

public class Factorial{


public static void Main(){

IncrementDelegate [] values=
{ Incrementer, Incrementer,
Incrementer, Incrementer,
Incrementer};
IncrementDelegate del=(IncrementDelegate)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

IncrementDelegate.Combine(
values);
long result=1;
short count=1;
foreach(IncrementDelegate number
in del.GetInvocationList()) {
result=result*number(ref count);
}
Console.WriteLine("{0} factorial is {1}",
del.GetInvocationList().Length,
result);
}

public static int Incrementer(


ref short refCount){
return refCount++;
}

}
}

Methods and properties Several members of delegate object, such as GetInvocationList, have already
been introduced. Table 8-1 is a list of some of the public properties and methods of the MulticastDelegate
type. Some of the members are inherited from System.Delegate.
Table 8-1:
Delegate
Members

Me De
mb scr
er ipti
on

Be Inv
gin ok
Inv es
ok a
e del
eg
ate
as
yn
chr
on
ou
sly
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-1:
Delegate
Members

Me De
mb scr
er ipti
on

Co Co
mb mb
ine ine
s
del
eg
ate
s
int
o
a
mu
ltic
ast
del
eg
ate
.
Thi
s
is
a
sta
tic
me
tho
d.

Cre Def
ate ine
Del s
eg a
ate del
eg
ate
at
run
tim
e.
Thi
s
is
a
sta
tic
me
tho
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-1:
Delegate
Members

Me De
mb scr
er ipti
on

Dy Dy
na na
mi mi
cIn call
vo y
ke inv
ok
es
a
del
eg
ate
tha
t
wa
s
cre
ate
d
at
run
tim
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-1:
Delegate
Members

Me De
mb scr
er ipti
on

En Re
dIn qu
vo est
ke s
the
res
ult
s
of
a
del
eg
ate
tha
t
wa
s
ex
ec
ute
d
as
yn
chr
on
ou
sly
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-1:
Delegate
Members

Me De
mb scr
er ipti
on

Inv Ex
ok ec
e ute
s
a
del
eg
ate
,
whi
ch
call
s
all
fun
cti
on
s
co
nta
ine
d
in
the
del
eg
ate
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-1:
Delegate
Members

Me De
mb scr
er ipti
on

Me Thi
tho s
d is
a
pro
per
ty
tha
t
ret
urn
s
the
Me
tho
dIn
fo
typ
e
of
the
las
t
fun
cti
on
in
the
inv
oc
ati
on
list
.
Me
tho
dIn
fo
pro
vid
es
a
de
scr
ipti
on
of
a
fun
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-1:
Delegate
Members

Me De
mb scr
er ipti
on

Re Re
mo mo
ve ves
a
del
eg
ate
fro
m
a
mu
ltic
ast
del
eg
ate
.
Thi
s
is
a
sta
tic
me
tho
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-1:
Delegate
Members

Me De
mb scr
er ipti
on

Re Re
mo mo
ve ves
All the
inv
oc
ati
on
list
of
a
del
eg
ate
fro
m
the
inv
oc
ati
on
list
of
an
oth
er
del
eg
ate
.
Th
e
res
ult
is
ret
urn
ed.
Thi
s
is
a
sta
tic
me
tho
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-1:
Delegate
Members

Me De
mb scr
er ipti
on

Tar Thi
get s
is
a
pro
per
ty
tha
t
ret
urn
s
the
ins
tan
ce
of
the
las
t
fun
cti
on
in
the
inv
oc
ati
on
list
.
For
sta
tic
fun
cti
on
s,
Tar
get
is
null
.

Generics and Delegates


A delegate can contain closed generic methods, whereas open generic methods cannot be added to a
delegate. Some permutation of the generic method must be compatible with the signature of the delegate.
Otherwise, the generic cannot be added to the invocation list. If the generic method contains actual
parameters, the type is inferred. However, the return type cannot be inferred and must be specified.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

In addition, the delegate itself can be generic and closed when the delegate is created. Functions added to a
generic delegate need to match the signature of the closed generic delegate.

This is an example of a normal delegate initialized with a generic method:

using System;

namespace Donis.CSharpBook{
public delegate void DelegateClass(int data);
public class Starter{
public static void Main(){
DelegateClass del1=MethodA<int>;
del1(5);
DelegateClass del2=MethodA;
del1(10); // inferred
}

public static void MethodA <T>(T data) {


Console.WriteLine("MethodA ({0})", data);
}
}
}

This is an example of a generic delegate being initialized with a normal method:

using System;

namespace Donis.CSharpBook{
public delegate void DelegateClass<T>(T data);
public class Starter{
public static void Main(){
DelegateClass <string> del=MethodA;
del("data");
}

public static void MethodA(string data) {


Console.WriteLine("MethodA ({0})", data);
}
}
}

Asynchronous Invocation

Delegates are invoked synchronously via the Invoke method or call operator. Delegates can also be invoked
asynchronously on a separate worker thread. A delegate performing a time-consuming task might improve
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

application performance by running on a separate thread. This is especially true for Windows Forms
applications, in which responsiveness of the user interface is a concern. The user interface could freeze for
an extended period time while a synchronous delegate is performing an extended task. Other types of
operations benefit from asynchronous delegates: network services, methods dependent on hardware devices,
timed routines, and more. Synchronous solutions are simpler. However, this often falls short of the
sophistication required for a professional application. Developers must be concerned with thread
synchronization in asynchronous executions, which undoubtedly adds complexity. There is much more to
writing robust multithread applications then simply spawning threads.

When a delegate is defined, the C# compiler adds several methods for invoking function pointers. The Invoke
method is for synchronous invocation, while the BeginInvoke and EndInvoke methods are included for
asynchronous invocation. The default for the call operator is synchronous execution.

BeginInvoke Method
BeginInvoke is callable on single-cast delegates alone. A single-cast delegate is a multicast delegate that
contains a single function pointer. BeginInvoke adds the operation to a queue, where it is then serviced by a
separate thread from a Common Language Runtime (CLR) managed thread pool. Therefore, functions on the
invocation list run on a different thread from the caller of the delegate. The thread pool for asynchronous
execution has a maximum of 25 threads per processor.

This is the syntax of the BeginInvoke method:


 IAsyncResult BeginInvoke(arguments, AsyncCallback callback, object AsynState)

BeginInvoke begins with the parameters of the delegate signature. If the delegate signature names four
arguments, those are the first four parameters of BeginInvoke. The next parameter is the completion routine.
This routine is called back when the asynchronous call has completed. The final parameter is a state object.
The completion routine and state objects are optional and either can be set to null. The return is an
IAsyncResult object, which maintains the state of the object. IAsyncResult has four properties, which are
listed in Table 8-2.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-2:
IAsyncResult
Properties

Pr De
op scr
ert ipti
y on

As Th
ync e
Sta sta
te te
obj
ect
tha
t
ha
s
info
rm
ati
on
on
the
as
yn
chr
on
ou
s
op
era
tio
n.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-2:
IAsyncResult
Properties

Pr De
op scr
ert ipti
y on

As Us
ync e
Wa the
itH Wa
an itH
dle an
dle
to
blo
ck
unt
il
the
as
yn
chr
on
ou
s
op
era
tio
n
is
co
mp
let
ed.

Co Indi
mp cat
let es
eS tha
ync t
hro the
no op
usl era
y tio
n
co
mp
let
ed
sy
nc
hro
no
usl
y.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 8-2:
IAsyncResult
Properties

Pr De
op scr
ert ipti
y on

IsC Indi
om cat
ple es
ted tha
t
the
as
yn
chr
on
ou
s
op
era
tio
n
ha
s
co
mp
let
ed.

The following code highlights the IAsyncResult and delegate state object:

using System;
using System.Threading;

namespace Donis.CSharpBook{
public delegate void DelegateClass();

public class Starter{

public static void Main(){


DelegateClass del=MethodA;
DelegateStateBag state=new DelegateStateBag();
IAsyncResult ar=del.BeginInvoke(Callback, state);
if(ar.IsCompleted==true) {
Console.WriteLine("MethodA completed");
}
else {
Console.WriteLine("MethodA not completed");
}
ar.AsyncWaitHandle.WaitOne();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

// doing something else

Thread.Sleep(100);
lock(state) {

Console.WriteLine("Back in Main");
Console.WriteLine(state.message);
}
}

public static void Callback(IAsyncResult ar) {


DelegateStateBag state=
(DelegateStateBag) ar.AsyncState;
lock(state) {
Console.WriteLine("Callback running");
((DelegateStateBag) ar.AsyncState).message=
"State object modified in callback.";
}
}

public static void MethodA() {


Console.WriteLine("MethodA running...");
Thread.Sleep(200);
}
}

class DelegateStateBag {
public string message;
}
}

This is the result of the application:

MethodA not completed


MethodA running...
Callback running
Back in Main
State object modified in callback.

Interestingly, the not completed message is received before MethodA has even started. This confirms that
BeginInvoke does not directly invoke the function in the delegate. Rather, it adds a request to the thread
pool queue, which is eventually handled. There is a Thread .Sleep statement near the end of the Main
method. If removed, a race condition would exist between Main and the completion routine called Callback.
What is the source of the race condition? Note the WaitHandle.WaitOne command in Main, which blocks
Main until the asynchronous operation is complete. As the completion routine, Callback also waits for the
asynchronous operation to finish. When the asynchronous operation finishes, the Main and Callback
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

routines both resume, and the race begins. Callback needs to update the state object before Main displays
the contents of the state object. The Thread.Sleep statement is a primitive way of removing the race
condition and allowing the Callback routine to lock the shared state object first.

EndInvoke Method
EndInvoke provides that the result of an asynchronous operation is callable in the completion routine or the
thread of the delegate caller. EndInvoke has the same signature as the delegate without the value
parameters and has an additional final parameter, which is an IAsyncResult object. To obtain the signature
of the EndInvoke method, remove the value parameters from the delegate signature and add an IAsyncResult
parameter. The IAsyncResult parameter is the same IAsyncResult object that is returned from BeginInvoke.
The return type of EndInvoke is identical to the return of the delegate.

This is the syntax of the EndInvoke method:


 returntype EndInvoke(ref_out_arguments, IAsyncResult ar)

Calling EndInvoke before functions of the asynchronous delegate has finished executing blocks the caller
until the operation is completed. For each BeginInvoke, there should be a complementing EndInvoke to
confirm the results of the operation, detect an exception, and to allow the CLR to properly clean up the
delegate. Calling the EndInvoke method more than once on the same delegate yields undefined results and
should be avoided.

Here is sample code for the EndInvoke method:

using System;
using System.Threading;

namespace Donis.CSharpBook{
public delegate int DelegateClass(out DateTime start,
out DateTime stop);

public class Starter{

public static void Main(){


DelegateClass del=MethodA;
DateTime start;
DateTime stop;
IAsyncResult ar=del.BeginInvoke(out start, out stop,
null, null);

ar.AsyncWaitHandle.WaitOne();

// doing something else

int elapse=del.EndInvoke(out start, out stop, ar);


Console.WriteLine("Start time: {0}",
start.ToLongTimeString());
Console.WriteLine("Stop time: {0}",
stop.ToLongTimeString());
Console.WriteLine("Elapse time: {0} seconds",
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

elapse);
}

public static int MethodA(out DateTime start,


out DateTime stop) {
start=DateTime.Now;
Thread.Sleep(5000);

stop=DateTime.Now;
return (stop-start).Seconds;
}
}
}

Asynchronous Delegate Diagram

The preceding text explains how to invoke a delegate asynchronously and to obtain the results. Figure 8-1
diagrams the relationship and sequence of operations. This includes the delegate, the BeginInvoke method,
the EndInvoke method, and the delegate completion routine.

Figure 8-1: Asynchronous processing of a delegate

Delegate Internals
Delegates may appear to be magical to developers because so much is hidden. The magician is the C#
compiler. This section explains the magic of the compiler. Why should you care? Understanding how
delegate are implemented internally should help in the how, where, and when to use delegates.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The C# compiler builds a class from the definition of a delegate. The class shares the name of the delegate
and has four methods: a constructor, Invoke, BeginInvoke, and EndInvoke. Importantly, the delegate class
is derived from System.MulticastDelegate. This is a typical definition of a delegate:

public delegate int ADelegate(int arg1, ref int arg2);

As viewed in ildasm, C# creates the ADelegate class from this delegate. (See Figure 8-2.)

Figure 8-2: C# manifested delegate class

Members of the delegate class, such as Invoke and BeginInvoke, were described earlier in this chapter.
However, it is comforting to actually see them. It is not magic after all. There may be a slight surprise: The
constructor of the delegate has two arguments. The code in this chapter shows the delegate constructor
being called with a single parameter. The C# compiler helps us here: It interprets the single parameter as a
target object and function pointer, which are the parameters of the two argument constructors. Also notice
that the signatures of Invoke, BeginInvoke, and EndInvoke were defined as described earlier in this chapter.

Exceptions

What happens if an unhandled exception is raised in a multicast delegate? If the delegate is invoked inside a
protected block of code, the exception is trapped. The invocation list is called until an exception occurs.
Functions later in the invocation list do not execute. Let us assume that the invocation list has pointers to
MethodA, MethodB, MethodC, and MethodD. They were also added to the delegate in that order. If an
unhandled exception is raised in MethodB, MethodC and MethodD are not called. The situation might appear
to be more complicated if the exception is raised in a delegate that is running asynchronously. In this
circumstance, the exception is raised on a different thread. However, the run time will route the exception
back to the calling thread, as evidenced in the following code. Therefore, the exception is handled as if the
delegate were called synchronously.

using System;
using System.Threading;

namespace Donis.CSharpBook{

public delegate void DelegateClass();

public class Starter{


public static void Main(){
Console.WriteLine("Running on primary thread");
try {
DelegateClass del=MethodA;
IAsyncResult ar=del.BeginInvoke(null, null);
del.EndInvoke(ar);
}
catch(Exception except){
Console.WriteLine("Running on primary thread");
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("Exception caught: "


+except.Message);
}
}

public static void MethodA() {


if(Thread.CurrentThread.IsThreadPoolThread==true) {
Console.WriteLine(
"Running on a thread pool thread");
}
else {
Console.WriteLine("Running on primary thread");
}
throw new Exception("failure");
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Anonymous Methods
An anonymous method is a nameless method. Sometimes a function is intended exclusively for a delegate.
Without an anonymous method, you would have to define a separate function as part of a class. The function
can then be assigned to the delegate. Assigning an anonymous method prevents creating a separate
method. This is cleaner and more convenient than a named method. Anonymous methods can substitute for
delegates as parameters, return values, and in other situations.

Define an anonymous method with the delegate keyword. This code assigns an anonymous method to a
delegate:

using System;
using System.Threading;

namespace Donis.CSharpBook{

public delegate void DelegateClass();

public class Starter{


public static void Main(){
DelegateClass del= delegate {
Console.WriteLine("Running anonymous method");
};
del();
}
}
}

In the preceding example, the anonymous method does not have a signature. The signature of the
anonymous method is inferred from the delegate signature, which is another example of delegate inference.
Despite not having a signature, the return of the anonymous method must match the delegate return. The
advantage of an anonymous method without a signature is its compliance with almost any delegate. The
disadvantage is that anonymous methods defined without a signature cannot access the parameters of the
delegates. This means that the anonymous method cannot utilize the parameters. For this reason,
anonymous methods without a signature cannot be employed where delegates have out parameters. Out
parameters must be initialized in the called method, which is impossible in an anonymous method. When an
anonymous method is called through the delegates, the parameters must still be provided, even if ignored
inside the method. Of course, if the delegate has no parameters, none should be provided.

This is the syntax of an anonymous method:


 delegate optional_signature {anonymous method expression}

The C# compiler performs several tasks to assign an anonymous method without a signature to a delegate:
1. Validates the signature of the delegate—no out parameters
2. Infers the signature of the anonymous method from the delegate
3. Confirms that the return type of the delegate is compatible with the anonymous method
4. Creates a new delegate that is initialized with a function pointer to the anonymous method

Anonymous methods can be assigned a signature, which is appended to the delegate keyword. This
restricts the anonymous method to a delegate with a matching signature and return type. Like conventional
methods, the parameters are initialized with the parameters from the delegate call. This is an example of an
anonymous method with a signature:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System;
using System.Threading;

namespace Donis.CSharpBook{

public delegate int DelegateClass(out int param);

public class Starter{


public static void Main(){
int var;
DelegateClass del= delegate(out int inner) {
inner=12;
Console.WriteLine("Running anonymous method");
return inner;
};
del(out var);
Console.WriteLine("Var is {0}", var);
}
}
}

As demonstrated in the preceding code, anonymous methods can be used for delegates. The exception is
the -= assignment operator. Because the anonymous method is unnamed, it cannot be used to remove a
named method from a multicast delegate. This is the exception to freely substituting delegates with
anonymous methods.

Actually, anonymous methods are not nameless. The C# compiler implements the anonymous method as
the named method in the containing class. The generated method is both static and private. The wrapper
delegate is initialized with this method. The following format is used to name anonymous methods:
 <functionname>uniqueid

The function name is the function in which the anonymous method is implemented. The unique identifier is a
combination of a letter and number. The method has the same signature as the target delegate.

The wrapper delegate initialized with the anonymous method is also added to the class as a static and
private field. This is the format of the wrapper delegate. The identifier is a compiler-generated number,
whereas # is a character added to the name of the wrapper delegate.

<>id__CachedAnonymousMethodDelegate#

The following code offers two delegates and anonymous methods:

using System;

namespace Donis.CSharpBook{

public delegate void ADelegate(int param);


public delegate int BDelegate(int param1, int param2);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class Starter{


public static void Main(){
ADelegate del= delegate(int param) {
param=5;
};
}

public int MethodA() {


BDelegate del= delegate(int param1, int param2) {
return 0;
};
return 0;
}
}
}

Figure 8-3 is a disassembly of this application program. It shows the wrapper delegates and anonymous
methods.

Figure 8-3: Disassembly showing wrapper delegates and anonymous methods

Outer Variables

Anonymous methods can refer to local variables of the containing function and class members within the
scope of the method definition. Local variables used in an anonymous method are called outer variables.

The scope of a local variable is closely linked to the method in which the local is declared. When the method
ends, local variables are removed from memory. Local variables used in an anonymous method are captured,
which extends the lifetime of the variable. The lifetime of a captured or outer variable is of the same as that of
the delegate. The outer variable is removed when the delegate is garbage-collected. In the following code, the
local variable of MethodA is captured in the anonymous method. The lifetime of the local variable would
usually end when MethodA is exited. However, the delegate is garbage-collected until the end of the
program, which extends the lifetime of the local variable for the entire program.

using System;

namespace Donis.CSharpBook{
public delegate void DelegateClass(out int arg);

public class Starter{

public static void Main(){

DelegateClass del=MethodA();
int var;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

del(out var);

Console.WriteLine(var);
}

public static DelegateClass MethodA() {


int local=0;
return delegate(out int arg) {
arg=++local;
};
}
}
}

Because the lifetime of outer variables is aligned with the delegate, it remains persistent across invocations
of the anonymous method. In the following code, the anonymous method is invoked thrice through the
delegate. As a local variable, local would be initialized on each call to the method. However, as an outer
variable, it is initialized once in MethodA and maintains its value across multiple calls to the anonymous
method. Therefore, the value displayed is 3.

using System;

namespace Donis.CSharpBook{

public delegate void DelegateClass(out int var);

public class Starter{

public static void Main(){

DelegateClass del=MethodA();
int var;
del(out var);
del(out var);
del(out var);
Console.WriteLine(var);
}

public static DelegateClass MethodA() {


int increment=0;
return delegate(out int var) {
var=++increment;
};
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The C# compiler creates a private nested class for anonymous methods that capture local variables,
whereas anonymous methods that contain no outer variables are implemented as private static methods.
The nested class has a public field for each outer variable used in the anonymous method. The local variable
is persisted to this public field. It also contains a named method for the anonymous method. The named
method has the same signature as the related delegate. This is the method used to initialize the wrapper
delegate. Figure 8-4 illustrates the nested class created for an anonymous method.

Figure 8-4: Disassembly of nested class for an anonymous method that uses outer variables

Locals are fixed variables and are not normally available to garbage collection. Local variables are removed
from memory when the applicable method is exited. When a local variable is captured, it becomes a movable
variable. Movable variables are placed on the managed heap. As such, outer variables then become available
for garbage collection. For this reason, captured variables must be pinned or otherwise fixed before being
used with unsafe code.

Generic Anonymous Methods

Anonymous methods can use generic parameters of the class or delegate. However, anonymous methods
cannot define new generic parameters and constraints. Here are two examples of anonymous methods using
generic parameters:

public delegate void ADelegate<T>(T tvalue);

public class ZClass{


public void MethodA() {
ADelegate<int> del=delegate(int var) {
};
}
}

public class YClass<T>{


public delegate void BDelegate(T tValue);
public void MethodA() {
BDelegate del=delegate(T tValue) {
};
}
}

Limitations of Anonymous Methods

Although anonymous methods are similar to other methods, they also have some limitations (some have
already been mentioned):
 Do not attempt to jump out of an anonymous method.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 Do not use a ref or out outer variable in an anonymous method.


 Do not define new generic parameters or constraints.
 Do not apply attributes to anonymous methods.
 Do not use anonymous method with -= assignment operator.
 Cannot be a member method.
 Cannot be an unsafe method.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Events
An event is an occurrence that an object or class wants to notify someone else about. (The someone else is
either another object or class.) A button notifies a form object that someone clicked on the button. A timer
notifies some other object that a time period has elapsed. An application domain notifies an application of an
unhandled event. A Web application notifies an object of an application event. You can create custom
events, such as a device notifying a monitoring application that data transmission has started or stopped.
This list of events is somewhat eclectic, which underscores that there is no strict definition. Events are
literally anything worth notifying someone else about. Public events are exposed as public members of a
publisher class, such as a button class. You can also have private and protected events that are used within
the realm of the containing or derived class.

Any object or class interested in an event can subscribe. Subscribers register for an event by submitting a
delegate. The delegate must be single cast and contain a single function pointer. That function is the
subscriber's response to the event. When the event is raised, the publisher calls the function, affording the
subscriber an opportunity to respond to the event. For this reason, the function is called an event handler.
Events can have multiple subscribers. A device could publish a power-off event in which multiple applications
might want to be notified and respond.

What happens when there are no subscribers to a particular event? In other words, if a tree falls in the woods
and no one hears it, does it make a sound? If the tree is an event, no sound is made. Events that have no
subscribers are not raised.

Publishing an Event

Both classes and objects can publish events. Static events are published at classes, whereas objects
publish instance events. Multicast delegates underlie events. You must create a delegate for the event or
leverage a predefined event. Events are defined with the event keyword. This is the syntax for defining an
event:
 accessibility event delegatename eventname

Events are defined as a field in a class. The accessibility of an event is typically public or protected.
Protected events restrict subscribers to child objects. A public event is available to every interested
subscriber. Delegate name is the underlying delegate of the event, which defines the signature of the event.
Event name is the identity of the event.

public delegate void DelegateClass();


public event DelegateClass MyEvent;

As a best practice, event handlers should return void and have two arguments. EventHandler is a predefined
delegate created for this purpose. It is included in the .NET Framework class library (FCL) and prevents you
from having to declare a separate delegate for the standard event type. The first parameter is the object that
raised the event. The second parameter is an EventArgs derived instance, which offers optional data that
further explains the event.

Internally, events declared in a class become a field of that class. Delegates used to define the event, which
is a multicast delegate, are types used for the field. The C# compiler also inserts methods to add and
remove subscribers to the event. The names of the methods are add_EventName and remove_EventName,
respectively. The fourth member added to the class is the event itself. See Figure 8-5 for a disassembly of an
event class.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 8-5: Disassembly of the event class

Subscribe

The publisher/subscriber relationship is a one-to-many relationship. For each publisher there can be zero or
more subscribers. Conversely, a subscriber can subscribe to multiple events. For example, a form can
subscribe to a button click and a text change event. Subscribers add a delegate to an event to register for
the event. The delegate is a wrapper for the function to be called when the event is raised. Subscribe to an
event using the add method or the += assignment operator:

using System;

namespace Donis.CSharpBook{
class Publisher {
public event EventHandler MyEvent;
}

public class Subscriber{

public static void Handler(object obj, EventArgs args) {


}

public static void Main(){


Publisher pub=new Publisher();
pub.MyEvent+=Handler;
// other processing
}
}
}

Cancel a subscription to a delegate with the -= assignment operator.

Raising an Event

At the discretion of a publisher, an event is raised and the methods of the subscribers are called back. Raise
an event with the call operator "()". Adding the call operator to the event raises the event. Because a
delegate underlies an event, the Invoke method inherited from a multicast delegate is another means to
raising an event. The signature of both the call operator and the Invoke method match the delegate of the
event. Any parameters are passed to the called methods of the subscribers. If an event returns a value as
defined by the event delegate, the function of the last subscriber sets the return. Do not raise an event for
events without subscribers. Events with no subscribers are null, which can be tested. An application that
raises an event that has no subscribers will incur an exception because of a null reference. This is the proper
way to raise an event:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void SomeMethod() {


if(anEvent!=null) {
anEvent(null, null);
}
}

EventArgs
Events sometime provide subscribers with custom information pertaining to the event. The mouse click event
provides the x and y coordinates of the mouse pointer in the MouseEventArgs class. The
DataRowChangeEventArgs class provides the affected row and action of several database-related events,
such as the RowChanged event. The PaintEventArgs class is instantiated in a paint event. It gives
developers the clip rectangle and graphics object for the paint event. Custom information about an event is
defined in an EventArgs derived class. MouseEventArgs, DataRowChangeEventArgs, PaintEventArgs, and
other related classes derive from the EventArgs class. These classes represent the state information for the
event.

The EventArgs derived class that contains the state information of the event is typically passed as the
second parameter of the event. State information can also be specified in the other parameters of events.

This is code for a bank account. The NSF event is raised when the account is overdrawn. The
BankEventArgs class provides the bank account balance and amount of the transaction that would overdraw
the account.

using System;

namespace Donis.CSharpBook{

public class Starter {


public static void Main(){
Bank account=new Bank();
account.NSF+=NSFHandler;
account.Deposit(500);
account.Withdrawal(750);
}

public static void NSFHandler(object o,


BankEventArgs e) {
Console.WriteLine("NSF Transaction");
Console.WriteLine("Balance: {0}", e.Balance);
Console.WriteLine("Transaction: {0}",
e.Transaction);
}

public delegate void OverDrawn(object o, BankEventArgs e);


public class Bank {
public event OverDrawn NSF; // non sufficient funds
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public decimal Deposit(decimal amountDeposit) {


propBalance+=amountDeposit;
return propBalance;
}

public decimal Withdrawal(decimal amountWithdrawn) {


decimal newBalance=propBalance-amountWithdrawn;
if(newBalance < 0) {
if(NSF != null) {
BankEventArgs args=new BankEventArgs(
Balance, amountWithdrawn);
NSF(this, args);
}
return propBalance;
}
return propBalance=newBalance;
}
private decimal propBalance=0;
public decimal Balance {
get {
return propBalance;
}
}

public class BankEventArgs: EventArgs {

public BankEventArgs(decimal amountBalance,


decimal amountTransaction) {
propBalance=amountBalance;
propTransaction=amountTransaction;
}

private decimal propBalance;


public decimal Balance {
get {
return propBalance;
}
}

private decimal propTransaction;


public decimal Transaction {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

get {
return propTransaction;
}
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Exception Handling
This chapter focused on delegates and events. In the next chapter we will cover the importance and benefits
of exception handling.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 9: Exception Handling


Overview
Exception handling is an important ingredient of a robust application and should be included in the
application design of every .NET program. Exception handling helps applications identify and respond to
exceptional events in a known and robust manner. This enhances the correctness of an application, which
naturally improves customer satisfaction. Unfortunately, exception handling is often an afterthought, which
leads to poorly implemented solutions for exception handling and a less robust application. Starting with
application design, exception handling should be included in all aspects of application planning and
development.

What is an exception? Exceptions are exceptional events or error conditions within an application and are
categorized as system or application exceptions. System exceptions are raised by the Common Language
Runtime (CLR) and include null reference, out of memory, divide by zero, and stack overflow exceptions.
Application exceptions, considered custom exceptions, are thrown by the application, not by the CLR. Some
exceptional events or error conditions are detectable by application logic, not by the runtime. Application
exceptions are useful in those circumstances. As an example, constructors that fail are not always
detectable by the CLR. In addition, constructors implicitly return void, which prevents returning an error code.
For these reasons, throwing an application exception in the failed constructor is the best solution.

Exceptions should be used only for exceptions. Exception handling is not a substitute for transfer of control
or a goto statement. Exceptions are expensive when compared with conventional transfer of control.
Whenever possible, applications should preempt exceptions and avoid the accompanying costs. Performing
data validation, where incorrect values can cause exceptions, is one measure that prevents exceptions. Data
validation and, if necessary, returning an error code is undoubtedly cheaper than raising an exception.

The overuse of exceptions makes code harder to read and maintain. Errors that frequently occur should not
be handled with exception handling, but with error codes or returns. Remember, exceptions should be
reserved for exceptional events.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Exception Example
A common exception is dividing by zero. Exceptions are generally linked to an action. For dividing by zero,
the action is a divisor of zero. Integer division, where the divisor is zero, triggers a divide by zero exception.
(However, floating-point division by zero does not cause an exception; instead, infinity is returned.) The
following code causes an unhandled divide by zero exception, which terminates the application:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
int var1=5, var2=0;
var1/=var2; // exception occurs
}
}
}

Place code that is likely to raise an exception in a try block because code in a try block is protected from
exceptions. Exceptions raised in the try block are trapped. The stack is then walked by the CLR, searching
for the appropriate exception handler. Code not residing in a try block is unprotected from exceptions. In this
circumstance, the exception eventually evolves into an unhandled exception. As demonstrated in the
previous code, an unhandled exception is apt to abort an application.

In the following code, the divide by zero exception is caught in a try block. Trapping, catching, and handling
an exception are separate tasks. The catch statement consists of a catch filter and block. The
DivideByZeroException filter catches the divide by zero exception. The catch block handles the exception,
which is to display the stack trace. The proximity of the infraction is included in the stack trace. Execution
then continues at the first statement after the catch block.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
try {
int var1=5, var2=0;

var1/=var2; // exception occurs


}
catch(DivideByZeroException except) {
Console.WriteLine("Exception "+except.StackTrace);
}
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Common Exception Model


.NET offers a common exception model. Exception handling is implemented within the CLR and is not
specific to a managed language. Each managed language exposes exception handling using
language-specific syntax. The uniform exception model contributes to language independence, which is an
important tenet of .NET. In addition, exceptions raised in one managed language can be caught in a different
managed language. Prior to .NET, there were competing models for error handling: Microsoft Visual Basic
6.0, Win32 SDK, MFC, COM, and more. In a component-driven architecture, this disparity contributed to
complexity and potential product instability. In .NET, exception handling between disparate components is
consistent, simple, and stable.

As part of the common exception model, .NET advocates structured exception handling, which is essentially
the try and catch statements. C-based and Java developers are probably familiar with structured exception
handling. For Visual Basic developers, this is a seismic shift from unstructured exception handling. The
unstructured model, such as on error goto and on error resume, is thankfully now obsolete.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Structured Exception Handling


A structured exception evaluates the stack to determine when code is protected and where an exception is
caught and handled. When exceptions occur, the stack is walked in search of an exception handler. When a
matching catch filter is located, the exception is handled in the exception handler, which is the catch block.
This sets the scope of the exception on the stack. After the exception is handled, the CLR unwinds the
stack to that scope.

Try Statement

Try blocks are observers; they watch for exceptions in protected code. Place code prone to raising
exceptions in a try block. Do not attempt to protect an entire application in a try block—there are more
convenient and practical means of accomplishing the same feat, as described later in this chapter.

As mentioned, exceptions are stack-based. The following code contains a fence-post error that happens
when the bounds of the array are exceeded. The result is an exception in the unprotected MethodA method.
Main calls MethodA, where the scope of Main encompasses MethodA.

For this reason, the try block in Main extends protection to MethodA. The exception is trapped in Main.

using System;

namespace Donis.CSharpBook{
public class Starter{

public static void Main(){


try {
MethodA();
}
catch(Exception except) {
Console.WriteLine(except.Message);
}
}

public static void MethodA() {


int [] values={1,2,3,4};
for(int count=0; count<=values.Length; ++count) {
Console.WriteLine(values[count]);
}
}
}
}

This is the syntax of the try statement:


 try { protected} catch 1(filter 1) { handler 1} catch n(filter n) { handler n} finally {terminationhandler}

Try statements must be paired with either a catch statement or a finally statement. There can be zero or
more catch statements attached to a try statement; there are zero or one finally statements. If both catch
and finally are present, the catch statement should precede the finally statement. The following code has
various combinations of try, catch, and finally statements:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

// try..catch
try {
}
catch(Exception e) {
}

// try..finally
try {
}
finally{
}

// try..catch..finally
try {
}
catch(Exception e) {
}
finally{
}

// try..catches..finally
try {
}
catch(Exception e) {
}
catch {
}
finally{
}

Catch Statement

Catch statements filter and handle exceptions. When an exception is raised, the filter sets which exceptions
are handled at that scope in the stack. If the filter matches the exception, the exception is suppressed, and
control is transferred to the adjoining catch block to be handled. The CLR searches the stack for an
appropriate filter. If a matching filter is not found, the exception becomes an unhandled exception.

Exceptions must be derived from System.Exception. The catch filter defines an exception type and catches
exception of that type or any descendants. The exception object contains details of the exception, such as a
user-friendly message describing the exception. The exception object caught in the filter is accessible only
in the catch block. System.Exception is the base class of .NET exceptions and the generic filter.

A System.Exception filter catches all managed exceptions. Derived classes of System.Exception catch
more-specific exceptions. In the previous code, the DivideByZeroException filter caught integer divide by zero
exceptions and nothing else. A try block can be appended to multiple catches for catching distinct
exceptions. The catches are ordered from specific to generic. The following code has several exception
filters, from specific to generic:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
try {
int var1=5, var2=0;
var1/=var2;
}
catch(DivideByZeroException except) {
Console.WriteLine("Exception "+except.Message);
}
catch(System.ArithmeticException except) {
Console.WriteLine("Exception "+except.Message);
}
catch(Exception except) {
Console.WriteLine("Exception "+except.Message);
}
}
}
}

In the preceding code, DivideByZeroException is very specific and catches only divide by zero exceptions.
ArithmeticException is less specific and catches a variety of arithmetic exceptions, including the divide by
zero exception. Exception catches all managed exceptions, which includes divide by zero and arithmetic
exceptions. In the preceding code, the exception is caught at the DivideByZeroException catch handler.

The catch filter is optional, and the default is catch all. Although System.Exception catches any managed
exceptions, catch all catches both managed and unmanaged exceptions. In most circumstances, native
exceptions are mapped to managed exceptions, which are thrown in the RaiseTheException native function.
RaiseTheException uses the RaiseException API to construct the managed exception. Exceptions not
mapping to managed exceptions are outside this normal mechanism. A catch with no catch filter is a catch
all. This code has a catch all:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
try {
int var1=5, var2=0;
var1/=var2;
}
catch(DivideByZeroException except) {
Console.WriteLine("Exception "+except.StackTrace);
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

catch {
// catch remaining managed and unmanaged exceptions
}
}
}
}

Propagating Exceptions
Exceptions are not always handled locally where the exception is caught. It is sometimes beneficial to catch
an exception and then propagate the exception. Propagating an exception is catching and then rethrowing
the exception. Rethrowing an exception continues the search along the call stack to find an appropriate
handler. Here are some reasons to propagate an exception:
 There is a centralized handler for the exception. There are several reasons for implementing
centralized handlers, including code reuse. Instead of handling an exception in various locations in
an application, concentrate code for certain exceptions in a centralized handler. Wherever the
exception is raised, the proper response is to record the exception and then delegate to the
centralized handler. A central handler can be used to handle all exceptions in a single place.
 Resources required to handle the exception are not available locally. For example, an exception is
raised because of an invalid database connection. However, the correct connection string is read
from a file not available where the exception occurs. The solution is to propagate the exception to
a handler that has access to the file resource.
 Propagate unwanted exceptions caught in the umbrella of the exception filter. This would be
useful for catching all DataException types with the exception of the DuplicateNameException.
One solution would be to write 12 individual catches—one for each of the data exceptions except
for the DuplicateNameException exception. A better solution is to catch the DataException type
and propagate the DuplicateNameException when necessary. This is one catch statement versus
12 catch statements and eliminates redundant code.
 Catch an exception to gather information or to report on an exception, and then propagate the
exception.

To propagate an exception, rethrow the same exception or another exception in the catch block. An empty
throw statement propagates the caught exception. Alternatively, throw a different exception.

Exceptions might propagate through several layers of an application. Ultimately, the exception could
percolate to the user interface level. As an exception percolates, the exception becomes less specific.
Exceptions from the lower echelon of an application contain detailed information appropriate to the
application developer, but probably not relevant to the user. Internal exceptions might contain security and
other sensitive information not appropriate for a benign (or malicious) user. Record the facts of the internal
exception if logging is preferable. Exceptions that reach the user should present user-relevant information: a
user-friendly message, steps to resolve the exception, or even a customer support link.

When an original exception is rethrown, you can preserve the that exception in the InnerException attribute.
Successive InnerException attributes form a chain of exceptions from the current exception to the original
exception. The InnerException can be initialized in the constructor of the new exception. Here is sample
code that propagates an exception and sets the inner exception:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
try {
MethodA();
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

catch(Exception except) {
Console.WriteLine(except.Message);
}
}

public static void MethodA() {


try {
MethodB();
}
catch(DivideByZeroException inner) {

// record divide by zero exception in


// event log.

// except is inner exception


throw new Exception("Math exception",
inner);
}
}

public static void MethodB() {


int var1=5, var2=0;
var1/=var2;
}
}
}

Finally Statement

The finally block is the termination handler. When an exception is raised, protected code after the infraction
is not executed. What if it is cleanup code? If cleanup code is not executed, resources are left dangling.
Termination handlers are the solution. Code that must execute, regardless of an exception occurring, is
placed in a termination handler. When an exception is raised, the finally blocks within scope are called
before the stack is unwound. Note that the termination handler is executed even when there is no occurrence
of an exception. Execution simply falls through the try block into the attached finally block. In the termination
handler, you could close a file, release a database connection, or otherwise manage resources.

Here is a typical termination handler:

using System;
using System.IO;

namespace Donis.CSharpBook{
public class FileWriter{
public static void Main(){
StreamWriter sw=null;
try {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

sw=new StreamWriter("date.txt");
sw.Write(DateTime.Now.ToLongTimeString());
throw new ApplicationException("exception");
// dangling code
}
finally {
sw.Close();

Console.WriteLine("file closed");
}
}
}
}

Exception Information Table

The CLR refers to the Exception Information Table to track protected code in an efficient manner. Because of
the Exception Information Table, there is no overhead associated with an exception unless an exception
occurs.

An Exception Information Table is constructed for every managed application. The table has an entry for
each method in the program. Each entry is an array, where the array elements describe the filters and
handlers of that method. Entries in the array represent a catch filter, user-filtered handler, catch handler, or
termination handler. User-filtered handlers use the when clause and are available in Visual Basic .NET, but
not in C#.

When an exception occurs, the CLR consults the Exception Information Table. The entry for the method
hosting the exception is searched for a filter that matches the exception. If the array is empty or a matching
filter is not found, the entry of the outer method is examined next. When the boundary of the application is
reached, the exception is considered unhandled.

Nested Try Blocks

Try blocks can be nested. The order of evaluation is more complex with nested try blocks. This is the order
of execution when an exception occurs:
1. The first step is to find an appropriate try block. If an exception is raised outside a protected
block, the exception is not trapped and is therefore unhandled.
2. From the try block, walk the stack until a matching catch filter is found. If a matching filter is not
found, the exception is unhandled. This defines the scope of the exception.
3. Before the stack is unwound, finally blocks within the scope of the exception are run. The
innermost finally blocks are executed first.
4. The catch block of the filter is executed as the exception handler.
5. Execution continues at the first statement after the catch block.
6. Finally blocks at scope of exception are executed.

Figure 9-1 diagrams the sequence when an exception is raised in a nested try block.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 9-1: Execution sequence of exception handling

The following code has several nested try blocks:

using System;

namespace Donis.CSharpBook{
public class Starter{

public static void Main(){


try {

Console.WriteLine("outer - try");
try {
Console.WriteLine("inner - try");
throw new ApplicationException("exception");
}
finally {
Console.WriteLine("inner - finally");
}
}
catch(Exception except){
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("outer - catch");
}
finally {
Console.WriteLine("outer - finally");
}

}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

System.Exception
System.Exception is the base exception class. All exceptions in .NET are derived from System.Exception.
System.SystemException is the base class for system exceptions raised by the CLR, such as
System.Data.DataException or System.FormatException. SystemException is derived directly from
System.Exception. System.SystemException does not refine System.Exception. However, it is an important
marker that distinguishes between system and application exception, as demonstrated in the following code:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
try {
int var1=5, var2=0;
var1/=var2; // exception occurs
}
catch(Exception except) {
if(except is SystemException) {
Console.WriteLine("Exception thrown by runtime");
}
else {
Console.WriteLine("Exception thrown by application");
}
}
}
}
}

System.Exception Functions

System.Exception has four constructors:

public Exception 1()


public Exception 2(string message)
public Exception 3(string message, Exception innerException)
protected Exception 4(Serialization info, StreamingContext context)

Exception 1 is the default constructor. Exception 2 constructor sets the user-friendly message of the
exception. Exception 3 constructor also sets the inner exception, which is the originating exception. Exception
4 deserializes an exception raised remotely.

The Exception class has several other helpful functions. Table 9-1 lists the important methods of the class.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 9-1: Exception Methods

Method Name Result

GetBaseException Returns the root exception in a chain of exception objects

GetObjectData Serializes data of the Exception class

GetType Returns the type of the exception

ToString Concatenates the name of the exception object with the user-friendly message

The following code calls GetBaseException and outputs the error message of the initial exception. If the
current exception is the first exception in a chain of exceptions, GetBaseException returns null.
Alternatively, you can walk InnerException properties back to the first exception.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
try {
MethodA();
}
catch(Exception except) {
Exception original=except.GetBaseException();
Console.WriteLine(original.Message);
}
}

public static void MethodA(){


try {
MethodB();
}

catch(Exception except) {
throw new ApplicationException( "Inner Exception", except);
}
}

public static void MethodB(){


throw new ApplicationException("Innermost Exception");
}
}
}

System.Exception Properties

System.Exception has a full complement of attributes providing information on the exception. Table 9-2
describes the properties of the Exception class.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 9-2: Exception


Properties

Pr De Ty Re
op scr pe ad/
ert ipti Wr
y on ite

Dat Ret IDi R


a urn cti
s on
a ary
dic
tio
nar
y
coll
ect
ion
tha
t
pro
vid
es
opt
ion
al
us
er-
defi
ne
d
det
ails
of
ex
ce
pti
on.

Hel Lin stri R/


pLi k ng W
nk to
a
hel
p
file
for
the
ex
ce
pti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 9-2: Exception


Properties

Pr De Ty Re
op scr pe ad/
ert ipti Wr
y on ite

HR Th int R/
es e W
ult HR
ES
UL
T,
whi
ch
is
a
32-
bit
err
or
co
de
co
m
mo
n
to
CO
M,
as
sig
ne
d
to
the
ex
ce
pti
on.
Thi
s
is
a
pro
tec
ted
pro
per
ty.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 9-2: Exception


Properties

Pr De Ty Re
op scr pe ad/
ert ipti Wr
y on ite

Inn Wh Ex R
erE en ce
xce ex pti
pti ce on
on pti
on
s
are
pro
pa
gat
ed,
the
inn
er
ex
ce
pti
on
rep
res
ent
s
the
pre
vio
us
ex
ce
pti
on.

Me Us stri R
ss er-f ng
ag rie
e ndl
y
me
ss
ag
e
de
scr
ibin
g
the
ex
ce
pti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 9-2: Exception


Properties

Pr De Ty Re
op scr pe ad/
ert ipti Wr
y on ite

So Na stri R/
urc me ng W
e of
ap
plic
ati
on
or
obj
ect
wh
ere
ex
ce
pti
on
oc
cur
red
.

Sta Stri stri R


ck ng ng
Tra rep
ce res
ent
ati
on
of
the
call
sta
ck
wh
en
the
ex
ce
pti
on
oc
cur
red
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 9-2: Exception


Properties

Pr De Ty Re
op scr pe ad/
ert ipti Wr
y on ite

Tar Ref Me R
get ere tho
Sit nc dB
e e as
to e
the
me
tho
d
wh
ere
ex
ce
pti
on
is
rai
se
d.

The Message and InnerException properties are settable in constructors of the Exception class.

The following code uses some of the properties of the Exception class. In Main, MethodA is called, and an
exception is raised. The exception is caught and handled in Main. In the catch block, the exception flag is
set to false. Leveraging the TargetSite property, MethodA is then called again successfully. The TargetSite
property returns a MethodBase type, which can be used to late bind and invoke a method.

using System;
using System.Reflection;

namespace Donis.CSharpBook{
public class Starter{
public static bool bException=true;
public static void Main(){
try {
MethodA();
}
catch(Exception except) {
Console.WriteLine(except.Message);
bException=false;
except.TargetSite.Invoke(null, null);
}
}

public static void MethodA() {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

if(bException) {
throw new ApplicationException("exception message");
}
}
}
}

Application Exceptions

Application exceptions are custom exceptions and are thrown by the application, not by the CLR.
Application exceptions are derived from System.ApplicationException or System.Exception.
System.ApplicationException adds nothing to System.Exception. While System.SystemException is a
marker for system exceptions, System.ApplicationException brands application exceptions. A custom
exception derived from System.Exception accomplishes the same feat. When several custom exceptions are
planned, create a custom base exception class to categorize the exceptions. For convenience and
maintainability, deploy application exceptions together in a separate assembly.

Do not create an application exception for an existing exception. Research the available system exceptions
to avoid replicating an existing exception.

These are the steps for creating an application exception:


1. Name the application exception. As a best practice, the class name should have the Exception
suffix, as in ApplicationException.
2. Derive the application exception from System.Exception.
3. Define constructors that initialize the state of the application exception. This includes initializing
members inherited from the base class.
4. Within the application exception, refine System.Exception as desired, such as by adding
attributes that further delineate this specific exception.

To raise an application exception, use the throw statement. You can also throw system exceptions. Thrown
exceptions are considered software exceptions. The CLR treats software exceptions as standard exceptions.

throw syntax:

throw exceptioninstance 1;
throw 2;

The second syntax is specialized: It is available in the catch block, but nowhere else. This version of the
throw statement rethrows as an exception caught in the catch block. However, the best policy is to add
additional context to an exception before propagating the exception object. Propagating exceptions is
reviewed later in this chapter.

Application exceptions are typically prompted by an exceptional event. What is an exceptional event? A
strict definition does not exist. You define the basis of the event using whatever criteria are appropriate.
Remember, raising an exception simply for transfer of control or a nonexceptional event is bad policy. In an
application, the following could be considered exceptional events where throwing an application exception is
warranted:
 Constructor fails to initialize the state of an object.
 A property does not pass validation.
 Null parameters.
 An exceptional value is returned from a function.

ConstructorException is an application exception. Throw this exception when a constructor fails. It refines
the System.Exception base class with name of the type and time of exception. In addition, the Message
property is assigned a congruous message. This is the code for the ConstructorException class:

using System;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

namespace Donis.CSharpBook{

public class ConstructorException: Exception{

public ConstructorException(object origin)


: this(origin, null) {
}

public ConstructorException(object origin, Exception innerException)


: base("Exception in constructor", innerException) {
prop_Typename=origin.GetType().Name;
prop_Time=DateTime.Now.ToLongDateString()+" "+
DateTime.Now.ToShortTimeString();
}

protected string prop_Typename=null;


public string Typename {
get {
return prop_Typename;
}
}

protected string prop_Time=null;


public string Time {
get {
return prop_Time;
}
}
}
}

This code uses the ConstructorException class:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
try {
ZClass obj=new ZClass();
}
catch(ConstructorException except) {
Console.WriteLine(except.Message);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("Typename: "+except.Typename);
Console.WriteLine("Occured: "+except.Time);
}
}
}

class ZClass {
public ZClass() {
// initialization fails
throw new ConstructorException(this);
}
}
}

Exception Translation

In some circumstances, the CLR catches an exception and rethrows a different exception. The inner
exception of the translated exception contains the original exception. Invoking a method dynamically using
reflection is one such circumstance. Exceptions raised in methods invoked by MethodInfo.Invoke are
automatically trapped and converted to TargetInvocationException? NET documentation in MSDN will always
confirm when exception translation will happen. Here is an example of exception translation:

using System;
using System.Reflection;

namespace Donis.CSharpBook{

public class ZClass {


public static void MethodA() {
Console.WriteLine("ZClass.MethodA");
throw new Exception("MethodA exception");
}
}

public class Starter{


public static void Main(){
try {
Type zType=typeof(ZClass);
MethodInfo method=zType.GetMethod("MethodA");
method.Invoke(null, null);
}
catch(Exception except) {
Console.WriteLine(except.Message);
Console.WriteLine("original: "+
except.InnerException.Message);
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
}

COM Interoperability Exceptions

.NET applications often host COM components or expose managed components to COM clients. These
applications must be prepared to handle and possibly throw COM exceptions, respectively. The prevalence
of COM components makes COM interoperability an important consideration for managed applications into
the foreseeable future.

COM Exceptions
COM components should sandbox exceptions, which protects COM clients from potential language-specific
exceptions. COM methods return an HRESULT structure, which is the result code of the method. An
HRESULT is a 32-bit structure, where the severity bit is the high-order bit. The severity bit is set if an
exception is raised. The Win32 SDK defines constants representing various HRESULT codes.
E_NOINTERFACE, E_INVALIDARG, E_OUTOFMEMORY, S_OK, and S_FALSE are common HRESULT
codes. E_codes are error codes indicating that an exception was raised or some other exceptional event
happened. S_codes are success codes where no failure occurred.

When managed components call methods on COM objects, the CLR consumes the resulting HRESULT. If
the HRESULT represents a known COM error (E_code), the CLR maps the HRESULT to a managed
exception. For example, E_POINTER maps to the NullReferenceException, which is a managed exception.
An error code from an unknown HRESULT is mapped to a COMException object. No exception is thrown if
the HRESULT is a success code (S_code). Table 9-3 shows the common translations of HRESULT to
managed exceptions.
Table 9-3:
COM
Exception
Table

CO Ma
M na
Ex ge
ce d
pti Ex
on ce
pti
on

CO Ov
R_ erfl
E_ ow
OV Ex
ER ce
FL pti
O on
W

CO Thr
R_ ea
E_ dSt
TH op
RE Ex
AD ce
ST pti
OP on
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 9-3:
COM
Exception
Table

CO Ma
M na
Ex ge
ce d
pti Ex
on ce
pti
on

E_ Inv
NO alid
INT Ca
ER stE
FA xce
CE pti
on

E_ Not
NO Im
TI ple
MP me
L nte
dE
xce
pti
on

E_ Ou
OU tOf
TO Me
FM mo
EM ryE
OR xce
Y pti
on

E_ Nul
PO lRe
INT fer
ER en
ce
Ex
ce
pti
on

The COMException is derived from System.Runtime.InteropServices.ExternalException, which indirectly


derives from System.Exception. The COMException class has additional properties providing the details of
the unknown COM exception. The ErrorCode property contains the unrecognized HRESULT from the COM
method.

COM components implement Error objects to provide extended error information to clients. An Error object
implements the IErrorInfo interface. Members of the IErrorInfo interface correlate to members of the
COMException class and are therefore accessible to the managed client. Table 9-4 maps members of the
Error object to the COMException class.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 9-4:
IErrorInfo to
COMExceptio
n Mapping

IEr CO
ror ME
Inf xc
o ept
Me ion
mb Me
er mb
er

IEr CO
rorI ME
nfo xce
::G pti
etD on.
es Me
cri ss
pti ag
on e

IEr CO
rorI ME
nfo xce
::G pti
etS on.
our So
ce urc
e
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 9-4:
IErrorInfo to
COMExceptio
n Mapping

IEr CO
ror ME
Inf xc
o ept
Me ion
mb Me
er mb
er

If CO
IEr ME
rorI xce
nfo pti
::G on.
etH Hel
elp pLi
Fil nk
e
is
no
n-z
ero
,
IEr
rorI
nfo
::G
etH
elp
Fil
e+"
#"+
IEr
rorI
nfo
::H
elp
Co
nte
xt

The following code is a partial listing from an ATL project that publishes a COM component. The COM
component exposes the CComponentZ::MethodA. Using the AtlReportError API, CComponentZ::MethodA
builds an Error object to return extended error information to the client. The method also returns a custom
error code in the HRESULT, which will be unknown to the CLR.

// ComponentZ.cpp : Implementation of CComponentZ

#include "stdafx.h"
#include "ComponentZ.h"
#include ".\componentz.h"
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

// CComponentZ

STDMETHODIMP CComponentZ::MethodA(void) {
// TODO: Add your implementation code here

HRESULT hResult=MAKE_HRESULT( 1, FACILITY_NULL, 12 );

MessageBox(NULL, "COM component", "Hello from", MB_OK);

return AtlReportError (GetObjectCLSID(), "My error message", 5,


"http://error.asp",GUID_NULL, hResult);
}

The following code is managed code, in which the ATL component is called from a managed COM client.
Because the HRESULT is unknown, the error code appears as a COMException exception.

using System;
using System.Runtime.InteropServices;

namespace COMClient {
class Program {
static void Main(string[] args) {
try {
COMLib.CComponentZClass com_object =
new COMLib.CComponentZClass();
com_object.MethodA();
}
catch (COMException except){
Console.WriteLine(except.ErrorCode);
Console.WriteLine(except.HelpLink);
Console.WriteLine(except.Message);
}
catch (Exception) {

}
}
}
}

Generating COM Exceptions


Managed components have an HRESULT property that translates a managed exception to a COM error
result. System exceptions are already assigned an appropriate HRESULT. For application exceptions, you
should initialize the HRESULT property in the constructor. It is important that managed components that
expect COM clients set the HRESULT to a known COM error code.

TypeException is an application exception, which should be thrown when an object is the wrong type.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

TypeException has two overloaded constructors. Both constructors set the HResult property of the exception
to the E_NOTIMPL error code (0x80004001). The one-argument constructor accepts a type object, which is
the required type that was not implemented. The name of the type is added to the error message of the
exception. This is the code for the TypeException class:

using System;

namespace Donis.CSharpBook{

public class TypeException: Exception{

public TypeException()
: base("object type wrong") {
HResult=unchecked((int) 0x80004001); // E_NOTIMPL
}

public TypeException(Type objectType)


: base("Argument type wrong: "+objectType.Name
+" required"){
prop_RequiredType=objectType.Name;
HResult=unchecked((int) 0x80004001); // E_NOTIMPL
}

private string prop_RequiredType;


public string RequiredType {
get {
return prop_RequiredType;
}
}
}
}

The Delegator class uses the TypeException class. Delegator delegates method calls of Delegator .MethodA
to an external object. For the delegation to be successful, the external object must also implement the
MethodA method, which is defined in the ZInterface. Appropriately, the code in Delegator.MethodA confirms
that the external object implements the ZInterface. If not, the TypeException is thrown. Otherwise,
Delegator.MethodA proceeds with the delegation:

using System;

namespace Donis.CSharpBook{
interface ZInterface {
void MethodA();
}

public class Delegator {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public Delegator(object obj) {


externalobject=obj;
}

public void MethodA() {


if(externalobject is ZInterface) {
((ZInterface)externalobject).MethodA();
}
else {
throw new TypeException(
typeof(ZInterface));
}
}

private object externalobject;


}
}

YClass creates an instance of the Delegator class. A ZClass object is passed into the Delegator constructor
as the external object. ZClass does not implement MethodA. Delegator.MethodA is called in
YClass.UseDelegator. A TypeException is thrown because the ZClass does not implement the appropriate
interface:

using System;
using System.Runtime.InteropServices;
using Donis.CSharpBook;

class ZClass {
}

[ClassInterface(ClassInterfaceType.AutoDual)]
public class YClass{
public void UseDelegator(){
ZClass obj=new ZClass();
Delegator del=new Delegator(obj);
del.MethodA();
}
}

COM clients can access managed code through COM Callable Wrappers (CCWs). The following unmanaged
code creates an instance of YClass and invokes YClass.UseDelegator. As expected, an exception occurs,
which translates to E_NOTIMPL in unmanaged code. The COM client checks for this exception and displays
the appropriate message.

#import "..\yclass.tlb" no_namespace, raw_interfaces_only, named_guids


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

#include "objbase.h"

void main() {
CoInitialize(NULL);
_YClassPtr obj(CLSID_YClass);
HRESULT hResult=obj->UseDelegator();
if(hResult==E_NOTIMPL) {
MessageBox(NULL,"Required interface not implemented",
"In Managed Component", MB_OK);
}
else {
MessageBox(NULL, "Managed Component", "No error",
MB_OK);
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Remote Exceptions
Exceptions sometime occur in remote code. An exception that is raised in a different application domain is a
remote exception. Remote exceptions include exceptions thrown in a .NET Remoting application or a Web
service application. Exceptions that cross application domains must be serialized to maintain the state.
System exceptions are serializable. However, you need to make application exceptions serializable.

Follow these steps to serialize an application exception:


1. Adorn the application exception with the serializable attribute.
2. Implement a two-argument constructor with a SerializationInfo and StreamingContext parameter.
Deserialize the exception with the SerializationInfo parameter, which is a state bag. Retrieve state
information of the exception using the Get methods of the SerializationInfo object. The
StreamingContext parameter provides additional data about the source or target of the
serialization process. In addition, call the same constructor in the base class to allow the base
class to deserialize its state.
3. Implement the GetObjectData method to serialize the exception. The method also has two
parameters: Serialization and StreamingContext. Use the Serialization.AddValue to serialize the
state of the exception. Invoke GetObjectData on the base class to allow it to serialize itself.
4. For the exception to be available in the client assembly, share the assembly through a global
assembly cache or an application configuration file. If the assembly is not shared, the assembly
must be copied into the private directory of the client application.

CustomException is an application exception that supports remoting. There is one property, prop_Time,
which is serialized in GetObjectData and deserialized in the two-argument constructor:

using System;
using System.Reflection;
using System.Runtime.Serialization;

[assembly:AssemblyVersion("1.1.0.0")]
[assembly:AssemblyCultureAttribute("")]

namespace Donis.CSharpBook{

[Serializable]
public class CustomException: Exception{

public CustomException()
: base("custom exception", null) {
prop_Time=DateTime.Now.ToLongDateString()+" "+
DateTime.Now.ToShortTimeString();
}

protected CustomException(SerializationInfo info,


StreamingContext context) : base(info, context){
prop_Time=info.GetString("Time");
}

public override void GetObjectData( SerializationInfo info,


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

StreamingContext context ){
info.AddValue("Time", prop_Time, typeof(string));
base.GetObjectData(info,context);
}

protected string prop_Time=null;


public string Time {
get {
return prop_Time;
}
}
}
}

In Microsoft Visual Studio, the assembly attributes, such as AssemblyVersion, are found in the
AssemblyInfo.cs file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Unhandled Exceptions
Unhandled exceptions are not handled directly in application code; they are handled in a global handler. The
global handler reports the exception in an error box that offers the Debug, Send Error Report, and Don't Send
buttons. For applications within the realm of a debugger, a potential unhandled exception is handled in the
debugger.

What is the life cycle of an exception? Exceptions are initially categorized as first chance exceptions. If the
application is attached to a debugger, the debugger is first consulted about the exception. Debuggers
typically ignore first chance exceptions, and the exception is forwarded to the application next. When no
debugger is present, the first chance exception is immediately sent to the application. If the application does
not handle the first chance exception, the exception becomes a high-priority second chance exception. If a
debugger is attached, the second chance exception is handled by the debugger. Upon finding a second
chance exception, the Visual Studio debugger transfers the user to the location in the source code where
the exception happened. If no debugger is present, execution is transferred to a global exception handler,
which displays an error dialog box and then terminates the application. Figure 9-2 shows the life cycle of an
exception.

Figure 9-2: Life cycle of an exception

Applications can trap unhandled exceptions. The mechanism is different for Windows Forms and for Console
applications. For Windows Forms, add a handler to the Application.ThreadException event. For Console
applications, the handler is added to the AppDomain.UnhandledException event. Methods added to the
Application.ThreadException event chain catch and handle the exception. This is an advantage when
compared with AppDomain.UnhandledException. Methods added to the AppDomain.UnhandledException
event can respond to an unhandled exception, but the exception is not caught. Therefore, the exception will
resurface after the handlers have completed.

Do not use the unhandled exception handler to catch all exceptions. Proper application design identifies
specific exceptions that an application should anticipate. Those exceptions should be caught and handled
within the confines of structured exception handling. Reserve the unhandled exception method for
unanticipated exceptions.

Application.ThreadException
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

In a Windows Forms application, the windows procedure raises the Application.ThreadException event upon
an unhandled exception. Subscribe to the ThreadException event to handle the unhandled exception. The
subscriber is an exception handler, which prevents the application from being terminated. Do not propagate
an exception caught in this manner in the unhandled exception handler. The new exception is unprotected
and will likely terminate the application. After the unhandled exception handler completes, execution
continues at the next message in the message pump.

Subscribe to the ThreadException event with a ThreadExceptionEventHandler delegate, which has two
parameters. The object parameter is the thread object of the thread that raised the exception. The
ThreadExceptionEventArg parameter of the System.Threading namespace contains the exception that was
unhandled. This is the signature of the ThreadExceptionEventHandler:

ThreadExceptionEventHandler syntax:

void ThreadExceptionEventHandler(object sender,


ThreadExceptionEventArgs e)

In the following code, the OnThreadException handler is added to the ThreadException event. The
bthException_Click method raises an unhandled divide by zero exception. The unhandled exception is then
handled in the OnThreadException method, which displays an informative message. Run the application in
release mode for the expected results. Otherwise, the Visual Studio debugger intercedes the exception.

private void btnException_Click(object sender, EventArgs e) {


int vara = 5, varb = 0;
vara /= varb;
}

private void Form1_Load(object sender, EventArgs e) {


Application.ThreadException += new
System.Threading.ThreadExceptionEventHandler(
OnThreadException);
}

void OnThreadException(object sender, ThreadExceptionEventArgs e) {


Thread t = (Thread) sender;
Exception threadexception = e.Exception;
string errormessage = "Thread ID: " +
t.ManagedThreadId.ToString() +
" [ "+ threadexception.Message + " ]";
MessageBox.Show(errormessage);
}

AppDomain.UnhandledException

When an unhandled exception is manifested in a Console application, the AppDomain .UnhandledException


is raised. Subscribe to the event to clean up the resources of the application, such as closing files and
relinquishing data connections. You might also record the unhandled exception in the event log or another
location. It is important to note that the exception is not caught in the AppDomain.UnhandledException
handler. After the handler finishes, the unhandled exception causes the application to be terminated. The
AppDomain.UnhandledException event is triggered only in the initial application domain; it is ignored in other
application domains.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Subscribe to the AppDomain.UnhandledException event with an UnhandledExceptionEventHandler delegate.


The delegate has two parameters. The object parameter is the AppDomain object of the initial application
domain. The UnhandledExceptionEventArgs parameter contains the specifics of the unhandled exception.
This is the syntax of the UnhandledExceptionEventHandler:

UnhandledExceptionEventHandler syntax:
 void UnhandledExceptionEventHandler(object sender, UnhandledExceptionEventArgs e)

UnhandledExceptionEventArgs offers the IsTerminating and ExceptionObject properties. IsTerminating is a


Boolean property indicating the status of the application. If true, the application is terminating because of the
exception. If false, the application survives the exception. In .NET 2.0, this property is always true.
Unhandled exceptions on both managed and unmanaged threads terminate an application. This is cleaner
than the .NET 1.1 unhandled exception model, where exceptions raised on managed threads were nonfatal.
The Exception property is an exception object for the unhandled exception. Inexplicably, this property is an
object type, not an Exception type. Cast the property to the Exception type to access the details of the
exception.

In the following Console application, the OnUnhandledException method is added to the


AppDomain.UnhandledException event. When the subsequent divide by zero exception occurs, the
OnUnhandledException method is called.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
AppDomain.CurrentDomain.UnhandledException+=
new UnhandledExceptionEventHandler(
OnUnhandledException);

int vara = 5, varb = 0;


vara /= varb;
}

public static void OnUnhandledException(


object sender, UnhandledExceptionEventArgs e) {
string application_name=sender.ToString();
Exception except=(Exception) e.ExceptionObject;
string errormessage = "Application " +application_name+
" [ Exception " + except.Message + " ]";
Console.WriteLine(errormessage);
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Managing Exceptions in Visual Studio


Visual Studio 2005 can configure exceptions for debugging. The Exception Assistant provides helpful
information to developers when an unhandled exception is raised. The Exceptions dialog box alters how the
Visual Studio debugger handles exceptions.

Exception Assistant

The Exception Assistant appears in Visual Studio when an unhandled exception occurs. It displays a
translucent frame that partially obfuscates the application code. The source code that prompted the
exception is highlighted and tethered to the Exception Assistant window. The Exception Assistant is shown
in Figure 9-3.

Figure 9-3: The Exception Assistant

The Exception Assistant header identifies the unhandled exception and offers a brief explanation. The
Troubleshooting Tips section offers hints to diagnose the exception. Each hint is also a link to further
information. The Actions pane specifies two actions:
 New Detail displays the properties of the exception object.
 Copy Exceptional Detail To The Clipboard copies basic information on the exception onto the
Clipboard.

The Exception Assistant can be disabled or otherwise configured from the Tools menu. Select the Options
menu item. Configure the Exception Assistant in the Debugging pane.

Exceptions Dialog Box

In the Exceptions dialog box, the Visual Studio debugger can be instructed to interrupt on first chance
exceptions. Open the Exceptions dialog box from the Debug menu. Choose the Exceptions menu item.
Figure 9-4 shows the Exceptions dialog box.

Figure 9-4: The Exceptions dialog box

The Thrown and User-unhandled columns have a series of option boxes that are organized into categories
and specific exceptions. Visual Studio debugger interrupts on first chance exceptions for exceptions
selected in the Thrown column. For protected code, the debugger intercedes before the exception is caught.
In the development phase of an application, it can be instructive to be notified of exceptions that would
otherwise be consumed in an exception handler. The second column selects specific user-handled
exceptions to break on. The Add button appends application exceptions to the list of available exceptions
that are selectable in the dialog box. These exceptions can later be deleted.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Metadata and Reflections


.NET assemblies adhere to the Portable Executable Common Object File Format (PE COFF). PE COFF
files have headers and sections, such as a PE and CLR Header. .NET assemblies consist of metadata and
MSIL code. Metadata describes the types and other characteristics of the assembly. You can inspect the
metadata of an assembly using reflection. Tools, such as ILDASM, browse an assembly using reflection.
Reflection also provides support for late binding. The next chapter explores metadata and reflection.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Part IV: Debugging


Chapter List

Chapter 10: Metadata and Reflection

Chapter 11: MSIL Programming

Chapter 12: Debugging with Visual Studio 2005

Chapter 13: Advanced Debugging


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 10: Metadata and Reflection


Overview
Metadata, which is often described as data about data, formalizes the composition of an assembly.
Metadata is the actualization of the state of an assembly. As a reflection of an assembly, metadata includes
all information pertaining to the assembly, including a detailed description of each type, the attributes of the
assembly, and other particulars of the assembly itself. Metadata is similar to a type library in COM, except
that metadata is always persisted in the application that it describes. For this reason, assemblies are often
referred to as self-describing. Because metadata is indigenous to the assembly, metadata cannot be lost,
and versioning problems are avoided. Metadata is emitted primarily by managed language compilers and
consumed by metadata browsers, other .NET tools, and managed applications. The Common Language
Runtime (CLR) uses metadata extensively. Just-in-time compilation, code access security, garbage
collection, and other services of the CLR rely heavily on metadata. Once emitted, metadata is read-only.

Metadata is important to anyone programming in the managed environment. Assembly inspection, late
binding, and advanced concepts such as self-generating code require a nontrivial understanding of metadata.
You can interrogate metadata by using reflection. Reflection facilitates late binding and other means of
leveraging metadata. Most important, mastery of metadata promotes a better understanding of the managed
world, which (one hopes) translates into better-written code.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Metadata
Metadata about the overall assembly and modules is called the manifest. Some of the macro information
assembled in the manifest includes the simple name, version number, external references, module name,
and public key of the assembly. A portion of the manifest is created from the assembly attributes found in
the AssemblyInfo.cs file of a Microsoft Visual Studio .NET C# project. This is a partial listing of a typical
AssemblyInfo.cs file:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following


// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WindowsApplication4")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WindowsApplication4")]
[assembly: AssemblyCopyright("Copyright © 2005")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Metadata also chronicles the microdata of the assembly, such as types, methods, and attributes. Metadata
paints a portrait of each type, including the type name, methods of the type, parameters of each method of
the type, each field of the type, and further details related to the loading and executing of that type at run
time. Types are probably the most important construct in a .NET application, and metadata about types is
used throughout the life cycle of a managed application. Here are a couple of examples. At startup,
metadata is used to identify the entry point method where the program starts executing. During program
execution, when a class is first touched, an EECLASS is built ostensibly from metadata to represent that
type to the just-in-time compiler. The EECLASS is an important component of the just-in-time process. The
EECLASS is further described in Chapter 13, "Advanced Debugging."

To extend either manifest or type-related metadata, employ attributes. Attributes are the adjectives of a
managed application and extend the description of an assembly, class, method, field, or other target.
Attributes are recorded as metadata and extend the axiomatic metadata of an assembly. In addition, the
Microsoft .NET Framework class library (FCL) offers predefined-custom and pseudo-custom attributes.
Obsolete and StructLayout attributes are examples of predefined attributes. Serializable is an example of a
pseudo-custom attribute. The Obsolete attribute marks an entity as deprecated, whereas the StructLayout
attribute stipulates the memory layout of fields in the context of unmanaged memory. The latter attribute is
essential when passing a managed type to an unmanaged function or application programming interface
(API). You can augment the predefined attributes with programmer-defined custom attributes, where the limit
is only your imagination. Applying a version number to a class, assigning the name of the responsible
developer or team to a class, and identifying design documents used to architect an application are some
ways to exploit custom attributes.

Metadata persisted to an assembly is organized as a nonhierarchical but relational database of


cross-referencing tables. The metadata database has many tables that can—and often do—reference each
other. However, no parent-child relationship between tables is ever implied. Each categorization of data is
maintained in a separate table, such as the TypeDef and MethodDef tables. Types alone are stored in the
TypeDef table. Each record of the TypeDef table represents a type. If there were six types in the assembly,
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

there would be six records or rows in the TypeDef table. Methods of all types are stored in the MethodDef
table. Each row of the MethodDef table describes a method. The TypeDef table references the MethodDef
table to link types to member methods. The MethodList column of the TypeDef table has record indexes
(RIDs) into the MethodDef table. Extending this model, the MethodDef table has a ParamList column, which
is index to the method's parameters found in the Param table.

Metadata tables are assigned unique table identifiers, which are 1-byte unsigned integers. For example, the
table identifier for the TypeDef table is 2, whereas 6 identifies the MethodDef table. Metadata tables reserved
for the run time are not published and not assigned an external table identifier for the RID. Table 10-1 lists
some of the popular metadata tables.
Table 10-1: Metadata Tables

Table Table Table Description


Name ID

Assembly 0x20 Data related to assembly

Field 0x04 Fields (data member) of types

MethodDef 0x06 Methods (member functions) of types

NestedClass 0x29 Type definitions for nested types

Param 0x08 Method parameters of methods

Property 0x17 Properties of types

TypeDef 0x02 Type definitions of types in current assembly

TypeRef 0x01 Type definitions of types external to this module

Metadata tables are collections of records and columns. A metadata table contains a certain type of data,
and each record is an instance of that type. Columns represent specific data on each instance, and each
column contains a constant or index. The index references another table or heap where the metadata token
is an example of an index. Metadata tokens are used as metadata pointers, allowing tables to
cross-reference each other. Metadata tables can be optimized (compressed) or not optimized. For the
purpose of this book, it is assumed that metadata is optimized. Metadata that is not optimized requires
intermediate tables for ordered access between tables.

Tokens

Metadata tokens cross-reference other metadata tables and heaps. Tokens are 4-byte unsigned integers
and a combination of the table identifier and RID. As shown in Figure 10-1, the high byte is the table
identifier, and the lower 3 bytes are the RID. A token into the Field table might be 04000002. The token
refers to the second row of the Field table. The RID is one-based, not zero-based. Because tokens are
padded with zeros, the run time might optimize them. Metadata tokens are probably the most public
manifestation of metadata. You will repeatedly see metadata tokens over the next few chapters.

Figure 10-1: Layout of a metadata token

In addition to other tables, metadata tables reference metadata heaps. Records of metadata tables hold
fixed-length metadata information. Variable-length data is stored in one of the metadata heaps. Methods
signatures are variable length and typical of content found on the String heap.

Metadata Heaps

The four metadata heaps are as follows: String, Userstring, Blob, and GUID.
 The String heap is an array of null-terminated strings. Namespace, type, field, and method
names, as well as other identifiers, are stored on the String heap.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 User-defined strings are not placed on the String heap but instead reside on the Userstring heap,
which is also an array of null-terminated strings. String literals from your program are cached on
this heap.
 The Blob heap is a binary heap and a composite of length prefix data, such as default values,
method signatures, and field signatures.
 The GUID heap is an array of globally unique identifiers (GUIDs). Yes, this is obvious. You might
remember GUIDs from COM as 16-byte unique identifiers assigned to almost everything—most
notably, class identifiers (CLSIDs) are assigned to class factories. What kind of GUID is stored on
the GUID heap? The GUID heap contains module version identifiers (MVIDs).

Streams

Physically, metadata tables and heaps are persisted in streams as part of an assembly. Six possible
streams, including streams for each metadata heap, are available in .NET. There are also two mutually
exclusive streams, optimized and nonoptimized, which are reservoirs of metadata tables. Metadata tables
are optimized or not optimized. There is no concept of partially optimized metadata tables. If the metadata
tables are optimized, the optimized stream is present. Otherwise, the nonoptimized stream is available.
Therefore, a managed application has at most five streams. Table 10-2 provides a complete list of the
metadata streams.
Table 10-2:
Metadata
Streams

Na De
me scr
ipti
on

#~ Op
tim
ize
d
or
co
mp
res
se
d
me
tad
ata
tab
les

#- No
no
pti
mi
ze
d
me
tad
ata
tab
les
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-2:
Metadata
Streams

Na De
me scr
ipti
on

#Bl Ph
ob ysi
cal
rep
osi
tor
y
of
the
blo
b
he
ap

#G Ph
UI ysi
D cal
rep
osi
tor
y
of
the
GU
ID
he
ap

#St Ph
rin ysi
g cal
rep
osi
tor
y
the
Stri
ng
he
ap
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-2:
Metadata
Streams

Na De
me scr
ipti
on

#U Ph
S ysi
cal
rep
osi
tor
y
of
the
Us
ers
trin
g
he
ap

Metadata Validation

Managed execution is largely dependent on metadata. Improperly formed metadata could cause a managed
application to fail unceremoniously. An assembly with bad metadata is like a house built on quicksand.
Loading a class, just-in-time compilation, code access security, and other run-time operations depend on
robust data. Metadata validation tests the correctness of metadata and is enacted preemptively, preventing
applications with inferior metadata from being executed. Preventing application crashes manifested by
improper metadata enforces code isolation.

Several tests are performed to validate metadata. Here is a short list:


 Cross-references between tables are validated.
 Offsets into metadata heaps are validated.
 Metadata tables must have a valid number of rows. For example, the Assembly table is allowed
one row.
 Metadata tables cannot have duplicate rows.
 Several more tests are enacted to certify metadata.

Developers can request metadata validation on demand with the PEVerify and Intermediate Language
Disassembler (ILDASM) tools. Both tools are included in the .NET Framework software development kit
(SDK).

PEVerify submits an assembly for metadata validation and Microsoft intermediate language (MSIL)
verification and then reports the results. (MSIL verification is discussed in Chapter 11, "MSIL Programming.")
This is the basic syntax for PEVerify:
 PEVerify assemblyname

PEVerify validates the metadata of assemblyname. If metadata validation is successful, MSIL verification is
applied next. MSIL verification is skipped if the metadata validation fails. If validation fails, execution is not
viable. This removes a compelling reason to conduct MSIL verification. PEVerify offers a variety of optional
arguments, including the capability to force MSIL verification even when the metadata validation fails.

Table 10-3 lists some of the PEVerify arguments.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-3:
PEVerify
Options

Ar De
gu scr
me ipti
nt on

/br Ab
ea ort
k= s
err veri
orc fica
ou tio
nt n
wh
en
err
ors
ex
ce
ed
err
orc
ou
nt.

/cl Col
oc lec
k ts
dat
a
an
d
rep
ort
s
dur
ati
on
of
veri
fica
tio
n
an
d
vali
dat
ion
tes
ts.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-3:
PEVerify
Options

Ar De
gu scr
me ipti
nt on

/he Hel
lp p
info
rm
ati
on
on
par
am
ete
rs.

/ig Ign
nor ore
e= s
err list
orc ed
od err
e1, or
err co
orc de
od s.
e2,
err
oro
co
de
n
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-3:
PEVerify
Options

Ar De
gu scr
me ipti
nt on

/il Co
nd
uct
s
MS
IL
veri
fica
tio
n.
Wh
en
yo
u
us
e
thi
s
co
m
ma
nd,
if
me
tad
ata
vali
dat
ion
is
als
o
req
uir
ed
it
mu
st
be
req
ue
ste
d
ex
plic
itly
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-3:
PEVerify
Options

Ar De
gu scr
me ipti
nt on

/m Co
d nd
uct
s
me
tad
ata
vali
dat
ion
. If
MS
IL
veri
fica
tio
n
an
d
me
tad
ata
vali
dat
ion
are
join
tly
de
sir
ed,
MS
IL
veri
fica
tio
n
sh
oul
d
be
req
ue
ste
d
ex
plic
itly
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-3:
PEVerify
Options

Ar De
gu scr
me ipti
nt on

/? Sa
me
as
the
/he
lp
arg
um
ent
.

The following is a simple Hello World application, which is compiled to hello.exe. It is a minimal application,
in which not much can go wrong. PEVerify will confirm this.

using System;

class Starter {
static void Main() {
Console.WriteLine("Hello, World!");
}
}

The following code shows the result of running PEVerify on Hello.exe with the /il and /clock options. Since
the md command is omitted, metadata verification is skipped.

c:\>peverify /il /clock hello.exe

All Classes and Methods in hello.exe Verified.


Timing: Total run 125 msec
IL Ver.cycle 125 msec
IL Ver.pure 93 msec

The elapsed cycle for validation and pure times is listed. Pure time is the duration of the actual metadata
validation, whereas cycle encapsulates the startup and shutdown processes.

ILDASM is a .NET tool that performs validation and can browse and display the metadata of an assembly.
ILDASM inspects an assembly using reflection and presents the results in a window, console, or file.

ILDASM Tool

ILDASM, which is a .NET disassembler and metadata browser, is a popular tool for developers. It proffers an
internal representation of an assembly, which includes the metadata and MSIL code of an assembly in a
variety of formats. ILDASM exercises reflection to inspect an assembly. The core syntax of ILDASM requires
only an assembly name, which opens ILDASM and displays the metadata of the assembly:
 ildasm assemblyname
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The following simple application is a basic .NET application that references a library. The simple application
has a ZClass and ZStruct type, whereas the dynamic-link library (DLL) publishes the YClass type.

using System;

namespace Donis.CSharpBook{

interface IA {
}

struct ZStruct {
}

class Starter {

public static void Main() {


YClass obj1=new YClass();
obj1.DisplayCreateTime();
ZClass obj2=new ZClass();
obj2.DisplayCreateTime();
}
}

class ZClass: IA {

public enum Flag {


aflag,
bflag
}

public event EventHandler AEvent=null;

public void DisplayCreateTime() {


Console.WriteLine("ZClass created at "+m_Time);
}

private string m_Time=DateTime.Now.ToLongTimeString();


public string Time {
get {
return m_Time;
}
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 10-2 is a view of Simple.exe from ILDASM. ILDASM displays a hierarchal object graph with an icon for
each element of the application.

Figure 10-2: Simple.exe displayed in ILDASM

Some icons are collapsible and expandable, as indicated by a + or - symbol. The Assembly icon expands to
show the details of the loaded assembly, the Namespace icon expands to show the members of the
namespace, and so on. You can drill down the object graph from the assembly down to the class members.
An icon depicts each item category of the graph. Table 10-4 describes each icon for which the action is
double-clicking the icon.
Table 10-4:
Elements of
ILDASM

Ico Act
n ion
De
scr
ipti
on
s

As Sh
se ow
mb s
ly ele
me
nts
of
the
as
se
mb
ly

Cla Sh
ss ow
s
me
mb
ers
of
a
cla
ss
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-4:
Elements of
ILDASM

Ico Act
n ion
De
scr
ipti
on
s

En Sh
um ow
s
me
mb
ers
of
en
um
typ
e

Ev Vie
ent ws
me
tad
ata
an
d
MS
IL
co
de
of
eve
nt

Fie Vie
ld ws
me
tad
ata
of
fiel
d

Int Sh
erf ow
ac s
e me
mb
ers
of
int
erf
ac
e
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-4:
Elements of
ILDASM

Ico Act
n ion
De
scr
ipti
on
s

Ma Vie
nife ws
st attr
ibu
tes
of
an
as
se
mb
ly

Me Vie
tho ws
d me
tad
ata
an
d
MS
IL
co
de
of
me
tho
d

Na Sh
me ow
sp s
ac me
e mb
ers
of
the
na
me
sp
ac
e
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-4:
Elements of
ILDASM

Ico Act
n ion
De
scr
ipti
on
s

Pro Vie
per ws
ty me
tad
ata
an
d
MS
IL
co
de
of
pro
per
ty

Sta Vie
tic ws
Fie me
ld tad
ata
of
sta
tic
fiel
d

Sta Vie
tic ws
Me me
tho tad
d ata
an
d
MS
IL
co
de
of
sta
tic
me
tho
d
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-4:
Elements of
ILDASM

Ico Act
n ion
De
scr
ipti
on
s

Val Sh
ue ow
Ty s
pe me
mb
ers
of
a
val
ue
typ
e

Some elements are displayed twice. For example, a property is presented as itself and separately as
accessor and mutator methods.

ILDASM has a variety of command-line options. Table 10-5 lists these parameters.
Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

Ou Re
t nd
ers
me
tad
ata
an
d
MS
IL
to
a
tex
t
file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

Te Re
xt nd
ers
me
tad
ata
an
d
rel
ate
d
MS
IL
to
co
ns
ole
.

HT Co
ML mb
ine
s
wit
h
the
out
opt
ion
to
dis
pla
y
me
tad
ata
an
d
MS
IL
in
an
HT
ML
for
ma
t.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

RT Re
F nd
ers
me
tad
ata
an
d
MS
IL
in
Ric
h
Te
xt
For
ma
t.

Byt Sh
es ow
s
MS
IL
co
de
wit
h
op
co
de
s
an
d
rel
ate
d
byt
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

Ra Sh
we ow
h s
lab
el
for
m
of
try
an
d
cat
ch
dir
ect
ive
s
in
raw
for
m.

To Sh
ke ow
ns s
me
tad
ata
tok
en
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

So Sh
urc ow
e s
MS
IL
int
erl
ac
ed
wit
h
co
m
me
nte
d
so
urc
e
co
de;
for
thi
s
co
m
ma
nd,
the
so
urc
e
co
de
an
d
de
bu
g
file
mu
st
be
ac
ce
ssi
ble
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

Lin Ins
en ert
um s
line
dir
ect
ive
s
int
o
an
out
put
str
ea
m
tha
t
ma
tch
es
so
urc
e
co
de
to
MS
IL.
Thi
s
co
m
ma
nd
req
uir
es
the
de
bu
g
file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

Vis Dis
ibili as
ty se
mb
les
onl
y
me
mb
ers
wit
h
the
sta
ted
visi
bilit
y:
pu
b
(pu
blic
),
pri
(pri
vat
e),
fa
m
(fa
mil
y),
as
m
(as
se
mb
ly),
FA
A
(fa
mil
y
an
d
as
se
mb
ly),
foa
(fa
mil
y
an
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

Pu Dis
bo as
nly se
mb
les
onl
y
pu
blic
ele
me
nts
;
sh
ort
not
ati
on
for
visi
bili
ty=
pu
b.

Qu Bra
ote ck
All ets
Na all
me ide
s ntifi
ers
in
sin
gle
qu
ote
s.

NO Ex
CA clu
de
s
cu
sto
m
attr
ibu
tes
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

CA Dis
Ver pla
bal ys
blo
b
info
rm
ati
on
of
cu
sto
m
attr
ibu
tes
in
sy
mb
olic
for
m
an
d
not
bin
ary
.

NO Do
BA not
R dis
pla
y
pro
gre
ss
bar
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

UT Re
F8 nd
ers
out
put
file
in
UT
F8
(de
faul
t
AN
SI).

UN Re
IC nd
OD ers
E out
put
file
in
UN
IC
OD
E.

NO Do
IL not
dis
as
se
mb
le
lan
gu
ag
e
so
urc
e
co
de.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

For Ge
war ner
d ate
s
for
war
d
ref
ere
nc
es
an
d
as
se
mb
le
in
the
Cla
ss
Str
uct
ure
De
cla
rati
on
se
cti
on.

Ty Dis
pe pla
Lis ys
t list
of
typ
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

He Incl
ad ud
ers es
DO
S,
PE
,
CO
FF,
CL
R,
an
d
me
tad
ata
he
ad
er
info
rm
ati
on.

Ite Dis
m as
se
mb
les
a
par
tic
ula
r
cla
ss
or
me
tho
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

Sta Dis
ts pla
ys
sta
tist
ical
info
rm
ati
on
on
file,
PE
He
ad
er,
CL
R
He
ad
er,
an
d
me
tad
ata
.

Cla Pro
ss vid
Lis es
t a
co
m
me
nte
d
list
of
cla
ss
es
wit
h
attr
ibu
tes
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

All Co
mb
ina
tio
n
of
the
He
ad
er,
Byt
es,
Sta
ts,
Cla
ss
Lis
ts,
an
d
To
ke
ns
co
m
ma
nd
s.

Me Dis
tad pla
ata ys
sp
ecif
ic
info
rm
ati
on
rel
ate
d
to
me
tad
ata
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-5:
ILDASM
Options

IL De
DA scr
SM ipti
Op on
tio
n

Ob Sh
jec ow
tfil s
e me
tad
ata
of
a
libr
ary
file.

The user interface of ILDASM presents the same choices as the command-line options. The following
command line is typical. It disassembles simple.exe and outputs the resulting metadata, MSIL, metadata
tokens, and source code in the simple.il file.

ildasm /out=simple.il /source /tokens simple.exe

The source option of the preceding command interlaces source code in between MSIL code. The source
code is commented. Associating MSIL to source code is invaluable when debugging.

The tokens generated per the tokens option are also commented. The disassembly created by ILDASM is a
valid MSIL program that can be recompiled (which is the reason for the il extension, as in client.il). The
assembly can be reassembled with the ILASM compiler, which compiles MSIL code. The newly assembled
assembly is identical to the original assembly.

Some ILDASM options impede the creation of a full disassembly. When a partial disassembly is requested,
ILDASM issues a warning, which prevents you from attempting to use a partial assembly as a full assembly.
One limitation is that partial assemblies cannot be reassembled using ILASM. The following command
creates a partial assembly:

ildasm /out=simple.il /item=Donis.CSharpBook.ZClass simple.exe

The preceding command targets only the ZClass of the simple.exe assemblies. Because other types are
omitted from the disassembly, it is not complete. For this reason, a warning is added to the output file.
Following is a partial listing of the output file with the embedded warning:

// Microsoft (R) .NET Framework IL Disassembler. Version 2.0.50601.0


// Microsoft Corporation. All rights reserved.

// warning : THIS IS A PARTIAL DISASSEMBLY, NOT SUITABLE FOR RE-ASSEMBLING

.class private auto ansi beforefieldinit Donis.CSharpBook.ZClass


extends [mscorlib]System.Object
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

implements Donis.CSharpBook.IA
{
.field private class [mscorlib]System.EventHandler AEvent
.field private string m_Time
.method public hidebysig specialname instance void

This is the final example of ILDASM and command-line options. This command profiles the metadata yields
counts, validates the metadata, and persists the results to the simple.txt file:

ildasm /metadata=csv /metadata=validate /out=simple.txt simple.exe


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Reflection
An assembly is a piñata stuffed with goodies such as type information, MSIL code, and custom attributes.
You use reflection to break open the assembly piñata to examine the contents. Reflection adds important
features to .NET, such as metadata inspection, run-time creation of types, late binding, MSIL extraction,
self-generating code, and so much more. These features are crucial to solving complex real-world problems
that developers face every day.

The Reflection namespace is the container of all things related to reflection. Assembly, Module,
LocalVariableInfo, MemberInfo, MethodInfo, FieldInfo, and Binder are some of the important members of the
Reflection namespace. Reflection exposes several predefined customer attributes, such as
AssemblyVersionAttribute, AssemblyKeyFileAttribute, and AssemblyDelaySignAttribute. The Reflection
namespace contains other reflection-related namespaces; most notably the Reflection.Emit nested
namespace. Reflection.Emit is a toolbox filled with tools for building assemblies, classes, and methods at
run time, including the ability to emit metadata and MSIL code. Reflection.Emit is reviewed in Chapter 11.

The central component of reflection is the Type object. Its interface can be used to interrogate a reference or
value type. This includes browsing methods, fields, parameters, and custom attributes. General information
pertaining to the type is also available via reflection, including identifying the hosting assembly. Beyond
browsing, Type objects support more intrusive operations. You can create instances of classes at run time
and perform late binding of methods.

Obtaining a Type Object

The Object.GetType method, the typeof operator, and various methods of the Assembly object return a Type
object. GetType is a member of the Object class, which is the ubiquitous base class. Therefore, GetType is
inherited by .NET types and available to all managed instances. Each instance can call GetType to return
the related Type object. The typeof operator extracts a Type object directly from a reference or value type.
Assembly objects have several members that return one or more Type objects. For example, the
Assembly.GetTypes method enumerates and returns the Types of the target assembly.

As a member base class object, GetType is accessible to all instances of reference and values types.
GetType returns the Type object of the instance. This is the syntax of the GetType method:

Type Type.GetType method:


Type GetType()

The following code creates instances of a value and a reference type, which are passed individually as object
parameters to successive calls to the DisplayType method, which homogenizes the objects, where each
object loses its distinction. The function extracts the type of the instance and displays the Type name.
Finally, if the Type represents a ZClass, the ZClass.Display method is called:

using System;

namespace Donis.CSharpBook{
class Starter{

static void Main() {


int localvalue=5;
ZClass objZ=new ZClass();
DisplayType(localvalue);
DisplayType(objZ);
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

static void DisplayType(object parameterObject) {


Type parameterType=parameterObject.GetType();
string name=parameterType.Name;
Console.WriteLine("Type is "+name);
if(name == "ZClass") {
((ZClass) parameterObject).Display();
}
}

class ZClass {

public void Display() {


Console.WriteLine("ZClass::Display");
}
}
}

The typeof operator returns a Type object from a type. The typeof operator is evaluated at compile time,
whereas the GetType method is invoked at run time. For this reason, the typeof operator is quicker but less
flexible than the GetType method:

typeof operator:
typeof( type )

An assembly is typically the host of multiple types. Assembly.GetTypes enumerates the types defined in an
assembly. Assembly.GetType is overloaded four times. The zero-argument method returns the Type object
of the Assembly and essentially the GetType method derived from the Object class. The one-argument
version, in which the parameter is a string, returns a specific type defined in the assembly. The final two
versions of GetType are an extension of the one-argument overloaded method. The two-argument method
also has a Boolean parameter. When true, the method throws an exception if the type is not located. The
three-argument version has a second Boolean parameter that stipulates case sensitivity. If this parameter is
false, the case of the type name is significant.

Here are the methods:

Assembly.GetTypes method:
Type [] GetTypes()
Assembly.GetType method:
Type GetType()
Type GetType(string typename)
Type GetType(string typename, bool throwError)
Type GetType(string typename, bool throwError, bool ignoreCase)

An assembly can be diagrammed through reflection. The result is called the Reflection tree of that assembly.
Each element of reflection, such as an AssemblyInfo, Type, MethodInfo, and ParameterInfo component, is
placed on the tree. AppDomain is the root of the tree; GetAssemblies expands the tree from the root. The
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Reflection tree is a logical, not a physical representation. Assembly, Type, and ParameterInfo are some of
the branches on the Reflection tree. You can explore the Reflection tree while inspecting the metadata of the
application by using enumeration. For example, Assembly.GetCurrentAssembly returns the current
assembly. Assembly.GetTypes will enumerate the types defined in the assembly. Type.GetMethods will
enumerate the methods of each type. This process can continue until the application is fully reflected.

Figure 10-3: Diagram of the Reflection tree

Loading Assemblies

Assemblies near the root of the reflection tree can be loaded at run time using Assembly.Load and
Assembly.LoadFrom. Assembly.Load uses the assembly loader to locate and bind to the correct assembly.
Assembly.LoadFrom consults the assembly resolver to locate an assembly, which uses a combination of
the strong name identifier and probing to bind and then load an assembly. The strong name includes the
simple name, version, culture, and public key token of the assembly. Probing is the algorithm for locating an
assembly. Both Assembly.Load and Assembly.LoadFrom are static methods that are overloaded several
times. This is the core syntax:

Assembly.Load method:
static Assembly Assembly Load(string assemblyName)
Assembly.LoadFrom method:
static Assembly Assembly.LoadFrom(string AssemblyFileName)

When the chosen assembly isn't found, Assembly.Load and Assembly.LoadFrom will fail. The Assembly
Binding Log Viewer Tool (fuslogvw.exe), included in the .NET Framework SDK, is a useful tool for diagnosing
probing failures because it displays information on the binding error.

The following sample code accentuates the difference between Assembly.Load and Assembly.LoadFrom:

using System;
using System.Reflection;

namespace Donis.CSharpBook{
class Starter{
static void Main(){
Assembly library=Assembly.Load("library, Version=2.0.0.0, "+
"Culture=Neutral, PublicKeyToken=9b184fc90fb9648d");
Console.WriteLine("Assembly.Load: {0}", library.FullName);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

library=Assembly.LoadFrom("library.dll");
Console.WriteLine("Assembly.LoadFrom {0}", library.FullName);
}
}
}

Assembly.Load and Assembly.LoadFrom reference external assemblies. How about referencing the
currently executing assembly? Assembly.GetExecutingAssembly is a static method and returns a reference
to the currently executing assembly. This is valuable for interrogating the metadata or MSIL of the running
assembly.

Assembly.GetExecutingAssembly method:
static Assembly Assembly.GetExecutingAssembly()

Both Assembly.Load and Assembly.LoadFrom return a reference to an assembly. That assembly can be
reflected, code loaded, and then executed. Assembly.ReflectionOnlyLoad and
Assembly.ReflectionOnlyLoadFrom load an assembly only for reflection, so the code cannot be executed
later. Although you could reflect a type and iterate all the methods, you could not invoke a method of that
type. To confirm the way an Assembly is loaded, use the ReflectionOnly property. ReflectionOnly is a
Boolean attribute of an Assembly and is true if an Assembly is loaded for reflection only.
Assembly.ReflectionOnlyLoad and Assembly.ReflectionOnlyLoadFrom are equivalent to Assembly.Load and
Assembly.LoadFrom, respectively, without the execute capability. ReflectionOnly yields performance
benefits.

The following program benchmarks the performance of Assembly.Load versus Assembly.ReflectionOnlyLoad.


The DateTime function has poor resolution and is inferior for most testing scenarios. Instead, a
high-performance timer is needed to obtain added resolution. The QueryPerformanceCounter API returns a
high-performance counter accurate to a nanosecond. Prior to .NET Framework 2.0,
QueryPerformanceCounter was available only through interoperability. The Stopwatch class, which is a thin
wrapper for the QueryPerformanceCounter and related APIs, was introduced in .NET Framework 2.0 and
found in the System.Diagnostics namespace:

using System;
using System.Reflection;
using System.Diagnostics;

namespace Donis.CSharpBook{
class OnlyLoad{
static void Main() {
Stopwatch duration=new Stopwatch();
duration.Reset();
duration.Start();
Assembly a=Assembly.Load("library");
duration.Stop();
Console.WriteLine(duration.ElapsedTicks.ToString());
duration.Reset();
duration.Start();
a=Assembly.ReflectionOnlyLoad("library");
duration.Stop();
Console.WriteLine(duration.ElapsedTicks.ToString());
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
}

Execution time of Assembly.Load versus Assembly.ReflectionOnlyLoad might vary between different


implementations of the CLI and other factors. The program compares ticks, which is an abstraction of time.
Running the problem several times indicates that Assembly.ReflectionOnlyLoad is about 29 percent faster
than Assembly.Load. This is only an approximation.

Type.ReflectionOnlyGetType combines the functionality of Assembly.ReflectionOnlyLoad and the typeof


operator. The named assembly is loaded for inspection only, and a Type object is returned to the specified
type. Because the assembly is opened only for browsing, you cannot create an instance of the type or
invoke a method on the type. ReflectionOnlyGetType is a static method of the Type class and loads a Type
for inspection only. The method returns a Type object:

Type.ReflectionOnlyType method:
static Type ReflectionOnlyType(string typeName, bool notFoundException,
bool ignoreCase)

The typeName parameter is a combination of the Assembly and Type names. The Assembly and Type
names are comma-delimited. To raise an exception if the type is not found, set the notFoundException
parameter to true. When false, the ignoreCase parameter indicates that the Type name is case sensitive:

using System;
using System.Reflection;

namespace Donis.CSharpBook{
class ReflectOnlyType{

static void Main() {


Type zType=Type.ReflectionOnlyGetType("Donis.CSharpBook.ClassA,
Library", false, false);
Console.WriteLine(zType.Name);
}
}
}

Browsing Type Information

Inspecting a type begins with the Type object. Reflection has a straightforward interface for mining the
metadata of a type. Inspecting the metadata of a type essentially consists of spanning a series of
collections. The Type object interface publishes several methods and properties related to reflection.

Type.GetMembers returns the ultimate collection: the collection of all members. All members, whether the
member is a method, field, event, or property, are included in the collection. GetMembers returns a
MemberInfo array that contains an item for each member. GetMember returns a single MemberInfo object
for the named member. MemberInfo.MemberType is a property of the MemberInfo.MemberTypes type, which
is a bitwise enumeration distinguishing a member as a method, field, property, event, constructor, or
something else. (See Table 10-6.) MemberInfo has relatively few properties and operations. Here are some of
the more useful. The MemberInfo.Name offers the name of the type member. MemberInfo.MetadataToken,
another property, returns the metadata token of the member. MemberInfo.ReflectedType provides the Type
object from which the MemberInfo object was extracted.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-6:
MemberTypes
Enumeration

Me Va
mb lue
er
Ty
pe

Me 0x
mb 01
erT
ype
s.C
on
str
uct
or

Me 0x
rm 40
ber
Ty
pe
s.C
ust
om

Me 0x
mb 02
erT
ype
s.E
ven
t

Me 0x
mb 04
erT
ype
s.F
ield

Me 0x
mb 08
erT
ype
s.
Me
tho
d
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-6:
MemberTypes
Enumeration

Me Va
mb lue
er
Ty
pe

Me 0x
mb 80
erT
ype
s.N
est
ed
Ty
pe

Me 0x
mb 10
erT
ype
s.P
rop
ert
y

Me 0x
mb 20
erT
ype
s.T
ype
Inf
o

Me 0x
mb BF
erT
ype
s.A
ll

Type.GetMembers creates a basket that contains all the members of the reflected type. You can be
somewhat more granular. Type.GetMethods or Type.GetMethod returns a collection of methods or a specific
method. Type.GetFields or Type.GetField similarly returns a collection of fields or a specific field. Table 10-7
lists the methods that return specific collections where the nonplural method returns a specific member of
that collection.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-7: Type


Methods That Return
Metadata Collections

Me Re Ty
tho tur pe
d ns of
Me
mb
er

Ge Co Co
tCo nst nst
nst ruc ruc
ruc torI tor
tor nfo
s []

Ge Ob Cu
tCu jec sto
sto t [] m
mA attr
ttri ibu
but te
es

Ge Me Def
tDe mb aul
fau erI t
ltM nfo me
em [] mb
ber er
s

Ge Ev Ev
tEv ent ent
ent Inf
s o []

Ge Fie Fie
tFi ldI ld
eld nfo
s []

Ge Ty Im
tInt pe ple
erf [] me
ac nte
es d
int
erf
ac
e

Ge Me All
tM mb me
em erI mb
ber nfo ers
s []
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-7: Type


Methods That Return
Metadata Collections

Me Re Ty
tho tur pe
d ns of
Me
mb
er

Ge Me Me
tM tho tho
eth dIn d
od fo
s []

Ge Ty Ne
tNe pe ste
ste [] d
dT Ty
ype pe
s

Ge Pro Pro
tPr per per
op tyI ty
erti nfo
es []

The Type.GetMethods that return MethodInfo arrays are overloaded to be called with no parameters or with a
single parameter, which is BindingFlags:

Type. GetMethods method:


MethodInfo [] GetMethods ();
MethodInfo[] GetMethods (BindingFlags binding)

BindingFlags is a bitwise enumeration that filters the results of a collection. For example, to include private
members in a collection stipulates the BindingFlags.NonPublic flag. Some BindingFlags, such as
InvokeMember, are not applicable in this context. When stipulating BindingFlags, there are no default flags.
If you specify one flag, you must specify every required flag. Each inclusion must be specified explicitly. The
zero-argument version of GetMethods grants default bindings, which vary depending on the method. At a
minimum, most of the methods default to BindingFlags.Public and BindingFlags.Instance. Notably, the
BindingFlags.Static flag is not always defaulted and static members are often excluded from a collection.
The following code first iterates private instance (nonpublic) members. Afterward, static public members are
iterated.

using System;
using System.Reflection;

namespace Donis.CSharpBook{
class DumpType{
public static void Main() {
ZClass zObj=new ZClass();
Type tObj=zObj.GetType();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

MemberInfo [] members=tObj.GetMembers(
BindingFlags.Instance|
BindingFlags.NonPublic);
foreach(MemberInfo member in members) {
Console.WriteLine(member.Name);
}
members=tObj.GetMembers(
BindingFlags.Public|BindingFlags.Static);

Console.WriteLine(" ");
foreach(MemberInfo member in members) {
Console.WriteLine(member.Name);
}
}
}

class ZClass {
private int vara=5;
public int PropA {
get {
return vara;
}
}
static public void MethodA() {
Console.WriteLine("ZClass::MethodA called.");
}
}
}

The following application calls DumpMethods to dump the public methods of a class. This code
demonstrates various aspects of Reflection.

using System;
using System.Reflection;

namespace Donis.CSharpBook{
class DumpType{
static void Main(string [] argv) {
targetType=LoadAssembly(argv[0], argv[1]);
DumpReportHeader();
DumpMethods();
}

static public Type LoadAssembly(string t, string a) {


return Type.ReflectionOnlyGetType(t+","+a, false, true);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

static void DumpReportHeader() {


Console.WriteLine("\n{0} type of {1} assembly",
targetType.Name, targetType.Assembly.GetName().Name);
Console.WriteLine("\n{0,22}\n", "[ METHODS ]");
}

static void DumpMethods() {


string dashes=new string('-', 50);
foreach(MethodInfo method in targetType.GetMethods()) {
Console.WriteLine("{0,12}{1,-12}", " ", method.Name+" "+
"<"+method.ReturnParameter.ParameterType.Name+">");
int count=1;
foreach(ParameterInfo parameter in method.GetParameters()){
Console.WriteLine("{0, 35}{1, -12}",
" ", (count++).ToString()+" "+ parameter.Name+
" ("+parameter.ParameterType.Name+")");
}

Console.WriteLine("{0,12}{1}", " ", dashes);


}
}

private static Type targetType;


}
}

In the preceding code, a type name and an assembly name are read from the command line. The type to be
dumped is argv[0], while the assembly hosting the type is argv[1]. With this information, the LoadAssembly
method employs Type.ReflectionOnlyGetType and loads the type for inspection only. The DumpMethods
function iterates the methods of the target type, and then iterates the parameters of each method. The name
of each method and parameter is displayed. This dumps the members of the Console class:

dumpmethods System.Console mscorlib.dll

Dynamic Invocation

Methods can be dynamically invoked at run time using reflection. The benefits and perils of early binding
versus late binding were reviewed in the discussion on delegates earlier in the book.

In dynamic binding, you build a method signature at run time and then invoke the method. This is somewhat
later than late binding with delegates. When compared with delegates, dynamic binding is more flexible, but
is regrettably slower. At compile time, the method signature must match the delegate at the site of the
run-time binding. Dynamic binding removes this limitation, and any method can be invoked at the call site,
regardless of the signature. This is more flexible and extensible than run-time binding.

In reflection, there are two approaches to invoking a method dynamically: MethodInfo.Invoke and
Type.InvokeMember, where MethodInfo.Invoke is the simplest solution. However, Type.InvokeMember is
more malleable. The basic syntax of MethodInvoke requires only two parameters: an instance of a type and
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

an array of parameters. The method is bound to the instance provided. If the method is static, the instance
parameter is null. To avoid an exception at run time, which is never fun, care must be taken to ensure that
the instance and parameters given to MethodInfo.Invoke match the signature of the function.

This is the MethodInfo.Invoke syntax:

object Invoke 1(object obj, object [] arguments)


object Invoke 2 (object obj, BindingFlags flags, Binder binderObj,
object [] arguments, CultureInfo culture)

The second Invoke method has several additional parameters. The obj parameter is the instance that
method is bound. If invoking a static method, the obj parameter should be null but is otherwise ignored.
BindingFlags are next and further describe the Invoke operation, such as Binding.InvokeMethod. When no
binding flags are specified, the default is BindingFlags.DefaultBinding. Binderobj is used to select the
appropriate candidate among overloaded methods. Arguments is the array of method arguments as defined
by the method signature. The culture argument sets the culture, which defaults to the culture of the system.
Return is the method return or null for a void return.

Alternatively, you can invoke a method dynamically at run time using Type.InvokeMember, which is
overloaded several times.

This is the Type.InvokeMember syntax:

object InvokeMember 1(string methodName, BindingFlags flags,


Binder binderObj, object typeInstance, object [] arguments)
object InvokeMember 2(string methodName, BindingFlags flags,
Binder binderObj, object typeInstance, object [] arguments,
CultureInfo culture)
object InvokeMember 3(string methodName, BindingFlags flags,
Binder binderObj, object typeInstance, object [] arguments,
ParameterModifier [] modifiers, CultureInfo culture,
string [] namedParameters)

InvokeMember 1 is the core overloaded method, and it has several parameters. The methodName parameter
is the name of the method to invoke. The next parameter is BindingFlags. Binderobj is the binder used to
discriminate between overloaded methods. The object to bind the method again is typeInstance. arguments
is the array of method parameters. InvokeMember 2 adds an additional parameter. To set the culture, use the
culture parameter. InvokeMember 3 is the final overload with one additional parameter: namedParameters,
which is used to specify named parameters.

In the following code, dynamic invocation is demonstrated with MethodInfo.Invoke and Type.InvokeMember:

using System;
using System.Reflection;

namespace Donis.CSharpBook{

class Starter{

static void Main(){


ZClass obj=new ZClass();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Type tObj=obj.GetType();
MethodInfo method=tObj.GetMethod("MethodA");

method.Invoke(obj, null);
tObj.InvokeMember("MethodA", BindingFlags.InvokeMethod,
null, obj, null);
}
}
class ZClass {

public void MethodA() {


Console.WriteLine("ZClass.Method invoked");
}
}
}

Binders
Members such as methods can be overloaded. In reflection, binders determine the specific method to invoke
from a list of possible candidates. The default binder selects the best match based on the number and type
of arguments. You can provide a custom binder and choose a specific overloaded member. Both
MethodInfo.Invoke and Type.InvokeMember offer a binder argument for this reason.

The Binder class is an abstract class; as such, it is implemented through a derived concrete class. Binder
has abstracted methods to select a field, property, and method from available overloaded candidates. Binder
is a member of the Reflection namespace. Table 10-8 lists the public members of the Binder class. Each
method included in the table is abstract and must be overridden in any derivation.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-8:
Abstract
Methods of
the Binder
Class

Bi De
nd scr
er ipti
Me on
tho
d

Bin Sel
dT ect
oFi s
eld a
fiel
d
fro
m
a
set
of
ove
rlo
ad
ed
fiel
ds

Bin Sel
dT ect
oM s
eth a
od me
tho
d
fro
m
a
set
of
ove
rlo
ad
ed
me
tho
ds

Ch Co
an erc
ge es
Ty the
pe typ
e
of
an
obj
ect
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-8:
Abstract
Methods of
the Binder
Class

Bi De
nd scr
er ipti
Me on
tho
d

Re Re
ord set
erA s
rgu the
me arg
ntA um
rra ent
y arr
ay;
as
so
cia
ted
wit
h
the
sta
te
par
am
ete
r
of
Bin
dT
oM
eth
od
me
mb
er
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-8:
Abstract
Methods of
the Binder
Class

Bi De
nd scr
er ipti
Me on
tho
d

Sel Sel
ect ect
Me s
tho a
d me
tho
d
fro
m
ca
ndi
dat
e
me
tho
ds

Sel Sel
ect ect
Pro s
per a
ty pro
per
ty
fro
m
ca
ndi
dat
e
pro
per
tie
s

Binder.BindToMethod is called when a method is invoked dynamically. To override the default selection
criteria of overloaded methods, create a custom binder class. Inherit the binder class and at least minimally
override and implement each abstract method of the base class. How the binder is used determines the
methods to fully implement. If the MethodInfo.Invoke and Type.InvokeMember methods are called with the
BindingFlags.InvokeMethod flag set, BindToMethod will be invoked and should be completely implemented.

The Binder.BindToMethod syntax is as follows:

public abstract BindToMethod(BindingFlags flags, MethodBase [] match,


ref object [] args, ParameterModifier [] modifiers, CultureInfo culture,
string [] names, out object state)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The first parameter of BindToMethod is BindingFlags, which is the usual assortment of binding flags. match
is a MethodBase array with an element for each possible candidate. If there are three candidates, match has
three elements. At present, MethodBase-derived classes are limited to ConstructorInfo; MethodInfo.args are
the values of method parameters. Modifiers is an array of ParameterModifier used with parameter signatures
of modified types. Culture sets the culture. Names are the identifiers of methods included as candidates. The
modifiers, culture, and names parameters can be null. The final parameter, state, is used with parameter
reordering. If this parameter is non-null, Binder.ReorderArgumentArray is called after BindToMethod and
returns the parameters to the original order.

There is no prescription for selecting a method from a set of candidates. You are free to be creative and
employ whatever logic seems reasonable. Here is a partially implemented but workable custom Binder
class. BindToMethod is implemented but the other methods are essentially stubbed. This code is somewhat
circumscribed and not written for general-purpose application.

using System;
using System.Reflection;
using System.Globalization;

class CustomBinder:Binder {
public override FieldInfo BindToField(BindingFlags bindingAttr,
FieldInfo[] match, object value, CultureInfo culture) {
return null;
}

public override MethodBase BindToMethod(BindingFlags bindingAttr,


MethodBase[] match, ref object[] args,
ParameterModifier[] modifiers, CultureInfo culture,
string[] names, out object state) {
Console.WriteLine("Overloaded Method:");
foreach(MethodInfo method in match) {
Console.Write("\n {0} (", method.Name);
foreach(ParameterInfo parameter in
method.GetParameters()) {
Console.Write(" "+parameter.ParameterType.ToString());
}
Console.WriteLine(")");
}
Console.WriteLine();
state=null;
if(long.Parse(args[0].ToString())>int.MaxValue) {
return match[0];
}
else {
return match[1];
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public override object ChangeType(object value, Type type,


CultureInfo culture) {
return null;
}

public override void ReorderArgumentArray(ref object[] args,


object state){
}

public override MethodBase SelectMethod(BindingFlags bindingAttr,


MethodBase[] match, Type[] types,
ParameterModifier[] modifiers) {
return null;
}

public override PropertyInfo SelectProperty(BindingFlags bindingAttr,


PropertyInfo[] match, Type returnType, Type[] indexes,
ParameterModifier[] modifiers) {
return null;
}
}

class ZClass {
public void MethodA(long argument) {
Console.WriteLine("Long version: "+argument.ToString());
}

public void MethodA(int argument) {


Console.WriteLine("Int version: "+argument.ToString());
}

public void MethodA(int argument, int argument2) {


Console.WriteLine("ZClass::Method 2 arg");
}
}

class Starter {
public static void Main() {
ZClass obj=new ZClass();
Type tObj=obj.GetType();
CustomBinder theBinder=new CustomBinder();
tObj.InvokeMember("MethodA", BindingFlags.InvokeMethod,
theBinder, obj, new Object[] {int.MinValue});
Console.WriteLine();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

tObj.InvokeMember("MethodA", BindingFlags.InvokeMethod, theBinder,


obj, new Object[] {long.MaxValue});
}
}

In the preceding code, CustomBinder inherits from the Binder class. As mentioned, BindToMethod is the
sole method implemented in the code. This function lists the signatures of each candidate. The appropriate
method is then chosen. The first foreach loop iterates the candidates while listing the method names. The
inner foreach loop iterates and lists the parameters of each MethodInfo object. This version of BindToMethod
is written specifically for the one-argument methods of the ZClass BindToMethod. The argument value is
tested. If the value is within the range of a long, the first method is returned. This method has a long
parameter. Otherwise, the second candidate, which has an integer parameter, is returned.

In Main, an instance of the ZClass and custom binder is created. ZClass is a simple class with an
overloaded method. ZClass.MethodA is overloaded three times. The type object is then extracted from the
ZClass instance, and Type.InvokeMember is called twice with the custom binder. InvokeMember is called to
dynamically invoke "MethodA", first with an integer parameter and then with a long parameter. This is the
output from the application:

Overloaded Method:
MethodA ( System.Int64 )

MethodA ( System.Int32 )

Int version: -2147483648

Overloaded Method:

MethodA ( System.Int64 )

MethodA ( System.Int32 )

Long version: 9223372036854775807

Type Creation

Until now, the emphasis of this chapter has been on reflecting existing objects. Object instances can also
be created dynamically at run time. You can reflect, bind methods, and otherwise treat the dynamic object
as a static object. As often with Reflection, the primary benefit is added flexibility. What if the type of an
instance is not determinable at compile time? With Reflection, that decision can be delayed until run time,
when the particular class can be chosen by the user, stipulated in a configuration file, or otherwise selected
by some intermediary.

The Activator class is a member of the Reflection namespace and facilitates the creation of objects at run
time. Activator consists of four static member methods: CreateInstance creates an instance of a type;
CreateInstanceFrom leverages Assembly.LoadFrom to reference an assembly and then create an instance
of a type found in the assembly; and CreateComInstanceFrom and GetObject instantiate a COM object and
a proxy to a Remote object, respectively. To simply create an instance of a .NET type, call CreateInstance
or CreateInstanceFrom. Both CreateInstance and CreateInstanceFrom are overloaded several times. This is
the list of CreateInstance methods:

Activator.CreateInstance syntax:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

static T CreateInstance<T>()
static public ObjectHandle CreateInstance(ActivationContext context)
static object CreateInstance(Type type)
static public ObjectHandle CreateInstance(ActivationContext context, string
[] customData)
static ObjectHandle CreateInstance(string assemblyName, string typeName)
static object CreateInstance(Type type, bool ctorPublic)
static object CreateInstance(Type type, object [] ctorArgs)
static ObjectHandle CreateInstance<T, U> (T, U)
static ObjectHandle CreateInstance(string assemblyName, string typeName,
object [] activationAttributes)
static object CreateInstance(string assemblyName, string TypeName,

object [] activationAttributes)
static object CreateInstance(Type type, BindingFlags bindingAttr,
Binder binder, object [] args, CultureInfo culture)
static object CreateInstance(Type type, object [] args, object []
activationAttributes)
static Object CreateInstance(Type type, BindingFlags bindingAttr, Binder
binder,
object [] args, CultureInfo culture, object [] activationAttributes)
static ObjectHandle CreateInstance(string assemblyName, string typeName,
bool ignoreCase, BindingFlags bindingAttr, Binder Binder,
object [] args, CultureInfo culture, object [] activationAttributes,
Evidence securityInfo)

Some CreateInstance methods—and all CreateInstanceFrom methods—return an ObjectHandle, which is


usually returned when creating an instance of a type foreign to the current assembly. ObjectHandle is found
in the System.Runtime.Remoting namespace. ObjectHandle.Unwrap unwraps the ObjectHandle to disclose
a proxy to the remoted object. Alternatively, the AppDomain.CreateInstanceFromAndUnwrap method creates
an instance of the type and returns the object unwrapped with one less step. Of course, this means that an
additional step of obtaining an AppDomain object is necessary. However, if the AppDomain object is handy,
CreateInstanceFromAndUnwrap is convenient.

The following code creates three instances of the same type. A local and two remote proxies to object
instances are constructed:

using System;
using System.Reflection;
using System.Runtime.Remoting;

namespace Donis.CSharpBook{

class ZClass {
public void MethodA(DateTime dt) {
Console.WriteLine("MethodA invoked at "+
dt.ToLongTimeString());
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

class Starter{

static void Main() {


CreateLocal();
CreateRemote1();
CreateRemote2();
}

static void CreateLocal() {


object obj=Activator.CreateInstance(typeof(ZClass));
((ZClass) obj).MethodA(DateTime.Now);
}

static void CreateRemote1() {


ObjectHandle hObj=Activator.CreateInstance("library",
"Donis.CSharpBook.ZClass");
object obj=hObj.Unwrap();

MethodInfo method=obj.GetType().GetMethod("MethodA");
method.Invoke(obj, new object [1] {DateTime.Now});
}

static void CreateRemote2() {


AppDomain domain=AppDomain.CurrentDomain;
object obj=domain.CreateInstanceFromAndUnwrap("library.dll",
"Donis.CSharpBook.ZClass");
MethodInfo method=obj.GetType().GetMethod("MethodA");
method.Invoke(obj, new object [1] {DateTime.Now});
}

}
}

The preceding code presents three vehicles for creating an instance of a type, binding a method to the type,
and finally invoking that method dynamically. Dynamically invoking a method through casting is a
mechanism not previously demonstrated. (Method.Invoke and Type.InvokeMember were reviewed earlier.)

The code for engaging a method through casting is listed as follows. Calling a method dynamically through
casting has substantial performance gains when compared with MethodInfo.Invoke or Type.InvokeMember. (
MethodInfo.Invoke and Type.InvokeMember were reviewed earlier in this chapter.)

((ZClass) obj).MethodA(DateTime.Now);

Either directly or indirectly, the Activator.CreateInstance and CreateInstanceFrom methods return an object.
As the preceding code demonstrates, you can cast the generic object to a specific type and invoke the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

chosen method. This combines late and early binding, which has significant performance benefits when
compared with late binding the type and method.

Late Binding Delegates

A delegate is a repository of type-safe function pointers. A single-cast delegate holds one function pointer,
whereas a multicast delegate is a basket of one or more delegates. Delegates are type-safe because the
signatures of the delegate and function pointer must match. Normally a compile error is generated if there is
a mismatch. Unlike MethodInfo, a function pointer is discriminatory and bound to a specific object.
MethodInfo is nondiscriminatory and can be associated with any affiliated object. This is the reason why
MethodInfo.Invoke and Type.InvokeMember methods have an object parameter to associate an instance
with the target method. This section assumes a fundamental understanding of delegates. If you would like a
review, take a look at Chapter 8, "Delegates and Events." The following code is typical of delegates:

using System;
using System.Reflection;

namespace Donis.CSharpBook{
delegate void XDelegate(int arga, int argb);

class ZClass {
public void MethodA(int arga, int argb) {
Console.WriteLine("ZClass.MethodA called: {0} {1}", arga, argb);
}
}

class Starter{
static void Main(){
ZClass obj=new ZClass();
XDelegate delObj=new XDelegate(obj.MethodA);
delObj.Invoke(1,2);
delObj(3,4);
}
}
}

In this code, XDelegate is the delegate type. MethodA is then added to the delegate and invoked. First,
invoke using the Delegate.Invoke method. Second, invoke the function through the delegate using the C#
syntax. At compile time, XDelegate expands into a class derived from a Delegate type. The Invoke method
is the most important member implemented and added to the class interface of the derived type. The
signature of Invoke matches the signature of the delegate. Therefore, XDelegate.Invoke has two integer
parameters and enforces type safeness of related function pointers.

The preceding code assumes the delegate signature is known at compile time. What if the signature of the
delegate is not known at compile time? Because a delegate is an implied class that is similar to any class,
you can create an instance of a delegate at run time, bind a method to the delegate, and invoke the method.
Instead of invoking a member method, a function pointer is bound and executed against the delegate. The
Delegate.CreateDelegate and Delegate.DynamicInvoke methods provide this behavior. Late binding is not as
type-safe as compile-time type checking. (This also pertains to late binding of delegates.) Care must be
taken to avoid run-time exceptions. As always, the seminal benefit of late binding is additional flexibility, but
performance might suffer.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

CreateDelegate constructs a new delegate at run time and then assigns a function pointer to the newly
invented delegate. CreateDelegate is an overloaded method where the essential parameters are the delegate
type and method identity. The delegateType is the type of delegate being created. Method is the initial
function pointer being assigned to the delegate. The signature of the method represented by a MethodInfo
object should match that of the delegate type. These are the overloaded methods:

The Delegate.CreateDelegate syntax is as follows:

static Delegate CreateDelegate(Type type, MethodInfo method)


static Delegate CreateDelegate(Type type, MethodInfo method, bool
thrownOnBindFailure)
static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo
method)
static Delegate CreateDelegate(Type type, object target, string method)
static Delegate CreateDelegate(Type type, Type target, string method)

static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo


method, bool
throwOnBindFailure)
static Delegate CreateDelegate(Type type, object target, string method,
bool ignoreCase)
static DelegateCreateDelegate(Type type, object firstArgument, Type target,
string method)
static Delegate CreateDelegate(Type type, Type target, string method, bool
ignoreCase)
static Delegate CreateDelegate(Type type, object target, string method, bool
ignoreCase,
bool throwOnBindFailure)
static Delegate.CreateDelegate(Type type, object firstArgument, Type target,
string method,
bool ignoreCase)
static Delegate.CreateDelegate(Type type, Type target, string method, bool
ignoreCase, bool
throwOnBindFailure)
static Delegate.CreateDelegate(Type type, object firstArgument, Type target,
string method,
bool ignoreCase, bool throwOnBindFailure)

After creating a delegate at run time, call DynamicInvoke to invoke any function pointers assigned to the
delegate. The dynamically created delegate is deprived of the Invoke method and language-specific
operations. Subsequently, you cannot call the Invoke method on a delegate returned from CreateDelegate.
This is the major difference between compile-time and run-time instances of delegates. An array of function
arguments is the only parameter of DynamicInvoke.

This is the DynamicInvoke syntax:

object DynamicInvoke(object [] args)

CreateDelegate and DynamicInvoke are demonstrated in the following code:


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System;
using System.Reflection;

namespace Donis.CSharpBook{
delegate void theDelegate(int arga, int argb);

class ZClass {
public void MethodA(int arga, int argb) {
Console.WriteLine("ZClass.MethodA called: {0} {1}", arga, argb);
}
}

class Starter{
static void Main(){
Type tObj=typeof(System.MulticastDelegate);
ZClass obj=new ZClass();
Delegate del=Delegate.CreateDelegate(typeof(theDelegate), obj,
"MethodA");
del.DynamicInvoke(new object [] {1,2});
}
}
}

Function Call Performance

Several ways to invoke a method have been presented in this chapter—from a simple method call to the
more complex dynamic invocation. Performance is an important criterion when evaluating competing
methodologies. For example, a simple call bound at compile time should be quicker than a method bound at
run time. Depending on the application, the differentiation might be material. Losing a few nanoseconds
occasionally might not be conspicuous in a user interface—driven application. However, a few lost
nanoseconds in a server application multiplied by thousands of users can pose a real problem.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Reflection and Generics


In .NET Framework 2.0, Reflection is extended to accommodate open and closed generic types and
methods. Predictably, the Type class is the focal point of changes to accommodate generic types. For
generic methods, MethodInfo has been enhanced to reflect generic methods. (Generics were introduced in
Chapter 6.) Open types are generic types with unbound type parameters, whereas closed types have bound
type parameters. With Reflection, you can browse bound and unbound parameters, create instances of
generic types, and invoke generic methods at run time.

IsGeneric and IsGenericTypeDefinition

With Reflection, you can query the state of a generic type of method. Is this a generic type or method? If
confirmed, is the generic type or method open or closed? Type.IsGeneric is a Boolean property that confirms
the presence of a generic type; Type.IsGenericTypeDefinition, another Boolean property, indicates whether
the generic is open or closed. For methods, the MethodInfo.IsGenericMethod property confirms that a
method is a generic method, whereas the MethodInfo.IsGenericTypeDefinition property indicates whether the
generic method is open or closed. This program demonstrates the four properties:

using System;
using System.Reflection;

public class ZClass<T, V> {


public T membera;
}

public class XClass {


public void MethodA<T>() {
}
}

namespace Donis.CSharpBook{

class Starter{

static void Main(){


Type [] types={typeof(ZClass<,>), typeof(ZClass<int,int>)};
bool [,] bresp= { {types[0].IsGenericType,
types[0].IsGenericTypeDefinition},
{types[1].IsGenericType,
types[1].IsGenericTypeDefinition}};
Console.WriteLine("Is ZClass<,> a generic type? "+bresp[0,0]);
Console.WriteLine("Is ZClass<,> open? "
+bresp[0,1]);
Console.WriteLine("Is ZClass<int,int> a generic type? "
+bresp[1,0]);
Console.WriteLine("Is ZClass<int,int> open? "+bresp[1,1]);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Type tObj=typeof(XClass);
MethodInfo method=tObj.GetMethod("MethodA");
bool [] bMethod={method.IsGenericMethod,
method.IsGenericMethodDefinition};
Console.WriteLine("Is XClass.MethodA<T> a generic method? "
+bMethod[0]);
Console.WriteLine("Is XClass.MethodA<T> open? "+bMethod[1]);
}
}
}

typeof

The typeof operator is used in the preceding code to extract the Type object of an open or constructed type.
The Type object has a single parameter, which is a string and identifies the generic type. Connote an open
type using empty parameters. For example, ZClass<T> would be ZClass<>. Multiple generic type
parameters are indicated with n-1 commas. For the typeof operator, ZClass<,> is compatible with
ZClass<K,V>. Indicate a closed type by including the actual parameter types, such as ZClass<int, int>. In
addition to the typeof operator, Type.GetType and Type.GetGenericTypeDefinition methods return Type
objects representing generic types.

GetType

Type.GetType is available in two flavors: an instance and a static method. Type.GetType is an instance
method and returns the open type used to construct the object. The method has no parameters. The
Type.GetType static method is overloaded to return a Type object for either an open or a closed type. The
pivotal parameter of the static GetType method is a string naming the generic type. To specify an open type,
the string is the name of the generic with the number of parameters affixed. The suffix is preceded with a "`".
For example, "NamespaceA .XClass`2" would represent XClass<K,V>. XClass has two type parameters.
For a closed type, you need to add the bound type parameters. After the number of type parameters, list the
bound type parameters. The bound type parameters are contained in square brackets.

"NamespaceB.ZClass`3[System.Int32, System.Int32, System.Decimal]" identifies ZClass <int, int, decimal>.


This is the general format:

Open type: GenericType`NumberofParameters


Closed Type: GenericType`NumofParameters[parameter list]

The following sample code demonstrates both the instance and static GetType methods:

using System;

namespace Donis.CSharpBook {

class ZClass<K,V> {
public void FunctionA(K argk, V argv) {
}
}

class XClass<T> {
public void FunctionB(T argt) {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

class Starter {

public static void Main() {


ZClass<int, decimal> obj=new ZClass<int, decimal>();
Type typeClosed=obj.GetType();
Console.WriteLine(typeClosed.ToString());

Type typeOpen=Type.GetType("Donis.CSharpBook.XClass`1");
Console.WriteLine(typeOpen.ToString());
Type typeClosed2=Type.GetType(
"Donis.CSharpBook.ZClass`2[System.Int32, System.Decimal]");
Console.WriteLine(typeClosed2.ToString());
}
}
}

GetGenericTypeDefinition

Closed types are constructed from open types. Type.GetGenericTypeDefinition returns the Type object of
the open type used to construct a closed type.

This is the Type.GetGenericTypeDefinition syntax:

Type GetGenericTypeDefinition()

The following code highlights the GetGenericTypeDefinition method:

using System;

namespace Donis.CSharpBook {

class ZClass<K,V> {
public void FunctionA(K argk, V argv) {
}
}

class Starter {

public static void Main() {


ZClass<int, decimal> obj=new ZClass<int, decimal>();
ZClass<string, float> obj2=new ZClass<string, float>();

Type closedType=obj.GetType();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Type openType=closedType.GetGenericTypeDefinition();

Type closedType2=obj2.GetType();
Type openType2=closedType2.GetGenericTypeDefinition();

Console.WriteLine(openType.ToString());
Console.WriteLine(openType2.ToString());
}
}
}

The preceding code displays identical strings. Why? The open type of ZClass<int, decimal> and
ZClass<string, float> is the same, which is ZClass<K, V>.

Type.GetMethod and MethodInfo.GetGenericMethodDefinition are comparable to Type.GetType and


Type.GetGenericTypeDefinition, respectively, but pertain to generic methods.

GetGenericArguments

You can now extract a Type object for a generic type and a MethodInfo object for a generic method.
Determining the number of unbound or bound parameters is a natural next step. If bound, the type of each
parameter would be useful. GetGenericArguments is the universal method for enumerating parameters of
generic type or method. GetGenericArguments enumerates unbound and bound parameters.

This is the Type.GetGenericArguments syntax:

Type [] GetGenericArguments()
MethodInfo.GetGenericArguments syntax:
Type [] GetGenericArguments()

The following code demonstrates both Type.GetGenericArguments and MethodInfo.GetGenericArguments:

using System;

namespace Donis.CSharpBook {

class ZClass<K,V> {
public void FunctionA(K argk, V argv) {

}
}

class Starter {

public static void Main() {


ZClass<int, decimal> obj=new ZClass<int, decimal>();
ZClass<string, float> obj2=new ZClass<string, float>();

Type closedType=obj.GetType();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Type openType=closedType.GetGenericTypeDefinition();

Type closedType2=obj2.GetType();
Type openType2=closedType2.GetGenericTypeDefinition();

Console.WriteLine(openType.ToString());
Console.WriteLine(openType2.ToString());
}
}
}

Creating Generic Types

Generic types can be created at run time using Reflection. First, extract the open type of the generic. This
chapter has shown several ways to accomplish this, including using GetType and GetGenericTypeDefinition.
Next, bind the type arguments of the open type. The result will be a bound (closed) type. Finally, create an
instance of the bound type in the customary manner. (Activator.CreateInstance works well.)

The Type.MakeGenericType method binds type parameters to an open type of a generic. MakeGenericType
has a single parameter, which is an array of Type objects. Each element of the array matches a specific
type to a generic parameter. If the generic has three parameters, the array passed to MakeGenericType will
have three elements—each representing a bound parameter.

This is the prototype of the MakeGenericType method:

Type.MakeGenericType syntax:
void MakeGenericType(Type [] genericArguments)

Generic methods, like nongeneric methods, can be invoked dynamically at run time.
MethodInfo.MakeGenericType binds parameters to generic types, similar to Type.MakeGenericType. The
benefits and pitfalls of dynamic invocation are similar to nongeneric methods. After binding parameters to a
generic method, the method can be invoked using Reflection. The following code creates a generic type and
then invokes a generic method at run time:

using System;
using System.Reflection;

namespace Donis.CSharpBook{

public class GenericZ <K, V, Z>


where K: new()
where V: new() {

public void MethodA<A>(A argument1, Z argument2) {


Console.WriteLine("MethodA invoked");
}

private K field1=new K();


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

private V field2=new V();


}

class Starter{

static void Main(){


Type genericType=typeof(GenericZ<,,>);
Type [] parameters={typeof(int),typeof(float),
typeof(int)};
Type closedType=genericType.MakeGenericType(parameters);
MethodInfo openMethod=closedType.GetMethod("MethodA");
object newObject = Activator.CreateInstance(closedType);
parameters=new Type [] {typeof(int)};
MethodInfo closedMethod=
openMethod.MakeGenericMethod(parameters);
object[] methodargs={2, 10};
closedMethod.Invoke(newObject, methodargs);
}
}
}

Reflection Security

Some reflection operations, such as accessing protected and private members, require ReflectionPermission
security permission. ReflectionPermission is typically granted to local and intranet applications, but not to
Internet applications. Set the appropriate ReflectionPermission flag to grant or deny specific reflection
operations.

Table 10-9 lists the ReflectionPermission flags.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-9:
ReflectionPer
mission Flags

Fla De
g scr
ipti
on

Me Ref
mb lec
erA tio
cc n
es of
s no
nvi
sibl
e
me
mb
ers
gra
nte
d.

No Ref
Fla lec
gs tio
n
de
nie
d
to
no
nvi
sibl
e
typ
es.

Ref Sy
lec ste
tio m.
nE Ref
mit lec
tio
n.E
mit
op
era
tio
ns
gra
nte
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 10-9:
ReflectionPer
mission Flags

Fla De
g scr
ipti
on

Ty Thi
peI s
nfo flag
rm is
ati no
on w
de
pre
cat
ed.

All Co
Fla mb
gs ine
s
Ty
peI
nfo
rm
ati
on,
Me
mb
erA
cc
es
s,
an
d
Ref
lec
tio
nE
mit
flag
s.

Attributes

Attributes extend the description of some elements of an assembly. Attributes fulfill the role of adjectives in
.NET and annotate assemblies, classes, methods, parameters, and other elements of an assembly.
Attributes are commonplace in .NET and fulfill many roles: They delineate serialization, stipulate import
linkage, set class layout, indicate conditional compilation, mark a method as deprecated, and much more.

Attributes extend the metadata of the targeted element. An instance of the attribute is stored alongside the
metadata and sometimes the MSIL code of the constituent. This is demonstrated in the following code and
in Figure 10-4. The Conditional attribute marks a method for conditional compilation. Use this attribute to flag
one or more symbols. If the symbol is defined, the target method and call sites are included in the compiled
applications. If not defined, the method and any invocation are ignored.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 10-4: The Conditional attribute in MSIL code

#define LOG

using System;
using System.IO;
using System.Diagnostics;

namespace Donis.CSharpBook{

class Starter{
static void Main(){
LogInfo(new StreamWriter(@"c:\logfile.txt"));
}

[Conditional("LOG")]
private static void LogInfo(StreamWriter sr) {
// write information to log file
}
}
}

This is the MSIL code of the LogInfo method as displayed in ILDASM. Notice the custom directive that
defines the Conditional attribute. It is integrated into the MSIL code of the method (see Figure 10-4).

Attributes are available in different flavors: predefined custom attributes, programmer-defined custom
attributes, and pseudo-custom attributes.

Predefined Attributes
Predefined custom attributes, which are defined in the .NET FCL, are the most prevalent custom attributes.
There is an encyclopedic list of predefined custom attributes fulfilling a variety of responsibilities in .NET. A
short list of predefined custom attributes includes AssemblyVersion, Debuggable, FileIOPermission, Flags,
Obsolete, and Serializable. The following code uses the Obsolete attribute to flag a method as deprecated:

[Obsolete("Deprecated Method", false)]


public static void MethodA() {
Console.WriteLine("Starter.MethodA");
}

Combining Attributes
An entity can be assigned multiple attributes. In certain circumstances, even the same attribute can be
applied multiple times. There are two ways to combine attributes: They can be grouped together or listed
separately. Here, the attributes are applied separately:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

[Obsolete("Deprecated Method", false)]


[FileIOPermission(SecurityAction.Demand,
Unrestricted=true)]
public static void MethodA() {
Console.WriteLine("Starter.MethodA");
}

In the following code, two attributes are combined and applied to a method:

[Obsolete("Deprecated Method", false),


FileIOPermission(SecurityAction.Demand,
Unrestricted=true)]
public static void MethodA() {
Console.WriteLine("Starter.MethodA");
}

Programmer-Defined Custom Attributes


You can also create programmer-defined custom attributes to personally extend metadata of an application.
There are few limitations to a programmer-defined custom attribute: Your attributes can be applied to any
entity, except another programmer-defined custom attribute, and can be designed for almost any purpose.

Pseudo-Custom Attributes
Pseudo-custom attributes are interpreted by the run time and modify the metadata of the assembly. Unlike
predefined or custom attributes, pseudo-custom attributes do not extend metadata. Examples of
pseudo-custom attributes include DllImport, MarshalAs, and Serializable.

Anatomy of an Attribute
What exactly is an attribute? Attributes are derived from the System.Attribute class, which is the common
template of all attributes. System.Attribute is an abstract class defining the intrinsic services of an attribute.
Manage compilers and the run time often accord special treatment to attributes. For example, the
ObsoleteAttribute causes the compiler to generate error or warning messages when a deprecated member
is used.

This is the syntax of an attribute:

[target type: attribute name(positional parameter 1, positional parameter n,


named parameter 1=
value, named parameter n=value)] target

The target type designates the type of the target and must be included in the defined attribute usages.
Attribute target is optional and usually inferred correctly if not omitted.

Here is a list of the valid target types:


 field
 event
 method
 Param
 Property
 Return
 Type
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The attribute name is the class name of the attribute. By convention, attribute names have an Attribute
suffix. OneWayAttribute is representative of an attribute name. You can also use the alias of an attribute,
which omits the Attribute suffix. The alias for OneWayAttribute is OneWay.

Attributes accept zero or more positional parameters. If present, position parameters are not optional and
must be listed in a declared sequence. In addition, an attribute can offer any number of named parameters,
which must follow positional parameters and are optional. Named parameters are not ordered and can be
presented in any sequence.

The following code applies the UIPermissionAttribute to the Starter class:

[type: UIPermissionAttribute(SecurityAction.Demand,
Clipboard=UIPermissionClipboard.OwnClipboard)]
class Starter{
static void Main(){

}
}

This is the same attribute expressed somewhat more succinctly:

[UIPermission(SecurityAction.Demand)]
class Starter{
static void Main(){

}
}

Creating a Custom Attribute

You can create custom attributes for personal consumption or to be published in a library for others. There
are definitive procedures to creating a programmer-defined custom attribute. Here are the steps to follow:
1. Select an appropriate name for the custom attribute. As mentioned, attribute names should
conclude with the Attribute suffix.
2. Define an attribute class that derives from System.Attribute.
3. Set potential targets with the AttributeUsage attribute.
4. Implement class constructors, which determine the positional parameters.
5. Implement write-accessible properties, which define the named parameters.
6. Implement other members of the attribute class.

ClassVersionAttribute is a programmer-defined custom attribute that can apply a version number to types. It
illuminates the steps to creating a custom attribute. The attribute assigns a target and current version
number to a type. The target version is the version number of the type that the attribute adorns. The current
version number is the version applied to the most recent version of the type. When the target type of the
attribute is the most recent version, the target and current version are identical. In addition, the
ClassVersionAttribute can request that future instances of the target type be replaced with the current type.

The first and most important task of creating a programmer-defined attribute is selecting a fabulous name.
Alas, ClassVersionAttribute is a mundane but descriptive name. As an attribute, ClassVersionAttribute must
inherit System.Attribute. AttributeUsageAttribute sets the potential target of the attributes. AttributeTargets
is the only positional parameter of the AttributeUsageAttribute and is a bitwise enumeration.
AttributeUsageAttribute has three named parameters: AllowMultiple, Inherited, and ValidOn. AllowMultiple is
a Boolean flag. When true, the attribute can be applied multiple times to the same target. The default is
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

false. Inherited is another Boolean flag. If true, which is the default, the attribute is inheritable from base
classes. ValidOn is an AttributeTargets enumeration. This is an alternate method of setting the potential
target of the attribute.

Here is a list of the available AttributeTargets flags:


 All
 Assembly
 Class
 Constructor
 Delegate
 Enum
 Event
 Field
 GenericParameter
 Interface
 Method
 Module
 Parameter
 Property
 ReturnValue
 Struct

This is the start of the ClassVersionAttribute class:

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct,
Inherited=false)]
public class ClassVersionAttribute: System.Attribute {
}

Instance constructors of an attribute provide the positional parameters for the attribute. Attributes are created
at compile time, upon reflection, and when applied at run time. When attributes are created, the selected
constructor runs. The positional arguments should match the signature of a constructor in the attribute.
Overloading the constructor allows different sets of positional parameters. Positional and named parameters
are restricted to certain types. The following is a list of available attribute parameter types.
 bool
 byte
 char
 double
 float
 int
 long
 sbyte
 short
 string
 uint
 ulong
 ushort

ClassVersionAttribute has two overloaded constructors. The first constructor accepts the target version; the
second constructor accepts the target and current version number:

public ClassVersionAttribute(string target)


:this(target, target) {
}

public ClassVersionAttribute(string target,


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

string current) {
m_TargetVersion=target;
m_CurrentVersion=current;
}

Define named parameters as write-only or read-write instance properties of the derived attribute class. You
can duplicate positional parameters as named parameters for additional flexibility. ClassVersionAttributes
offers a UseCurrentVersion and CurrentName named parameter. UseCurrentVersion is a Boolean value. If
true, instances of the current type should be substituted for the target type. CurrentName names the type of
the current version. This is how the named parameters are described in the ClassVersionAttribute class:

private bool m_UseCurrentVersion=false;


public bool UseCurrentVersion {
set {
if(m_TargetVersion != m_CurrentVersion) {
m_UseCurrentVersion=value;
}
}
get {
return m_UseCurrentVersion;
}
}

private string m_CurrentName;


public string CurrentName {
set {
m_CurrentName=value;
}

get {
return m_CurrentName;
}
}

For completeness, read-only properties are added to the ClassVersionAttribute class for the target and
current version. Here is the completed ClassVersionAttribute class:

using System;

namespace Donis.CSharpBook{
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct,
Inherited=false)]
public class ClassVersionAttribute: System.Attribute {

public ClassVersionAttribute(string target)


:this(target, target) {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public ClassVersionAttribute(string target,


string current) {
m_TargetVersion=target;
m_CurrentVersion=current;
}

private bool m_UseCurrentVersion=false;


public bool UseCurrentVersion {
set {
if(m_TargetVersion != m_CurrentVersion) {
m_UseCurrentVersion=value;
}
}
get {
return m_UseCurrentVersion;
}
}

private string m_CurrentName;


public string CurrentName {
set {
m_CurrentName=value;
}
get {
return m_CurrentName;
}
}

private string m_TargetVersion;


public string TargetVersion {
get {
return m_TargetVersion;
}
}

private string m_CurrentVersion;


public string CurrentVersion {
get {
return m_CurrentVersion;
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The ClassVersionAttribute class is compiled and published in a DLL. The following application minimally
uses the ClassVersionAttribute:

using System;
namespace Donis.CSharpBook{
class Starter{
static void Main(){

}
}

[ClassVersion("1.1.2.1", UseCurrentVersion=false)]
class ZClass {
}
}

Attributes and Reflection

Programmer-defined custom attributes are valuable as information. However, the real fun and power is in
associating a behavior with an attribute. You can read custom attributes with Reflection using the
Attribute.GetCustomAttribute and Type.GetCustomAttributes methods. Both methods return an instance or
instances of an attribute. You can downcast the attribute instance to a specific attribute type and leverage
the intricacies of the attribute to implement the appropriate behavior.

Type.GetCustomAttributes returns attributes applied to a type. GetCustomAttributes is also available with


other metadata elements, including Assembly.GetCustomerAttributes, MemberInfo.GetCustomAttributes,
and ParameterInfo.GetCustomerAttributes. GetCustomAttributes has a single Boolean parameter. If true,
the inheritance hierarchy of the type is evaluated for additional attributes.

This is the Type.GetCustomAttributes method:

object [] GetCustomAttributes(bool inherit)


object [] GetCustomAttribute(type AttributeType, bool inherit)

Attribute.GetCustomAttribute, which is a static method, creates and returns an instance of a specific


attribute. When a specific attribute is desired, GetCustomAttribute is invaluable and more efficient than
GetCustomAttributes. GetCustomAttribute assumes that the attribute is assigned only once to the target.
GetCustomAttribute is overloaded for each potential target, with one notable exception: GetCustomAttribute
is not overloaded for a type target, which is inexplicable. Type.GetCustomAttributes is the sole option for
enumerating attributes of a Type. GetCustomAttribute is overloaded for two and three arguments. The
two-argument versions have the target and attribute type as parameters. The three-argument version has an
additional parameter, which is the inherit parameter. If the inherit parameter is true, the ascendants of the
target class are also searched for the attribute.

This is the Attribute.GetCustomAttribute method:

static Attribute GetCustomAttribute (Assembly targetAssembly, type


attributeType)
static Attribute GetCustomAttribute(MemberInfo targetMember, type
attributeType)
static Attribute GetCustomAttribute(Module targetModule, type attributeType)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

static Attribute GetCustomAttribute(ParameterInfo targetParameter, type


attributeType)

This following sample code uses GetCustomAttribute:

using System;
using System.Reflection;

namespace Donis.CSharpBook{

class Starter{

static void Main(){


Type tObj=typeof(Starter);
MethodInfo method=tObj.GetMethod("AMethod");
Attribute attrib=Attribute.GetCustomAttribute(
method, typeof(ObsoleteAttribute));
ObsoleteAttribute obsolete=(ObsoleteAttribute) attrib;
Console.WriteLine("Obsolete Message: "+obsolete.Message);
}

[Obsolete("Deprecated function.", false)]


public void AMethod() {
}
}
}

The following is sample code of GetCustomAttributes. The application inspects the ClassVersionAttribute
attribute with the GetCustomAttributes method and acts upon the results. The application contains two
versions of ZClass and both are applied to the ClassVersionAttribute. Each version of ZClass shares a
common interface: IZClass. The ClassVersionAttribute of Donis.CSharpBook.ZClass lists
ANamespace.ZClass as the current version or most recent version. Also, UseCurrentVersion is assigned true
to indicate that the newer version should replace instances of Donis.CSharpBook.ZClass. The function
CreateZClass accepts a ZClass as defined by the IZClass interface. Within the foreach loop,
GetCustomAttributes enumerates the attributes of the ZClass. If the attribute is a ClassVersionAttribute, the
attribute is saved and the foreach loop is exited. Next, the properties of the attribute are examined. If
UseCurrentVersion is true and a current version is named, an instance of the new version is created and
returned from the method. Otherwise, the target version is returned.

using System;
using System.Reflection;

interface IZClass {
void AMethod();
}

namespace Donis.CSharpBook{
class Starter{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

static void Main(){


IZClass obj=CreateZClass(typeof(ZClass));
obj.AMethod();
}

private static IZClass CreateZClass(Type tObj) {


ClassVersionAttribute classversion=null;
foreach(Attribute attrib in tObj.GetCustomAttributes(false)) {
if(attrib.ToString()==
typeof(ClassVersionAttribute).ToString()) {
classversion=(ClassVersionAttribute) attrib;
}
else {
return null;
}
}
if(classversion.UseCurrentVersion &&
(classversion.CurrentName != null)) {
AppDomain currDomain=AppDomain.CurrentDomain;
return (IZClass) currDomain.CreateInstanceFromAndUnwrap(
"client.exe", classversion.CurrentName);
}
else {
return (IZClass) Activator.CreateInstance(tObj);
}
}

[ClassVersion("1.1.2.1", "2.0.0.0", UseCurrentVersion=true,


CurrentName="Donis.CSharpBook.ANamespace.ZClass")]
public class ZClass: IZClass {
public void AMethod() {
Console.WriteLine("AMethod: old version");
}
}

namespace ANamespace {
[ClassVersion("2.0.0.0", UseCurrentVersion=false)]
public class ZClass: IZClass {
public void AMethod() {
Console.WriteLine("AMethod: new version");
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

MSIL
Metadata and the ability to inspect metadata using Reflection were the topics of this chapter. .NET
assemblies consist of metadata and MSIL, in which understanding MSIL is equally important to a developer.
(MSIL is the topic of Chapter 11.) Understanding MSIL is important for writing, maintaining, and, later,
debugging a C# application. Reflection can be used with MSIL code. You can inspect MSIL code at run
time, create self-generating code, and otherwise manipulate MSIL using Reflection.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 11: MSIL Programming


Overview
Microsoft intermediate language (MSIL) is the programming language of the Common Language Runtime
(CLR) and the Common Instruction Language (CIL) for managed code. A managed application undergoes two
compilations. The first compilation is from source code to MSIL and is performed by the language compiler.
The second compilation occurs at run time, when the MSIL is compiled to native code. The CLR
orchestrates the second compilation as part of process execution. The CLR is blind to the original source
code. From the perspective of the CLR, managed applications are simply MSIL code and metadata. For this
reason, .NET is considered language-agnostic, or independent. The process execution of a managed
application is identical regardless of the source language, such as C# or Microsoft Visual Basic .NET.

MSIL promotes the concept of compile-once-and-run-anywhere in the .NET environment. Just-in-time (JIT)
compilers, otherwise known as jitters, compile assemblies into native binary that targets a specific platform.
You can write an application or component once and then deploy the application to Microsoft Windows,
Linux, and other environments in which a compliant .NET platform is available. Prior to .NET, vendors
maintained different versions of their product, which is costly and time-consuming. Another advantage to
compile-once-and-run anywhere is the ability to assemble applications from components deployed on
disparate hardware and platforms. This was one of the objectives of component technologies such as
Component Object Model (COM) and Common Object Request Broker Architecture (CORBA), but it was
never truly realized. .NET makes this a reality. If platform-agnostic code is a design goal for an application,
best practices must be adopted to insulate the program from platform-specific code. This includes avoiding
or isolating interoperability and calls to native application programming interfaces (APIs).

MSIL is a full-featured, object-oriented programming (OOP) language. However, there are some differences
when compared with C# programming. For example, global functions are allowed in MSIL, but not supported
in the C# language. Despite being a lower-level language, MSIL has expanded language elements. It
encompasses the constituents common to most object-oriented languages: classes, structures, inheritance,
transfer-of-control statements, an assortment of arithmetic operators, and much more. Indeed, you can write
.NET applications directly in MSIL.

This is a book on C# programming. In that context, why is understanding MSIL important? An understanding
of MSIL code advances a deeper comprehension of C# programming and .NET in general. It isn't just magic.
MSIL removes much of the mystery and helps C# developers better maintain, debug, and write efficient code.

Managed applications, particularly production applications purchased from third-party vendors, are
sometimes deployed without the original source code. How is an application maintained without the source
code? For a managed application, as part of the assembly, the MSIL code is always available. The
exception is when the assembly is obfuscated. Several tools, including Intermediate Language Disassembler
(ILDASM), can disassemble an assembly and provide the MSIL code. With the MSIL code, a developer can
essentially read the application. You can even modify the code as MSIL and reassemble the application.
This is called roundtripping. Of course, this assumes that the developer is erudite in MSIL programming.

In a native application, debugging without a debug file (.pdb) is a challenge (which is an understatement).
Debugging a native application without symbol files invariably meant interpreting assembly code. That was
the challenge. More than a visceral understanding of assembly programming is needed to debug without
symbol files. MSIL can be viewed as the assembly code of the CLR. Debugging a managed application
without the germane symbol files requires more than a superficial understanding of MSIL. However, when
compared to the tedious task of reading assembly, MSIL is a leisure cruise.

MSIL is instructive in managed programming. Learning MSIL programming is learning C# programming. What
algorithms are truly efficient? When has boxing occurred? Which source code routines expand the footprint
of the application? These secrets can be found in understanding MSIL code.

Inline MSIL is mentioned in numerous programming blogs, but is not currently available. I am an advocate of
inline MSIL for C#. MSIL is more than an abstraction of higher-level source code. There are unique features in
MSIL code that are not exposed in C#. In addition, C# is a code generator that emits MSIL code. In rare
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

circumstances, the MSIL may not be as ideal for your specific application. For these reasons, I favor inline
MSIL. However, the problem with inline MSIL is maintaining safe code. Inline MSIL is inherently unsafe and
could lead to abuse. If a safe implementation of inline MSIL is not possible, it should not be added to the
language. As mentioned, managed applications incur two compilations. First the language compiler and then
the run time (jitter) compiles the application. You can compile MSIL code directly into an assembly with the
MSIL compiler Intermediate Language Assembler (ILASM). Conversely, you can disassemble an assembly
by engaging the MSIL disassembler (ILDASM).

This chapter is an overview of MSIL programming, not a comprehensive narrative on MSIL. The intention is to
convey enough information on the language to aid in the interpretation, maintenance, and debugging of C#
applications. For an authoritative explanation of MSIL, I recommend Inside Microsoft .NET IL Assembler,
written by Serge Lidin (Microsoft Press, 2002). Serge is one of the original architects of the ILASM compiler,
the ILDASM disassembler, and other tools included in the .NET Framework. Alternatively, consult the
European Computer Manufacturers Association (ECMA) documents pertaining to CIL, which are available
online at http://www.ecma-international.org/publications/standards/Ecma-335.htm.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

"Hello World" Application


An example is a great place to begin an exploration of MSIL code programming. Following is a variation of
the universally known Hello World application. It displays "Hello Name", where Name is read from the
memory of a local variable.

// Hello World Application

.assembly extern mscorlib {}


.assembly hello {}

/* Starter class with entry point method */

.namespace Donis.CSharpBook {
.class Starter {
.method static public void Main() cil managed {
.maxstack 2
.entrypoint
.locals init (string name)
ldstr "Donis"
stloc.0
ldstr "Hello, {0}!"
ldloc name
call void [mscorlib] System.Console::WriteLine(
string, object)
ret
}
}
}

This is the command line that compiles the MSIL code to create a hello executable:

ilasm /exe /debug hello.il

The exe option indicates that the target is a console application, which is also the default. The dll option
specifies a library target. The debug option asks the compiler to generate a debug file (pdb) for the
application. A debug file is useful for a variety of reasons, including viewing source code in a debugger or
disassembler.

The application begins with comments and three declaratives:

// Hello World Application


.assembly extern mscorlib{}
.assembly hello{}
/* Starter class with entry point method */
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

.namespace Donis.CSharpBook {

MSIL supports C++ style comments—both single and multiline comments. The first declarative is an
external reference to the mscorlib library. Mscorlib.dll contains the core of the .NET Framework class library
(FCL), which includes the System.Console class. The assembly directive describes the executing assembly,
in which the simple name of the assembly is hello. Notice that the simple name does not include the
extension. The third directive defines a namespace.

The next two lines define a class and a method. This class directive introduces a public class named Starter,
which implicitly inherits the System.Object class. The method directive defines Main as a member method.
Main is a managed, public, and static function:

.class Starter {
.method static public void Main() cil managed {

The Main method starts with three directives. The .maxstack directive sets the size of the evaluation stack to
two slots. The .entrypoint directive designates Main as the entry point of the application. By convention, Main
is always the entry point of a C# executable. In MSIL, the entry point method is whatever method contains
the .entrypoint directive, which could be a method other than Main. Finally, the .local directive declares a
local string variable called name.

.maxstack 2
.entrypoint
.locals init (string name)

Table 11-1 describes the MSIL code of the Main method.


Table 11-1:
Hello World
MSIL Code
Open table as
spreadsheet

Ins De
tru scr
cti ipti
on on

lds Lo
tr ad
"D the
oni stri
s" ng
"D
oni
s"
ont
o
the
eva
lua
tio
n
sta
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-1:
Hello World
MSIL Code
Open table as
spreadsheet

Ins De
tru scr
cti ipti
on on

stl Sto
oc. re
0 "D
oni
s"
fro
m
the
eva
lua
tio
n
sta
ck
int
o
the
firs
t
loc
al
vari
abl
e,
whi
ch
is
call
ed
na
me
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-1:
Hello World
MSIL Code
Open table as
spreadsheet

Ins De
tru scr
cti ipti
on on

lds Lo
tr ad
"H the
ello "H
, ello
{0}! "
" stri
ng
pre
fix
ont
o
the
eva
lua
tio
n
sta
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-1:
Hello World
MSIL Code
Open table as
spreadsheet

Ins De
tru scr
cti ipti
on on

ldlo Lo
c ad
na the
me loc
al
vari
abl
e
ont
o
the
eva
lua
tio
n
sta
ck.
(Lo
cal
vari
abl
es
are
ref
ere
nc
ed
by
ind
ex
or
by
na
me
.)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-1:
Hello World
MSIL Code
Open table as
spreadsheet

Ins De
tru scr
cti ipti
on on

call Cal
voi l
d the
[m Co
sc ns
orli ole
b] ::
Sy Wri
ste teL
m. ine
Co me
ns tho
ole d,
:: whi
Wri ch
teL co
ine ns
(str um
ing es
, the
obj two
ect ite
) ms
on
the
eva
lua
tio
n
sta
ck
as
par
am
ete
rs
fro
m
rig
ht
to
left
.
"H
ello
na
me
"
is
dis
pla
ye
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-1:
Hello World
MSIL Code
Open table as
spreadsheet

Ins De
tru scr
cti ipti
on on

ret Ret
urn
fro
m
the
me
tho
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Evaluation Stack
The evaluation stack, which is mentioned often in the description of the Hello World application, is the pivotal
structure of MSIL applications. It is the bridge between your application and memory locations. It is similar to
the conventional stack frame, but there are salient differences. The evaluation stack is the viewer of the
application, and you can use it to view function parameters, local variables, temporary objects, and much
more. Traditionally, function parameters and local variables are placed on the stack. In .NET, this information
is stored in separate repositories, in which memory is reserved for function parameters and local variables.
You cannot access these repositories directly. Accessing parameters or local variables requires moving the
data from memory to slots on the evaluation stack using a load command. Conversely, you update a local
variable or parameter with content on the evaluation stack using a store command. Slots on the evaluation
stack are either 4 or 8 bytes.

Figure 11-1 shows the relationship between the evaluation stack and the repositories for function parameters
and local variables.

Figure 11-1: A depiction of the evaluation stack, function parameters, and local variables

The evaluation stack is a stack and thereby a last in/first out (LIFO) instrument. When a function starts, the
evaluation stack is empty. As the function runs, items are pushed and popped from the evaluation stack.
Before the function exits, except for a return value, the evaluation stack must once again be empty. The jmp
and tail instructions are exceptions to this rule. If the evaluation stack is not empty at exit, the run time
raises an InvalidProgramException exception.

The .maxstack directive limits the number of items permitted simultaneously on the stack. The directive is
optional. If the directive is not present, eight slots are reserved on the evaluation stack. The .maxstack
directive is a confirmation that an application is performing as expected. Extra items on the evaluation stack
are an indication of potential logic problems in an application or a security violation. In either circumstance,
this is a violation worthy of a notification.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

MSIL in Depth
Here are some basic facts about MSIL programming. The content of an MSIL program is case sensitive.
MSIL is also a freeform language. Statements can span multiple lines of code, in which lines can be broken
at the white space. Statements are not terminated with a semicolon. Comments are the same as in the C#
language. Double slashes (//) are used for single-line comments, and "/* comment */" is used for multiline
comments. Code labels are colonterminated and reference the next instruction. Code labels must be unique
within the scope in which it is defined.

In addition to the evaluation stack, the other important elements of a MSIL application are directives and the
actual MSIL source code. Directives are dot-prefixed and are the declarations of the MSIL program. Source
code is the executable content and control flow of the application.

Directives
There are several categories of directives. Assembly, class, and method directives are the most prominent.
Assembly directives contain information that the compiler emits to the manifest, which is metadata
pertaining to the overall assembly. Class directives define classes and the members of the class. This
information is also emitted as standard metadata, which is data about types. Method directives define the
particulars of a method, such as any local variables and the size of the evaluation stack.

Assembly Directives
Table 11-2 lists common assembly directives.
Table 11-2: Assembly Directives

Directive Description

.assembly The .assembly directive defines the simple name of the assembly. The simple name
does not include the extension. Assembly probing will uncover the correct extension.
Adding the extension will cause normal probing to fail and manifest a binding exception
when the assembly is referenced.
This is the syntax of the .assembly directive:
 .assembly name {block}
The assembly block contains additional directives that further describe the assembly.
These directives are optional. You need to provide only enough directives to uniquely
identify the assembly. This is an assembly block with additional details:

.assembly Hello {
.ver 1:0:0:0
.locale "en.US"
}
These are some of the directives available in the assembly block:
 .ver—The four-part version number of the assembly
 .publickey—The 8-byte public key token of the public/private key pair used to
encrypt the hash of the assembly
 .locale—The language and culture of the assembly
 .custom—Custom attributes of the assembly
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-2: Assembly Directives

Directive Description

.assembly The .assembly extern directive references an external assembly. The public types and
extern methods of the referenced assembly are available to the current assembly.
This is the syntax of the .assembly extern directive:
 .assembly extern name as aliasname {block}
The as clause is optional and for referencing assemblies that are similarly named but a
different version, public key, or culture.
Add the .ver, .publickey, .locale, and .custom directives to the assembly extern block to
refine the identification of that assembly.
Because of the importance of mscorlib.dll, the ILASM compiler automatically adds an
external reference to that library. Therefore, assembly extern mscorlib is purely
informative.

.file The .file directive adds a file to the manifest of the assembly. This is useful for
associating documents, such as a readme file, with an assembly.
This is the syntax of the .file directive:
 .file nometadata file name .hash = (bytes) .entrypoint
The file name is the sole required element of the declaration. Nometadata is the primary
option and stipulates that the file is unmanaged.

.file nometadata documentation.txt

.subsystem The .subsystem directive indicates the subsystem used by the application, such as the
graphical user interface (GUI) or console subsystem. This is distinct from the target type
of the application, which is an executable, library, module, or so on. The ILASM compiler
inserts this directive based on options specified when the application is compiled. You
can also explicitly add this directive.
This is the syntax of the .subsystem directive:
 .subsystem number
Number is a 32-bit integer in which:
 2 is a GUI application.
 3 is a console application.

.corflags The .corflags directive sets the run-time flag in the CLI header. This defaults to 1, which
stipulates an IL-only assembly. The corflags tool, introduced in .NET 2.0, allows the
configuration of this flag.
This is the syntax of the .corflags directive:
 .corflags flag
The flag is a 32-bit integer.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-2: Assembly Directives

Directive Description

.stackreserve The .stackreserve directive sets the stack size. The default size is 0x00100000. The
following code calls MethodA iteratively. Without the .stackreserve directive, which
defaults to 0x00100000, the MethodA method is called iteratively more than 110,000
times before exhausting the stack. Set the stack size to 0x0001000 using the
.stackreserve directive. Now MethodA is called only about 21,000 times before quitting.
Although the results may vary on your actual computer, the relative values are consistent.

.assembly iterative {}
.imagebase 0x00800000
.stackreserve 0x00001000

.namespace Donis.CSharpBook {
.class Starter {
.method static public void Main() il managed {
.entrypoint
ldc.i4.0
call void Donis.CSharpBook.Starter::
MethodA(int32)
ret
}

.method static public void MethodA(int32)


il managed {
ldarg.0
ldc.i4.1
add
dup
call void [mscorlib]
System.Console::WriteLine(int32)
call void Donis.CSharpBook.Starter::
MethodA(int32)
ret
}
}
}

.imagebase The .imagebase directive sets the base address where the application is loaded. The
default is 0x00400000. The load address of the application image and stack size is
confirmable using the dumpbin tool. For example:
 dumpbin /headers iterative.exe >iterative.txt

Class Directives
Table 11-3 describes the important class directives.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-3: Class


Directives

Dir Description
ect
ive

.cl The .class


as header
s directive
he introduces a
ad new reference
er type, value
{ type, or
me interface into
mb an assembly.
ers The syntax of
} the .class
header
directive is as
follows:
attributes
classname
extends
basetype
implements
interfaces
There are a
variety of
attributes.
This is a short
list of the
common
attributes:
 abstrac
t—The
type is
abstrac
t, and
instanc
es
cannot
be
created
.
 ansi
and
unicod
e—
Strings
can be
marsha
led as
ANSI
or
UNICO
DE.
 auto—
The
memor
y
layout
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-3: Class


Directives

Dir Description
ect
ive

.cu The .custom


sto directive adds
m a custom
co attribute to
nst the type.
ruc
tor
sig
nat
ure
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-3: Class


Directives

Dir Description
ect
ive

.m The .method
eth directive
od defines a
method. C#
does not
support global
methods.
Therefore, the
.method
directive is
always
included
within a type.
This is the
syntax of the .
method
directive:
 .metho
d
attribut
es
callingc
onv
return
method
name
argume
nts
implattr
ibutes
{
method
body }
The method
attributes are
varied,
including the
accessibility
attributes:
public, private,
family, and
others. The
default is
private. Static
methods have
the static
attribute,
whereas
instance
methods
possess the
instance
attribute. The
default is an
instance
method.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-3: Class


Directives

Dir Description
ect
ive

.fie The .field


ld directive
defines a new
field, which
contains state
for a class or
instance.
The syntax of
the .field
directive is as
follows:
 .field
attribut
es
type
fieldna
me
fieldinit
at
datalab
el
The
accessibility
attributes are
the same as
described with
methods.
Fields can be
assigned the
static attribute
but not the
instance
attribute. The
default is an
instance field.
This is a list
of other
common field
attributes:
 initonly

Defines
a
readonl
y field.
 special
name
—The
field is
special
.
 rtspeci
alname
—The
field
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-3: Class


Directives

Dir Description
ect
ive

.pr The .property


op directive
ert introduces a
y property
member to a
class. It also
declares the
get and set
methods
associated
with the
property.
This is the
syntax of the .
property
directive:
 .propert
y
attribut
es
return
propert
yname
parame
ters
default
{
propert
yblock}
The attributes
of a property
can be
specialname
or
rtspecialname.
The return is
the return
type of the
property. The
composition
of
propertyname
and
parameters is
the signature
of the
property. The
default option
sets the
default value
of the property.
Within the
property
block, the .get
directive
declares the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-3: Class


Directives

Dir Description
ect
ive

.ev The .event


ent directive
defines a new
event in a
class.
This is the
syntax of the .
event directive:
 .event
classre
f
eventn
ame {
eventb
ody }
Classref is
the underlying
type of the
event, such
as
EventHandler.
The .
eventbody
directive
encapsulates
the .addon
and .removeon
directives. The
.addon
directive
declares the
method used
to add
subscribers.
The .removeon
directive
declares the
method for
removing
subscribers.
The add and
remove
methods are
implemented
in the class
and not the
event.
This is the C#
code that
declares an
event:

public event
EventHandler
EventA;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Method Directives
The .method directive adds a method to a class. MSIL allows for global methods. Global methods break the
rules of encapsulation and other tenets of OOP. For this reason, C# does not support global methods. MSIL
generated from the C# compiler (csc) uses the .method directive solely to define member methods. The
method block contains further directives and the implementation code (MSIL).

Table 11-4 lists the directives that are frequently included in the method block.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-4: Directives


Included in the Method
Block

Dir Description
ect
ive

.lo The .locals


cal directive
s declares local
variables that
are
accessible
using a
symbolic
name or
index. Local
variables form
a zero-based
array.
This is the
syntax of the .
locals
directive:
 .locals 1
(
[index]l
ocal1,
[index]
local2,
[index]
localn)
 .locals 2
init (
[index]l
ocal1,
[index]
local2,
[index]
localn)
The .locals 1
directive
defines one or
more local
variables.
Explicit
indexes can
be set for
each local
variable. By
default, the
local variables
are indexed
sequentially
starting at
zero.
The .locals 2
directive adds
the init
keyword,
which
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-4: Directives


Included in the Method
Block

Dir Description
ect
ive

.m The .maxstack
axs directive sets
tac the number of
k slots available
on the
evaluation
stack.
Without this
directive, the
default is
eight slots,
which is the
number of
items that can
be placed on
the evaluation
stack
simultaneously
.
This is the
syntax of the .
maxstack
directive:
 .maxst
ack
slots
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-4: Directives


Included in the Method
Block

Dir Description
ect
ive

.en The .entrypoint


try directive
poi designates a
nt method as the
entry point
method of the
application.
This directive
can appear
anywhere in
the method,
but best
practice
places the .
entrypoint
directive at
the start of
the method.
In C#, the
entry point
method is
Main. In MSIL,
any static
method can
be accorded
this status.

The following program defines MSILFunc as the entry point method. The .entrypoint directive is found at the
end of this method. The .locals directive defines two locals and assigns explicit indexes. Essentially, the
normal indexes are reversed. The instruction stloc.0 will update the second local variable. MSILFunc refers to
the local variables both as symbolic names and indexes. The MSILFunc method returns void. In MSIL code,
the ret instruction is required even when a function returns nothing. In C#, the return is optional for methods
returning void. The method displays the values of 10 and then 5.

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class Starter {

.method static public void MSILFunc() il managed {


.locals init ([1] int32 locala, [0] int32 localb)
ldc.i4.5
stloc.0
ldc.i4 10
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

stloc.1
ldloc locala
call void [mscorlib] System.Console::WriteLine(int32)
ldloc localb
call void [mscorlib] System.Console::WriteLine(int32)
.entrypoint
ret
}
}
}

MSIL Instructions
MSIL includes a full complement of instructions, many of which were demonstrated in previous examples.
Each instruction is also assigned an opcode, which is commonly 1 or 2 bytes. 2-byte opcodes are always
padded with a 0xFE byte in the high-order byte. Opcodes are often followed with operands. Opcodes, which
provide an alternate means of defining MSIL instructions, are used primarily when emitting code dynamically
at run time. The ILGenerator .Emit method records instructions using opcodes, which is in the
System.Reflection.Emit namespace.

The byte option of ILDASM adds opcodes to the disassembly. The following is a partial listing of the
hello.exe disassembly, which includes just the Main method. As ascertained from the disassembly, the
opcode for ldstr is 72, the opcode for stloc is 0A, and the opcode for call is 28.

.method public static void Main() cil managed


{
.entrypoint
.maxstack 2
.locals init (string V_0)
IL_0000: /* 72 | (70)000001 */ ldstr "Donis"
IL_0005: /* 0A | */ stloc.0
IL_0006: /* 72 | (70)00000D */ ldstr "Hello, {0}!"
IL_000b: /* FE0C | 0000 */ ldloc V_0
IL_000f: /* 28 | (0A)000001 */ call void
[mscorlib]System.Console::WriteLine(string, object)
IL_0014: /* 2A | */ ret
}

Short Form Some MSIL instructions have normal and short-form syntax. The short forms of the instruction
have a .s suffix. The short form of the ldloc instruction is ldloc.s. The short form of the br instruction is br.s.
Normal instructions have 4-byte operands, and short-form instructions are limited to 1-byte operands.

When used injudiciously, the short-form syntax can cause unexpected results:

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

.class Starter {
.method static public void Main() il managed {
.entrypoint
ldc.i4.s 50000
call void [mscorlib] System.Console::WriteLine(int32)
ret
}
}
}

In the preceding application, a constant of 50000 is placed on the evaluation stack. However, the ldc
instruction is in the short form. It is difficult to fit 50000 into a single byte, so the constant overflows the byte.
For this reason, the application incorrectly displays 80.

The next section of the book reviews the categories of MSIL instructions, such as branch, arithmetic, call,
and array groups of instructions. Because of the prevalence of the evaluation stack, load and store
instructions are the most frequently used of all MSIL instructions. That is a good place to start.

Load and Store Methods Load and store instructions transfer data between the evaluation stack and
memory. Load commands push memory, such as a local variable, to the evaluation stack. Store commands
move data from the evaluation stack to memory. Information placed on the evaluation stack is then
consumed by method parameters, arithmetic operations, and other MSIL instructions. Data not otherwise
consumed should be removed from the evaluation stack before the current method returns. The pop
instruction is the best command to remove extraneous data from the evaluation stack. Data needed for an
instruction should be placed on the evaluation stack immediately prior to the execution of that instruction. If
not, an InvalidProgramException is triggered. Method returns are also placed on the evaluation stack.

Table 11-5 lists the basic load instructions.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-5: Load


Instructions

Ins Description
tru
cti
on

ldc The ldc


instruction
posts a
constant to
the evaluation
stack, which
can be an
integral or
floating-point
value.
This is the
syntax of the
ldc instruction:
 ldc 1.
type
value
 ldc 2.i4.
number

 ldc 3
.i4.s
number

The ldc 1
instruction
loads a
constant of
the specified
type onto the
evaluation
stack.
The ldc 2
instruction is
more efficient
and transfers
an integral
value of -1 and
between 0
and 8 to the
evaluation
stack. The
special format
for -1 is
ldc.i4.m1.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-5: Load


Instructions

Ins Description
tru
cti
on

ldlo The ldloc


c instruction
copies the
value of a
local variable
to the
evaluation
stack.
This is the
syntax of the
ldloc
instruction:
 ldloc 1
index
 ldloc 2.s
index
 ldloc 3
name
 ldloc 4.s
name
 ldloc 5.n

The ldloc 1 and


ldloc 2
instructions
use an index
to identify a
local variable,
which is then
loaded on the
evaluation
stack. The
ldloc 3 and ldloc
4 instructions

identify the
local variable
with the
symbolic
name. The
short form of
ldloc
efficiently
loads local
variables from
4 to 255. The
ldloc 5
instruction is
optimized to
load local
variables from
0 to 3.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-5: Load


Instructions

Ins Description
tru
cti
on

lda The ldarg


rg instruction
places a
method
argument on
the evaluation
stack.
This is the
syntax of the
ldarg
instruction,
which is
identical to
the ldloc
instruction:
 ldarg 1
index
 ldarg 2.s
index
 ldarg 3
name
 ldarg 4.s
name
 ldarg 5.n

ldn The ldnull


ull instruction
places a null
on the
evaluation
stack. This
instruction
has no
operands.

Table 11-6 lists the basic store instructions.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-6: Store


Instructions

Ins Description
tru
cti
on

stl The stloc


oc instruction
transfers a
value from the
evaluation
stack to a
local variable.
The value is
then removed
from the
evaluation
stack.
This is the
syntax of the
stloc
instruction,
which is the
same as the
ldloc
instruction:
 stloc
index
 stloc.s
index
 stloc
name
 stloc.s
name
 stloc.n
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-6: Store


Instructions

Ins Description
tru
cti
on

sta The starg


rg instruction
moves a value
from the
evaluation
stack to a
method
argument. The
value is then
popped from
the evaluation
stack.
This is the
syntax of the
starg
instruction:
 starg
num
 starg.s
num
The short form
of the starg
instruction is
efficient for
the first 256
arguments.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Complex Tasks
Until now, the focus has been on individual instructions. Most programs consist of complex tasks, such as
creating a new class, creating an array, or executing a for loop. Complex tasks consist of multiple
instructions.

Managing Types
Classes contain static and instance members. The static members are accessible through the class name,
whereas instance members are bound to an object. The WriteLine method is a static method. As
demonstrated, WriteLine is called directly on the Console class (for example, System.Console::WriteLine).
Instance members require an object. The newobj instruction creates an instance of a class and then invokes
the constructor to initialize the object. It also deposits a reference to the object onto the evaluation stack.
This reference can be used to call a member method or access a field. Such an action consumes the
reference and removes it from the evaluation stack. Several actions require several references. The dup
instruction is convenient for duplicating a reference or whatever is on the top of the evaluation stack.

This is the syntax of the newobj instruction:


 newobj instance instruction:
o new ctorsignature

Constructors are specially named methods. The name of a constructor is ctor, and a constructor is declared
with the .ctor directive. By convention in C#, constructors return void, which is enforced by the C# compiler.
In MSIL code, a constructor can return a value. Static constructors are named cctor and are declared with
the identically named directive. The static constructor is called when the class or instance is first accessed.

The .field directive adds a field to the class. The ldfld and ldsfld instructions load an instance and static field
onto the evaluation stack, respectively. Conversely, the stfld and stsfld instructions store data on the
evaluation stack into a field. The stfld and stsfld instructions consume a reference to the related object. The
load and store instructions have a single operand, which is the field signature.

The following program creates a class that contains an instance and static field in which the instance and
static constructors initialize the fields. The AddField and SubtractField methods return the total and
difference of the fields. An instance of the object is created in the Main method. The resulting reference is
duplicated with the dup instruction. Why? Both the AddField and SubtractField methods are called, which
require two references:

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class Starter {

.method static public void Main() il managed {


.entrypoint
.locals (int32 temp)
newobj instance void Donis.CSharpBook.ZClass::.ctor()
dup
call instance int32 Donis.CSharpBook.ZClass::AddFields()
stloc.0
ldstr "The total is {0}"
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

ldloc.0
box int32
call void [mscorlib] System.Console::WriteLine(string, object)
call instance int32 Donis.CSharpBook.ZClass::SubtractFields()
stloc.0
ldstr "The difference is {0}"
ldloc.0
box int32
call void [mscorlib] System.Console::WriteLine(string, object)
ret
}
}

.class ZClass {

.method private hidebysig specialname rtspecialname


static void .cctor() cil managed {
ldstr "In static constructor"
call void [mscorlib] System.Console::WriteLine(string)
ldc.i4.s 10
stsfld int32 Donis.CSharpBook.ZClass::fielda
ret
}

.method public hidebysig specialname rtspecialname


instance void .ctor() cil managed {
ldstr "In constructor"
call void [mscorlib] System.Console::WriteLine(string)
ldarg.0

ldc.i4.s 5
stfld int32 Donis.CSharpBook.ZClass::fieldb
ret
}

.method public int32 AddFields() cil managed {


ldsfld int32 Donis.CSharpBook.ZClass::fielda
ldarg.0
ldfld int32 Donis.CSharpBook.ZClass::fieldb
add
ret
}

.method public int32 SubtractFields() cil managed {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

ldsfld int32 Donis.CSharpBook.ZClass::fielda


ldarg.0
ldfld int32 Donis.CSharpBook.ZClass::fieldb
sub
ret
}

.field static private int32 fielda


.field private int32 fieldb

}
}

Boxing The previous code uses the box instruction.

ldstr "The total is {0}"


ldloc.0
box int32
call void [mscorlib] System.Console::WriteLine(string, object)

The box instruction prevents an exception. The Console::WriteLine method has two parameters, which are
both reference types. However, the top of the evaluation stack has a value type and a reference type. The
assignment of a value to a reference type is the problem. The memory models are inconsistent. The box
instruction removes the value type from the evaluation stack, creates an object on the managed heap that
boxes the value type, and places a reference to the newly created object back on the evaluation stack. Now
that the value type has been replaced with a reference type, Console::WriteLine is called successfully. The
unbox instruction works in reverse. It unboxes a reference that is on the evaluation stack. This instruction
unboxes the reference type to the specified value type. The reference is replaced on the evaluation stack
with the unboxed value.

This is the syntax of the box and unbox instructions:


 box valuetype
 unbox valuetype

Inheritance In previous examples in this chapter, no class has directly inherited from another class. The
classes implicitly inherited System.Object. Most classes can be inherited explicitly, including System.Object
, by using the extends keyword. The child class will inherit most members of the base class, except
constructors. In the base class, methods that are expected to be overridden in the child should be prefixed
with the keyword virtual. The callvirt instruction calls a function overridden in a child. A child instance should
be on the evaluation stack. Here is sample code of inheritance in MSIL code:

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class Starter {

.method static public void Main() il managed {


.entrypoint
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

newobj instance void Donis.CSharpBook.XClass::.ctor()


dup
call instance void Donis.CSharpBook.ZClass::MethodA()
callvirt instance void Donis.CSharpBook.XClass::MethodC()
ret
}
}

.class abstract ZClass {

.method public instance void MethodA() il managed {


ldstr "ZClass::MethodA"
call void [mscorlib] System.Console::WriteLine(string)
ret
}

.method public virtual instance void MethodC() il managed {


ldstr "ZClass::MethodC"
call void [mscorlib] System.Console::WriteLine(string)
ret
}
}

.class XClass {

.method public specialname rtspecialname


instance void .ctor() cil managed {
ret
}

.method public instance void MethodB() il managed {


ldstr "XClass::MethodB"
call void [mscorlib] System.Console::WriteLine(string)
ret
}

.method public virtual instance void MethodC() il managed {


ldstr "XClass::MethodC"
call void [mscorlib] System.Console::WriteLine(string)
ret
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Did you notice the following statement in the preceding code?

call instance void Donis.CSharpBook.ZClass::MethodA()

This statement is interesting. Before this instruction is executed, there is a reference to an XClass object on
the evaluation stack. XClass has inherited MethodA from the ZClass. XClass does not override or hide the
interface of MethodA in the base class. Therefore, the implementation of MethodA resides solely in the base
class. Therefore, you must call the base function on the derived reference to successfully invoke the method.

Interfaces Classes are permitted to inherit from one class but can implement multiple interfaces. There is
no interface directive; instead, add the interface keyword to the details of the class directive. The interface
keyword enforces the semantics of an interface type on the class. Member methods must be public,
abstract, and virtual. Fields are not allowed in an interface class. In addition, constructors and destructors
are not permitted. The ILASM compiler enforces these and other rules. A class identifies interfaces to
implement with the implements keyword. The class must implement all the members of the interface to
prevent run-time errors. This code demonstrates an interface and the implementation of an interface:

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class interface public abstract IA {


.method public abstract virtual instance void MethodA() il managed {
}
}

.class Starter{
.method static public void Main() il managed {
.entrypoint
newobj instance void Donis.CSharpBook.ZClass::.ctor()
callvirt instance void Donis.CSharpBook.ZClass::MethodA()

ret
}
}

.class ZClass implements Donis.CSharpBook.IA {


.method public specialname rtspecialname
instance void .ctor() cil managed {
ret
}

.method public virtual instance void MethodA() il managed {


ldstr "ZClass:MethodA"
call void [mscorlib] System.Console::WriteLine(string)
ret
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
}

MethodA is defined as part of interface IA and is an abstract function. In C#, abstract functions do not have a
function body. In MSIL code, however, abstract methods have a body, but the body cannot contain an
implementation. An abstract method has a body but no code.

Structures As discussed, interfaces are defined with the class directive. Structures are similarly defined. To
define a structure, declare a type with the class directive and add the value keyword to the class detail. The
semantics of a structure are then enforced by the MSIL compiler. For example, a structure does not have a
default constructor or destructor, a structure is sealed, and so on. The value keyword is implemented by the
ILASM compiler as an explicit inheritance of System.ValueType. You could drop the value keyword and
inherit the System. ValueType directly. The compiler also adds keywords required for a structure, such as
the sealed keyword.

As a value type, structures are defined as local variables with the .locals directive. Value types are stored on
the stack, not on the managed heap. Accessing a member, such as calling a member method, requires
binding to the address of the structure. This entails loading the address of the structure onto the evaluation
stack before accessing a member. The ldloc instruction would load the structure on the evaluation stack. We
need the address of the structure. To load the address of a local variable, use the ldloca instruction. (The "a"
variation of an MSIL instruction refers to an address.)

Call the constructor of a structure explicitly with the call instruction, not the newobj instruction. Structures
are not created on the heap. When the constructor is called directly, the type is simply initialized.

This code creates and initializes a structure:

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class Starter {
.method static public void Main() il managed {
.entrypoint
.locals init (valuetype Donis.CSharpBook.ZStruct obj)
ldloca.s obj
ldc.i4.s 10
call instance void Donis.CSharpBook.ZStruct::.ctor(int32)
ldloca.s obj

ldfld int32 Donis.CSharpBook.ZStruct::fielda


call void [mscorlib]System.Console::WriteLine(int32)
ret
}
}

.class value ZStruct {

.method public specialname rtspecialname


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

instance void .ctor(int32) cil managed {


ldarg.0
ldarg.1
stfld int32 Donis.CSharpBook.ZStruct::fielda
ret
}

.field public int32 fielda


}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Branching
The branch instruction is available in various permutations, but in all circumstances it is essentially a goto
statement. The target of a branch instruction is a label. Most branch instructions are conditional and based
on a comparative expression or a Boolean condition. For an unconditional goto, use the br instruction. Loop
and other transfer-of-control statements in C# are implemented as some combination of branch instructions.

A conditional branch can be made with the brtrue and brfalse statements. The brtrue instruction branches
on a true condition, whereas the brfalse branches on a false condition. These instructions consume a
Boolean value, which should be on the evaluation stack.

Compare instructions perform a comparison on the top two values of the evaluation stack. The two values are
replaced on the evaluation stack with the result of the comparison, which is either true or false. The
comparison should be between related types.

Table 11-7 lists the compare instructions. In the table, assume that t2 is top value on the evaluation stack,
and t1 is the second value. t2 is the last item placed on the evaluation stack and the next to be removed.
Table 11-7: Compare Instructions

Instruction Comparison

ceq t1 equal to t2

cgt t1 greater than t2

clt t1 less than t2

cgt.un and clt.un Unsigned or unordered version of the comparison operations

This sample code shows unconditional and conditional branching. It also contains an example of a
comparison instruction:

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class Starter {

.method static public void Main() il managed {


.entrypoint
ldc.i4.3
ldc.i4.1
cgt
brtrue greater
ldstr "{0} is less than or equal {1}"
br end
greater: ldstr "{0} is greater than {1}"
end: ldc.i4.3
box int32
ldc.i4.m1
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

box int32
call void [mscorlib] System.Console::WriteLine(
string, object, object)
ret
}
}
}

As a convenience, branch and compare instructions are combinable. The combined instruction compares the
top two values of the evaluation stack and branches on the result. These are called comparative branching
instructions. Instead of requiring two instructions to perform the test, only one is needed.

Table 11-8 lists comparative branching instructions.


Table 11-8:
Comparative
Branching

Ins De
tru scr
cti ipti
on on

Be Bra
q nc
h
on
eq
ual

Bn Bra
e nc
h
on
not
eq
ual

Bg Bra
e nc
h
on
gre
ate
r
tha
n
or
eq
ual
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-8:
Comparative
Branching

Ins De
tru scr
cti ipti
on on

Bgt Bra
nc
h
on
gre
ate
r
tha
n

Ble Bra
nc
h
on
les
s
tha
n
or
eq
ual

Blt Bra
nc
h
on
les
s
tha
n

bgt Th
.un e
, un
blt. sig
un, ne
an d
d ver
bn sio
e.u n
n of
the
se
ins
tru
cti
on
s

Here is an example of a for loop in MSIL code. The loop increments the count from zero to five. The current
count is displayed in iterations of the loop:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class Starter {

.method static public void Main() il managed {


.entrypoint
.locals (int32 count)
ldc.i4.0
stloc.0
br.s loop
for: ldloc count
ldc.i4.1
add
dup
stloc count
call void [mscorlib] System.Console::WriteLine(int32)
loop: ldloc count
ldc.i4.5
clt
brtrue.s for
ret
}
}
}

The sample code uses the short form of the branch instruction. Be careful when branching in the short form.
As with all short-form instructions, the operand is limited to a single byte. The short form of branch
instructions cannot jump to a label further than 1 byte away. The distance from the branch site to the label
must be describable in a single byte. If not, the application might branch to the wrong location.

Calling Methods
There are a variety of ways to call methods. So far, only the call and callvirt methods have been shown in
sample code. Some instructions or actions, such as newobj, call a method implicitly. The newobj instruction
calls a constructor, whereas the static constructor is called implicitly on the first access to the class or
object.

The call methods have the same general syntax:


 callsuffix returntype [assembly] signature

The returntype is placed on the evaluation stack; assembly is the location of the method. If in the current
assembly, the assembly element can be ignored. The complete signature of the method is represented by
signature.

Table 11-9 lists the call instructions in MSIL.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-9: Call


Instructions

Ins Description
tru
cti
on

call Intended for


calling
nonvirtual
methods.
However, the
instruction
can be
applied to
virtual
methods. The
invocation is
still
interpreted as
a nonvirtual
call.

call Calls a virtual


virt method. For
nonvirtual
methods, a
nonvirtual call
is conducted.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-9: Call


Instructions

Ins Description
tru
cti
on

call Calls a
i function
indirectly
through a
function
pointer. Place
each function
parameter and
then the
function
pointer on the
evaluation
stack. The
calli syntax is
slightly
different from
other call
instructions. It
does not
include the
target
assembly or
method name
in the syntax.
Use the ldftn
instruction to
place a
function
pointer on the
stack for a
particular
method.
This sample
code includes
both the calli
and ldftn
instructions:

.assembly
extern
mscorlib {}
.assembly
application
{}

.namespace
Donis.CSharpB
ook {

.class
Starter {

.method
static
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-9: Call


Instructions

Ins Description
tru
cti
on

jm Jumps from
p the current
method to the
target method
and transfers
the
arguments.
The caller and
callee must
have matching
signatures.
Code after the
jmp site in the
calling
function is
abandoned.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-9: Call


Instructions

Ins Description
tru
cti
on

Here is
sample code
of the jmp
instruction:

.assembly
extern
mscorlib {}
.assembly
application
{}
.namespace
Donis.CSharpB
ook {
.class
Starter {

.method
static
public void
Main() il
managed {

.entrypoint

ldstr
"Aloha!"
call
void

Donis.CSharpB
ook.Starter::
MethodA(strin
g)
ret
}

.method
static
public void

MethodA(strin
g) il
managed {

ldstr
"Before jump"
call
void
[mscorlib]
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-9: Call


Instructions

Ins Description
tru
cti
on

tail The tail


command is a
prefix
instruction
and similar to
the jmp
command.
However, the
arguments
must be
loaded
explicitly on
the evaluation
stack and the
method
signatures
can be
different.
Otherwise,
the functions
are
operationally
equivalent.
This is the
syntax of the
tail instruction:
 tail.
 call
suffix
returnty
pe [
assem
bly]
signatu
re
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Arrays
An array is a collection of related types, and there are several ways to declare an array in MSIL. Regardless,
the underlying type of any array is System.Array. Exploiting the array reference, you can call the methods
and access the properties of System.Array.

Table 11-10 lists different syntaxes for defining an array.


Table 11-10: Syntax for Defining Arrays

Array Syntax Description

type [] arrayname Declares a one-dimensional array of an undetermined size.

type [,] arrayname Declares a two-dimensional array of an undetermined size.

type [n] arrayname Declares an array of n-size.

type [m,n] arrayname Declares an array in which the size is m-columns and n-rows.

type [][] arrayname Declares a jagged array of undetermined size.

type [m][] arrayname Declares a jagged array of m arrays.

The newarr instruction initializes a one-dimensional array. In addition, the instruction pushes a reference to
the array onto the evaluation stack. You might want to use the array for some time. Move the array reference
from the evaluation stack to memory, such as a local variable, to extend to the array. The newarr instruction
requires the number of elements, which should be stored on the evaluation stack.

The syntax is as follows:


 newarr type

Elements of an array can be accessed with the ldelem or stelem instructions. The ldelem instruction loads
an element of an array onto the evaluation stack; the stelem instruction stores a value from the evaluation
stack into an element of an array. Both instructions have variations that depend on the type of data being
manipulated. The variations of ldelem are ldelem.i1, ldelem.i2, ldelem.i4, ldelem.i8, ldelem.u1, ldelem.u2,
ldelem.u4, ldelem.u8, ldelem.r4, ldelem.r8, ldelem.i, and ldelem.ref. The permutations of the stelem
instruction are stelem.i1, stelemi2, stelem.i4, stelem.i8, stelem.r4, stelem.r8, stelem.i, and stelem.ref . The
ldelem instruction requires, in order, the array reference and the element index. The stelem instruction
requires the array reference, element index, and the new value.

In the following code, an array of three strings is created. Each element is initialized to a different color. The
array elements are then displayed in a loop.

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class starter {

.method static public void Main() il managed {


.locals init (string [] names, int32 count)
.entrypoint
ldc.i4.3
newarr string
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

stloc names
ldloc names
ldc.i4.0
ldstr "Aqua"
stelem.ref
ldloc names
ldc.i4.1
ldstr "Violet"
stelem.ref
ldloc names
ldc.i4.2
ldstr "Orange"
stelem.ref
ldc.i4.0
stloc count
loop: ldloc names
ldloc count
ldelem.ref
call void [mscorlib] System.Console::WriteLine(string)
ldloc count
ldc.i4.1
add
dup
stloc count
ldc.i4.3
blt loop
ret
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Arithmetic Instructions
MSIL supports the standard arithmetic instructions. The operands of the arithmetic operation are retrieved
from the evaluation stack and replaced with the result. For example, the add instruction has two operands,
which are removed for the evaluation stack and replaced with the summation.

Table 11-11 lists the common arithmetic instructions. The final column is the number of operands consumed
from the evaluation stack during the instruction.
Table 11-11: Arithmetic Instructions

Instruction Description Operands

add Addition 2

sub Subtraction 2

mul Multiplication 2

div Division 2

rem Remainder 2

neg Negate 1

Conversion Operations
It is often necessary to convert between types. The conv instruction casts between primitive types. The
instruction has a single operand, which is the target of the cast. Conversions can cause overflows when the
memory size of the source is larger than the target. For example, this could happen when casting from a
64-bit integer to a 32-bit integer. The high-order bits are trimmed when an overflow occurs, which changes
the normal results. It's important to note that the overflow is ignored, and subtle bugs are possible. The
conv.ovf instruction prevents an overflow from going undetected. When an overflow occurs, the modified
instruction raises an overflow exception.

The following code contains an ostentatious overflow condition. The conversion raises the overflow exception.
This code is not protected from exceptions, and the application is terminated.

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class Starter {

.method static public void Main() il managed {


.entrypoint
ldc.i8 4000000000
conv.ovf.i4
pop
ret
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Exception Handling
Exception handling is implemented in the CLR. Each managed language exposes exception handling in a
language-specific manner. In C#, there are the try, catch, throw, and finally keywords. The language
compiler, such as csc, compiles code for exception handling into language-agnostic MSIL code. For the
details of exception handling in C#, read Chapter 9, "Exception Handling."

There are two strategies for implementing exception handling in MSIL code: as exception clauses or as
scoped exceptions.

Exception clauses are implemented after the core MSIL code of a method in the exceptionhandling section.
An exception clause consists of a protected block, an exception identification, and an exception handler.
Execution must fall into a protected block naturally. Also, you cannot jump into a protected block. To exit
the protected block or handler, use the leave instruction. Of course, when an exception is raised, execution
is transferred away from the protected block. Do not attempt to exit a protected block or exception handler
with a branch statement.

Exception clauses have a handler. There are four types of handlers, and each is assigned a unique code.
Table 11-12 lists the four handlers.
Table 11-12:
Exception
Clauses

Co De
de scr
ipti
on

0 Thi
s
cla
us
e
defi
ne
s
an
ex
ce
pti
on
ha
ndl
er.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-12:
Exception
Clauses

Co De
de scr
ipti
on

1 Thi
s
cla
us
e
defi
ne
s
an
ex
ce
pti
on
filte
r.
Th
e
filte
r
det
er
mi
ne
s
wh
en
the
ha
ndl
er
sh
oul
d
be
run
.
Th
e
ex
ce
pti
on
filte
r
en
ds
at
an
en
dfil
ter
ins
tru
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-12:
Exception
Clauses

Co De
de scr
ipti
on

2 Thi
s
cla
us
e
defi
ne
s
a
fina
lly
ha
ndl
er.
Th
e
fina
lly
ha
ndl
er
is
call
ed
wh
eth
er
an
ex
ce
pti
on
is
rai
se
d
or
not
.
Cle
an
up
co
de
tha
t
mu
st
be
ex
ec
ute
d
reg
ard
les
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-12:
Exception
Clauses

Co De
de scr
ipti
on

4 Thi
s
cla
us
e
defi
ne
s
a
faul
t
ha
ndl
er.
Thi
s
is
si
mil
ar
to
a
fina
lly
ha
ndl
er,
ex
ce
pt
tha
t
thi
s
cla
us
e
is
call
ed
onl
y
wh
en
an
ex
ce
pti
on
is
rai
se
d.
Th
e
faul
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

This is the syntax of the try clause:


 .try label 1 to label 2 exceptiontype handler label 3 to label 4

label 1 and label 2 define the protected code, whereas label 3 and label 4 set the scope of the handler. The
exception type specifies the type of handler as catch, filter, finally, or fault handler.

In the previous example, an overflow exception is thrown and not caught. The following code catches the
overflow exception:

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class Starter {

.method static public void Main() il managed {


.entrypoint

start: ldc.i8 4000000000


conv.ovf.i4
pop
leave done
stop: callvirt instance string [mscorlib]
System.Exception::get_Message()
call void [mscorlib] System.Console::WriteLine(string)
leave done
done: ret
.try start to stop catch [mscorlib] System.Exception
handler stop to done
}
}
}

Scoped exceptions are similar to exception handling in C#, in which there is a try and catch block. Scoped
exceptions do not employ exception clauses at the end of the method.

This is the conversion exception code written for scoped exceptions:

.assembly extern mscorlib {}


.assembly application {}

.namespace Donis.CSharpBook {

.class Starter {

.method static public void Main() il managed {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

.entrypoint
.try {
ldc.i8 4000000000
conv.ovf.i4
pop
leave done
}
catch [mscorlib] System.Exception {
callvirt instance string
[mscorlib] System.Exception::get_Message()
call void
[mscorlib] System.Console::WriteLine(string)
leave done
}
done: ret
}
}
}

Miscellaneous Operations
This chapter includes several tables that explain categories of MSIL instructions. However, some MSIL
instructions appearing in the sample code of this chapter have not been included in any table. Other
instructions have not appeared in the body of code or in a table but are valuable nonetheless. Table 11-13
details some of these miscellaneous MSIL instructions.
Table 11-13:
Miscellaneou
s MSIL
Instructions

Ins De
tru scr
cti ipti
on on

an Bit
d wis
e
an
d.

bre Ins
ak ert
a
de
bu
gg
er
bre
ak
poi
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-13:
Miscellaneou
s MSIL
Instructions

Ins De
tru scr
cti ipti
on on

ca Ca
stc st
las an
s ins
tan
ce
to
a
diff
ere
nt
typ
e.

du Du
p plic
ate
the
top
slo
t
of
the
eva
lua
tio
n
sta
ck.

do No
p no
per
ati
on
al
ins
tru
cti
on
(a
bla
nk
ins
tru
cti
on)
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 11-13:
Miscellaneou
s MSIL
Instructions

Ins De
tru scr
cti ipti
on on

or Bit
wis
e
or.

po Re
p mo
ve
the
top
ele
me
nt
of
the
eva
lua
tio
n
sta
ck.

ret Pro
hro pa
w gat
e
an
ex
ce
pti
on.

thr Thr
ow ow
an
ap
plic
ati
on
ex
ce
pti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Process Execution
How and when is MSIL code compiled to native binary? The MSIL code is compiled into binary at run time.
Only methods that are called are compiled into binary. This is part of a larger procedure called process
execution. Most of the information in this section is obtained from the Shared Source CLI, which is an open
source implementation of the Common Language Infrastructure (CLI). The Shared Source CLI is often
referred to as Rotor. For more information on Rotor, visit this page: msdn.microsoft.com/net/sscli. This
section explains method compilation in the examination of how the entry point method is executed.

Process execution begins when a managed application is launched. At that time, the CLR is bootstrapped
into the application. The CLR is bootstrapped as the mscoree.dll library. This library starts the process of
loading the CLR into the memory of the application. _CorExeMain is the starting point in mscoree.dll. Every
managed application includes a reference to mscoree.dll and _CorExeMain. You can confirm this with the
dumpbin.exe tool. Execute the following command line on any managed application for confirmation:

dumpbin /imports application .exe

Figure 11-2 shows the result of the dumpbin command.

Figure 11-2: The dumpbin command with the imports option

Managed applications have an embedded stub. The stub fools the Windows environment into loading a
managed application. The stub temporarily masks the managed application as a native Windows application.
The stub calls _CorExeMain in moscoree.dll. _CorExeMain then delegates to _CorExeMain2 in mscorwks.

_CorExeMain2 eventually calls SystemDomain::ExecuteMainMethod. As the name implies,


ExecuteMainMethod is responsible for locating and executing the entry point method. The entry point method
is a member of a class. The first step in executing the method is locating that class. During process
execution, classes are represented as EECLASS structures internally. ExecuteMainMethod calls
ClassLoader::LoadTypeHandleFromToken to obtain an instance of the EECLASS for the class that has the
entry point method. LoadTypeHandleFromToken is provided the metadata token for the class and returns an
instance of an EECLASS as an out parameter. In a managed application, only classes that are touched have
a representative EECLASS structure. The important members of the EECLASS are a pointer to the parent
class, a list of fields, and a pointer to a method table.

The method table contains an entry for each function in the class. The entries are called method descriptors.
The method descriptor is subdivided into parts. The first part is m_CodeOrIL. Before a method is jitted,
m_CodeOrIL contains the relative virtual address to the MSIL code of the method. The second part is a stub
containing a thunk to the JIT compiler. The first time the method is called, the jitter is invoked through the
stub. The jitter used the IL RVA part to locate and then compile the implementation of the method into
binary. The resulting native binary is cached in memory. In addition, the stub and m_CodeOrIL parts are
updated to reference the virtual address of the native binary. This is an optimization and prevents additional
jitting of the same method. Future calls to the function simply invoke the native binary.

Roundtripping
Roundtripping is disassembling an application, modifying the code through the disassembly, and then
reassembling the application. This provides a mechanism for maintaining or otherwise updating an
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

application without the original source code.

The following C# application simply totals two numbers, where the project name is "Add". The result is
displayed in the console window.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(string [] args){
if(args.Length<2) {
Console.WriteLine("Not enough parameters.");
Console.WriteLine("Program exiting...");
return;
}

try {
byte value1=byte.Parse(args[0]);
byte value2=byte.Parse(args[1]);
byte total=(byte) (value1+value2);
Console.WriteLine("{0} + {1} = {2}",
value1, value2, total);
}
catch(Exception e) {
Console.WriteLine(e.Message);
}
}
}
}

Let us assume that the above program was purchased from a third-party vendor for quintillion dollars. Of
course, the source code was not included with the application—even for quintillion dollars. Almost
immediately, a bug is discovered in the application. When the program is executed, the total is sometimes
incorrect. Look at the following example:

C:\ >add 200 150


200 + 150 = 94

The result should not be 350, not 94. How is this problem fixed without the source code? Roundtripping is
the answer. This begins by disassembling the application. For convenience, the ILDASM disassembler is
used:

ildasm /out=newadd.il add.exe

Open newall.il in a text editor. In examining the MSIL code, we can easily find the culprit. The addition
instruction adds two byte variables. The result is cached in another byte variable. This is an unsafe action
that occasionally causes an overflow in the total. Instead of notifying the application of the overflow event, the
value is cycled. This is the reason for the errant value. Add the ovf suffix to the conv instruction to correct the
problem. The exception is now raised when the overflow occurs.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

You can use roundtripping to add features not otherwise available directly in C#. C# supports general
exception handling but not exception filters. When an exception is raised, the exception filter determines
whether the exception handler executes. If the exception filter evaluates to one, the handler runs. If zero, the
handler is skipped.

Here is a partial listing of the disassembled program. It is modified to throw an exception when the additional
overflows the total. An exception filter has also been added to the exception handling. Changes in the code
are highlighted:

IL_0035: ldelem.ref
IL_0036: call uint8 [mscorlib]System.Byte::Parse(string)
IL_003b: stloc.1
IL_003c: ldloc.0
IL_003d: ldloc.1
IL_003e: add
IL_003f: conv.ovf.u1

IL_0040: stloc.2
IL_0041: ldstr "{0} + {1} = {2}"
IL_0046: ldloc.0
IL_0047: box [mscorlib]System.Byte
IL_004c: ldloc.1
IL_004d: box [mscorlib]System.Byte
IL_0052: ldloc.2
IL_0053: box [mscorlib]System.Byte
IL_0058: call void [mscorlib]System.Console::WriteLine(string,
object,
object,
object)
IL_005d: nop
IL_005e: nop
IL_005f: leave.s IL_0072

} // end .try
filter
{
pop
ldc.i4.1
endfilter
}
// catch [mscorlib]System.Exception
{
IL_0061: stloc.3
IL_0062: nop
IL_0063: ldloc.3
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Because the filter returns one, the exception is always handled. The ILASM compiler can reassemble the
application, which completes the roundtrip. Here is the command:

ilasm newadd.il

Run and test the newadd application. The changed program is more robust. Roundtripping has been a
success!
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Debugging with Visual Studio 2005


The first two chapters of Part IV, "Debugging," review the metadata and MSIL code of an assembly. The next
two chapters focus on debuggers. There is a variety of debuggers available for managed code. Chapter 12
starts with Visual Studio 2005.

The Visual Studio 2005 debugger has two primary advantages. First, Visual Studio uses a familiar graphic
user interface. Second, the debugger is integrated with other aspects of the programming environment. You
can develop, test, debug, and return to developing an application within a single product. This is very
convenient.

The debugger in Visual Studio 2005 has a plethora of rapid application development (RAD) tools for
debugging, including a multitude of debug windows, a specialized toolbar, the ability to open dumps, and
much more. The next chapter explores these tools and how to debug an application with Visual Studio 2005.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 12: Debugging with Visual Studio 2005


Overview
Microsoft Visual Studio is a popular development environment that has an effective debugger to help
developers quickly diagnose and correct application problems. The Visual Studio debugger is a multipurpose
tool that includes an assortment of tools, features, and windows to help developers quickly ascertain and
correct problems. Use the Visual Studio debugger to inspect the values of variables, view the call stack,
determine thread status, dump memory, set various types of breakpoints, and much more. Visual Studio
2005 introduces new features such as visualizers, tracepoints, crash dumps (opening directly), and the
Exception Assistant. One benefit of the Visual Studio debugger is the familiar user interface. Developers
experienced with the Visual Studio environment should be comfortable with the look and feel of the debugger.

Visual Studio debugging is extensible. Developers can customize many aspects of the debugger, including
extending many of the types related to debugging. For example, developers can create user-defined
visualizers and trace listeners. Visual Studio debugging is adaptable to specific problems, objectives, and
goals.

In a debugging session, developers control how an application executes. A developer can start, interrupt, or
stop a debugging session. These are the controls explained in Table 12-1.
Table 12-1: Control of a Debugging Session

Control Description

Start From the Debug menu, there are various commands to start a debugging session. If you use
Execution the Start Debugging, Step Into, or Step Over menu command, the application is in running
mode. Alternatively, the Start Without Debugging menu command starts an application
without attaching the Visual Studio debugger.
You can also start a debugging session with the Run To Cursor command. In the source
editor, position the cursor on the target source code. Open the shortcut menu and select
the Run To Cursor menu command. This command starts an application in debug mode, but
breaks when a breakpoint or the cursor is reached. If neither occurs, the application runs
uninterrupted.

Break You can break into an application running in a debug session, which is most commonly
Execution accomplished by setting breakpoints. Developers can forcibly break into an application
using the Break All menu command from the Debug menu. The command interrupts all
applications currently being debugged by the Visual Studio debugger. After breaking into the
application, the user is transferred to the source code being executed when the break
occurred. If source code is not available, the user is transferred to the disassembly. When
execution is interrupted, the application is in break mode.

Stop Developers can choose to end a debugging session. From the Debug menu, select the Stop
Execution Debugging command to end a debugging session.
You can terminate an attached process in the Processes window. In that window, select the
process and choose the Terminate Process menu command from the context menu.
A debug session can be stopped and restarted again. On the Debug menu, the Restart
menu command restarts a debugging session.

Applications in a debugging session are either in a running mode or a break mode. In running mode, an
application is executing. In break mode, an application is interrupted, which is when a developer commonly
diagnoses an application. Certain features are applicable only in break mode, such as the Threads and Call
Stack windows. While debugging, an application can transition between running and break modes. The
following actions can transfer an application from running to break mode:
 A breakpoint is hit.
 A tracepoint is hit.
 The cursor is hit with a Run To Cursor command.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 The Break All command is executed.


 An unhandled exception is raised.
 Stepping through an application.

You can transition from break mode to running mode by starting execution again, which is defined in Table
12-1.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Debugging Overview
Debugging techniques vary between project types. For example, the strategy for debugging a Microsoft
Windows application is different from debugging a class library. This section provides an overview of
debugging strategies for basic project types.

Debugging Windows Forms Projects

Of the project types, managing a debugging session for a Windows Forms project is probably the easiest.
Initiate a debugging session to begin debugging a Windows Forms application.

Start a debugging session of a Windows Forms project with a start execution action, such as the Start
Debugging menu command. When the execution starts, the Visual Studio debugger is attached to the
application.

Set breakpoints before or during the debugging session. Windows Forms applications are event driven, and
breakpoints can be placed in event handlers. Breakpoints can also be added to functions called from event
handlers. When the breakpoint is hit, the debugging session is transferred to break mode. To run between
breakpoints, use the Start Debugging menu command.

Attaching to a Running Process


You can attach the debugger to processes running outside of Visual Studio. At that time, a debug session is
initiated. There are several reasons to attach to a process:
 When a problem occurs in an application, you can immediately debug the situation. Attach the
debugger and diagnose the problem.
 You can debug a class library project in the context of a running process.
 You can debug a production application. If you attach to an application that is not a debug build,
an error message box is displayed. You can then proceed into a debugging session. However,
source code, symbols, and other ingredients of a normal debugging session might not be
available. Care must be taken when debugging a production application. Some actions can
interfere with the normal execution of the program. For example, breakpoints can interrupt
execution of the application and strand users.

Open the Attach To Process window to attach to a process. (From the Debug menu, choose the Attach To
Process menu command.) Figure 12-1 shows the Attach To Process window. The Debug menu is not
available when no solution is open. In that circumstance, choose the Attach To Process menu command
from the Tools menu.

Figure 12-1: Attach To Process window

A list of processes is presented in the Attach To Process window. To attach to a specific process, select a
process from the Available Processes list and then click the Attach button. If not a debug build, an error
message box is displayed. The debugger can be attached to multiple processes. All the attached processes
are dimmed in the process list. However, you can actively debug only a single process, which defaults to the
last process attached. You can change a current process by using the Debug Location toolbar and the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Process drop-down list, which is shown in Figure 12-2. You can also select the Debug Location toolbar from
the Toolbars submenu on the View menu.

Figure 12-2: Debug Location toolbar

The Attach To Process window has several options. Transport is the transport used to connect to a target
device or remote machine. Default connects to a local machine or remote machine using the Microsoft
Visual Studio Remote Debugging Monitor (msvsmon.exe). The Qualifier window is the name of the target
machine. The Attach To choice selects the target type as managed, native, script, or T-SQL. The default is
managed. The Show Processes For All Users option lists processes from all users of the current logon
session. For Terminal Service clients remotely connected to a machine, Show Processes In All Sessions
displays the processes of the remote machine session. The process list is not static. As new processes
start up and existing processes finish, the list of running processes changes. The Refresh button updates
the list box to reflect any changes in the process list.

After attaching to an application, interrupt the application with a breakpoint. You can then use debugging
techniques and the various debugging windows to debug the application. To set a breakpoint, open the
source code of the application and insert a breakpoint. When execution hits the breakpoint, the application
is interrupted. Alternatively, use the BreakAll menu command on the Debug menu.

Terminate the debugging session to detach the debugger from the running process. For example, the Stop
Debugging menu command on the Debug menu terminates a debugging session and detaches from a
running process. The running process will continue to execute.

Debugging Console Application Projects


Debugging a Console project is similar to debugging a Windows application, with some notable differences:
 Console applications typically output to the Console window, but debug messages are normally
displayed in the Output window. Displaying messages in separate windows has both advantages
and disadvantages. Clarity in isolation of debug messages is the primary advantage. Parsing
debug and normal messages in separate windows helps track both. Conversely, the advantage of
a single window for all output is convenience. The developer need not toggle between the Console
and Output windows. With the TraceSource type, you have the option of displaying trace
messages in several locations, including the Console window, Output window, or both windows
simultaneously.
 Console applications often require command-line arguments. Open Project properties from the
Project menu. From the Debug window, enter the command-line arguments as part of the Startup
Options. Be sure to refresh the command-line arguments as needed.
 In a debugging session, the results of a short running console application are only briefly
displayed before the console window is closed. Therefore, the results may be difficult to view.
Freeze the window by inserting a Console.ReadLine statement. Alternatively, after debugging the
application, execute in release mode to persist the Console window. In that case, Press Any Key
To Continue is displayed.

Debugging Class Library Projects


A class library project creates a dynamic-link library (DLL), which does not execute directly. This makes the
proposition of debugging more challenging. The DLL must run within the context of another application. The
execution of the host application precedes the DLL. The host loads the DLL when needed.

You can specify the host application in the debug settings for the project. In the Debug pane of the Project
properties window, select the Start External Program option as the Start action and enter the name of the
hosting application. At the start of the debugging session, the specified host is executed and the DLL is
loaded as needed. You can then debug the class library project.

If the host application and class library projects are in the same solution, setting the external program is not
necessary. Simply set the host application to the startup project. Start a debugging session normally and
debug both the host and class library projects.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

When the host application is already running, attach the debugger to that process in the Attach To Process
window. This process will initiate a debug session in which the class library project can then be debugged.

Debugging Setup

The Visual Studio debugger is fully configurable. Debugging sessions can be tailored to a developer or to the
specific requirements of an application. For convenience, debug settings are saved in a configuration. Debug
and Release are the default configurations and represent the most commonly used settings. The Debug
configuration contains the project options for creating debug builds of an application. The Release
configuration contains the options for release builds. Prior to changing project settings, it is good policy to
confirm the active configuration. This avoids inadvertently changing the wrong configuration.

Debug and Release Configurations


As mentioned, the default configurations are Debug and Release. There are literally dozens of project options
set in the predefined Debug and Release configurations. You can view and set debug configurations from
Project properties in Solution Explorer. Open Project properties using the project context menu.

The important settings of the Debug configuration are as follows:


 The DEBUG and TRACE constants—which control the behavior of the TraceSource, Debug, and
Trace types—are defined.
 The Debug Info option is set to full. This option requests the creation of a symbol file (pdb)
whenever a project is built.
 The output path is bin\debug.
 The Optimize Code option is set to false, which disables code optimization.

The settings of the Release configuration are as follows:


 The DEBUG constant is not defined; however, the TRACE constant is defined.
 The Debug Info option is set to pdb-only.
 The output path is bin\release.
 The Optimize Code option is set to true, which enables code optimization.

Configuration Manager
Use the Configuration Manager to view, edit, and create configurations of project settings. To open the
Configuration Manager, choose the Configuration Manager menu command from the Build Menu. Figure 12-3
shows the Configuration Manager. The Configuration Manager lists the current configuration of each project
in the solution.

Figure 12-3: Configuration Manager

In the Configuration Manager, the Active Solution Configuration drop-down list selects a common
configuration for every project. You can also create a new configuration from the drop-down list. In addition,
you can rename or remove an existing configuration. The Active Solution Platform drop-down list selects the
current platform.

Each row of the Configuration Manager represents a project. The project list has several columns of
information:

 Project This column shows the name of each project.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 Configuration This column selects the current configuration of each project.

 Platform This column selects the target platform of each project.

 Build This column is an option box, which includes or excludes projects in builds of the solution.

Debug Settings

The Visual Studio environment, solution, and project maintain separate debug settings:
 Debug settings of the Visual Studio environment are set in the Options dialog box. (From the
Tools menu, choose the Options menu command.)
 Debug settings of a project are set in the Project properties dialog box, which is opened by using
the Project properties menu command on the Project menu.
 Debug settings of a solution are set in the Solution properties window. Open this window from the
context menu of the solution in Solution Explorer.

Visual Studio Environment Debug Settings


Debug settings for the Visual Studio product affect all projects. You can configure Edit And Continue,
just-in-time (JIT) debugging, native debugging options, symbol servers, and general debugging options for the
environment.

General window The general debugging options are an assortment of miscellaneous options. Each option
can be enabled or disabled. Figure 12-4 shows the General window for setting these options.

Figure 12-4: The General window for setting general debugging options

Each option is described in Table 12-2.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

As Thi En
k s abl
Bef opt ed
ore ion
Del req
eti ue
ng sts
All co
Bre nfir
ak ma
poi tio
nts n
wit
h
the
Del
ete
All
Bre
ak
poi
nts
co
m
ma
nd.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Bre Thi En
ak s abl
All opt ed
Pro ion
ce int
ss err
es upt
Wh s
en all
On pro
e ce
Pro ss
ce es
ss bei
Bre ng
ak de
s bu
gg
ed
wh
en
a
bre
ak
oc
cur
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Bre Thi Dis


ak s abl
Wh opt ed
en ion
Ex as
ce ks
pti the
on Co
s m
Cro mo
ss n
Ap La
pD ng
om ua
ain ge
Or Ru
Ma nti
na me
ge (CL
d/N R)
ativ to
e cat
Bo ch
un ex
dar ce
ies pti
(M on
an s
ag tha
ed t
Onl cro
y) ss
an
ap
plic
ati
on
do
ma
in
or
cro
ss
bet
we
en
ma
na
ge
d
an
d
nat
ive
co
de.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

En Thi En
abl s abl
e opt ed
Ad ion
dre allo
ss- ws
Lev cer
el tai
De n
bu op
ggi era
ng tio
ns
at
the
ad
dre
ss
lev
el,
su
ch
as
set
tin
g
bre
ak
poi
nts
on
ins
tru
cti
on
ad
dre
ss
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Sh Thi Dis
ow s abl
Dis opt ed
as ion
se req
mb ue
ly sts
If tha
So t
urc the
e dis
Is as
Not se
Av mb
aila ly
ble win
do
w
be
dis
pla
ye
d
wh
en
us
er
so
urc
e
co
de
is
not
ava
ilab
le.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

En Thi En
abl s abl
e opt ed
Bre ion
ak let
poi s
nt dev
Filt elo
ers per
s
set
filte
rs
on
bre
ak
poi
nts
,
whi
ch
ca
n
limi
t
the
sc
op
e
of
a
bre
ak
poi
nt
to
a
thr
ea
d,
pro
ce
ss,
or
ma
chi
ne.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

En Thi En
abl s abl
e opt ed
Th ion
e aut
Ex om
ce ati
pti call
on y
As dis
sis pla
tan ys
t the
Ex
ce
pti
on
As
sis
tan
t
wh
en
an
ex
ce
pti
on
is
rai
se
d
whi
le
de
bu
ggi
ng.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Un Thi En
win s abl
d opt ed
Th ion
e allo
Cal ws
l the
Sta us
ck er
On to
Un un
ha win
ndl d
ed the
Ex call
ce sta
pti ck
on on
s a
firs
t
ch
an
ce
ex
ce
pti
on,
in
whi
ch
co
de
ch
an
ge
s
ca
n
be
ma
de
incl
udi
ng
rep
airi
ng
the
so
urc
e
of
the
ex
ce
pti
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

En Thi En
abl s abl
e opt ed
Jus ion
t allo
My ws
Co the
de de
(M bu
an gg
ag er
ed to
Onl ste
y) p
int
o
us
er
co
de.
Ot
her
co
de,
su
ch
as
sy
ste
m
co
de,
is
ski
pp
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Wa Thi En
rn s abl
If opt ed
No ion
Us dis
er pla
Co ys
de a
On war
La nin
un g
ch wh
en
de
bu
ggi
ng
is
initi
ate
d
if
no
us
er
co
de
is
ava
ilab
le.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

En Thi En
abl s abl
e opt ed
Pro ion
per eva
ty lua
Ev tes
alu the
ati res
on ult
An of
d pro
Ot per
her tie
Im s
plic an
it d
Fu oth
nct er
ion im
Cal plic
ls it
fun
cti
on
call
s
in
Wa
tch
an
d
Var
iabl
es
win
do
ws.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Cal Thi En
l s abl
To opt ed
Stri ion
ng( call
) s
On To
Obj Stri
ect ng
s im
In plic
Var itly
iabl on
es obj
Wi ect
nd s
ow dis
s pla
(C# ye
Onl d
y) in
vari
abl
es
win
do
ws.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

En Thi Dis
abl s abl
e opt ed
So ion
urc req
e ue
Ser sts
ver tha
Su t
pp Vis
ort ual
Stu
dio
get
so
urc
e
co
urs
e
fro
m
the
so
urc
e
co
de
ser
ver
(sr
csr
v.dl
l).
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Pri Thi Dis


nt s abl
So opt ed
urc ion
e dis
Ser pla
ver ys
Dia me
gn ss
ost ag
ics es
Me fro
ss m
ag the
es so
To urc
Th e
e ser
Ou ver
tpu in
t the
Wi Ou
nd tpu
ow t
win
do
w.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Hig Thi Dis


hlig s abl
ht opt ed
Ent ion
ire hig
So hlig
urc hts
e an
Lin ent
e ire
For line
Bre of
ak so
poi urc
nts e
An co
d de
Cur to
ren em
t ph
Sta asi
te ze
me the
nt cur
ren
t
bre
ak
poi
nt
or
sta
te
me
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Re Thi En
qui s abl
re opt ed
So ion
urc as
e ks
Fil the
es Vis
To ual
Ex Stu
act dio
ly de
Ma bu
tch gg
Th er
e to
Ori veri
gin fy
al tha
Ver t
sio the
n cur
ren
t
so
urc
e
file
ma
tch
es
the
ver
sio
n
buil
t
wit
h
the
ap
plic
ati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Re Thi Dis
dir s abl
ect opt ed
All ion
Ou red
tpu ire
t cts
Wi me
nd ss
ow ag
Te es
xt fro
To m
Th the
e Ou
Im tpu
me t
dia win
te do
Wi w
nd to
ow the
Im
me
dia
te
win
do
w.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Sh Thi Dis
ow s abl
Ra opt ed
w ion
Str dis
uct abl
ure es
Of de
Obj bu
ect gg
s er
In cu
Var sto
iabl mi
es zat
Wi ion
nd s,
ow su
s ch
as
the
De
bu
gg
erD
ispl
ay
attr
ibu
te.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Su Thi En
ppr s abl
es opt ed
s ion
JIT dis
opt abl
imi es
zat JIT
ion opt
s imi
On zat
Mo ion
dul s,
e whi
Lo ch
ad ca
(M n
an ma
ag ke
ed co
Onl de
y) ea
sie
r
to
de
bu
g.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-2: General


Debugging Options

Op De De
tio scr fau
n ipti lt
on

Wa Thi En
rn s abl
If opt ed
No ion
Sy dis
mb pla
ols ys
On a
La war
un nin
ch g
(Na wh
tive en
Onl no
y) sy
mb
ol
info
rm
ati
on
is
ava
ilab
le.

Edit And Continue window Edit And Continue permits changes to the source code while debugging. The
changes are applied immediately without having to rebuild and restart the application. Edit And Continue is
automatically enabled when breaking and then stepping through an application.

Most changes within a method are supported, such as deleting a line of code. However, Edit And Continue
supports few changes that are made outside of a method. For example, deleting class members is not
allowed. The following changes are not supported in Edit And Continue:
 Modifying an active statement.
 Surrounding an active statement with a foreach, using, or lock block.
 If the active statement is in the current stack frame, you cannot surround the active statement
with a catch or finally block. You also cannot add a nested exception handler beneath six levels.
 If the active statement is not in the current stack frame, you cannot surround the active statement
with a try, catch, or finally block. In addition, you cannot add a nested exception handler beneath
six levels. Finally, you cannot change the code in the try block that contains the active statement.
 Adding a new member.
 Adding or changing a global symbol.
 Changing the signature of a member.
 Editing an anonymous method or a function containing a anonymous method.
 Changing, adding, or deleting an attribute.
 Changing or deleting a local variable.
 Modifying a method that contains a yield return or yield break statement.
 Changing, adding, or deleting a using directive.
 Modifying a constructor that contains a local variable that is initialized in an anonymous method.

Edit And Continue is not available in the following environments:


 Mixed-mode debugging
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 SQL debugging
 Unhandled exceptions, unless the Unwind The Call Stack On Unhandled Exceptions general
debugging option is enabled
 Attached application debugging
 64-bit application debugging
 After a failed rebuild of the current application

In the Edit And Continue window, the Edit And Continue feature can be enabled or disabled. Figure 12-5
shows the Edit And Continue window. The remaining settings pertain to native code.

Figure 12-5: Edit And Continue debug settings

Just-In-Time Debugging window The JIT debugger is attached to a running application when the program
fails. Register Visual Studio as the JIT debugger in the Just-In-Time Debugging window. (See Figure 12-6.)
Visual Studio can be the JIT debugger for Managed code, Native code, and Scripting. JIT debugging is
discussed in the next chapter, "Advanced Debugging."

Figure 12-6: Just-In-Time Debugging window

Native window The Native window has two debugging options. Enable the Load DLL Exports option to load
the export tables for DLLs. This is beneficial when the debug symbols are not available. For example, you
can set breakpoints on functions exported from the library even though symbols are not available. The
Enable RPC Debugging option enables stepping into Component Object Model (COM) remote procedure
calls. Both options are disabled by default.

Symbols window Visual Studio can be configured to consult a symbol server and download the correct
debugging symbols for the environment. Developers can use the Microsoft public symbol server or a local
symbol server. Identify symbol servers and downstream paths in the Symbols window, which is shown in
Figure 12-7. In the Symbol File Locations list box, symbol server paths can be entered or removed. Enter
downstream servers in the Cache Symbols From Symbol Servers To This Directory Value.

Figure 12-7: Symbols window


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Symbols can be loaded manually in the Modules window, as shown in Figure 12-8. Open the Modules
window from the Debug menu and the Windows submenu. The Modules window lists the modules loaded in
the current application. This window is applicable in break mode, not running mode. Each row of the window
has the name of the module, path to the module, whether the module is optimized, source code availability,
symbol status, and fully qualified path to the symbol file. The Symbol Status column indicates whether the
symbols are loaded or skipped. Symbols are automatically skipped for optimized code. For skipped
symbols, you can manually load the symbols for a specific module using the context menu. The Load
Symbols menu command loads the symbols for the selected module. The Load Symbols and Symbol File
columns are then updated. The Symbol Status column shows whether the symbols are successfully loaded
for the module. The Symbol File column displays the path to the loaded symbol file. If the symbol file cannot
be found for the specified module, you are prompted with the Find Symbols dialog box, as shown in Figure
12-9. From there, you can browse to the relevant symbol file.

Figure 12-8: Modules window

Figure 12-9: Find Symbols dialog box

From a module's context menu, the Symbol Load Information menu command displays general information
about the symbols for the module. There is also a Symbol Setting menu command, which opens the Symbol
debug window. You can configure symbols in this window.

Debug Settings for a Solution


Debug settings for a solution are set in the Solution property pages. The only settings available are Debug
Source Files settings. (The Debug Source Files window is shown in Figure 12-10.) In this window, you can
designate the directories that include and exclude source files.

Figure 12-10: Debug Source Files window


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Debug Settings for a Project


Debug settings for a project set the startup action, command-line arguments, and other debug options. Figure
12-11 shows the Debug pane of the Project Property pages.

Figure 12-11: Debug pane of the Project Property pages

The Start Action option box indicates the startup action for debugging, which determines the application to
launch when starting a debugging session. Here are the options:
 The Start Project option, which is the default, starts the application of the startup project.
 The Start External Program option is typically selected to debug class library projects. Specify
the hosting application that loads the DLL of the class library project. You can then debug into the
class library.
 The Start Browser With URL option is useful for debugging Web applications. Browse to a URL
that is controlled by the Web application. The Web application is then loaded via the Web server,
which provides an opportunity to debug the Web application.

The Start Options option box contains the following miscellaneous settings:
 Enter command-line arguments for the application in the Command Line Arguments text box.
 The Working Directory text box sets the working directory of the application. This is the default
path for directory- and file-related tasks.
 The Use Remote Machine option names a remote machine, where the target application resides.

The Enable Debuggers option box indicates the kind of code that can be debugged:
 The Enable Unmanaged Code Debugging option enables mixed-mode debugging. Developers can
debug between managed and unmanaged code.
 The Enable SQL Server Debugging option allows developers to debug CLR assemblies running
within Microsoft SQL Server 2005.
 The Enable The Visual Studio Hosting Process option activates the Visual Studio hosting
process, which is a new feature in Visual Studio 2005.

Visual Studio Debugging User Interface

The user interface in Visual Studio 2005 has new debugging features, which include data tips and
visualizers. These enhancements improve developers' debugging experience. Other features, such as
tracepoints, represent improvements of existing features. Tracepoints are a new style of breakpoints.

Data Tips
While you are debugging, a data tip is displayed when the cursor is paused over a variable. Previously, data
tips were helpful when viewing simple types, such as integers and other value types. However, the details of
a complex type were not visible in a data tip. In Visual Studio 2005, data tips are improved and can display
the fields of a complex type. The complex type is at first collapsed in the data tip. Expansion displays the
type members and values in the data tip.

Visualizers
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Visualizers display the underlying HTML, XML, or text associated with a data tip. For example, the improved
data tip can display the composition of a dataset, which is a complex type. A dataset is more than the
composition of all its members. Datasets are an abstraction of an XML data source. The ability to view the
underlying data while debugging is invaluable. Imagine programmatically parsing XML data and receiving
incorrect results. You need to know if the problem is in the XML or the program logic. The XML Visualizer
provides a convenient way to view the source XML data.

Data tips now have an optional menu that displays available visualizers. When a data tip detects values that
are compatible with a visualizer, the visualizer menu is automatically displayed.

In the following code, myxml is a field that contains XML. The XML defines an array of books.

private string myxml = "<books><book><title>" +


"The Gourmet Microwave</title>" +
"<price>19.95</price>" +
"</book><book><title>Sushi, Anyone?</title>" +
"<price>49.99</price></book></books>";

The following code changes the content of the myxml field:

string newbook="<book><title>" +
"Donis's Great Adventure</title>" +
"<price>9.95</price>" +
"</book>";

myxml=myxml.Insert(5, newbook);

A string that contains XML, which describes another book, is added to the myxml string. A data tip can
easily display the modified myxml string. Viewing myxml as XML provides additional clarification and
important information. Move the cursor over the myxml variable, and a data tip appears. The modified string is
displayed. From the data tip menu, select XML Visualizer. The XML Visualizer opens, as shown in Figure
12-12. The Visualizer uncovers a problem, which is that the underlying XML is not well-formed. Why not? The
additional book was inserted at the wrong location in the myxml string, which is not detected from a simple
data tip. However, the problem is caught by the Visualizer.

Figure 12-12: XML Visualizer uncovers a problem

The following code is modified to insert the book at the correct location in the myxml string. Now the XML
Visualizer correctly displays the XML of the string. (See Figure 12-13.) You have just found and successfully
resolved a bug!
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 12-13: XML Visualizer of myxml

myxml=myxml.Insert(7, newbook);

Visualizers are extensible; developers can create user-defined visualizers. The DataSet Visualizer is an
example of a custom visualizer. It will display the data behind a dataset, which is very helpful. The following
code displays rows in a dataset. A breakpoint is placed on the highlighted line.

DataSet ds = new DataSet();


ds.ReadXml(@"C:\Xml\titles.xml");
DataRowCollection rows = ds.Tables[0].Rows;

foreach (DataRow row in rows)


{
lblData.Items.Add(row[0].ToString());
}

The cursor is placed over the ds variable, which is an instance of a dataset. A data tip appears, which has
several rows. There is a Visualizer menu on the row of the DataSet type. Choose the DataSet Visualizer
from the menu. The dataset is then displayed in DataSet Visualizer window, with the results shown in Figure
12-14. From here, you can choose the data table to view, sort the data columns, and make basic changes to
the fields.

Figure 12-14: Dataset Visualizer

Breakpoints

Breakpoints are stop signs in code where execution is interrupted. When a breakpoint is hit, the application
enters the break mode. You can then debug the application with a variety of Visual Studio debugger
commands. There are different kinds of breakpoints. A normal breakpoint appears as a red circle to the left of
the target.

The F9 function key is the breakpoint command that sets a simple breakpoint on the selected line of source
code. F9 is a toggle, which sets or clears a breakpoint. In addition, clicking in the leftmost dimmed column
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

sets or clears a breakpoint. The Continue menu command (F5) on the Debug menu resumes an application.
The application runs until another breakpoint is hit, the application is otherwise interrupted, or the debug
session ends. Other commands, such as Run To Cursor, also resume execution.

You can add new breakpoints from the Debug menu and the New Breakpoint submenu. Break At Function
adds a function breakpoint. New Data Breakpoint sets a breakpoint that breaks when a variable has
changed. This option is not available in C# or Microsoft Visual Basic .NET.

Function Breakpoints
Function breakpoints break on the first line of a function and can be set at compile time or run time.

Set a function breakpoint from the New Breakpoint submenu. Choose the Break at Function command.
Figure 12-15 shows the New Breakpoint dialog box. The shortcut key is Ctrl+B. In this example, a
breakpoint is set on the first line of the WClass.MethodA function. As a shortcut, select the name of the
target function first and open the New Breakpoint dialog box. The function name will automatically appear in
the New Breakpoint dialog box. If you're breaking on an ambiguous or overloaded name, the Choose
Breakpoints dialog box opens. For example, in the sample code, MethodA is ambiguous. There are several
instances of MethodA in the application. In Figure 12-16, the New Breakpoint dialog box sets a breakpoint on
MethodA. Figure 12-17 displays the Choose Breakpoints dialog box that subsequently appears, in which the
user can select a specific location to set the breakpoint. To avoid ambiguity, you can enter the class name (
Classname.Methodname) or the method signature.

Figure 12-15: New Breakpoint dialog box

Figure 12-16: Setting a breakpoint on MethodA

Figure 12-17: Choose Breakpoints dialog box

The Use IntelliSense To Verify The Function Name option of the New Breakpoint dialog box requests the
Choose Breakpoint dialog box whenever a user enters an ambiguous or overloaded function name. With this
option, users are notified of invalid function names. With the option disabled, there is no notification, and the
New Breakpoint dialog box simply closes without setting the breakpoint.

You can also set breakpoints in the Call Stack window, which is available on the Debug menu within the
Windows submenu. A function breakpoint on the call stack breaks upon re-entering that method as the
stack unwinds. For example, MethodA calls MethodB. MethodB then calls MethodC. A breakpoint is then
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

set on MethodA in the Call Stack window. When MethodB returns and the related stack frame is removed,
the application is interrupted on re-entering MethodA. The Call Stack window is available in break mode. Set
a breakpoint for a specific method using the context menu or the F9 breakpoint keyboard shortcut. A
breakpoint set on MethodA in the call stack is exhibited in Figure 12-18.

Figure 12-18: Breakpoint in the Call Stack window

Breakpoints Window
Developers can manage breakpoints in the Breakpoints window (opened from the Debug menu and the
Windows submenu). Figure 12-19 shows the Breakpoints window.

Figure 12-19: Breakpoints window

In the Breakpoints window, breakpoints are shown on separate rows. The first column of each row is the
enabled/disabled options box. If a breakpoint is enabled, the option box is checked. Uncheck the column to
disable the breakpoint. The next column provides the description and location of the breakpoint. The
Condition column shows any conditions set on the breakpoint. The final column shows the hit count. In that
column, Break Always means that the program is interrupted every time the breakpoint is hit.

The context menu has several valuable options that affect the selected breakpoint. The first menu command
is Delete, which removes the breakpoint. The Go To Source Code menu command redirects to the
breakpoint in the source code. The Go To Disassembly menu command redirects to the disassembly at the
breakpoint. For this command, the application must be in break mode. The remaining commands of the
context menu customize the selected breakpoint and are explained in the following sections.

Location This command changes the location of a breakpoint. You are presented with the Address
Breakpoint or File Breakpoint dialog box (shown in Figures 12-20 and 12-21). The Address Breakpoint dialog
box is displayed for memory breakpoints, such as a breakpoint set on the call stack. The File breakpoint
dialog box is displayed for line breakpoints in source code.

Figure 12-20: Address Breakpoint Dialog Box


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 12-21: File Breakpoint Dialog Box

Condition This command sets additional criteria for honoring a breakpoint. The condition can be a Boolean
expression. If true, the breakpoint is honored. Otherwise, the breakpoint is ignored. The condition can also
be based on changes to a value. If the value is changed, the breakpoint is honored.

Look at the following sample code. The breakpoint is set on the dimmed line. We want to honor the
breakpoint only when ivalue contains an even value.

int[] numbers ={1,2,3,4,5,6,7,8,9,10,


11,12,13,14,15,165,17,18,18,20};
int total = 0;

foreach (int ivalue in numbers)


{
total += ivalue;
}

The Breakpoint Condition dialog box, shown in Figure 12-22, sets the condition to break on even values.

Figure 12-22: Conditional Breakpoint dialog box

Hit Count This command honors a breakpoint based on the hit count. Table 12-3 lists the hit count options.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-3:
Hit Count
Options

Op De
tio scr
n ipti
on

Bre Thi
ak s
Al opt
wa ion
ys alw
ay
s
ho
nor
s
the
bre
ak
poi
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-3:
Hit Count
Options

Op De
tio scr
n ipti
on

Bre Thi
ak s
Wh opt
en ion
Th ho
e nor
Hit s
Co the
unt bre
Is ak
Eq poi
ual nt
To wh
en
tha
t
ins
tan
ce
of
the
bre
ak
poi
nt
oc
cur
s.
For
ex
am
ple
,
int
err
upt
on
the
fou
rth
oc
ca
sio
n
of
a
sp
ecif
ic
bre
ak
poi
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-3:
Hit Count
Options

Op De
tio scr
n ipti
on

Bre Thi
ak s
Wh opt
en ion
Th ho
e nor
Hit s
Co the
unt bre
Is ak
A poi
Mu nt
ltipl as
e a
Of mu
ltipl
e
of
a
val
ue,
for
ex
am
ple
,
eve
ry
thir
d
ins
tan
ce
of
the
bre
ak
poi
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-3:
Hit Count
Options

Op De
tio scr
n ipti
on

Bre Thi
ak s
Wh opt
en ion
Th ho
e nor
Hit s
Co the
unt bre
Is ak
Gr poi
eat nt
er sta
Th rtin
an g
Or at
Eq a
ual cer
To tai
n
ins
tan
ce;
for
ex
am
ple
,
ho
nor
the
bre
ak
poi
nt
at
the
thir
d
an
d
eve
ry
su
cc
es
siv
e
ins
tan
ce.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The Breakpoint Hit Count dialog box, shown in Figure 12-23, honors every third instance of the selected
breakpoint.

Figure 12-23: Breakpoint Hit Count dialog box

Filter This command sets the affinity of a breakpoint to a machine, thread, or process. The breakpoint
interrupts only in the context of the stated filter. Table 12-4 lists the available contexts.
Table 12-4:
Filter
Contexts

Co De
nte scr
xt ipti
on

Ma Thi
chi s
ne co
Na nte
me xt
is
the
na
me
of
the
ma
chi
ne.
Bre
ak
poi
nt
is
ho
nor
ed
if
the
pro
ce
ss
is
run
nin
g
on
tha
t
ma
chi
ne.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-4:
Filter
Contexts

Co De
nte scr
xt ipti
on

Pro Thi
ce s
ssI co
d nte
xt
is
the
pro
ce
ss
ide
ntifi
er.
Bre
ak
poi
nt
is
ho
nor
ed
if
co
de
is
ex
ec
uti
ng
in
the
sp
ecif
ied
pro
ce
ss.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-4:
Filter
Contexts

Co De
nte scr
xt ipti
on

Pro Thi
ce s
ss co
Na nte
me xt
is
the
pro
ce
ss
na
me
.
Fu
nct
ion
ally
eq
uiv
ale
nt
to
the
Pro
ce
ssI
d
co
nte
xt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-4:
Filter
Contexts

Co De
nte scr
xt ipti
on

Thr Thi
ea s
dId co
nte
xt
is
the
thr
ea
d
ide
ntifi
er.
Bre
ak
poi
nt
is
ho
nor
ed
if
co
de
is
ex
ec
uti
ng
on
a
sp
ecif
ic
thr
ea
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-4:
Filter
Contexts

Co De
nte scr
xt ipti
on

Thr Thi
ea s
dN co
am nte
e xt
is
the
thr
ea
d
na
me
.
Fu
nct
ion
ally
eq
uiv
ale
nt
to
the
Thr
ea
dId
co
nte
xt.

The following code creates two threads that asynchronously execute the same method (MethodA). The
threads are named FirstThread and SecondThread. A breakpoint is set on the highlighted line in MethodA.
As a standard breakpoint, both threads are interrupted—probably alternating between the threads.

private void btnFilter_Click(object sender, EventArgs e)


{
Thread t1=new Thread(new
ThreadStart(MethodA));
t1.Name="FirstThread";
t1.IsBackground=false;
Thread t2=new Thread(new
ThreadStart(MethodA));
t2.Name="SecondThread";
t2.IsBackground = false;
t1.Start();
t2.Start();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void MethodA()


{
while (true)
{
Thread.Sleep(3000);
}
}

To break on the first thread alone, open the Breakpoint Filter dialog box, shown in Figure 12-24. Specify
FirstThread as the thread name. Future instances of the breakpoint interrupt the first thread, but not the
second thread. You can confirm the results in the Threads window.

Figure 12-24: Breakpoint Filter dialog box

When Hit This command creates a tracepoint (discussed in the next section).

The Breakpoints window toolbar, shown in Figure 12-25, offers several shortcuts. The controls on the toolbar
are New, Delete, Delete All Breakpoints, Disable All Breakpoints, Go To Source Code, Go To Disassembly,
and Columns. The New drop-down list inserts a new function or data breakpoint. Data breakpoints are not
available in managed code. The Columns button customizes the content of the Breakpoints window, in which
developers can add or remove columns of information.

Figure 12-25: Breakpoints window toolbar

Tracepoints
Tracepoints assign an operation to a breakpoint. You can assign source code or a macro to a breakpoint.
When the breakpoint is hit, the source code or macro is executed. Before tracepoints, this process required
two steps: setting a breakpoint and inserting temporary code into source file. When the breakpoint was no
longer needed, the developer had to remember to remove the temporary code.

There are two methods for setting a tracepoint. You can open the context menu on the source line in which
the tracepoint should be inserted. Select the Breakpoint submenu and the Insert Tracepoint menu command.
Alternatively, you can open the context menu on a source line that already contains a breakpoint. From the
Breakpoint submenu, choose the When Hit menu command. Either approach opens the When Breakpoint Is
Hit dialog box, in which a tracepoint is defined. (See Figure 12-26.)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 12-26: When Breakpoint Is Hit dialog box

In the Print A Message edit box, enter a display string for the output window. Expressions are entered within
curly braces: {expression}. Special keywords can be used, such as $ADDRESS, $TID, and $FUNCTION. In
the Run A Macro edit box, enter the name of a macro. This macro is run when the breakpoint is hit. The
Continue Execution option sets a soft breakpoint. When the breakpoint is hit, soft breakpoints do not
interrupt the application; they execute the designated code or macro. Soft breakpoints appear as diamonds
in the source code editor.

The statement in the following When Breakpoint Is Hit dialog box (shown in Figure 12-27) adds two local
variables and displays the results in the output window.

Figure 12-27: Print a message selected in the When Breakpoint Is Hit dialog box

From the preceding tracepoint, the following code is displayed in the Output window:

Function: WindowsApplication1.WClass.MethodA() [5 + 10 = 15]

Table 12-5 lists the special keywords that can be used in the Print a message statement.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-5:
Tracepoint
Keywords

Ke De
yw scr
or ipti
d on

$A Thi
DD s
RE ke
SS yw
ord
ret
urn
s
the
ad
dre
ss
of
the
cur
ren
t
ins
tru
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-5:
Tracepoint
Keywords

Ke De
yw scr
or ipti
d on

$C Thi
AL s
LE ke
R yw
ord
ret
urn
s
the
na
me
of
the
pre
vio
us
fun
cti
on
on
the
call
sta
ck,
whi
ch
is
the
call
ing
fun
cti
on.

$C Thi
AL s
LS ke
TA yw
CK ord
ret
urn
s
the
call
sta
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-5:
Tracepoint
Keywords

Ke De
yw scr
or ipti
d on

$F Thi
UN s
CT ke
IO yw
N ord
ret
urn
s
the
na
me
of
the
cur
ren
t
fun
cti
on.

$PI Thi
D s
ke
yw
ord
ret
urn
s
the
pro
ce
ss
ide
ntifi
er
of
the
cur
ren
t
pro
ce
ss.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-5:
Tracepoint
Keywords

Ke De
yw scr
or ipti
d on

$P Thi
NA s
ME ke
yw
ord
ret
urn
s
the
na
me
of
the
cur
ren
t
pro
ce
ss.

$TI Thi
D s
ke
yw
ord
ret
urn
s
the
thr
ea
d
ide
ntifi
er
of
the
cur
ren
t
thr
ea
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-5:
Tracepoint
Keywords

Ke De
yw scr
or ipti
d on

$T Thi
NA s
ME ke
yw
ord
ret
urn
s
the
na
me
of
the
cur
ren
t
thr
ea
d.

Breakpoint Symbols
Breakpoints are annotated with icons in both the source code and the Breakpoints window. Each category of
breakpoint has a different symbol, as described in Table 12-6.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-6:
Breakpoint
Symbols

Sy De
mb scr
ol ipti
on

Fill Thi
ed s
cir ico
cle n
sig
nifi
es
a
nor
ma
l
bre
ak
poi
nt,
su
ch
as
a
fun
cti
on
or
loc
ati
on
bre
ak
poi
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-6:
Breakpoint
Symbols

Sy De
mb scr
ol ipti
on

Dia Thi
mo s
nd ico
n
sig
nifi
es
a
tra
ce
poi
nt
tha
t
ha
s
the
Co
nti
nu
e
exe
cut
ion
opt
ion
en
abl
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-6:
Breakpoint
Symbols

Sy De
mb scr
ol ipti
on

Fill Thi
ed s
cir ico
cle n
wit sig
h nifi
a es
plu a
s+ filte
r
bre
ak
poi
nt.
Filt
er
bre
ak
poi
nts
incl
ud
e
the
Co
ndi
tio
n,
Hit
Co
unt
,
an
d
Filt
er
bre
ak
poi
nts
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-6:
Breakpoint
Symbols

Sy De
mb scr
ol ipti
on

Hol Thi
low s
ed ico
cir n
cle sig
nifi
es
a
dis
abl
ed
bre
ak
poi
nt.

Code Stepping

Stepping through source code is the most common action in a debugging session. Step commands execute
an application in source line increments. With each step, execution continues incrementally. Between
steps, expressions can be evaluated, variables updated, functions called, and scope changed. Debug
windows are updated at each step to reflect any changes that occurred during the partial execution. This
sometimes requires refreshing. Extensive monitoring and expressions in debug windows can precipitously
hurt performance.

Step Commands
There are several step commands, described as follows:

 Step Into This command steps to the next source line. If that is a function call, the debugger
steps into the function. You can then step through that function. For nested function calls, the
Step Into command steps into the innermost functions first.

 Step Over This command steps to the next source line. However, it will not step into a function
call. The function call is treated as a single line of source code.

 Step Out This command executes the remainder of the current function. Execution is then
interrupted at the first source line after the call site.

 Set The Next Statement This command lets developers change the next statement, which is
useful for skipping one or more lines of source code. In the source editor, the current line is
highlighted with a yellow arrow. This is the next statement to execute. When the cursor hovers
over the yellow arrow, it changes into an arrow itself. You can then drag the current source line up
or down. The next step selected must be within the scope of the current source line. For example,
dragging the next step to another function is illegal. This command is not available during JIT
debugging. It is also not available when debugging a StackOverflowException or
ThreadAbortException exception.

Set The Next Statement Walkthrough


This walkthrough demonstrates the Next Statement command. In the sample application, variables locala
and localb are initialized in MethodA. They are then incremented. The SwitchValues method is called to
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

swap the values of the local variables. The parameters are passed by reference. After the method call, locala
is 11 and localb is 6. This is the code:

public void MethodA()


{
int locala = 5, localb = 10;
++locala;
++localb;
SwitchValues(ref locala, ref localb);
MessageBox.Show(locala.ToString());
MessageBox.Show(localb.ToString());
}

public void SwitchValues(ref int param1,


ref int param2)
{
int temp = param1;
param1 = param2;
param2 = temp;
}

These are the steps of the walkthrough that uses the previous code:
1. Set a breakpoint on the source line where locala is incremented. When the breakpoint is hit, the
current line is marked with a yellow arrow. The breakpoint and the current source line are initially
at the same location, as shown in Figure 12-28.
2. Drag the yellow highlight for the current line down to the first MessageBox.Show statement, which
jumps past the statements that increment the local variables and the SwitchValues method call.
Therefore, the values are neither incremented nor swapped. Figure 12-29 shows the repositioned
current line.
3. Continue execution, and the values for locala and localb are displayed. The locala variable is 5,
whereas localb is 10. Otherwise, the values would have been 11 and 6, respectively.

Figure 12-28: Breakpoint and current line


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 12-29: Repositioned current line

Debug Toolbar

The Debug toolbar contains shortcuts to several debugging commands, including the step commands. (See
Figure 12-30.) Some of the buttons and commands are enabled only in break mode.

Figure 12-30: Debug toolbar

The first set of buttons on the toolbar includes the Start Debugging, Break All, Stop Debugging, and Restart
buttons. The next set of buttons includes the Show Next Statement, Step Into, Step Over, and Step Out
buttons. The Show Next Statement button redirects to the next statement in the code editor. This statement
is highlighted with a yellow arrow. Next is the Hexadecimal button, which changes the values in the debug
windows from decimal to hexadecimal. The final button is a drop-down list that displays a menu of debug
commands.

Debug Windows

To assist in debugging, Visual Studio 2005 offers a myriad of debug windows, described in the following
sections.

Breakpoints Window
Manage breakpoints in the Breakpoints window. In this window, you can insert, delete, and disable
breakpoints. (The Breakpoints window was shown and discussed in detail earlier in this chapter.)

Output Window
This window contains messages from various sources in Visual Studio. The Output window is also available
from the View menu. The Output window is displayed in Figure 12-31.

Figure 12-31: Output window

The Output window has a toolbar, which has several buttons. Output From is the first button on the toolbar. It
filters the message sources, such a Build and Debug messages. The next three buttons locate build errors
in the code editor: Find Message in Code, Go to Previous Message, and Go to Next Message. The next
button, Clear All, erases the content of the Output window. The Toggle Word Wrap button toggles word wrap
in the Output window.

Script Explorer Window


ASP.NET Web applications have client- and server-side code. Client-side code is written in either JavaScript
or VBScript. In the Script Explorer window, developers can debug client-side scripts, including setting
breakpoints. The window lists script files and their scripts. The Script Explorer window is shown in Figure
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

12-32. In the sample Script Explorer window, the scripts of the default.aspx page are listed. The anonymous
scripts are usually scripts associated with for server-side controls, such as validation controls.

Figure 12-32: Script Explorer window

To use the Script Explorer window, you must enable Script debugging in Microsoft Internet Explorer. The
Disable Script Debugging (Internet Explorer) option is enabled by default in Internet Explorer. This option
must be disabled to allow script debugging. Open the Tools menu and select the Internet Options menu
command. On the Advanced tab, disable the Disable Script Debugging (Internet Explorer) option.

Watch Window
You can watch variables and expressions in a Watch window. The Watch, Locals, Auto, and QuickWatch
windows are considered variables windows—they have the same general user interface and functionality. The
variables windows are disabled in running mode; you must be in break mode to use them. A Watch window,
like other variables windows, has three columns. The Name column has the variable name or expression to
evaluate. The Value column displays the variable value or result of the expression. The Type column is the
data type of the variable or expression. There are four Watch windows for grouping related values.

Variable values can be modified directly in a Watch window. Changed values are highlighted in red. This is
an exceptional way to test applications with values that stress the program. You can also test how the
application handles errant conditions.

You can add variables and expressions in a Watch window directly. The QuickWatch dialog box is an
expedited means of inspecting a value or expression and optionally adding that item to a permanent Watch
window. The QuickWatch dialog box has an Add Watch button. If desired, you can enter new expressions in
the Expression text box. The QuickWatch window is available on the Debug menu. Shortcuts for
QuickWatch are Ctrl+Alt+Q or Shift+F9. Before opening the QuickWatch window, select the target variable
in the source editor.

Expressions Debugger expressions are expressions entered in the Watch, Quickwatch, Breakpoints, or
Immediate window. These expressions are evaluated by the Managed Expression Evaluator of the Visual
Studio debugger. Use debugger expressions to calculate values or to call methods. IntelliSense is available
when entering debugger expressions in a debug window or visualizer. The added flexibility of doing more than
examining static data is invaluable.

Debugger expressions are evaluated similarly to regular expressions. There are some unique idiosyncrasies
of the Managed Expression Evaluation.
 It ignores access modifiers.
 All members, regardless of accessibility, are available.
 Expressions are evaluated in an implicitly unsecure context.
 Checked blocks are ignored and evaluated as unchecked.
 Anonymous methods are not supported in debugger expressions.

Expressions can contain constants, function calls, and identifiers within scope, such as locals, parameters,
and fields. Most operators, such as +, -, ==, !=, ++, --, and / are available. You can even use the typeof and
sizeof operators. The this reference is supported. In addition, simple casts are allowed.

Expressions are evaluated between every step command. Refresh the expression to view any updates.
Beware of side effects, which can alter the state or execution of the programming unknowingly. For example,
calling a function in an expression that changes the state or outcome of the application may cause adverse
side effects.

Expression walkthrough The following steps list a walkthrough of expressions. A breakpoint is set on the
Form_Load event in the Expressions application. Run the application until the breakpoint is hit.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

1. Open a Watch window from the Debug menu. The Form_Load method has a sender and an e
parameter. (You can view their values in the Watch window.) This Watch window, including the
two parameters, is shown in Figure 12-33.
2. The Sample application has a ZClass, which is relatively simple:
3.
4. class ZClass
5. {
6. private int fielda = 5;
7. private int fieldb = 10;
8.
9. public int MethodA()
10. {
11. int locala = 5;
12. locala = 12;
13. return fielda + fieldb;
14. }
15. }
16. A breakpoint is set on the highlighted line in MethodA. When the breakpoint is hit, add fielda,
fieldb, locala, and localb to the Watch window. Click the Test button to hit the breakpoint. The
localb variable is not declared in the function. For that reason, it is displayed with an exclamation
symbol. Enter the ++fielda expression. Figure 12-34 shows the new Watch window.
17. Step two individual statements. (Press F10 twice.) Click the Refresh button to update the value of
the ++fielda expression. (The Refresh button is the green swirling button to the right of the field.)
18. The DumpType class has a static method, which dumps the methods and parameters of a type.
The DumpType.GetReflection method returns a string that contains the methods of a type. This
function is not called elsewhere in the program. It is created purely for debugging reasons. Enter
the DumpType.GetReflection in the expression. Pass the type of the current object as the sole
parameter. (See Figure 12-35.) You view the returning value of GetReflection with the Text
Visualizer. The results are shown in Figure 12-36.

Figure 12-33: Watch window with two parameters

Figure 12-34: Watch window with locala, localb, fielda, and fieldb values

Figure 12-35: DumpType.GetReflection expression in the Watch window


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 12-36: Results in the Text Visualizer

Autos Window
The Autos window lists the values from the current and preceding line of code, which includes this reference.
The items of the Autos window are populated by the Visual Studio debugger, not the developer. You can
change the values in the window, which are then highlighted in red. Figure 12-37 shows the Autos window.

Figure 12-37: Autos window

Locals Window
The Locals window lists the local variables that are currently in scope. Otherwise, the functionality is
identical to the Autos window.

Immediate Window
The Immediate window is the command-line version of the Visual Studio debugger. You can enter print
values, evaluate expressions, perform menu commands, execute statements, and more. This can be done
without having to change the application. Command windows are either in immediate or command mode.
Command mode is preferred for executing one or more Visual Studio commands. These are menu and other
commands.

For evaluating expressions, inspecting values, and otherwise debugging an application, immediate mode is
preferred. The default is the command mode. When in immediate mode, switch to command mode
temporarily by prefixing commands with a greater than (>) symbol. From the Immediate window, the cmd
command switches to command mode in the Command window. Switch back to immediate mode and the
Immediate window with the immed command.

You can navigate the Immediate window with arrows. Table 12-7 shows the various ways to navigate the
window.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-7:
Navigating
the
Immediate
Window

Ke De
yst scr
rok ipti
e on

Up Pre
arr vio
ow us
on co
co m
m ma
ma nd.
nd
line

Do Ne
wn xt
arr co
ow m
on ma
co nd.
m
ma
nd
line

Ctrl Up
+U win
p do
Arr w.
ow
or
Up
arr
ow
in
Co
m
ma
nd
win
do
w
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-7:
Navigating
the
Immediate
Window

Ke De
yst scr
rok ipti
e on

Ctrl Do
+D wn
ow win
n do
Arr w.
ow
or
Do
wn
arr
ow
in
Co
m
ma
nd
win
do
w
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-7:
Navigating
the
Immediate
Window

Ke De
yst scr
rok ipti
e on

Es Tra
c nsf
er
foc
us
to
co
de
edi
tor.
If
not
at
the
las
t
co
m
ma
nd
in
the
Im
me
dia
te
win
do
w,
Es
c
is
req
uir
ed.

There are limitations to the tasks that can be performed in the Immediate window. For example, you cannot
declare new variables, define a label, or create an instance of an object. Special commands such as the K
command are not available in managed-only code. Therefore, special commands for the Immediate window
are not explored here. In addition, the Immediate window does not accept goto, return, and loop statements,
or any statement requiring transfer of control.

Commands can have arguments and options. For example, the FindinFiles command has both. IntelliSense
will present the options, which are preceded with a forward slash. You must type a forward slash for
IntelliSense to display the available options. The following code is an example of the Edit.FindinFiles
command. If the command is represented by a window in the user interface, consult that window for an
understanding of options and arguments. In the window, edit text boxes are usually interpreted as
arguments, and everything else becomes an option. Figure 12-38 shows the Find In Files dialog box, which
has one text box and several options. The text box is the single argument of the FindinFiles command. You
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

can use as many options as needed. The defaults are defined in the window. In the example, the FindinFiles
command is used with two options: The first option requests a case-sensitive search, and the second option
directs the command to search all files in the root directory. This command has a single argument, which is
the search text.

Figure 12-38: Find in Files window

>Edit.FindinFiles /case /lookin:"c:\*" donis

Aliases are short forms of debugging commands. They are a convenience and never required. Table 12-8
lists some useful aliases.
Table 12-8:
Command
Aliases

Ali Co
as m
ma
nd

? De
bu
g.P
rint

bl De
bu
g.B
rea
kp
oin
ts

call De
sta bu
ck g.C
all
Sta
ck
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-8:
Command
Aliases

Ali Co
as m
ma
nd

cls De
bu
g.C
lea
rAll

cm Vie
d w.
Co
m
ma
nd
Wi
nd
ow

du Du
mp
Uni
co
de

g De
bu
g.S
tart

im To
me ols
d .Im
me
dia
te
Mo
de

K De
bu
g.L
ist
Cal
lSt
ac
k

loc De
als bu
g.L
oc
als
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-8:
Command
Aliases

Ali Co
as m
ma
nd

me De
mo bu
ry1 g.
Me
mo
ry1

me De
mo bu
ry2 g.
Me
mo
ry2

P De
bu
g.S
tep
Ov
er

pr De
bu
g.S
tep
Ou
t

pri Fil
nt e.P
rint

q De
bu
g.S
top
De
bu
ggi
ng

rtc De
bu
g.R
un
To
Cur
sor
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-8:
Command
Aliases

Ali Co
as m
ma
nd

sav Fil
eall e.S
ave
All

T Ste
p.I
nto

thr De
ea bu
ds g.T
hre
ad
s

~ De
bu
g.L
ist
Thr
ea
ds

~* De
k bu
g.L
ist
Cal
lSt
ac
k
/All
Thr
ea
ds

Developers might want to create user-defined aliases for frequently performed tasks. The alias command
defines a new alias. The following command defines two new aliases. The pripro alias replaces all instances
of the private with the protected keyword in the current source file. The propri alias performs the reverse
operation.

>alias pripro edit.replace /all private protected


>alias propri edit.replace /all protected private

Call Stack Window


The Call Stack window shows the functions currently on the stack. The current function is highlighted with a
yellow arrow. By default, the window has two columns: the name of the function and the source language.
The Name column combines several fields: the module name, function name, parameter information, line
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

number, and byte offset. Parameter information includes parameter type, parameter name, and parameter
values. Use the context menu to customize the display. Except for the function name, everything is optional.
Figure 12-39 shows the Call Stack window, which is available only in break mode.

Figure 12-39: Call Stack window

The call stack does not include external code. In some circumstances, information on external functions in
the call stack can be helpful. To view external code, disable the Enable Just My Code (Managed Only)
option in the Options dialog box of the Tools menu under the Debugging settings in the General node. Figure
12-40 shows the Call Stack window with this option disabled. For clarity, extraneous information is removed
from the Name column. You can now trace the call stack into System functions to obtain what may be
invaluable information.

Figure 12-40: Call Stack window with Enable Just My Code disabled

Each row of the call stack represents a function and a stack frame. Some variables windows are based on
the current stack frame. For example, the Autos and Locals windows are from the current stack frame.
However, you might want to view similar information about the other stack frame. To switch stack frames,
position the cursor on the target frame. Open the context menu in the call stack and choose the Switch To
Frame menu command. A curved green arrow appears next to the updated current stack frame. Variable
windows are updated according to the change.

Another option on the Call Stack context menu is the Include Calls From/To Other Threads menu command.
This command follows the call stack through thread calls. For example, this is helpful when tracing the call
stack from an XML Web Service into an ASP.NET application.

Function breakpoints and tracepoints are settable in the Call Stack window. You can use shortcut keys,
such as F9, or you can use the context menu.

Threads Window
The Threads window presents the active threads of the current process. This window is available only in
break mode. A thread is a single path of execution in a process. Threads own assets, such as local
variables, thread context, and thread local storage.

The Thread application is provided to create threads. You can assign a name and priority to each new
thread. Each thread executes the sample MethodA function. When you run the Thread application in a
debugging session, thread T1, T2, and T3 are created of varying priorities. Then the BreakAll command is
issued from the Debug menu. Figure 12-41 shows the Threads window for the application at that moment.

Figure 12-41: Threads window

The columns of the Threads window are Thread Identifier, Thread Name, Method Location, Thread Priority,
and Suspend Count. From the context menu, suspend a thread with the Freeze menu command.
Suspended threads are assigned a double-bar icon. Choose the Thaw menu command to resume the thread.
Forcibly suspending a thread can affect the normal operation of an application. The Switch To Thread menu
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

command of the context menu changes the current thread. You can also double-click the target thread to
switch the current thread. Some windows are based on the current thread, such as the Call Stack. These
windows are updated when the current thread is changed.

Modules Window
The Modules window lists the modules, executables, and DLLs, which are loaded into the application. There
is considerable information presented on each module, as described in Table 12-9.
Table 12-9:
Modules
Window
Columns

Co De
lu scr
mn ipti
on

Na Thi
me s
col
um
n
is
the
na
me
of
the
mo
dul
e.

Pat Thi
h s
col
um
n
pre
se
nts
the
full
y
qu
alifi
ed
pat
h
to
the
mo
dul
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-9:
Modules
Window
Columns

Co De
lu scr
mn ipti
on

Op Thi
tim s
ize col
d um
n
indi
cat
es
wh
eth
er
the
mo
dul
e
is
opt
imi
ze
d
dur
ing
JIT
co
mp
ilati
on.
Th
e
cur
ren
t
mo
dul
e
bei
ng
de
bu
gg
ed
is
like
ly
not
opt
imi
ze
d.
De
bu
g
ver
sio
ns
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-9:
Modules
Window
Columns

Co De
lu scr
mn ipti
on

Us Thi
er s
Co col
de um
n
indi
cat
es
wh
eth
er
us
er
co
de
is
ava
ilab
le
for
a
par
tic
ula
r
mo
dul
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-9:
Modules
Window
Columns

Co De
lu scr
mn ipti
on

Sy Thi
mb s
ol col
Sta um
tus n
indi
cat
es
wh
eth
er
sy
mb
ols
are
loa
de
d
for
thi
s
mo
dul
e.
It
als
o
indi
cat
es
if
ex
por
ts
are
onl
y
loa
de
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-9:
Modules
Window
Columns

Co De
lu scr
mn ipti
on

Sy Wh
mb en
ol loa
Fil de
e d,
thi
s
col
um
n
dis
pla
ys
the
full
y
qu
alifi
ed
pat
h
an
d
na
me
of
the
sy
mb
ol
file.

Or Thi
der s
col
um
n
list
s
the
loa
d
ord
er
of
mo
dul
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-9:
Modules
Window
Columns

Co De
lu scr
mn ipti
on

Ver Thi
sio s
n col
um
n
pro
vid
es
the
ver
sio
n
nu
mb
er
of
the
mo
dul
e.

Ti Thi
me s
sta col
mp um
n
is
the
tim
est
am
p
wh
en
the
mo
dul
e
wa
s
cre
ate
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-9:
Modules
Window
Columns

Co De
lu scr
mn ipti
on

Ad Thi
dre s
ss col
um
n
is
the
sta
rt
an
d
en
d
loa
d
ad
dre
ss
of
the
mo
dul
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-9:
Modules
Window
Columns

Co De
lu scr
mn ipti
on

Pro Thi
ce s
ss col
um
n
is
the
pro
ce
ss
ide
ntifi
er
of
the
ap
plic
ati
on
tha
t
ho
sts
the
mo
dul
e.

From the context menu, you can request additional information on the symbol file. You can also visit Symbol
settings in Project options, where symbols are managed.

Processes Window
The Processes window enumerates the processes being debugged by the Visual Studio debugger, including
attached processes. Table 12-10 describes each column of the window.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-10:
Processes
Window
Columns

Co De
lu scr
mn ipti
on

Na Thi
me s
col
um
n
is
the
na
me
of
the
pro
ce
ss.

ID Thi
s
col
um
n
is
the
pro
ce
ss
ide
ntifi
er
of
the
pro
ce
ss.

Pat Thi
h s
col
um
n
is
the
pat
h
to
the
ex
ec
uta
ble
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-10:
Processes
Window
Columns

Co De
lu scr
mn ipti
on

Titl Thi
e s
col
um
n
co
nta
ins
the
titl
e
of
ap
plic
ati
on.
For
a
Wi
nd
ow
s
For
ms
ap
plic
ati
on,
thi
s
is
the
co
nte
nt
of
the
titl
e
bar
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-10:
Processes
Window
Columns

Co De
lu scr
mn ipti
on

Sta Thi
te s
col
um
n
sh
ow
s
the
sta
te
of
the
ap
plic
ati
on,
su
ch
as
the
bre
ak
or
run
nin
g
sta
te.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-10:
Processes
Window
Columns

Co De
lu scr
mn ipti
on

De Thi
bu s
ggi col
ng um
n
indi
cat
es
the
typ
e
of
de
bu
ggi
ng,
su
ch
as
ma
na
ge
d
or
nat
ive
de
bu
ggi
ng.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-10:
Processes
Window
Columns

Co De
lu scr
mn ipti
on

Tra Thi
ns s
por col
t um
n
is
the
tra
ns
por
t
to
the
ap
plic
ati
on.
Th
e
def
aul
t
is
no
aut
he
nti
cat
ion
.

Tra Thi
ns s
por col
t um
Qu n
alifi is
er the
ma
chi
ne
na
me
.

Memory Window
The Memory window dumps the memory of the current process. (See Figure 12-42.) Other windows format
memory for specific purposes. For example, the Locals window displays the memory of local variables alone.
The Memory window provides an unfiltered and raw presentation of process memory. Four memory windows
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

provide the opportunity to maintain different views of the process. Memory windows are available in break
mode and only if the Enable Address-Level Debugging Option is enabled. Set this option within Debug
settings in the General node. Open from the Tools menu and the Options command.

Figure 12-42: Memory window

Enter a memory address in the Address edit box. You can enter a memory address directly or by using a
drag-and-drop operation. The Memory window displays rows of data at memory addresses. Column 1 of the
Memory window is the starting address of a row of data. The final column is the text translation. The memory
dump is in the intervening columns.

The Memory window can be formatted using the context menu. You can change the size of the data
columns to 1-, 2-, 4-, or 8-byte columns. The display can also be changed to 32- or 64-bit data presentation.
The text translation can be formatted as ANSI, Unicode, or hidden.

Disassembly Window
The Disassembly window shows the native assembly of the application, which is the native code generated
by JIT compilation. By default, if available, the source code is displayed also. Each assembly instruction is
displayed in several columns: the instruction address, mnemonic, and parameters. (See Figure 12-43.) Use
the context menu to change the format of the Disassembly window.

Figure 12-43: Disassembly window

Registers Window
The Registers window displays the state of the registers. Assembly-level programming typically relies heavily
on registers. For this reason, the Disassembly and Registers windows are often used together. The
Registers window is shown in Figure 12-44. Use the context menu to change the format of the display.

Figure 12-44: Registers window

Table 12-11 describes the common registers.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-11:
Registers

Re De
gis scr
ter ipti
on

EA Thi
X s
reg
ist
er
is
a
ge
ner
al-
pur
po
se
reg
ist
er.
It
is
co
m
mo
nly
us
ed
as
the
de
sti
nat
ion
of
a
ma
th
op
era
tio
n.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-11:
Registers

Re De
gis scr
ter ipti
on

EB Thi
X s
reg
ist
er
is
a
ge
ner
al-
pur
po
se
reg
ist
er.

EC Thi
X s
reg
ist
er
is
a
ge
ner
al-
pur
po
se
reg
ist
er
an
d
is
co
m
mo
nly
us
ed
for
co
unt
ing
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-11:
Registers

Re De
gis scr
ter ipti
on

ED Thi
X s
reg
ist
er
is
a
ge
ner
al-
pur
po
se
reg
ist
er.

EI Thi
P s
reg
ist
er
co
nta
ins
the
ne
xt
ins
tru
cti
on
poi
nte
r.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-11:
Registers

Re De
gis scr
ter ipti
on

ES Thi
P s
reg
ist
er
co
nta
ins
the
poi
nte
r
to
the
top
of
the
sta
ck.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-11:
Registers

Re De
gis scr
ter ipti
on

ES Thi
I s
reg
ist
er
is
the
so
urc
e
ind
ex.
Th
e
ES
I
an
d
ED
I
reg
ist
ers
are
fre
qu
ent
ly
us
ed
in
stri
ng
op
era
tio
ns.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-11:
Registers

Re De
gis scr
ter ipti
on

ED Thi
I s
reg
ist
er
is
the
de
sti
nat
ion
ind
ex.
Th
e
ES
I
an
d
ED
I
reg
ist
ers
are
fre
qu
ent
ly
us
ed
in
stri
ng
op
era
tio
ns.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-11:
Registers

Re De
gis scr
ter ipti
on

EB Thi
P s
reg
ist
er
co
nta
ins
the
ba
se
poi
nte
r
of
the
cur
ren
t
sta
ck
fra
me
.

Tracing

Tracing instruments an application through trace messages sent during program execution. Trace messages
are used for a variety of reasons. They can confirm the execution sequence of a program, which is useful for
assuring that program flow is correct (often the cause of bugs). Trace messages can display the state of the
application at different stages. You can track the state of objects, local variables, or other data throughout
the lifetime of an application. Finally, trace messages are used to track events, such as start, stop, and
user-defined events. Tracing replaces the old technique of monitoring an application via Console.WriteLine
statements.

In the Microsoft .NET Framework 2.0, TraceSource is the preferred type for tracing. It replaces the Debug
and Trace classes, which remain available as legacy types. The TraceSource class is in the
System.Diagnostics namespace. To enable tracing, the TRACE symbol must be defined in the application.
In the source code, this is accomplished with the #define statement. Alternatively, define the symbol while
compiling the program. The /d compiler option defines a symbol:

csc /d:TRACE test.cs

Table 12-12 explains the important members of the TraceSource class.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-12:
TraceSource
Methods

Le De
vel scr
ipti
on

Co Tra
nst ce
ruc So
tor urc
s e(s
Bot trin
h g
co na
nst me
ruc )
tor Tra
s ce
as So
sig urc
n e(s
a trin
na g
me na
to me
the ,
Tra So
ce urc
So eL
urc eve
e ls
obj def
ect aul
. tLe
Th vel)
e
two
-ar
gu
me
nt
co
nst
ruc
tor
als
o
set
s
a
def
aul
t
sev
erit
y
lev
el
for
all
tra
ce
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-12:
TraceSource
Methods

Le De
vel scr
ipti
on

Clo voi
se d
Thi Clo
s se(
me )
tho
d
clo
se
s
all
the
tra
ce
list
en
ers
in
the
Lis
ten
ers
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-12:
TraceSource
Methods

Le De
vel scr
ipti
on

Flu voi
sh d
Thi Flu
s sh(
me )
tho
d
flus
he
s
the
tra
ce
list
en
ers
in
the
Lis
ten
ers
coll
ect
ion
.
Thi
s
en
sur
es
tha
t
ca
ch
ed
me
ss
ag
es
are
rep
ort
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-12:
TraceSource
Methods

Le De
vel scr
ipti
on

Tra
ce [Condit
Dat ionalAt
a tribute(
Thi "TRAC
s E")]
me public
tho void
d Trace
cre Data(
ate
s
a Trace
tra EventT
ce ype
me eventT
ss ype,
ag
e int id,
co
nsi
Object
sti
data)
ng
of [Condit
eve ionalAt
nt tribute(
typ "TRAC
e, E")]
a public
tra void
ce Trace
ide Data(
ntifi
er,
an Trace
d EventT
an ype
y eventT
tra ype,
ce
dat int id,
a.
Th Object
e [] data)
eve
nt
typ
e
is
the
sev
erit
y
lev
el.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-12:
TraceSource
Methods

Le De
vel scr
ipti
on

Tra
ce [Condit
Ev ionalAt
ent tribute(
"TRAC
Thi E")]
s public
me void
tho Trace
d Event(
cre
ate
s Trace
a EventT
tra ype
ce eventT
me ype,
ss
ag int id)
e
[Condit
co
ionalAt
nsi
tribute(
sti
"TRAC
ng
E")]
of
an public
eve void
nt Trace
typ Event(
e
an Trace
d EventT
me ype
ss eventT
ag ype,
e,
whi
ch int id,
is
writ string
ten messa
to ge)
the [Condit
Lis ionalAt
ten tribute(
ers "TRAC
coll E")]
ect
ion public
. void
Th Trace
e Event(
firs
t Trace
ove EventT
rlo ype
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-12:
TraceSource
Methods

Le De
vel scr
ipti
on

Tra
ceI [Condit
nfo ionalAt
rm tribute(
ati "TRAC
on E")]
Thi public
s void
me TraceI
tho nforma
d tion(
cre
ate
s string
an messa
info ge)
rm [Condit
ati ionalAt
on tribute(
al "TRAC
me E")]
ss
public
ag
void
e,
TraceI
whi
nforma
ch
tion(
is
writ
ten string
to format,
the
Lis param
ten s
ers Object
coll [] args)
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-12:
TraceSource
Methods

Le De
vel scr
ipti
on

Tra
ce [Condit
Tra ionalAt
nsf tribute(
er "TRAC
Thi E")]
s public
me void
tho TraceT
d ransfer
cre (
ate
s
tra int id,
nsf
er string
me messa
ss ge,
ag
es,
Guid
whi
related
ch
Activit
are
yID)
writ
ten
to
the
Lis
ten
ers
coll
ect
ion
.

The TraceSource type also has several valuable properties. Table 12-13 lists the properties.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-13:
TraceSource
Properties

Pr Ty
op pe
ert
y

Att Stri
rib ng
ute Dic
s tio
Thi nar
s y
pro
per
ty
get
s
the
cu
sto
m
swi
tch
attr
ibu
tes
tha
t
are
defi
ne
d
in
the
ap
plic
ati
on
co
nfig
ura
tio
n
file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-13:
TraceSource
Properties

Pr Ty
op pe
ert
y

Lis Tra
ten ce
ers Lis
ten
Thi erC
s olle
pro cti
per on
ty
get
s
an
arr
ay
of
list
en
ers
.
Lis
ten
ers
are
the
tar
get
s
of
tra
ce
me
ss
ag
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-13:
TraceSource
Properties

Pr Ty
op pe
ert
y

Na stri
me ng

Thi
s
pro
per
ty
get
s
the
na
me
of
the
Tra
ce
So
urc
e
obj
ect
.
Thi
s
na
me
is
mo
st
like
ly
us
ed
wit
h
the
So
urc
eFi
lter
pro
per
ty
of
a
list
en
er.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-13:
TraceSource
Properties

Pr Ty
op pe
ert
y

Swi So
tch urc
eS
Thi wit
s ch
pro
per
ty
get
s
or
set
s
the
tra
ce
swi
tch
as
so
cia
ted
wit
h
thi
s
Tra
ce
So
urc
e
obj
ect
.
Thi
s
filte
rs
the
tra
ce
me
ss
ag
es
se
nt
fro
m
the
Tra
ce
So
urc
e
obj
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Tracing is based on criteria including severity levels, switches, listeners, and listener filters. This determines
when, where, and how trace messages are reported. TraceSource instances create trace messages.
Severity levels are assigned to trace messages, which set the message importance. Switches filter trace
messages based on their severity levels. Listeners receive trace messages. Finally, listener filters control
the trace messages reported from a listener. Tracing is configurable either programmatically or using an
application configuration file. The application configuration file is recommended. With the application
configuration file, tracing is controlled, enabled, or disabled without recompiling the program. For a
production application, this is essential. To introduce tracing concepts, the programmatic approach is
presented first.

Trace messages are set to severity levels. The trace levels determine the importance or urgency of a
message. Some trace messages are activity related, such as the start and stop time of an application.
Informational trace messages are used to stub methods and check program flow. Tracing the value of an
invalid parameter, which results in an exception, should be higher priority. TraceEventType enumeration
defines the trace levels. Table 12-14 enumerates the trace levels. The levels are listed in order of highest to
lowest priority.
Table 12-14:
Trace Levels

Le De
vel scr
ipti
on

Tra Thi
ce s
Ev err
ent or
Ty lev
pe. el
Crit is
ical res
erv
ed
for
co
ndi
tio
ns
tha
t
de
sta
bili
ze
an
ap
plic
ati
on
or
are
fat
al.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-14:
Trace Levels

Le De
vel scr
ipti
on

Tra Thi
ce s
Ev err
ent or
Ty lev
pe. el
Err is
or res
erv
ed
for
co
ndi
tio
ns
tha
t
de
sta
bili
ze
an
ap
plic
ati
on
but
are
rec
ove
rab
le.

Tra Thi
ce s
Ev err
ent or
Ty lev
pe. el
Wa is
rni res
ng erv
ed
for
no
ncr
itic
al
co
ndi
tio
ns.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-14:
Trace Levels

Le De
vel scr
ipti
on

Tra Thi
ce s
Ev err
ent or
Ty lev
pe. el
Inf is
or res
ma erv
tio ed
n for
ge
ner
al
info
rm
ati
on
tha
t
mi
ght
aid
in
the
dia
gn
osi
ng
of
an
err
or
co
ndi
tio
n.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-14:
Trace Levels

Le De
vel scr
ipti
on

Tra Thi
ce s
Ev err
ent or
Ty lev
pe. el
Ver is
bo res
se erv
ed
for
ge
ner
al
info
rm
ati
on
not
ne
ce
ss
aril
y
as
so
cia
ted
wit
h
an
err
or
co
ndi
tio
n.

Tra Se
ce e
Ev Ta
ent ble
Ty 12-
pe 14.
act
iviti
es

Some trace levels are related to activities, which are linked to events. The activity traces are grouped at the
same trace level, which is the lowest trace level, beneath the Verbose level. Table 12-15 shows the list of
activity traces.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-15:
Activity
Traces

Act De
ivit scr
y ipti
on

Tra Thi
ce s
Ev act
ent ivit
Ty y
pe. indi
Sta cat
rt es
tha
t
an
op
era
tio
n
is
sta
rtin
g.

Tra Thi
ce s
Ev act
ent ivit
Ty y
pe. indi
Sto cat
p es
tha
t
an
op
era
tio
n
is
sto
ppi
ng.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-15:
Activity
Traces

Act De
ivit scr
y ipti
on

Tra Thi
ce s
Ev act
ent ivit
Ty y
pe. indi
Su cat
sp es
en tha
d t
an
op
era
tio
n
is
su
sp
en
din
g.

Tra Thi
ce s
Ev act
ent ivit
Ty y
pe. indi
Re cat
su es
me tha
t
an
op
era
tio
n
is
res
um
ing
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-15:
Activity
Traces

Act De
ivit scr
y ipti
on

Tra Thi
ce s
Ev act
ent ivit
Ty y
pe. indi
Tra cat
nsf es
er a
ch
an
ge
of
cor
rel
ati
on
ide
ntit
y.

Switches filter trace messages based on trace levels, which determine which messages a TraceSource
sends. With switches, developers can selectively enable or disable certain trace messages. If an application
is crashing, you might decide to enable critical and error trace messages. When algorithms are performing
incorrectly, you might want to enable general and activity traces. Avoiding unnecessary tracing improves
performance. Tracing can generate a voluminous amount of information. A filter reduces the volume of trace
messages, which conserves resources. Switch filters are defined in the SourceSwitch class. The
SourceSwitch class has the Level property, which is a SourceLevels type. SourceLevels is the enumeration
that defines the trace messages that are filtered. This is a bitwise flag, and the various SourceLevels can be
combined. The source levels are detailed in Table 12-16.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-16:
Source Level

Filt De
er scr
ipti
on

So Thi
urc s
eL lev
eve el
ls. for
Act war
ivit ds
yTr act
aci ivit
ng y
tra
ce
me
ss
ag
es.
Ot
her
me
ss
ag
es
are
filte
red
.

So Thi
urc s
eL lev
eve el
ls. for
All war
ds
all
tra
ce
me
ss
ag
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-16:
Source Level

Filt De
er scr
ipti
on

So Thi
urc s
eL lev
eve el
ls. for
Crit war
ical ds
onl
y
crit
ical
tra
ce
me
ss
ag
es.

So Thi
urc s
eL lev
eve el
ls. se
Err nd
or s
err
or
an
d
crit
ical
tra
ce
me
ss
ag
es.
Ot
her
tra
ce
lev
els
are
filte
red
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-16:
Source Level

Filt De
er scr
ipti
on

So Thi
urc s
eL lev
eve el
ls.I filte
nfo rs
rm ver
ati bo
on se
an
d
act
ivit
y
tra
ce
me
ss
ag
es.
Ot
her
tra
ce
me
ss
ag
es
are
se
nt.

So Thi
urc s
eL lev
eve el
ls. filte
Off rs
all
tra
ce
me
ss
ag
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-16:
Source Level

Filt De
er scr
ipti
on

So Thi
urc s
eL lev
eve el
ls. filte
Ver rs
bo act
se ivit
y
tra
ce
me
ss
ag
es.
All
oth
er
me
ss
ag
es
are
se
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-16:
Source Level

Filt De
er scr
ipti
on

So Thi
urc s
eL lev
eve el
ls. filte
Wa rs
rni all
ng tra
ce
me
ss
ag
es
ex
ce
pt
for
Crit
ical
,
Err
or,
an
d
Wa
rni
ng
eve
nts
.

To set the filter, assign an instance of SourceSwitch to the TraceSource.Switch property. The SourceSwitch
has two constructors:
 public SourceSwitch(string name)
 public SourceSwitch(string name, string defaultLevel)
 SourceSwitch also has several useful properties, which are listed in Table 12-17.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-17:
SourceSwitch
Properties

Pr Ty
op pe
ert
y

Att Stri
rib ng
ute Dic
s tio
Thi nar
s y
pro
per
ty
get
s
the
cu
sto
m
attr
ibu
tes
tha
t
are
defi
ne
d
in
the
ap
plic
ati
on
co
nfig
ura
tio
n
file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-17:
SourceSwitch
Properties

Pr Ty
op pe
ert
y

De stri
scr ng
ipti
on
Thi
s
pro
per
ty
get
s
a
ge
ner
al
de
scr
ipti
on
of
the
swi
tch
. It
def
aul
ts
to
an
em
pty
stri
ng.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-17:
SourceSwitch
Properties

Pr Ty
op pe
ert
y

Dis stri
pla ng
yN
am
e
Thi
s
pro
per
ty
get
s
the
na
me
of
the
swi
tch
.

Lev So
el urc
Thi eL
s eve
pro ls
per
ty
get
s
or
set
s
the
lev
el
of
the
swi
tch
.

The following code creates an instance of TraceSource and TraceSwitch. The switch is then assigned to the
TraceSource.

TraceSource ts=new TraceSource("sample");


SourceSwitch sw=new SourceSwitch("switch");
sw.Level=SourceLevels.All;
ts.Switch=sw;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The event type of trace messages and the switch source level combine to determine which messages are
sent. The following code sends trace messages in each event type: critical, error, information, and so on.
The switch level, which is case sensitive, is read from the command line and determines which messages
are recognized. A console listener is used in the application, which displays the unfiltered trace messages in
a console window. This is an excellent program for understanding the combination of trace event types and
switch levels.

#define TRACE
using System;
using System.Diagnostics;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(string [] argv){
TraceSource ts=new TraceSource("sample");
SourceSwitch sw=new SourceSwitch("switch");

sw.Level=(SourceLevels)Enum.Parse(
typeof(SourceLevels), argv[0]);
ts.Switch=sw;
ConsoleTraceListener console=
new ConsoleTraceListener();
ts.Listeners.Add(console);
ts.TraceEvent(TraceEventType.Start, 0,
"Activity trace messages on");
ts.TraceEvent(TraceEventType.Verbose, 0,
"Verbose trace messages on");
ts.TraceEvent(TraceEventType.Information, 0,
"Information trace messages on");
ts.TraceEvent(TraceEventType.Warning, 0,
"Warning trace messages on");
ts.TraceEvent(TraceEventType.Error, 0,
"Error trace messages on");
ts.TraceEvent(TraceEventType.Critical, 0,
"Critical trace messages on");

ts.Flush();
ts.Close();

}
}
}

Trace messages can be sent to a variety of targets, including the console window, a text file, and a XML file.
Trace targets are called listeners. A TraceSource type maintains an array of listeners called the Listeners
collection. By default, the Listeners collection has a single element, the DefaultTraceListener, which
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

displays trace messages in the Output window of Visual Studio. When the Listeners collection contains
more than one listener, trace messages are sent to multiple targets. If the collection contains a
ConsoleTraceListener and the XMLWriterTraceListener, trace messages are displayed in the console
window and saved into an XML file. Trace listeners receive trace messages sent from a trace source, which
is filtered by the trace switch.

Table 12-18 reviews the available predefined listeners.


Table 12-18:
Trace
Listeners

Lis De
ten scr
ers ipti
on

Te Thi
xt s
Wri list
ter en
Tra er
ce for
Lis war
ten ds
er tra
ce
me
ss
ag
es
to
ins
tan
ce
s
of
str
ea
m-r
ela
ted
cla
ss
es,
su
ch
as
a
Te
xt
Wri
ter
cla
ss.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-18:
Trace
Listeners

Lis De
ten scr
ers ipti
on

Ev Thi
ent s
Lo list
gTr en
ac er
eLi for
ste war
ner ds
tra
ce
me
ss
ag
es
to
an
eve
nt
log
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-18:
Trace
Listeners

Lis De
ten scr
ers ipti
on

Def Thi
aul s
tTr list
ac en
eLi er
ste for
ner war
ds
tra
ce
me
ss
ag
es
to
the
Ou
tpu
t
win
do
w.
Thi
s
is
the
def
aul
t
list
en
er
an
d
initi
ally
the
onl
y
me
mb
er
incl
ud
ed
in
the
Lis
ten
ers
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-18:
Trace
Listeners

Lis De
ten scr
ers ipti
on

Co Thi
ns s
ole list
Tra en
ce er
Lis for
ten war
er ds
tra
ce
me
ss
ag
es
to
a
sta
nd
ard
out
put
or
err
or
str
ea
m.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-18:
Trace
Listeners

Lis De
ten scr
ers ipti
on

Del Si
imi mil
ted ar
Lis to
tTr the
ac Te
eLi xt
ste Wri
ner ter
Tra
ce
Lis
ten
er
cla
ss,
thi
s
list
en
er
for
war
ds
me
ss
ag
es
to
an
ins
tan
ce
of
a
str
ea
m-r
ela
ted
cla
ss.
Ho
we
ver,
the
me
ss
ag
es
are
se
par
ate
d
wit
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-18:
Trace
Listeners

Lis De
ten scr
ers ipti
on

Xm Thi
lWr s
iter list
Tra en
ce er
Lis sav
ten es
er tra
ce
s
me
ss
ag
es
as
XM
L-e
nc
od
ed
tex
t.

Trace listeners inherit the TraceListener base class, which provides the core functionality of a listener. Most
of the methods of the TraceListener mirror those of the TraceSource, Trace, and Debug types. TraceSource,
Trace, and Debug forward messages to listeners by invoking identically named trace operations in listeners.
All the listeners have a default constructor. Some listeners have multiargument constructors, in which the
listener is assigned a name or a destination is defined. For example, the following code creates a new
TextWriterTraceListener. It is named samplelistener and writes to the test.txt file.

TextWriterTraceListener file=new
TextWriterTraceListener("samplelistener", "test.txt");

Table 12-19 details the properties of the TraceListener class.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-19:
TraceListener
Properties

Pr Ty
op pe
ert
y

Att Stri
rib ng
ute Dic
s tio
Thi nar
s y
pro
per
ty
get
s
the
cu
sto
m
attr
ibu
tes
tha
t
are
defi
ne
d
in
the
ap
plic
ati
on
co
nfig
ura
tio
n
file.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-19:
TraceListener
Properties

Pr Ty
op pe
ert
y

Filt Tra
er ce
Thi Filt
s er
pro
per
ty
get
s
an
d
set
s
the
filte
r
of
the
list
en
er.

Ind int
ent
Lev
el
Thi
s
pro
per
ty
get
s
an
d
set
s
the
lev
el
of
ind
ent
ati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-19:
TraceListener
Properties

Pr Ty
op pe
ert
y

Ind int
ent
Siz
e
Thi
s
pro
per
ty
get
s
an
d
set
s
the
am
ou
nt
of
ind
ent
ati
on
per
ind
ent
ati
on
lev
el.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-19:
TraceListener
Properties

Pr Ty
op pe
ert
y

IsT bo
hre ol
ad
Saf
e
Thi
s
pro
per
ty
indi
cat
es
wh
eth
er
the
list
en
er
is
thr
ea
d-s
afe
.

Na stri
me ng

Thi
s
pro
per
ty
get
s
an
d
set
s
the
na
me
of
the
list
en
er.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-19:
TraceListener
Properties

Pr Ty
op pe
ert
y

Ne bo
edI ol
nd
ent

Thi
s
is
a
pro
tec
ted
pro
per
ty,
whi
ch
en
abl
es
or
dis
abl
es
ind
ent
ati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-19:
TraceListener
Properties

Pr Ty
op pe
ert
y

Tra Tra
ce ce
Ou Op
tpu tio
tO ns
pti
on
s
Thi
s
pro
per
ty
get
s
an
d
set
s
an
en
um
era
tio
n
tha
t
co
ntr
ols
the
out
put
opt
ion
s
of
the
list
en
er.

The values of the TraceOption enumeration are described in Table 12-20. These values are bitwise, which
allows multiple options to be combined.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-20:
TraceOptions
Values

Va De
lue scr
ipti
on

Tra Thi
ce s
Op opt
tio ion
ns. incl
Cal ud
lSt es
ac the
k call
sta
ck
in
ea
ch
tra
ce
me
ss
ag
e.
Thi
s
info
rm
ati
on
is
fou
nd
at
the
En
viro
nm
ent
.St
ac
kTr
ac
e
pro
per
ty.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-20:
TraceOptions
Values

Va De
lue scr
ipti
on

Tra Thi
ce s
Op opt
tio ion
ns. incl
Dat ud
eTi es
me the
dat
e
an
d
tim
e
in
ea
ch
tra
ce
me
ss
ag
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-20:
TraceOptions
Values

Va De
lue scr
ipti
on

Tra Thi
ce s
Op opt
tio ion
ns. incl
Lo ud
gic es
alO the
per logi
ati cal
on op
Sta era
ck tio
n
sta
ck
in
ea
ch
tra
ce
me
ss
ag
e.
Thi
s
info
rm
ati
on
is
fou
nd
at
the
Cor
rel
ati
on
Ma
na
ger
.Lo
gic
alO
per
ati
on
Sta
ck
pro
per
ty.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-20:
TraceOptions
Values

Va De
lue scr
ipti
on

Tra Thi
ce s
Op opt
tio ion
ns. ex
No clu
ne de
s
all
opt
ion
s.
Th
e
tra
ce
me
ss
ag
e
will
co
nta
in
no
opt
ion
al
dat
a.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-20:
TraceOptions
Values

Va De
lue scr
ipti
on

Tra Thi
ce s
Op opt
tio ion
ns. incl
Pro ud
ce es
ssI the
d cur
ren
t
pro
ce
ss
ide
ntifi
er
in
ea
ch
tra
ce
me
ss
ag
e.
Thi
s
info
rm
ati
on
is
fou
nd
at
the
Pro
ce
ss.
Id
pro
per
ty.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-20:
TraceOptions
Values

Va De
lue scr
ipti
on

Tra Thi
ce s
Op opt
tio ion
ns. incl
Thr ud
ea es
dId the
cur
ren
t
thr
ea
d
ide
ntifi
er
in
ea
ch
tra
ce
me
ss
ag
e.
Thi
s
info
rm
ati
on
is
fou
nd
at
the
Thr
ea
d.
Ma
ng
ed
Thr
ea
dId
pro
per
ty.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-20:
TraceOptions
Values

Va De
lue scr
ipti
on

Tra Thi
ce s
Op opt
tio ion
ns. incl
Ti ud
me es
Sta a
mp tim
est
am
p
in
the
ea
ch
tra
ce
me
ss
ag
e.
Thi
s
info
rm
ati
on
is
ret
urn
ed
fro
m
the
Sto
pw
atc
h.
Ge
tTi
me
Sta
mp
me
tho
d.

The listeners of a TraceSource type are managed at the TraceSource.Listeners property. The Listeners
property is a TraceListenerCollection type, which implements the IList, ICollection, and IEnumerable
interfaces. You can add a listener with the Add method. The TraceListenerCollection type also implements
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

the AddRange method. Call this method to add multiple listeners to the Listeners collection. The AddRange
method is overloaded to accept an array of listeners or a TraceListenerCollection type as the sole parameter.
The following code adds a ConsoleTraceListener to a Listeners collection:

ConsoleTraceListener console=
new ConsoleTraceListener();
ts.Listeners.Add(console);

Trace messages can be filtered at the collection. Listener filters are perfect for identifying important
messages in a flood of trace messages. You can focus on a particular problem. Listener filters and trace
switch are both filters. The trace switch filters messages from the TraceSource object. Those messages are
forwarded to a listener, in which the listener filter further refines the set of trace messages. There are two
types of listener filters: SourceFilter and EventTypeFilter. SourceFilter focuses the listener on a specific
source. For example, when tracing messages from several classes, you use SourceFilter to limit trace
messages to a specific class. EventTypeFilter further refines trace messages based on priority. The priority
of EventTypeFilter is usually a subset of the source switch filter.

This is the constructor of the SourceFilter type:


 SourceFilter constructor syntax:
o public SourceFilter(string source)

The only parameter is the name of the source. The listener will output only messages from the specific
source. If the name is invalid, the filter is ignored.

This is the constructor of the EventTypeFilter type:


 EventTypeFilter constructor syntax:
o public EventTypeFilter(SourceLevels level)

The SourceLevels parameter states the priority of allowed trace messages. Other trace messages are
ignored.

The following code demonstrates the SourceFilter type. The EventTypeFilter is included in a later example.
Three TraceSource instances are defined in the code. A ConsoleTraceListener is also defined, which
displays trace messages in the console window. The ConsoleTraceListener .Filter is then updated to display
trace messages from only the second source. Later, the SourceFilter is changed to limit trace messages to
the first source.

#define TRACE

using System;
using System.Diagnostics;

namespace Donis.CSharpBook{
public class Starter{

public static void Main() {


TraceSource ts1=new TraceSource("ts1");
TraceSource ts2=new TraceSource("ts2");
TraceSource ts3=new TraceSource("ts3");
SourceSwitch sw=new SourceSwitch("sw",
"Information");
ts1.Switch=sw;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

ts2.Switch=sw;
ts3.Switch=sw;
ConsoleTraceListener cs=new ConsoleTraceListener();
ts1.Listeners.Add(cs);
ts2.Listeners.Add(cs);
ts3.Listeners.Add(cs);

// Include only the ts2 source

Console.WriteLine("Filters t1 and t3 messages");


ts1.Listeners[1].Filter=new SourceFilter("ts2");
ts1.TraceInformation("ts1:trace");
ts2.TraceInformation("ts2:trace");
ts3.TraceInformation("ts3:trace");

// Include only the ts1 source

Console.WriteLine("\nFilters t2 and t3 messages");


ts1.Listeners[1].Filter=new SourceFilter("ts1");
ts1.TraceInformation("ts1:trace");
ts2.TraceInformation("ts2:trace");
ts3.TraceInformation("ts3:trace");

ts1.Flush();
ts2.Flush();
ts3.Flush();

ts1.Close();
ts2.Close();
ts3.Close();
}
}
}

Tracing Example
The following example code declares a ZClass and YClass; both classes contain a TraceSource instance. It
is a best practice to maintain separate TraceSource instances for individual classes, which affords
individualized management of tracing at the class level. For example, you could filter trace messages for
specific classes. Expose TraceSource as a static member of the class, which is initialized in the static
constructor. Functions of the class leverage the static TraceSource to send trace messages. If using the
disposable pattern, clean up the TraceSource object in the Dispose method.

public class ZClass: IDisposable {

static ZClass() {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

ts=new TraceSource("ZTrace");
ts.Switch=new SourceSwitch("sw1", "Information");
ts.Listeners.Add(new ConsoleTraceListener());
TextWriterTraceListener file=new
TextWriterTraceListener("samplelistener", "test.txt");
file.Filter = new EventTypeFilter(SourceLevels.Critical);
file.TraceOutputOptions=TraceOptions.DateTime;
ts.Listeners.Add(file);
}

static private TraceSource ts;

// partial listing

public void Dispose() {


ts.Flush();
ts.Close();
}

The following code is a complete listing of the sample code used in this section. Main also has a trace
source, which sends trace messages to listeners for the Output and Console windows. Both the ZClass and
YClass have separate trace sources. The methods of the ZClass and YClass use their respective
TraceSource instances to send trace messages. To demonstrate both techniques, the TraceEvent and
TraceData methods are called. The hash codes of the objects are used as the trace identifier, which
identifies trace messages by class type and instance. This is sometimes useful. The trace source of the
ZClass sends trace messages to listeners for the Output window, Console window, and a text file. The
switch of that trace source forwards all trace messages. However, the filter for the Console listener restricts
output to error type messages. The YClass trace source sends trace messages of error priority to listeners
for the Output and Console windows. The switch limits the trace messages to informational messages.

#define TRACE

using System;
using System.Diagnostics;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){

TraceSource ts=
new TraceSource("StarterTrace");
ts.Switch=new SourceSwitch("sw3");
ts.Switch.Level=SourceLevels.ActivityTracing;
ts.Listeners.Add(new ConsoleTraceListener());
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

ts.TraceEvent(TraceEventType.Start,
0, "Starting");

ZClass obj1=new ZClass();


obj1.MethodA();
obj1.MethodB(1,2,3);

YClass obj2=new YClass();


obj2.MethodC();

ZClass obj3=new ZClass();


obj1.MethodA();
obj1.MethodB(4,5,6);

ts.TraceEvent(TraceEventType.Stop,
0, "Stopping");

obj1.Dispose();
obj2.Dispose();

}
}

public class ZClass: IDisposable {

static ZClass() {

ts=new TraceSource("ZTrace");
ts.Switch=new SourceSwitch("sw1", "All");
ts.Listeners.Add(new ConsoleTraceListener());
TextWriterTraceListener file=new
TextWriterTraceListener("samplelistener", "test.txt");
file.Filter = new EventTypeFilter(SourceLevels.Critical);
file.TraceOutputOptions=TraceOptions.DateTime;
ts.Listeners.Add(file);
}

static private TraceSource ts;

public void MethodA() {


ts.TraceEvent(TraceEventType.Error,
GetHashCode(), "ZClass.MethodA");
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void MethodB(int parama, int paramb,


int paramc) {
ts.TraceData(TraceEventType.Critical,
GetHashCode(), "ZClass.MethodB", parama,
paramb, paramc);
}

public void Dispose() {


ts.Flush();
ts.Close();
}

public class YClass: IDisposable {

static YClass() {
ts=new TraceSource("YTrace");
ts.Switch=new SourceSwitch("sw2", "Information");
ts.Listeners.Add(new ConsoleTraceListener());
ts.Listeners[1].IndentSize=4;
ts.Listeners[1].IndentLevel=2;
}

static private TraceSource ts;

public void MethodC() {


ts.TraceEvent(TraceEventType.Error,
GetHashCode(), "YClass.MethodC");
}

public void Dispose() {


ts.Flush();
ts.Close();
}

}
}

Configuration File
Trace switches, listeners, and listener filters are configurable in an application configuration file. Actually,
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

this is the best practice and is preferable to programmatic configuration. Developers can update the specifics
of tracing without recompiling the application. The application configuration file has the same name as the
target assembly plus a .config extension. For example, the application configuration file for hello.exe is
hello.exe.config. The application configuration file should be in the same directory as the assembly. For a
software system, you can configure multiple applications with a publisher policy file, which is deployed in the
global assembly cache. Visit this link for a "how to" on publisher policy files:
msdn2.microsoft.com/en-us/library/dz32563a. You can configure tracing in both the configuration file and
programmatically. Where there is overlap, programmatic configuration takes precedent.

In the configuration file, the tracing is placed within the system.diagnostics element. For the co mplete
explanation of the system.diagnostics element, open this link: msdn2.microsoft.com/en-us/library/1txedc80.

<?xml version="1.0" encoding="utf-8" ?>


<configuration>
<system.diagnostics>
</system.diagnostics>
</configuration>

Sources element Define the trace sources within the sources element. A specific trace source is declared
in a source element. The important attributes of the source element are name and switchName. The name
attribute is the name of the trace source, and switchName names the switch assigned to the trace source.
Here is an example:

<sources>
<source name="ZTrace" switchName="sw1">
</source>
</sources>

Listeners element The listeners of a particular source are listed within the source elements. The listeners
element encapsulates the listeners of a trace source. Individual listeners are added to the Listeners
collection with the add element. The key attributes of the add element are type, name, traceOutputOptions,
and initializeData. The type attribute is the kind of listener. The name attribute is the name assigned to the
listener. The initializeData attribute is additional data used to create the listener, such as the target file
name. The traceOutputOtions attribute adds optional data to trace messages of the listener, such as a
timestamp. Here are example elements:

<sources>
<source name="ZTrace" switchName="sw1">
<listeners>
<add initializeData="data.txt"
type="System.Diagnostics.TextWriterTraceListener"
name="tListener" />
<add name="cListener" />
</listeners>
</source>
</sources>

sharedListeners element The listeners element assigns a listener to a specific trace source. You can also
share listeners. Listeners are shared between trace sources in the sharedListeners element. A shared
listener is added with an add element. Shared listeners are added to a specific trace source as a regular
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

listener. However, the add element need only have the name attribute, which identifies the shared listener:

<system.diagnostics>
<sharedListeners>
<add type="System.Diagnostics.ConsoleTraceListener"
name="cListener"
traceOutputOptions="None" />
</sharedListeners>
</switches>

Switches element Switches are defined within the switches elements. An individual switch is added with an
add element. The basic attributes are name and value . The name attribute is the name of the switch, and
the value attribute is the filter for the trace message. Here is an example:

<system.diagnostics>
<switches>
<add name="sw1" value="Critical" />
<add name="sw2" value="Information" />
</switches>
</system.diagnostics>
</configuration>

Tracing Example with a Configuration File


The programmatic example of tracing has been rewritten to leverage an application file. The following code is
the new source code for the application. The switch and collection code is removed from the source code
and placed in the configuration file.

#define TRACE

using System;
using System.Diagnostics;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){

TraceSource ts=
new TraceSource("StarterTrace");
ts.TraceEvent(TraceEventType.Start,
0, "Starting");

ZClass obj1=new ZClass();


obj1.MethodA();
obj1.MethodB(1,2,3);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

YClass obj2=new YClass();


obj2.MethodC();

ZClass obj3=new ZClass();


obj1.MethodA();
obj1.MethodB(4,5,6);

ts.TraceEvent(TraceEventType.Stop,
0, "Stopping");

obj1.Dispose();
obj2.Dispose();

}
}

public class ZClass: IDisposable {

static ZClass() {
ts=new TraceSource("ZTrace");
}

static private TraceSource ts;

public void MethodA() {


ts.TraceEvent(TraceEventType.Error,
GetHashCode(), "ZClass.MethodA");
}

public void MethodB(int parama, int paramb,


int paramc) {
ts.TraceData(TraceEventType.Critical,
GetHashCode(), "ZClass.MethodB", parama,
paramb, paramc);
}

public void Dispose() {


ts.Flush();
ts.Close();
}

}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class YClass: IDisposable {

static YClass() {
ts=new TraceSource("YTrace");
}

static private TraceSource ts;

public void MethodC() {


ts.TraceEvent(TraceEventType.Error,
GetHashCode(), "YClass.MethodC");
}

public void Dispose() {


ts.Flush();
ts.Close();
}

}
}

The following application configuration file sets up tracing for the application. There are some differences from
the first example. For example, the three trace sources share the same Console listener. The YTrace trace
source also has an XML listener. Otherwise, the results are virtually the same as the earlier code.

<?xml version="1.0" encoding="utf-8" ?>


<configuration>
<system.diagnostics>
<sources>
<source name="StarterTrace" switchName="sw3">
<listeners>
<add name="cListener" />
</listeners>
</source>
<source name="ZTrace" switchName="sw1">
<listeners>
<add initializeData="data.txt"
type="System.Diagnostics.TextWriterTraceListener"
name="tListener" />
<add name="cListener" />
</listeners>
</source>
<source name="YTrace" switchName="sw2">
<listeners>
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

<add name="cListener" />


<add name="xListener" />
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="data.xml"
type="System.Diagnostics.XmlWriterTraceListener"
name="xListener" traceOutputOptions="DateTime" />
<add type="System.Diagnostics.ConsoleTraceListener"
name="cListener"
traceOutputOptions="DateTime" />
</sharedListeners>
<switches>
<add name="sw1" value="Information" />
<add name="sw2" value="All" />
<add name="sw3" value="ActivityTracing" />
</switches>
</system.diagnostics>
</configuration>

DebuggerDisplayAttribute

The DebuggerDisplayAttribute type controls how values are displayed in a debugger window. This attribute is
valid for assembly, class, struct, enum, indexer, property, field, and delegate constructs. You cannot use
DebuggerDisplayAttribute on methods. When this attribute is used as an assembly-level attribute, the Target
property must be assigned the name of the applicable type. The DebuggerDisplayAttribute type is also found
in the System.Diagnostics namespace.

The DebuggerDisplayAttribute type has a one-argument constructor. The single argument, which is a string,
is the display value of the type in the debug window. The value can contain an expression. Expressions must
be enclosed in curly braces: {expression}. Constants, static members, and instance members are valid in
the expression. Prefix static members with the class name. The expression cannot contain pointers,
aliases, or local variables.

The DebuggerDisplayAttribute type is inheritable. A derived class inherits the attribute from the base class.
However, the derived class can redefined DebuggerDisplayAttribute as desired.

Figure 12-45 shows the values in a debug window for the ZClass and YClass instances without
DebuggerDisplayAttribute.

Figure 12-45: View of the ZClass and YClass instances before applying DebuggerDisplayAttribute

The following code decorates the ZClass and YClass with the DebuggerDisplayAttribute type. The ZClass is
assigned the value NewName, which is overridden in the derived class. In addition, ZClass.fielda is adorned
with the attribute, which contains an expression in this circumstance.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

[DebuggerDisplay("NewName")]
class ZClass
{
public static int test = 1;
public virtual void MethodA()
{
int vara=5, varb=10;
Console.WriteLine("{0} {1}", vara,

varb);
}

public void MethodB()


{
Console.WriteLine("ZClass.MethodB");
Console.WriteLine("ZClass.fielda {0}",
fielda);
}

[DebuggerDisplay("fielda = {fielda}")]
private int fielda = 5;
}

[DebuggerDisplay("DerivedName")]
class YClass : ZClass
{
public override void MethodA()
{
Console.WriteLine("YClass.MethodA");
Console.WriteLine("Fieldb: {0}", fieldb);
}

private int fieldb = 10;


}

Figure 12-46 shows the results of using the DebuggerDisplayAttribute type with the ZClass and YClass .

Figure 12-46: View of ZClass and YClass types in the debugger window after applying the
DebuggerDisplayAttribute type
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

DebuggerBrowsableAttribute
Another debugger attribute is the DebuggerBrowsableAttribute type, which determines how a member is
displayed in the debugger window. This attribute is valid for properties, indexers, and fields.

DebuggerBrowsableAttribute has one constructor, which is a one-argument constructor. The parameter is


the DebuggableBrowsableState enumeration. Table 12-21 lists the elements of the enumeration.
Table 12-21:
DebuggableB
rowserState
Values

Va De
lue scr
ipti
on

Ne Thi
ver s
ele
me
nt
hid
es
the
me
mb
er
in
the
de
bu
gg
er
win
do
w.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-21:
DebuggableB
rowserState
Values

Va De
lue scr
ipti
on

Col Thi
lap s
se ele
d me
nt
dis
pla
ys
the
me
mb
er,
whi
ch
is
coll
ap
se
d
initi
ally
.
Thi
s
is
the
def
aul
t.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-21:
DebuggableB
rowserState
Values

Va De
lue scr
ipti
on

Ro If
otH the
idd ele
en me
nt
is
an
arr
ay
or
coll
ect
ion
,
thi
s
ele
me
nt
hid
es
the
roo
t
me
mb
er
but
dis
pla
ys
the
chil
d
ele
me
nts
.
For
ex
am
ple
,
wh
en
ap
plie
d
to
a
pro
per
ty
tha
t
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 12-47 shows the values for the ZClass and YClass types without the DebuggerBrowsableAttribute
type.

Figure 12-47: View of ZClass and YClass types before applying the DebuggerBrowsableAttribute type

The following code shows the ZClass and YClass types decorated with DebuggerBrowsableAttribute. In the
ZClass, the array related to the propInts property is displayed. In the YClass type, fieldb is hidden.

class ZClass
{
public static int test = 1;
public virtual void MethodA()
{
int vara=5, varb=10;
Console.WriteLine("{0} {1}", vara,
varb);
}

public void MethodB()


{
Console.WriteLine("ZClass.MethodB");
Console.WriteLine("ZClass.fielda {0}",
fielda);
}

private int[] Ints ={ 1, 2, 3, 4, 5 };


[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public int[] propInts
{

get
{
return Ints;
}
}

private int fielda = 5;


}

class YClass : ZClass


{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public override void MethodA()


{
Console.WriteLine("YClass.MethodA");
Console.WriteLine("Fieldb: {0}", fieldb);
}

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int fieldb = 10;
}

Figure 12-48 shows the results of using the DebuggerBrowsableAttribute type on the ZClass and YClass.

Figure 12-48: View of ZClass and YClass types after applying DebuggerBrowsableAttribute

DebuggerTypeProxyAttribute
The DebuggerTypeProxyAttribute type names a type as a proxy for another type. The type proxy is
displayed instead of the type in debugger windows. The attribute type is DebuggerTypeProxyAttribute. This
attribute is valid for assembly, class, and struct constructs. When used at the assembly level, the target
name property must be assigned the name of the target type.

The proxy type must have a one-argument constructor that accepts an instance of the target type. For this
reason, it is recommended that the proxy type be nested within the target type. This provides the proxy type
constructor easy access to the instance of the surrounding object. Only public members of the proxy are
visible in the debugger window.

The DebuggerTypeProxyAttribute type is useful for hiding sensitive data within a type. In the following code,
XClass has a password field. This field should not be exposed during live debugging because passwords
represent sensitive data. The DebuggerTypeProxyAttribute type in the sample code names XClassDebug as
the proxy. XClassDebug hides the password field and displays an appropriate value, which is "Not Available".

This is the code for the XClass and the nested XClassDebug class, which is the proxy class:

[DebuggerTypeProxy(typeof(XClassDebug))]
public class XClass
{
public XClass(string _password)
{
password=_password;
}
private string password;
internal class XClassDebug
{
public XClassDebug(XClass obj)
{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public string password = "Not Available";


}
}

Dump Files

Visual Studio 2005 can open and interpret dump files from managed, native, or mixed-mode applications. A
dump is a snapshot of an application's memory that lets a developer debug an application at a convenient
location and time, which is particularly beneficial for debugging production applications. Dumps created on a
production machine can then be debugged on another machine, without interfering with the production
machine. Several tools are available for creating a dump, including Windbg, Dr. Watson, Autodump+
(ADPlus), and Visual Studio. Visual Studio can create dumps while debugging native applications, such as
Microsoft Visual C++ applications. This feature is not available in managed projects. Dump files and other
advanced debugging topics are discussed in the next chapter, "Advanced Debugging."

In Visual Studio, dump files are opened as projects. Choose the Open Solution/Project menu command from
the Open submenu of the File menu. Dump files have the .dmp extension. After opening the file, start a
debug session to examine the dump file. The Debug Start menu command (F5) on the Debug menu starts a
debug session. When debugging a dump, a breakpoint is hit almost immediately. You can then debug and
diagnose the dump using the various debug windows. Figures 12-49 and 12-50 show the Call Stack and
Modules debug windows, which provide different views of the dump.

Figure 12-49: Call Stack window for a dump

Figure 12-50: Modules window for a dump

The Debug windows of Visual Studio can provide a native perspective of an unmanaged application. This is
helpful with dumps of managed applications, but a managed view is also sometimes merited. Load the Son
of Strike debugger extension (SOS.DLL) for a managed perspective of a dump. Load Son of Strike with the
.load sos command in the Immediate window. You can then issue various Son of Strike commands, which
are prefixed with an exclamation point. In Figure 12-51, Son of Strike is loaded. Afterward, the DumpHeap
command is invoked. Output is shown in the Immediate window. Some Son of Strike commands are
thread-specific. Set the thread context in the Thread window before issuing one of those commands.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 12-51: Son of Strike in the Immediate window


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Advanced Debugging
A variety of tools are available for advanced debugging. Many of these tools are downloaded from the
Debugging Tools for Windows Web site. Windbg, the latest version of Son of Strike (SOS.DLL), and
Auto-Dump Plus are three of the most valuable tools received from the download.

Windbg is a native and kernel debugger, which is commonly used by software support engineers to diagnose
problems. It supports live and postmortem debugging. Live debugging is performed by attaching the debugger
to a running process. Postmortem analysis is conducted via dump files. This includes examining memory,
evaluating call stacks, setting breakpoints, viewing threads, and much more. SOS.DLL is a debugger
extension that publishes commands for managed debugging. Son of Strike can be used in Windbg and
Visual Studio 2005, as shown earlier in this chapter.

Mdg is the new managed debugger. As the dedicated managed debugger, it offers features that are found
neither in Visual Studio debugger nor in Windbg products.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 13: Advanced Debugging


Overview
Successful debugging is about asking the correct questions. Many (but not all) of those questions can be
answered with the Microsoft Visual Studio Debugger. Some questions require advanced debugging
techniques and tools. What are the outstanding synchronization objects? How much native versus managed
memory has been allocated? What is the size of each generation and the large object heap? These and
other advanced questions are not answerable in the Visual Studio Debugger, but may be essential to quickly
resolving a debugging problem.

This chapter provides general techniques for debugging managed applications. Some of these techniques are
also helpful in debugging Web applications. For guidance on debugging ASP.NET applications, refer to
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/DBGch01.asp.

Advanced debugging tools and services are available from a variety of sources, including the Microsoft
Windows operating environment, the Microsoft .NET Framework, Visual Studio .NET, and the Debugging
Tools for Windows Web site at Microsoft.com. Performance Monitor, Task Manager, and Dr. Watson are
distributed with the Windows environment. The .NET Framework has the Son of Strike (SOS) debugger
extension (SOS.dll), DbgClr, CorDbg, and other debugger tools. Visual Studio offers Spy++, Dependency
Walker, OLE Viewer, and much more. Advanced debugging tools can be downloaded from the Debugging
Tools for Windows Web site at www.microsoft.com/whdc/devtools/debugging. This Web site is updated
periodically.

You should download the current tools regularly. The Windows Debugger (WinDbg) and ADPlus script are
the most frequently used tools from this Web site.

WinDbg is the primary focus of this chapter. However, it is not intended as a replacement for the Visual
Studio Debugger. The first rule of debugging is to look for simple solutions first. The Visual Studio Debugger
is ideal for basic debugging: It is convenient, it has a familiar user interface, and superior documentation is
available. Visual Studio is a pen hammer, whereas WinDbg is a sledge hammer. If a problem occurs,
diagnose the problem first with Visual Studio before attempting a complete reclamation with WinDbg. Find
uninitialized variables or parameters, errant loop counters, logic errors, and code coverage problems with the
Visual Studio Debugger. These are likely problems in an erroneous application.

The goal of debugging is to resolve abnormal error conditions. Program hangs, crashes, memory leaks, and
unhandled exceptions are possible error conditions. Some abnormal conditions are not exceptional events.
These primarily include logic errors. For example, a program that reports incorrect results has a bug. It may
not be as intrusive as an exception, but it is a bug nonetheless.

Debugging is conducted in three phases: discovery, analysis, and testing. The discovery phase is the
process of gathering data related to the problem. In this stage, you capture the state of the application or
environment when the error condition occurred. The analysis (or debugging) phase is when the abnormal
condition is diagnosed. The testing phase validates the analysis phase. This is an iterative process. Based
on the results of the testing phase, further discovery, analysis, and testing could be mandated.

Debugging is an integral part of the life cycle of an application. Debugging a production application is a
challenge when compared with debugging in the development environment. First, the constraints are
different. The priority for debugging a production application is restarting the application, not exhaustive
analysis. With a high-traffic retail Web site, the primary concern of the client might be lost revenue. Second,
the production machine might lack debugging resources, such as symbols, source code, and debugging
tools. Third, re-creating the abnormal condition could be problematic. Load factors, memory stress, and
other conditions are hard to replicate on a developer machine. Finally, the production application may be
offsite—in a locked server closet or another otherwise inconvenient location. This might necessitate remote
debugging, which could entail setup and possible trust issues.

Debugging can be invasive or noninvasive. Noninvasive debugging is the preference for debugging production
applications that are running. The advantages of noninvasive debugging are that the debuggee is not altered
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

or shut down during the debugging process. Invasive debugging provides additional data and flexibility, but
should be limited to the development environment.

You can debug live applications or perform postmortem analysis. Live debugging is debugging an active and
running application, and it often involves breakpoints. Breakpoints are set where the live application should
be interrupted. Starting at the breakpoint, the developer can step through the application to verify program
logic, monitor local variables, inspect the heap, watch the call stack, and more. Live debugging usually
entails user interaction, which is not always possible. The antithesis to live debugging is postmortem
analysis. Postmortem analysis is performed against static data, such as a dump or log file. You can create
a dump or log file once and then debug as often as needed. Using a static file is often simpler than live
debugging, where the state is constantly evolving. Postmortem analysis also has disadvantages. It is harder
to pose future-tense questions with postmortem analysis. What is the call stack after a future operation is
performed? What is the effect of further executing a for loop? What is the impact of changing the value of a
local variable? Deriving answers to these questions from a dump or log file is indeed difficult.

Production and beta applications are typically release builds, whereas alpha and proof of concepts are often
debug builds. Release builds are optimized but harder to debug. Conversely, debug builds are not optimized
and run slightly slower. In .NET 1.1, release builds might have incomplete tracking information from the
inlining of methods. The missing stack frames could lead to unreliable stack traces in debuggers. This
optimization is not performed on .NET 2.0 applications. In addition, there is code optimization, which is a
compilation of several performance-improving techniques, including inserting jumps, reducing the lifetime of
local references, reordering instructions efficiently, and so on.

This chapter presents different versions of the Store application. Each version demonstrates a different
aspect of advanced debugging. The Store applications can be found in the companion Web content.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

DebuggableAttribute Attribute
Just-in-time (JIT) optimizations are defined in the DebuggableAttribute custom attribute. When compiled in
debug mode, this attribute is added to the metadata of the application with any optimizations disabled. The
DebuggableAttribute attribute contains the IsJITOptimizerDisabled and IsJITTrackingEnabled properties,
which indicate the status of JIT optimizations.

These optimizations can make debugging a production application difficult. Fortunately, you can create an
application initialization file that disables the optimization of a release product. The initialization file must be
in the same directory as the application, have the same root name of the application, and have the .ini
extension. For myapp.exe, the filename would be myapp.ini. The initialization file has two entries. The
GenerateTrackingInfo entry enables or disables generating complete tracking information. This entry is
redundant in .NET 2.0, where tracking information is always generated. The AllowOptimize entry controls
code optimization. In the initialization file, 1 is true and 0 is false. The following is an initialization file that
disables both JIT optimizations:

[.NET Framework Debugging Control]


GenerateTrackingInfo=1
AllowOptimize=0

This is a partial listing of assembly code generated by the JIT compiler with optimizations enabled:

00e40a0b 8b45b8 mov eax,[ebp-0x48]


00e40a0e 8b8854010000 mov ecx,[eax+0x154]
00e40a14 8b15086c3902 mov edx,[02396c08] ("Transaction cancelled")
00e40a1a 8b01 mov eax,[ecx]
00e40a1c ff9068010000 call dword ptr [eax+0x168]
00e40a22 83c301 add ebx,0x1
00e40a25 3b5ddc cmp ebx,[ebp-0x24]
00e40a28 0f8c58fdffff jl 00e40786
00e40a2e 8d65f4 lea esp,[ebp-0xc]
00e40a31 5b pop ebx
00e40a32 5e pop esi
00e40a33 5f pop edi
00e40a34 5d pop ebp
00e40a35 c20400 ret 0x4
00e40a38 e8713f2579 call mscorwks!JIT_RngChkFail (7a0949ae)
00e40a3d cc int 3

The following assembly originated from the same Microsoft intermediate language (MSIL) code as the
preceding assembly code. For this assembly, the JIT optimizations are disabled. I will not torment you with
the intricacies of assembly code. However, compare the before and after code—and note the differences.
Obviously, disabling optimizations made a considerable difference in the assembly code generated.

01050aba 90 nop
01050abb eb17 jmp 01050ad4
01050abd 8b45c0 mov eax,[ebp-0x40]
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

01050ac0 8b8854010000 mov ecx,[eax+0x154]


01050ac6 8b15086c3902 mov edx,[02396c08] ("Transaction cancelled")
01050acc 8b01 mov eax,[ecx]
01050ace ff9068010000 call dword ptr [eax+0x168]
01050ad4 ff45d4 inc dword ptr [ebp-0x2c]
01050ad7 8b45d4 mov eax,[ebp-0x2c]
01050ada 3b45d8 cmp eax,[ebp-0x28]
01050add 0f8c1efdffff jl 01050801
01050ae3 90 nop
01050ae4 8d65f4 lea esp,[ebp-0xc]
01050ae7 5b pop ebx
01050ae8 5e pop esi
01050ae9 5f pop edi
01050aea 5d pop ebp
01050aeb c20400 ret 0x4

Other differences can exist between release and debug products. Debug methods are likely to be omitted
from the release version. Trace methods are probably included in the release build, but that is not
guaranteed. These and other dissimilarities sometimes amount to relevant differences between a release and
debug version of a product. For that reason, an abnormal condition in a production application may
mysteriously disappear in a debug version. The opposite also applies. Errors in a debug version might
disappear in the release product. Make sure that Debug and Trace methods cause no side effects. This will
eliminate most cross-build problems. It's important to always extensively test both the debug and release
versions of products. After exhaustive unit testing of the debug build, submit the release build to identical
tests.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Debuggers
There are several useful tools and debuggers available to managed developers. The following list is a
compilation of some of these tools. (This list does not include third-party tools.)

 Visual Studio Debugger Most Windows developers have some experience with this tool.
Consult this debugger first to diagnose a problem. It is included with the installation of Visual
Studio .NET.

 Managed Debugger (MDbg) This tool is a console debugger that is dedicated to the advanced
debugging of managed code, so it has a wide variety of commands and options specific to
managed code that are not available in other debuggers. You download the code for MDbg at the
Microsoft downloads site: www.microsoft.com/downloads. It is described as the CLR Managed
Debugger (mdbg) Sample. There is a GUI extension available for MDbg that can also be
downloaded. It provides a user-friendly veneer to MDbg.

 CLR Debugger (DbgClr) This tool is a managed debugger and a scaled-down version of the
Visual Studio Debugger. It has the familiar Visual Studio interface, but with only debugging
capabilities. This tool provides some debugging preparedness for production machines in which
Visual Studio might not be installed. DbgClr does not support remote or mixed-mode debugging. It
is distributed with the .NET Framework.

 Performance Monitor Performance Monitor instruments a live application. It can plot a host of
data points onto a variety of graphs and reports. Alternatively, results can be logged in text files
for later examination. Performance Monitor is included with the Windows operating system.

 Windows Console Debugger (CDB) CDB is both a kernel- and user-mode debugger. To debug
managed applications, load the SOS debugger extension (SOS.dll). Download CDB from the
Debugging Tools for Windows Web site at Microsoft.com.

 Windows Debugger (WinDbg) WinDbg is also a kernel- and user-mode debugger. It offers a
user interface to many of the command-line instructions available in CDB and NTSD. The
command-line instructions of WinDbg and CDB are similar. Load SOS to debug managed
applications. WinDbg is probably the most popular of the advanced debugging tools. Download
WinDbg from the Debugging Tools for Windows Web site at Microsoft.com.

 Dr. Watson Dr. Watson is a JIT debugger that creates logs or dump files when an abnormal
condition occurs in an application. Dr. Watson is available on production machines on which other
debuggers may not be available. It is convenient and is the one debugging tool everyone should
have. This tool is distributed with the Windows operating environment.

 ADPlus (ADPlus.vbs) This service is a Visual Basic script that automates common CDB tasks,
such as creating dumps. This is another tool downloaded from the Debugging Tools for Windows
Web site at Microsoft.com.

 Son of Strike (SOS.dll) This tool is a debugger extension that exposes commands for debugging
managed applications. This tool is distributed with the .NET Framework and downloadable from
the Debugging Tools for Windows Web site at Microsoft.com. Several versions of the SOS.dll are
available. The version of the SOS.dll included in the clr10 subdirectory of Debugging Tools For
Windows is not compatible with some examples in this chapter.

Some of these tools are available from multiple sources. For example, SOS is found in the .NET Framework,
distributed with Visual Studio .NET, and downloaded at the Debugging Tools for Windows Web site at
Microsoft.com. When a tool is available from various sources, the most recent version is downloadable from
the Debugging Tools for Windows Web site at Microsoft.com.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Just-In-Time (JIT) Debugging


JIT debugging attaches a registered debugger to an application when an unhandled exception is raised or
otherwise crashes. The JIT debugger for these events can be set in the registry. You can inspect the registry
using the Regedit tool. In this text, HKLM is shorthand for HKEY_LOCAL_MACHINE.

For managed code, the following key manages JIT debugging:


 HKLM\Software\Microsoft\.NETFramework

The DbgJITDebugLaunchSetting value at this key sets the behavior of the just-in-time dialog box. There are
three possible values. A value of zero requests that the Microsoft Error Reporting dialog box is displayed for
JIT debugging. In the Microsoft Error Reporting dialog box, click the Don't Send button to launch the JIT
debugging dialog box. Both the Microsoft Error Reporting and the JIT debugging dialog boxes are shown in
Figures 13-1 and 13-2. A value of 1 causes the Microsoft Error Reporting dialog box to be suppressed. A
value of 2 forces the JIT debugging dialog box to be displayed when JIT debugging occurs. However, the
Microsoft Error Reporting dialog box is not shown. The default value for DbgJITDebugLaunchSetting is zero.
In addition to the DbgJITDebugLaunchSetting value, you can name the managed JIT debugger in the
DbgManagedDebugger value. Figure 13-3 has the managed debugging key and values.

Figure 13-1: Microsoft Error Report dialog box

Figure 13-2: Just-in-Time Debugging dialog box

Figure 13-3: View of the .NETFramework key and DbgManagedDebugger value

For unmanaged code, you configure JIT debugging at the following registry key:
 HKLM\Software\Microsoft\Windows NT\CurrentVersion\AeDebug

The Auto value of this key controls the Just-in-Time Debugging dialog box. Zero causes the Microsoft Error
Reporting dialog box to be displayed. If the Debug button is clicked on the Microsoft Error Reporting dialog
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

box, the Just-in-Time Debugging dialog box is displayed next. A value of 1 displays the Just-in-Time
Debugging dialog box directly. The Debugger value of the AeDebug registry key holds the name of the JIT
unmanaged debugger.

Visual Studio .NET is named as the default managed and unmanaged debugger when the product is
installed. If that changes, you can reappoint Visual Studio .NET as the default debugger from the Tools menu
and the Options dialog box. Choose the Just-In-Time section in the Debugging pane. From that window,
choose the types of code for which Visual Studio .NET should be the JIT debugger.

Figure 13-4 shows the JIT debugging selections.

Figure 13-4: Just-In-Time pane

You can install other debuggers as the default JIT debugger. The I startup option of the WinDbg or Dr.
Watson tools installs either as the default unmanaged debugger. You can also manually change the registry
to make these tools the default managed or unmanaged JIT debuggers:
 WinDbg -I
 Drwtsn32 -I
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Managed Debugger
MDbg supports user-mode debugging of managed applications and does not support mixed-mode
debugging. Because MDbg is dedicated to managed code, it has an expanded repertoire of debugging
commands specific to managed code. As mentioned previously, it is a console debugger. MDbg supersedes
the Runtime Debugger (CorDbg), which is the previous managed debugger. CorDbg remains available and
continues to be distributed with Visual Studio .NET and the .NET Framework.

Conveniently, MDbg and CorDbg share many of the same commands. However, MDbg commands are
different from those of WinDbg and SOS. For developers who switch between these tools frequently,
leveraging the benefits of each, the nonstandardization of the public interface of these tools is sometimes
frustrating. For example, here are three distinct commands to display a call stack. In WinDbg, you have the
k commands, such as k, kb , and kp. SOS offers the !clrstack command. MDbg has the most original name
for a stack trace command, which is the w (w for where) command.

The following walkthrough demonstrates and highlights many of the unique features of MDbg. As mentioned,
Store.exe is the demonstration application provided for walkthroughs in this chapter. In this application, you
record sales as transactions. To add a transaction, enter the number of transactions in the # of Transactions
text box and then click the Add Transactions button. The default number of transactions is 1. The
Transaction dialog box appears next, in which you select the items sold in this transaction. After accepting,
the new transaction is added to the list of transactions, and the display is updated. The Store application is
modified minimally to facilitate some of the walkthroughs. Each walkthrough has its own version of the Store
application. The generic Store application is shown in Figure 13-5.

Figure 13-5: The user interface of the Store application

MDbg Walkthrough
The ability to create instances of new objects or invoke managed functions is one of the coolest features
included in MDbg. You can seed an application with classes and functions that are used during debugging
sessions exclusively. They are never actually called in the application during normal operation, but are
instead called only from the debugger. A Debug class has been added to the Store application for this
purpose. Debug.Reset is a static method and the sole member of the Debug class. The Reset method
resets the Store application. The Debug class and Reset method are a normal class and method. There are
no hooks in them especially for the debugger. This is the Debug class:

public class Debug


{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static void Reset()


{
Form1.formItems.Clear();
Form1.formListBox.Items.Clear();
Form1.formMessage.Text = "Grand Total:";
Form1.formSummary.Text = "Summary: No Transactions";
Console.WriteLine("Application reset.");
}
}

These are the steps of the walkthrough:


1. Start the demonstration by running the Store application and adding multiple transactions.
2. Start MDbg.
3. Display the active processes by using the pro(cessnum) command. The command lists the
process identifier, executable, and domain of each process. The Store application is included in
the list.
4.
5. mdbg> pro
6. Active processes on current machine:
7. (PID: 3636) C:\codew\debugging\memory\bin\Release\Store.vshost.exe
8. (ID: 1) Store.vshost.exe
9. (PID: 3812) C:\Program Files\Microsoft Visual Studio
8\Common7\IDE\devenv.exe
10. (ID: 1) DefaultDomain
11. (PID: 2812) C:\store\Store.exe
12. (ID: 1) Store.exe
13. The a(ttach) command attaches MDbg to a running application. The prompt will change to indicate
that you are debugging an application. As part of attaching to the program, the debugger
interrupts the application.
14.
15. mdbg> a 2812
16. [p#:0, t#:0] mdbg>
17. How is the Reset method described in the debugger? That would help in calling that method. The x
command displays functions in a module. Without parameters, the x command lists the modules
in the application. List the modules:
18.
19. [p#:0, t#:0] mdbg> x
20. :0 mscorlib.dll#0 (no symbols loaded)
21. :1 Store.exe#0
22. :2 System.Windows.Forms.dll#0 (no symbols loaded)
23. :3 System.dll#0 (no symbols loaded)
24. :4 System.Drawing.dll#0 (no symbols loaded)
25. :5 System.Configuration.dll#0 (no symbols loaded)
26. :6 System.Xml.dll#0 (no symbols loaded)
27. Module ":1" is Store.exe. With that information, the functions in that module can be listed using
the x command again, this time with the ":1" parameter:
28.
29. [p#:0, t#:0] mdbg> x :1
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

30. ~0. Store.Transaction.Dispose(disposing)


31. ~1. Store.Transaction.InitializeComponent()
32. ~2. Store.Transaction..ctor()
33. ~3. Store.Transaction.btnAdd_Click(sender,e)
34. ~4. Store.Transaction.chkComputer_CheckedChanged(sender,e)
35. ~5. Store.Transaction.chkLaptop_CheckedChanged(sender,e)
36. ~6. Store.Transaction.chkPrinter_CheckedChanged(sender,e)
37. ~7. Store.Transaction.chkSoftware_CheckedChanged(sender,e)
38. ~8. Store.Transaction.get_newItem()
39. ~9. Store.Transaction.btnCancel_Click(sender,e)
40. ~10. Store.Form1.Dispose(disposing)
41. ~11. Store.Form1.InitializeComponent()
42. ~12. Store.Form1..ctor()
43. ~13. Store.Form1.get_formItems()
44. ~14. Store.Form1.get_formMessage()
45. ~15. Store.Form1.get_formSummary()
46.
47. ~16. Store.Form1.get_formListBox()
48. ~17. Store.Form1.btnTransaction_Click(sender,e)
49. ~18. Store.Form1.btnBad_Click(sender,e)
50. ~19. Store.Form1..cctor()
51. ~20. Store.Properties.Resources..ctor()
52. ~21. Store.Properties.Resources.get_ResourceManager()
53. ~22. Store.Properties.Resources.get_Culture()
54. ~23. Store.Properties.Resources.set_Culture(value)
55. ~24. Store.Program.Main()
56. ~25. Store.Properties.Settings.get_Default()
57. ~26. Store.Properties.Settings..ctor()
58. ~27. Store.Properties.Settings..cctor()
59. ~28. Store.Item..ctor()
60. ~29. Store.Item.get_Products()
61. ~30. Store.Item.set_Products(value)
62. ~31. Store.Item.get_ItemId()
63. ~32. Store.Item.Dispose()
64. ~33. Store.Item..cctor()
65. ~34. Store.Debug.Reset()
66. ~35. Store.Debug..ctor()
67. The Store.Debug.Reset method is found at the bottom of the list. Store is the namespace, Debug
is the class, and Reset is the method. The next time a transaction is added, we want to call this
method to reset the application. The button-click handler for adding transactions is
Store.Form1.btnTransaction_Click, which is also found in the preceding list. Set a breakpoint on
this method and resume the Store application. The b(reakpoint) command sets breakpoints, and
the g(o) command resumes an interrupted application:
68.
69. [p#:0, t#:0] mdbg> b Store.Form1.btnTransaction_Click
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

70. Breakpoint #1 bound (Store.Form1::btnTransaction_Click(+0))


71. [p#:0, t#:0] mdbg> g
72. Click the Add Transaction button in the Store application. The breakpoint is hit, and the MDbg
debugger interrupts the application. The source line where the program is interrupted is displayed.
We no longer need this breakpoint. The b command without parameters lists all breakpoints,
whereas the del(ete) command removes a breakpoint:
73.
74. STOP: Breakpoint 1 Hit
75. 64: {
76. [p#:0, t#:0] mdbg> b
77. Current breakpoints:
78. Breakpoint #1 bound (Store.Form1::btnTransaction_Click(+0))
79. [p#:0, t#:0] mdbg> del 1
80. The newo(bj) command creates new instances of classes. However, Reset is a static method and
does not require an instance. The method is called directly on the class. Invoke the method with
the f(unceval) command:
81.
82. [p#:0, t#:0] mdbg> f Store.Debug.Reset
83. STOP EvalComplete
84. Resume the Store application with the g command, and the application should be reinitialized.

Here is a second demonstration of the MDbg debugger. This walkthrough highlights exception management.
When a second-chance exception is raised in an attached application, MDbg does not intercede. Interesting,
this is contrary to the behavior of most debuggers. Second-chance exceptions are catastrophic. The
exception will terminate the application or prompt JIT debugging. If you want the debugger to intercede, you
can request that MDbg catch second-chance exceptions.
1. Restart the Store application.
2. Attach MDbg to the application and resume the program.
3. Click the Bad Action button. As advertised, a bad action occurs, which is an unhandled
exception. The Just-in-Time Debugging dialog box will most likely appear where the application
can be terminated. Terminate the application. The Bad Action button is not particularly creative in
manifesting an exception. The method has filler code but eventually raises a divide-by-zero
exception:
4.
5. private void btnBad_Click(object sender, EventArgs e)
6. {
7. int a = 5, b = 0;
8. ++a;
9. a /= 2;
10. a /= b;
11. }
12. Restart the Store application.
13. Attach the MDbg debugger.
14. Ask the MDbg debugger to catch all second-chance exceptions with the ca(tch) ex(ception)
command:
15.
16. [p#:0, t#:0] mdbg> ca ex
17. Resume the application and then click the Bad Action button. This time, the exception is trapped
in MDbg, and execution transfers to the debugger. In the debugger, the exception type and the
properties of the current exception object are dumped, providing important information on the
exception. The source code at the infraction is also displayed and shows the divide-by-zero
operation. You now have plenty of information to debug the problem.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

18.
19. [p#:0, t#:0] mdbg> g
20. STOP: Exception thrown
21. Exception=System.DivideByZeroException
22. _className=<null>
23. _exceptionMethod=<null>
24. _exceptionMethodString=<null>
25. _message="Attempted to divide by zero."
26. _data=<null>
27. _innerException=<null>
28. _helpURL=<null>
29. _stackTrace=array [24]
30. _stackTraceString=<null>
31.
32. _remoteStackTraceString=<null>
33. _remoteStackIndex=0
34. _dynamicMethods=<null>
35. _HResult=-2147352558
36. _source=<null>
37. _xptrs=1240048
38. _xcode=-1073741676
39. 134: a /= b;

MDbg Commands

MDbg has a full complement of commands for debugging managed applications. Some of the commands
were demonstrated in the previous walkthroughs. Table 13-1 lists the MDbg commands.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

? Th
an es
dh e
( are
elp the
) hel
p
co
m
ma
nd
s
an
d
dis
pla
y
the
MD
bg
co
m
ma
nd
s
wit
h
a
bri
ef
de
scr
ipti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

ap( Thi
pro s
ce co
ss) m
ma
nd
swi
tch
es
to
an
oth
er
ma
na
ge
d
pro
ce
ss,
whi
ch
is
cur
ren
tly
bei
ng
de
bu
gg
ed.
Wit
ho
ut
par
am
ete
rs,
the
co
m
ma
nd
dis
pla
ys
the
att
ac
he
d
pro
ce
ss
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

a( Thi
tta s
ch) co
m
ma
nd
att
ac
he
s
the
MD
bg
de
bu
gg
er
to
a
ma
na
ge
d
pro
ce
ss.
Wit
ho
ut
par
am
ete
rs,
the
co
m
ma
nd
list
s
the
ava
ilab
le
ma
na
ge
d
pro
ce
ss
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

b( Thi
rea s
kp co
oin m
t) ma
nd
set
s
a
sp
ecif
ic
bre
ak
poi
nt
or
dis
pla
ys
all
the
bre
ak
poi
nts
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

ca( Thi
tch s
) co
m
ma
nd
sti
pul
ate
s
whi
ch
eve
nts
to
cat
ch.
It
ca
n
als
o
dis
pla
y
the
eve
nts
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

co Thi
nf( s
ig) co
m
ma
nd
set
s
a
par
tic
ula
r
co
nfig
ura
tio
n
or
dis
pla
ys
the
co
nfig
ura
tio
n
opt
ion
s.

del Thi
( s
ete co
) m
ma
nd
del
ete
s
a
bre
ak
poi
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

de( Thi
tac s
h) co
m
ma
nd
det
ac
he
s
the
de
bu
gg
er
fro
m
the
cur
ren
t
de
bu
gg
ed
ap
plic
ati
on.

d( Thi
ow s
n) co
m
ma
nd
mo
ves
the
sta
ck
fra
me
do
wn.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

ec Thi
ho s
co
m
ma
nd
ec
ho
es
tex
t
to
the
dis
pla
y.

ex( Th
it) es
an e
dq co
(uit m
) ma
nd
s
exi
t
the
de
bu
gg
er.

fo( Thi
rea s
ch) co
m
ma
nd
ex
ec
ute
s
an
act
ion
on
all
thr
ea
ds.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

f( Thi
un s
cev co
al) m
ma
nd
call
s
a
me
tho
d.

g(o Thi
) s
co
m
ma
nd
res
um
es
ex
ec
uti
on
of
a
de
bu
gg
ed
ap
plic
ati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

ig( Thi
nor s
e) co
m
ma
nd
dis
pla
ys
or
sti
pul
ate
s
whi
ch
eve
nts
to
ign
ore
.
Thi
s
co
m
ma
nd
co
mp
le
me
nts
the
ca(
tch
)
co
m
ma
nd.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

int( Thi
erc s
ept co
) m
ma
nd
int
erc
ept
s
ex
ce
pti
on
at
the
sp
ecif
ied
sta
ck
fra
me
.

k( Thi
ill) s
co
m
ma
nd
kill
s
an
act
ive
pro
ce
ss.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

l( Thi
ist) s
co
m
ma
nd
list
s
loa
de
d
mo
dul
es,
Ap
pD
om
ain
s,
or
as
se
mb
lies
.

lo( Thi
ad) s
co
m
ma
nd
loa
ds
an
MD
bg
ext
en
sio
n.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

mo Thi
(de s
) co
m
ma
nd
set
s
a
sp
ecif
ic
MD
bg
opt
ion
or
dis
pla
ys
all
the
opt
ion
s.

ne Thi
wo( s
bj) co
m
ma
nd
cre
ate
s
an
ins
tan
ce
of
a
typ
e.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

n( Thi
ext s
) co
m
ma
nd
s
ste
ps
ove
r
the
ne
xt
ins
tru
cti
on.

o( Thi
ut) s
co
m
ma
nd
ste
ps
out
of
a
fun
cti
on.

pa( Thi
th) s
co
m
ma
nd
set
s
or
dis
pla
ys
the
so
urc
e
pat
h.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

p( Thi
rint s
) co
m
ma
nd
dis
pla
ys
the
val
ue
s
of
the
loc
al
or
de
bu
g
vari
abl
es.

pro Thi
c( s
es co
se m
nu ma
m) nd
en
um
era
tes
the
ava
ilab
le
ma
na
ge
d
pro
ce
ss
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

re( Thi
su s
me co
) m
ma
nd
res
um
es
a
su
sp
en
de
d
thr
ea
d.

r( Thi
un) s
co
m
ma
nd
run
s
a
pro
gra
m
wit
h
the
MD
bg
de
bu
gg
er
im
me
dia
tel
y
att
ac
he
d.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

set Thi
s
co
m
ma
nd
set
s
a
loc
al
or
de
bu
g
vari
abl
e
to
a
ne
w
val
ue.

set Thi
ip s
co
m
ma
nd
mo
ves
the
ins
tru
cti
on
poi
nte
r
wit
hin
the
cur
ren
t
fun
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

sh( Thi
ow) s
co
m
ma
nd
sh
ow
s
the
so
urc
e
co
de
at
the
cur
ren
t
ins
tru
cti
on.

s( Thi
tep s
) co
m
ma
nd
ste
ps
int
o
a
fun
cti
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

su( Thi
sp s
en co
d) m
ma
nd
su
sp
en
ds
a
run
nin
g
thr
ea
d.

sy( Thi
mb s
ol) co
m
ma
nd
set
s
or
dis
pla
ys
the
sy
mb
ol
pat
h.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

t( Thi
hre s
ad) co
m
ma
nd
swi
tch
es
to
a
sp
ecif
ied
thr
ea
d
or
dis
pla
y
all
thr
ea
ds.

U(p Thi
) s
co
m
ma
nd
mo
ves
up
the
sta
ck
fra
me
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

uw Thi
gc( s
ha co
ndl m
e) ma
nd
dis
pla
ys
the
obj
ect
sp
ecif
ied
by
the
GC
ha
ndl
e.

wh Thi
en s
co
m
ma
nd
ex
ec
ute
s
a
co
m
ma
nd
ba
se
d
on
a
de
bu
gg
er
eve
nt.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

w( Thi
her s
e) co
m
ma
nd
dis
pla
ys
a
sta
ck
tra
ce.

x Thi
s
co
m
ma
nd
dis
pla
ys
the
fun
cti
on
s
in
a
mo
dul
e
or
list
s
all
the
mo
dul
es.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-1:
MDbg
Commands

Co De
m scr
ma ipti
nd on

Ctrl Thi
+C s
ke
yst
rok
e
int
err
upt
s
a
run
nin
g
ap
plic
ati
on.

Ctrl Thi
+B s
rea ke
k yst
rok
e
ter
mi
nat
es
the
run
nin
g
ap
plic
ati
on
an
d
exi
ts
the
de
bu
gg
er.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

WinDbg
WinDbg is both a kernel- and user-mode debugger. It is pronounced Windbag, Win"d-b-g," or, more
intuitively, WinDebug. For many developers, WinDbg is the center of the advanced debugging universe. It has
been available for some time and has evolved to encompass an impressive array of commands. Some of
these commands are admittedly bewildering but always interesting. I have taught the .NET Advanced
Debugging Workshop at Microsoft for years, which includes coverage of WinDbg. I still learn something new
and amazing about WinDbg almost every month.

The focus of this book is C# and managed code. This is not the ideal place to troll the depths of WinDbg. It
would be fun, but probably not entirely relevant. However, some basic WinDbg commands are helpful even
when debugging managed applications. Although WinDbg offers a basic user interface, most developers
operate from the command line. For this reason, we will use the user interface in a limited manner.

WinDbg Basic Commands

When WinDbg is launched, the debugger can be attached to an application using commandline arguments.
This requires the process identifier of the debuggee. Tlist is a utility installed with Debugging Tools for
Windows to lists the process identifier of active processes.

The following is sample output from the Tlist utility. Applications are listed in execution sequence. The first
column is the process identifier, the second column is the program, and the final column contains a
description, if available.

C:\store>tlist
0 System Process
4 System
784 smss.exe
844 csrss.exe
872 winlogon.exe
916 services.exe
928 lsass.exe
736 KHALMNPR.exe KHALHPP_MainWindow
1052 gcasDtServ.exe GIANT AntiSpyware Data Service
1444 DVDRAMSV.exe
1488 inetinfo.exe
1524 mdm.exe
1748 sqlservr.exe
1828 nvsvc32.exe NVSVCPMMWindowClass
1440 wscntfy.exe
2380 iPodService.exe
2620 alg.exe
3384 iTunes.exe iTunes
3648 WINWORD.EXE MarshallChap14_0830 - Microsoft Word
2892 cmd.exe Visual Studio .NET Whidbey Command Prompt - tlist
2572 Store.exe Store
2696 tlist.exe

The -p argument attaches WinDbg to an application based on the process identifier:


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

windbg -p 2572

You can also attach to a running process simply with the application name:

windbg -pn store.exe

Alternatively, WinDbg can be started without being attached to anything. You can later attach to an
application using the File menu of the WinDbg user interface. From the File menu, select the Attach to a
Process command. Choose the debuggee from the list of available processes. The Open Executable
command on the same menu starts an application and immediately attaches the debugger. This is
convenient if the application is not already running.

When using WinDbg, some essential commands are helpful. Most of the WinDbg commands are case
insensitive, but there are exceptions. Table 13-2 lists the basic commands.
Table 13-2:
Basic
WinDbg
Commands

Co De
m scr
ma ipti
nd on

g(o Thi
) s
co
m
ma
nd
res
um
es
ex
ec
uti
on
of
the
de
bu
gg
ed
ap
plic
ati
on.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-2:
Basic
WinDbg
Commands

Co De
m scr
ma ipti
nd on

Ctrl Thi
+B s
rea ke
k yst
rok
e
int
err
upt
s
the
run
nin
g
ap
plic
ati
on.

q( Thi
uit) s
co
m
ma
nd
qui
ts
the
de
bu
gg
er.

? Thi
s
co
m
ma
nd
dis
pla
ys
hel
p
do
cu
me
nta
tio
n.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Now that the basic commands have been presented, we can discuss the more interesting commands.

Displaying the active threads and changing thread context are frequent requests for any debugger. In
WinDbg, the tilde (~) command is for thread manipulation.
 The ~ command without parameters lists the threads. Thread identifier, status, and address of the
thread environment block include some of the information reported. If the thread context is
elsewhere, the current thread is highlighted with the pound (#) prefix.
 The ~n command displays information on the specified thread, where n is the thread number.
Thread priority, status, priority class, and other thread-relevant information is presented.
 The ~ns command changes the thread context to the thread that is indicated. The WinDbg
prompt is updated to reflect the new thread context. When the context is changed, the context
record of the new thread is displayed, which includes the register values.

The following demonstration lists the threads, displays information pertaining to Thread 2, and then selects
Thread 3 as the current thread:

0:001> ~
0 Id: a1c.9c0 Suspend: 1 Teb: 7ffde000 Unfrozen
. 1 Id: a1c.804 Suspend: 1 Teb: 7ffdd000 Unfrozen
2 Id: a1c.ea0 Suspend: 1 Teb: 7ffdc000 Unfrozen
3 Id: a1c.de0 Suspend: 1 Teb: 7ffdb000 Unfrozen
# 4 Id: a1c.c04 Suspend: 1 Teb: 7ffda000 Unfrozen
0:001> ~2
2 Id: a1c.ea0 Suspend: 1 Teb: 7ffdc000 Unfrozen
Start: mscorwks!Thread::intermediateThreadProc (79ee80cf)
Priority: 2 Priority class: 32
0:001> ~3s
eax=4ec62ef0 ebx=0103fe7c ecx=0000d9c7 edx=7c90eb94 esi=00000000 edi=7ffdf000
eip=7c90eb94 esp=0103fe54 ebp=0103fef0 iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!KiFastSystemCallRet:
7c90eb94 c3 ret

Stack Trace Commands


Stack traces are invaluable when debugging. Even for managed code, viewing the unmanaged call stack can
be informative. As demonstrated later in this chapter, many of the answers and hints to abnormal conditions
in managed code are found in the unmanaged world.

In WinDbg, variations of the k command present varied permutations of a stack trace. Optionally, you can
follow a stack trace command with a number, which indicates the depth of the call stack.

Table 13-3 explains the common stack trace commands.


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-3:
Stack Trace
Commands

Co De
m scr
ma ipti
nd on

k Thi
s
co
m
ma
nd
list
s
the
me
tho
ds
on
the
call
sta
ck.
In
ad
diti
on,
the
chil
d
fra
me
poi
nte
r
an
d
the
ret
urn
ad
dre
ss
of
the
call
ing
me
tho
d
are
list
ed
in
col
um
ns.
No
par
am
ete
rs
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-3:
Stack Trace
Commands

Co De
m scr
ma ipti
nd on

kb Thi
s
co
m
ma
nd
list
s
the
call
sta
ck
an
d
the
firs
t
thr
ee
par
am
ete
rs
of
the
me
tho
ds.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-3:
Stack Trace
Commands

Co De
m scr
ma ipti
nd on

kp Thi
s
co
m
ma
nd
list
s
the
call
sta
ck
an
d
the
ent
ire
par
am
ete
r
list
of
the
me
tho
ds.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-3:
Stack Trace
Commands

Co De
m scr
ma ipti
nd on

kn Thi
s
co
m
ma
nd
list
s
the
call
sta
ck
wit
h
the
fra
me
nu
mb
er
for
ea
ch
me
tho
d.
Yo
u
ca
n
us
e
the
fra
me
info
rm
ati
on
to
mo
ve
bet
we
en
fra
me
s
on
the
call
sta
ck
usi
ng
the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The following is the call stack from a thread in the Store application. Three parameters are displayed
because the kb command is used.

0:003> kb
ChildEBP RetAddr Args to Child
0103fe50 7c90e9ab 7c8094f2 00000002 0103fe7c ntdll!KiFastSystemCallRet
0103fe54 7c8094f2 00000002 0103fe7c 00000001
ntdll!ZwWaitForMultipleObjects+0xc
0103fef0 77d495f9 00000002 0103ff18 00000000
KERNEL32!WaitForMultipleObjectsEx+0x12c
0103ff4c 77d496a8 00000001 0103ffac ffffffff
USER32!RealMsgWaitForMultipleObjectsEx+0x13e
0103ff68 4ec95846 00000001 0103ffac 00000000
USER32!MsgWaitForMultipleObjects+0x1f
0103ffb4 7c80b50b 00000000 00000000 0012e0d0 gdiplus!BackgroundThreadProc+0x59
0103ffec 00000000 4ec957ed 00000000 00000000 KERNEL32!BaseThreadStart+0x37

What if you want the stack trace of every thread? Each thread could be selected and a k command
submitted. However, that approach becomes tedious if there are dozens of threads. The solution is '~*'.
Commands prefixed with '~*' are applied to all threads of the application. This command performs a stack
trace on every thread:

~* k

Display Memory Commands


Displaying memory is another important tool of debugging. The d command is the fundamental display
memory command. There is a bounty of variants to the d command for dumping different types and
quantities of memory. Display commands list rows and columns of data. Rows begin with a memory
address. This is the starting address for the contiguous bytes displayed on that row. The memory is
organized in row order. By default, bytes are organized in two-byte columns. Certain display commands add
byte translation at the end of every row. This is a typical display of memory:

0:003> d 0103fe50
0103fe50 cc 33 66 00 ab e9 90 7c-f2 94 80 7c 02 00 00 00 .3f....|...|....
0103fe60 7c fe 03 01 01 00 00 00-00 00 00 00 00 00 00 00 |...............

0103fe70 00 00 00 00 02 00 00 00-00 00 00 00 94 06 00 00 ................


0103fe80 8c 06 00 00 cc 99 99 00-cc 99 cc 00 cc 99 ff 00 ................
0103fe90 cc cc 00 00 cc cc 33 00-cc cc 66 00 14 00 00 00 ......3...f.....
0103fea0 01 00 00 00 00 00 00 00-00 00 00 00 10 00 00 00 ................
0103feb0 cc ff 66 00 cc ff 99 00-cc ff cc 00 00 b0 fd 7f ..f.............
0103fec0 00 c0 fd 7f ff 00 33 00-00 00 00 00 7c fe 03 01 ......3.....|...

This is the syntax of a display command:


 dL address1 address2

The second letter (L) of the display command varies based on the actual display command, such as dc, dd,
and du. The second letter is also case sensitive. address1 is the beginning address, whereas address2 is
the ending address. Memory is displayed from address1 to address2. Omit the ending address, and a
default number of bytes are displayed. If neither the beginning nor the ending memory address is provided,
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

the command displays from the current address forward.

Table 13-4 lists some of the commands that display memory.


Table 13-4:
Common
Display
Memory
Commands

Co De
m scr
ma ipti
nd on

d Thi
s
co
m
ma
nd
rep
eat
s
the
pre
vio
us
dis
pla
y
co
m
ma
nd
an
d
def
aul
ts
to
the
db
co
m
ma
nd.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-4:
Common
Display
Memory
Commands

Co De
m scr
ma ipti
nd on

da Thi
s
co
m
ma
nd
dis
pla
ys
the
AS
CII
int
erp
ret
ati
on
of
the
me
mo
ry.

dc Thi
s
co
m
ma
nd
dis
pla
ys
the
dat
a
in
fou
r-b
yte
col
um
ns.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-4:
Common
Display
Memory
Commands

Co De
m scr
ma ipti
nd on

dd Thi
s
co
m
ma
nd
is
the
sa
me
as
dc,
ex
ce
pt
the
byt
e
tra
nsl
ati
on
is
om
itte
d
at
the
en
d
of
ea
ch
row
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-4:
Common
Display
Memory
Commands

Co De
m scr
ma ipti
nd on

du Thi
s
co
m
ma
nd
dis
pla
ys
the
Uni
co
de
int
erp
ret
ati
on
of
the
me
mo
ry.

The following command has four-byte columns of memory, three columns per row, and a starting address.
The /c option controls the number of columns displayed:

0:003> dd /c 3 0103fe50
0103fe50 006633cc 7c90e9ab 7c8094f2
0103fe5c 00000002 0103fe7c 00000001
0103fe68 00000000 00000000 00000000
0103fe74 00000002 00000000 00000694
0103fe80 0000068c 009999cc 00cc99cc
0103fe8c 00ff99cc 0000cccc 0033cccc
0103fe98 0066cccc 00000014 00000001
0103fea4 00000000 00000000 00000010
0103feb0 0066ffcc 0099ffcc 00ccffcc
0103febc 7ffdb000 7ffdc000 003300ff
0103fec8 00000000 0103fe7c

Breakpoints Memory Commands


Debugging requires being a detective, and breakpoints are important investigative tools. Breakpoints interrupt
a program based on certain conditions, such as memory address, location, or event. Setting effective
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

breakpoints is an art, which is obtained with experience.

Naturally, WinDbg offers several breakpoint commands, as detailed in Table 13-5.


Table 13-5: Common
Display Memory
Commands

Co Description
m
ma
nd

bp This is the
standard
breakpoint
command.
The program
is interrupted
when
execution
reaches the
specified
location.
This is an
abbreviated
syntax for the
bp command:
 bp
locatio
n
options

The /1 option
is useful for
defining
one-off
breakpoints.
This type of
breakpoint is
automatically
removed after
being hit.
Therefore, the
breakpoint is
reached only
once.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-5: Common


Display Memory
Commands

Co Description
m
ma
nd

ba This
command is
break on
access to a
memory
address.
This is the
abbreviated
syntax for the
ba command:
 ba
options
size
addres
s
options
specifies the
action to
break on:
 e—
execut
e
 r—
read/wr
ite
 w—
write
 i-
input/o
utput
size is the
width of the
memory
address.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-5: Common


Display Memory
Commands

Co Description
m
ma
nd

bc This
command
clears a
breakpoint.
You can clear
multiple
breakpoints in
a space- or
comma-delimit
ed list.
Alternatively,
specify a
range with a
hyphen.

bl This
command
lists the
available
breakpoints.
Multiple
breakpoints
can be
specified as
described for
the bc
command.

The following is a demonstration of the breakpoint command. The sxe command is the set exception
command. This command requests that the debugger interrupt on an exception or other event. In this
example, the sxe command asks the debugger to interrupt when the mscorwks module is loaded, which is
where the Common Language Runtime (CLR) is found. For a compound statement, use a semicolon. In the
following command, the sxe and g commands are combined into a compound statement.

The following command breaks when the mscorwks module is loaded (the application is then resumed):

0:000> sxe ld mscorwks;g


ModLoad: 77dd0000 77e6b000 C:\WINDOWS\system32\ADVAPI32.dll
ModLoad: 77e70000 77f01000 C:\WINDOWS\system32\RPCRT4.dll
ModLoad: 77f60000 77fd6000 C:\WINDOWS\system32\SHLWAPI.dll
ModLoad: 77f10000 77f56000 C:\WINDOWS\system32\GDI32.dll
ModLoad: 77d40000 77dd0000 C:\WINDOWS\system32\USER32.dll
ModLoad: 77c10000 77c68000 C:\WINDOWS\system32\msvcrt.dll
ModLoad: 76390000 763ad000 C:\WINDOWS\system32\IMM32.DLL
ModLoad: 629c0000 629c9000 C:\WINDOWS\system32\LPK.DLL
ModLoad: 74d90000 74dfb000 C:\WINDOWS\system32\USP10.dll
ModLoad: 79e70000 7a3cf000
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll

eax=00000000 ebx=00000000 ecx=009f0000 edx=7c90eb94 esi=00000000 edi=00000000


eip=7c90eb94 esp=0012f1c0 ebp=0012f2b4 iopl=0 nv up ei ng nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000296
ntdll!KiFastSystemCallRet:
7c90eb94 c3 ret

The following command sets a breakpoint on the ExecuteMainMethod method:

0:000> bp mscorwks!SystemDomain::ExecuteMainMethod;g
ModLoad: 78130000 781ca000
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSVCR80.dll
ModLoad: 7c9c0000 7d1d4000 C:\WINDOWS\system32\shell32.dll
ModLoad: 773d0000 774d2000 C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-
Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\comctl32.dll
ModLoad: 5d090000 5d127000 C:\WINDOWS\system32\comctl32.dll
ModLoad: 60340000 60348000
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\culture.dll
ModLoad: 790c0000 79baa000
C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\cee6ddb
471db1c489d9b4c39549861b5\mscorlib.ni.dll
Breakpoint 0 hit
eax=0012ff38 ebx=00000002 ecx=00000000 edx=ffffffff esi=00000000 edi=00000000
eip=79efb428 esp=0012ff1c ebp=0012ff68 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
mscorwks!SystemDomain::ExecuteMainMethod:
79efb428 55 push ebp

After the breakpoint is hit, the kb command performs a stack trace. You see ExecuteMainMethod in the call
stack:

0:000> kb
ChildEBP RetAddr Args to Child
0012ff18 79efb3cb 00400000 00000000 b4ebfe93
mscorwks!SystemDomain::ExecuteMainMethod
0012ff68 79ef8bc8 00400000 b4ebfe4b 00080000 mscorwks!ExecuteEXE+0x59
0012ffb0 790122f6 00d9fa9c 79e70000 0012fff0 mscorwks!_CorExeMain+0x11b
0012ffc0 7c816d4f 00080000 00d9fa9c 7ffd8000 mscoree!_CorExeMain+0x2c
0012fff0 00000000 790122c2 00000000 78746341 KERNEL32!BaseProcessStart+0x23

Step Commands
After reaching a breakpoint, it is common to step through an application and evaluate the results. There are
also plenty of other reasons and opportunities to step through an application. The best means of stepping
through an application is by using the Debugging toolbar. (Choose the View menu and the Toolbar option to
display the Debugging toolbar.)

Figure 13-6 shows the Step buttons on the Debugging toolbar: the Step In, Step Over, Step Out, and Run to
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Cursor buttons.

Figure 13-6: Step buttons on the Debugging toolbar

WinDbg Directives WinDbg commands affect the application currently being debugged. The commands
display, modify, or otherwise affect or inspect the debuggee. Conversely, WinDbg directives alter the
debugging session. For example, the .load directive loads a debugging extension dynamic-link library (DLL).
The .logopen directive opens a log file and echoes any subsequent activity to this file.

There are several WinDbg directions. Table 13-6 includes some of the available directives. Directives are
prefixed with a dot (.).
Table 13-6: WinDbg
Directives

Co Description
m
ma
nd

.lo This
ad command
dlln loads a
am debugger
e extension
DLL.
Extension
commands
are exposed
as the
exported
functions of
the DLL.
Developers of
managed
code routinely
load the SOS
(SOS.dll)
debugger
extension.
Commands
from debugger
extensions
are prefixed
with an
exclamation
point (!).

.un This
loa command
d unloads a
dlln debugger
am extension.
e
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-6: WinDbg


Directives

Co Description
m
ma
nd

.ch This
ain command
lists the
debugger
extensions
that are
presently
available.

.rel This
oa command
d reloads
symbols and
is usually
requested
after the
symbol path
has been
updated.
Normally,
symbols are
retrieved as
needed. The /f
option forces
the immediate
load of all
symbols.

.lo This
go command
pe opens a log
n file and
file echoes any
na subsequent
me activity to this
file.

.lo This
gcl command
os closes the log
e file.

.kil This
l command
terminates the
current
debuggee and
ends the
debugging
session.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-6: WinDbg


Directives

Co Description
m
ma
nd

.fra This
me command
n shifts the
stack to the
designated
frame number
or displays
the current
local context.

.sr This
cp command
ath sets or
displays the
source code
path.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-6: WinDbg


Directives

Co Description
m
ma
nd

.du This
mp command
opt creates a
ion user- or
s kernel-mode
file dump, which
na is used for
me postmortem
analysis.
.dump
filename
creates a
minidump.
The following
command
creates a
minidump with
full memory
and handle
information:
 .dump
/mfh
filenam
e
This
command
creates a full
dump. The full
dump
command is
available only
in
kernel-mode
operations of
WinDbg
(which is not
discussed in
this chapter):
 .dump
/f
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Son of Strike (SOS)


SOS is a debugger extension for debugging managed code and is used in collaboration with the unmanaged
debugger to diagnose abnormal conditions. Expect that some problems cannot be isolated with SOS alone.
It is the collaboration between the unmanaged debugger and SOS that is powerful. Problems in managed
applications are diagnosable without SOS, but that requires your interpretation of complex commands and
internal structures. With SOS, that challenge is avoided, allowing developers to concentrate on the problem—
debugging the application.

Any of the following statements loads the SOS extension DLL. To load a particular version of SOS, provide a
fully qualified directory path. When live debugging, the current version of WinDbg automatically loads SOS.
However, it is not automatically loaded for postmortem analysis.

.load sos

.load sos.dll

.load c:\path\sos.dll

SOS Walkthrough Part I

This walkthrough is an introduction to SOS. Details from previous walkthroughs and demonstration are
omitted for brevity. Some of the listings have also been abbreviated for clarity.
1. Start the Store application. Open the Transaction dialog box, as shown in Figure 13-7. For this
debugging session, do not complete or close this dialog box.
2. Launch the WinDbg debugger and then attach it to the Store application.
3. SOS has a !threads command, which lists the managed threads of the application. Use the
!threads command. This is the abbreviated result:
4.
5. 0:004> !threads
6. ThreadCount: 2
7. UnstartedThread: 0
8. BackgroundThread: 1
9. PendingThread: 0
10. DeadThread: 0
11. Hosted Runtime: no
12.
13. PreEmptive GC Alloc
Lock
14. ID OSID ThreadOBJ State GC Context Domain
Count
15. 0 1 424 001501f8 6020 Enabled 013da5dc:013dadb8 001483a8
0
16. 2 2 c24 00153e40 b220 Enabled 00000000:00000000 001483a8
0
17. Change to Thread 0, which is a managed thread.
18.
19. 0:004> ~0s
20. eax=790ff90c ebx=01392b50 ecx=013a7704 edx=0000ce7d esi=00000000
edi=013da5b8
21. eip=7c90eb94 esp=0012edb4 ebp=0012ee4c iopl=0 nv up ei pl zr
na po nc
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

22. cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000


efl=00000246
23. ntdll!KiFastSystemCallRet:
24. 7c90eb94 c3 ret
25. Enter the !clrstack command to show a stack trace of the current thread. The p option requests
that the parameters be displayed.
26.
27. 0:000> !clrstack -p
28. OS Thread Id: 0x424 (0)
29. ESP EIP
30. 0012edc0 7c90eb94 [InlinedCallFrame: 0012edc0]
System.Windows.Forms.UnsafeNativeMethod
31. s.WaitMessage()
32. 0012edbc 7b094838
System.Windows.Forms.Application+ComponentManager.System.Windows.For
33. ms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32,
Int32, Int32)
34. PARAMETERS:
35. this = 0x013a76ac
36. dwComponentID = <no data>
37. reason = 0x00000004
38. pvLoopData = 0x00000000
39.
40. 0012eef8 7b22e03e
System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window)
41. PARAMETERS:
42. this = 0x013b4494
43. owner = <no data>
44. The ShowDialog method appears in the stack trace, where the parameters are also shown. The
this reference is the first parameter of the method. Use the dumpobj command to dump the this
reference, which confirms that the Store.Transaction form is displayed.
45.
46. 0:000> !dumpobj 0x013b4494
47. Name: Store.Transaction
48. MethodTable: 00d453a4
49. EEClass: 00db3034
50. Size: 372(0x174) bytes
51. (C:\store\Store.exe)
52. Fields:
53. MT Field Offset Type VT Attr Value
Name
54. 790fa098 4000184 4 System.Object 0 instance 00000000
__identity
55. 7a765ca4 40008bc 8 ...ponentModel.ISite 0 instance 00000000
site
56. 7a762e84 40008bd c ....EventHandlerList 0 instance 013b6964
events
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

57. 790fa098 40008bb 108 System.Object 0 static 00000000


EventDisposed
58. 7b4777e4 40010fa 10 ...ntrolNativeWindow 0 instance 013b55c4
window
59. 7b4754b4 40010fb 14 ...ows.Forms.Control 0 instance 00000000
parent
60. 7b4754b4 40010fc 18 ...ows.Forms.Control 0 instance 00000000
reflectParent
61. 7b478924 40010fd 1c ...orms.CreateParams 0 instance 013b560c
createParams
62. 790fe920 40010fe 34 System.Int32 0 instance 346 x
63. 790fe920 40010ff 38 System.Int32 0 instance 22 y
64. 790fe920 4001100 3c System.Int32 0 instance 266
width

Figure 13-7: Store application and the Transaction dialog box

SOS Commands
Table 13-7 is an overview of some of the SOS commands. For a complete listing, see the help command.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-7: Son of


Strike Commands

Co Description
m
ma
nd

!Clr This
Sta command
ck displays the
call stack of
the current
thread.
Here are
some of the
options:
 The -l
option
include
s the
local
variable
s in
the
output.
 The -p
option
include
s the
parame
ters in
the
output.
 The -a
option
combin
es
both
the -l
and -p
options
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-7: Son of


Strike Commands

Co Description
m
ma
nd

!Du This
mp command first
He displays the
ap objects that
are on the
managed
heap. It then
displays
statistics
about the type
of objects on
the managed
heap.
Here are
some of the
options:
 The
-stat
option
display
s the
type of
objects
alone.
 The
-min
option
exclud
es
objects
less
than
the
minimu
m
addres
s from
the
report.
 The
-max
option
exclud
es
objects
greater
than
the
maxim
um
addres
s from
the
report.
 The -mt
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-7: Son of


Strike Commands

Co Description
m
ma
nd

!Du This
mp command
IL dumps the
md MSIL of the
ad method
dre associated
ss with the
method
descriptor.

!Du This
mp command
MT dumps
mt information
ad about the
dre method table.
ss The -md option
lists
information on
the method
descriptors in
the method
table, such as
the function
names and
method
descriptor
addresses.

!Du This
mp command
Ob dumps
j information on
obj the specific
ad object.
dre
ss

!Du This
mp command
Sta lists value
ck types and
Ob references
jec that are on
ts stack of the
opt current
ion thread. The
only option is
-verify.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-7: Son of


Strike Commands

Co Description
m
ma
nd

!E This
EH command
ea dumps
p information on
opt Generation 0,
ion 1, 2, and the
s managed
heap. The
-loader option
lists the
private heaps
of each
AppDomain,
module, and
heap
associated
with the JIT
compiler.

!E This
EV command
ers displays
ion information of
the run-time
environment,
such as the
version
number.

!Fi This
nali command
ze lists the
Qu objects on the
eu finalization
e queue. For
opt additional
ion information on
SyncBlocks
and
RuntimeCallab
leWrappers,
use the -detail
option.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-7: Son of


Strike Commands

Co Description
m
ma
nd

!G This
Cro command
ot lists
-op instances that
tio hold
ns references to
obj the specified
ad object. The
dre -nostacks
ss option
excludes
references
held on the
stack.

!IP This
2M command
D displays the
jita method
ddr descriptor of a
es jitted method.
s

!Na If target is a
me type, the
2E command
E dumps the
pro method table
gra of that type. If
m target is a
tar method name,
get the method
descriptor of
that method is
dumped.

!Sy This
nc command
blk lists the
indexes of the
sync block
table.

!Th This
rea command
ds lists the
managed
threads.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-7: Son of


Strike Commands

Co Description
m
ma
nd

!To For this


ke command, the
n2 token must be
EE an entry of the
tok typedef or
en methoddef
table. If it is a
typedef token,
the method
table address
and other
information
about the
token are
displayed. If it
is a methoddef
token, the
corresponding
method
descriptor is
displayed.

!He This
lp command
co displays
m detailed help
ma on SOS
nd commands.
Without the
command
option, an
overview of all
the
commands is
displayed.

SOS Walkthrough Part II

Now that a few more commands have been introduced, an additional walkthrough is helpful. The following
walkthrough dumps the source code, MSIL, and assembly code of the btnTransaction_Click button handler,
which is informative.
1. Start the walkthrough by running the Store application and attach WinDbg to the application.
2. Dump information about the btnTransaction_Click method with the !name2ee command. Notice
that the method has not been jitted yet, which means that the method has not been invoked
before. A function is jitted when it is first invoked.
3.
4. 0:004> !name2ee store.exe Store.Form1.btnTransaction_Click
5. Module: 00d40c14 (Store.exe)
6. Token: 0x06000004
7. MethodDesc: 00d43968
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

8. Name: Store.Form1.btnTransaction_Click(System.Object, System.EventArgs)


9. Not JITTED yet. Use !bpmd -md 00d43968 to break on run.
10. 0:004> !u 00d43968
11. Not jitted yet
12. Continue the Store application using the g(o) command and click the Add Transactions button.
Interrupt the program in the debugger with Ctrl+Break. Dump information on
Store.Form1.btnTransaction_Click again. This time, the method is shown as jitted, and the virtual
address of the cached native binary is displayed:
13.
14. 0:004> !name2ee store.exe Store.Form1.btnTransaction_Click
15. Module: 00d40c14 (Store.exe)
16. Token: 0x06000004
17. MethodDesc: 00d43968
18. Name: Store.Form1.btnTransaction_Click(System.Object, System.EventArgs)
19. JITTED Code Address: 00de07c0
20.
21. The !u command displays the assembly code of a jitted method. Use this command for the
btnTransaction_Click method:
22.
23. 0:004> !u 00d43968
24. Normal JIT generated code
25. Store.Form1.btnTransaction_Click(System.Object, System.EventArgs)
26. Begin 00de07c0, size 3e9
27. 00de07c0 55 push ebp
28. 00de07c1 8bec mov ebp,esp
29. 00de07c3 57 push edi
30. 00de07c4 56 push esi
31. 00de07c5 53 push ebx
32. 00de07c6 83ec50 sub esp,0x50
33. 00de07c9 33c0 xor eax,eax
34. 00de07cb 8945d0 mov [ebp-0x30],eax
35. 00de07ce 8945c4 mov [ebp-0x3c],eax
36. 00de07d1 33c0 xor eax,eax
37. 00de07d3 8945e8 mov [ebp-0x18],eax
38. 00de07d6 894dc0 mov [ebp-0x40],ecx
39. 00de07d9 8955dc mov [ebp-0x24],edx
40. 00de07dc 833dc80dd40000 cmp dword ptr [00d40dc8],0x0
41. Challenge two is to list the MSIL code for the btnTransaction_Click method. The dumpil
command shows the MSIL code of the method:
42.
43. 0:004> !dumpil 00d43968
44. ilAddr = 0040247c
45. IL_0000: nop
46. .try
47. {
48. IL_0001: nop
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

49. IL_0002: ldarg.0


50. IL_0003: ldfld Store.Form1::txtNumber
51. IL_0008: callvirt System.Windows.Forms.Control::get_Text
52. IL_000d: call System.Int32::Parse
53. IL_0012: stloc.0
54. IL_0013: nop
55. IL_0014: leave.s IL_001d
56. } // end .try
57. .catch
58. {
59. IL_0016: pop
60. IL_0017: nop
61. IL_0018: ldc.i4.1
62. IL_0019: stloc.0
63. IL_001a: nop
64. IL_001b: leave.s IL_001d
65. } // end .catch
66. The final task is to display the source code. Set the source code path in WinDbg. From the File
menu, choose the Source File Path command and then enter the source code path. Enter the lsf
command to set form1.cs as the source code file. List the source with the ls command. For the
walkthrough, lines 10 to 50 are displayed:
67.
68. 0:004> lsf form1.cs
69. 0:004> ls 10, 40
70. 22:
71. 23: private void btnTransaction_Click(object sender,
EventArgs e)
72.
73. 24: {
74. 25: int numofTransactions;
75. 26: try
76. 27: {
77. 28: numofTransactions= int.Parse(txtNumber.Text);
78. 29: }
79. 30: catch
80. 31: {
81. 32: numofTransactions = 1;
82. 33: }
83. 34: for (int count = 0; count < numofTransactions;
++count)
84. 35: {
85. 36: int itemTotal=0;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Dumps
Dumps are used for postmortem analysis, which is sometimes the most effective means of debugging an
application. When a program intermittently crashes, postmortem analysis may be the sole option to resolve
the problem. You can capture a dump when the crash occurs, which is then used to diagnose the problem.
Production applications are not ideal for live debugging. How do you perform live debugging on an active Web
server? Convenience is another advantage to postmortem analysis. You remove the dump to a developer
machine that hosts an assortment of debugging tools and resources. In this environment, diagnosing the
problem is much easier.

Postmortem analysis is usually conducted by scrutinizing a dump, which is a memory snapshot of an


application. There are full dumps and minidumps. A minidump is only a snapshot of the application memory.
Full dumps also include other modules in the memory snapshot—even system modules. The benefit of a full
dump is convenience, and symbols are more easily aligned. The disadvantage is that full dumps tend to be
large. Not all minidumps are equivalent—some minidumps contain more information than others. Check the
documentation for the command or tool that creates a minidump to confirm what the minidump includes.

Remember that memory dumps are static. The debugging paradigm is different from performing live
debugging. You cannot step through the application, threads cannot be restarted, and so on.

As documented earlier, the .dump directive in WinDbg creates dump files. Dump files can also be created
with ADPlus and Dr. Watson tools.

ADPlus

The ADPlus tool is downloaded from the Debugging Tools for Windows Web site at Microsoft.com. It is a
Microsoft VBScript that automates the CDB debugger. Use ADPlus to debug applications that hang or
crash. The utility creates dump and log files for postmortem analysis. Unique names are assigned to these
files to avoid overriding previously generated files. ADPlus operates in either the crash or hang mode.

In crash mode, ADPlus attaches cdb to the target processes. It is attached invasively. You run ADPlus
before the application crashes. At that time, a minidump and log file are created. ADPlus will also write an
entry into the Event Log. A crash is interpreted as the application ending from an unhandled exception or
other abnormal condition. To detach prematurely before a crash, open the minimized CDB console window
and press Ctrl+C. This is the syntax of running ADPlus in the crash mode. Multiple processes can be
attached to simultaneously. All instances of the named processes are attached.

adplus -crash -pn processname 1 -pn processname 2 -pn processname n

Alternatively, the process identifier can be used to identify the target processes:
 adplus -crash -p pid 1 -p pid 2 -p pid n

In hang mode, run ADPlus after the hang occurs, which attaches CDB to the target application noninvasively.
The debuggee is resumed after the dump is created. This is the syntax to start ADPlus in the hang mode:
 adplus -hang -pn processname 1 -pn processname 2 -pn processname n
 adplus -hang -p pid 1 -p pid 2 -p pid n

There are three other options worth mentioning:

 O(utput) option This option sets the output directory for dump and log files.

 Q(uiet) option This option suppresses alerts related to ADPlus.

 N(otify) option This option notifies a user that an application has crashed.

ADPlus Walkthrough The Store application for this walkthrough has an error and unexpectedly crashes.
ADPlus is used to create a dump when the application crashes. The dump is then opened in WinDbg, and
the problem is isolated:
1. Start the Store application.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

2. Click the Hang button. As expected, this procedure hangs the application.
3. Run ADPlus in hang mode to attach the CDB debugger to the Store application. Get the correct
process identifier from the tlist utility:
4.
5. C:\store>adplus -hang -p 3520 -o c:\dumps
6. Attaching the debugger to: STORE.EXE
7. (Process ID: 3520)
8. Start WinDbg and open the dump. From the File menu, choose the Open Crash Dump command.
Find and open the dump.
9. Load the Son of Strike extension. Change to Thread 0 and request a managed stack trace. The
following is a partial listing of the call stack. It shows correctly that the btnHang_Click handler
was the last method entered. This provides a starting point in uncovering the culprit that caused
the hang.
10.
11. 0:000> .load sos
12. 0:000> !clrstack
13. OS Thread Id: 0xae8 (0)
14. ESP EIP
15.
16. 0012f030 00de0906 Store.Form1.btnHang_Click(System.Object,
System.EventArgs)
17. 0012f044 7b070a8b
System.Windows.Forms.Control.OnClick(System.EventArgs)
18. 0012f054 7b114cd9 System.Windows.Forms.Button.OnClick(System.EventArgs)
19. 0012f060 7b114ddf
System.Windows.Forms.Button.OnMouseUp(System.Windows.Forms.MouseEventAr
gs)
20. 0012f084 7b0dfeea
System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message
21. ByRef, System.Windows.Forms.MouseButtons, Int32)
22. 0012f0d0 7b082bbf
System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message
ByRef)
23. 0012f0d4 7b09149e [InlinedCallFrame: 0012f0d4]
24. 0012f170 7b0913bb
System.Windows.Forms.Button.WndProc(System.Windows.Forms.Message ByRef)
25. 0012f178 7b08a70d
System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Wi
26. ndows.Forms.Message ByRef)
27. 0012f17c 7b08a6e6
System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows
28. .Forms.Message ByRef)
29. 0012f190 7b08a535 System.Windows.Forms.NativeWindow.Callback(IntPtr,
Int32, IntPtr, IntPtr)
30. 0012f324 003420d4 [NDirectMethodFrameStandalone: 0012f324]
System.Windows.Forms.Unsafe
31. NativeMethods.DispatchMessageW(MSG ByRef)
32. 0012f334 7b094682
System.Windows.Forms.Application+ComponentManager.System.Windows.For
33. ms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32,
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Int32, Int32)
34. 0012f3d4 7b094249
System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(I
35. nt32, System.Windows.Forms.ApplicationContext)
36. 0012f440 7b094087
System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32,
37. System.Windows.Forms.ApplicationContext)
38. 0012f470 7b0d66ea
System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
39. 0012f480 00de00a8 Store.Program.Main()
40. 0012f69c 79e80b8b [GCFrame: 0012f69c]

Dr. Watson

Dr. Watson (drwtsn32.exe) also creates dumps. This product is installed with the operating system. On
nondeveloper machines, Dr. Watson is the only JIT debugger present. Dr. Watson attaches to a failing
application to create a log file and optionally a dump file.

Figure 13-8 shows the main window of Dr. Watson. In this window, you configure Dr. Watson for JIT
debugging.

Figure 13-8: Main window of Dr. Watson

The following list describes the configurable items in the Dr. Watson window:

 Log File Path The path for the log files created by the Dr. Watson.

 Crash Dump The path and name of the dump file.

 Wave File The path to whatever musical accompaniment you deem appropriate for an application
failure. Flight of the Valkyrie might be appropriate.

 Number of Instructions The number of instructions to disassemble around the instruction pointer.

 Number of Errors to Save The maximum number of errors to save in the log file.

 Crash Dump Type The type of dump request: full, mini, or NT-compatible.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 Dump Symbol Table Dump the name and address of every symbol into the log file.

 Dump All Thread Contexts Include the thread context, register values, and other context data in
the log file.

 Append To Existing Log File Add the next log entry from a program failure to the current log
file. If not selected, a new log file is created for each failure.

 Visual Notification Display a dialog box to notify of program failure and just-in time debugging.

 Sound Notification Play the Flight of the Valkyrie or whatever WAV file is specified.

 Create Crash Dump File When a program fails, create a dump file.

Dr. Watson Walkthrough Following is a walkthrough of Dr. Watson, which is the only walkthrough that
does not use the Store application. The walkthrough uses the Crash application. The Crash application fails
immediately after the application is launched.
1. Make sure that Dr. Watson is installed as the native debugger.
2.
3. C:\>drwtsn32 -i
4. Configure Dr. Watson to create a minidump file, set the dump file path and name, and then
request notification. Accept all other defaults.
5. Run the Crash program. This program should immediately hang, which will prompt notification
from Dr. Watson.
6. Confirm that the dump and log file are created. Inspect the log file, which includes general
information, system information, task list, module list, thread context, stack trace, symbol table,
and a variety of raw dumps:
7.
8. Microsoft (R) DrWtsn32
9. Copyright (C) 1985-2001 Microsoft Corp. All rights reserved.
10.
11. Application exception occurred:
12. App: C:\codew\Crash\Debug\Crash.exe (pid=4004)
13.
14. When: 9/5/2005 @ 08:19:29.796
15. Exception number: 80000007
16. ()
17.
18. *----> System Information <----*
19. Computer Name: DONISMLAPTOP
20. User Name: Donis
21. Terminal Session Id: 0
22. Number of Processors: 2
23. Processor Type: x86 Family 15 Model 2 Stepping 9
24. Windows Version: 5.1
25. Current Build: 2600
26. Service Pack: 2
27. Current Type: Multiprocessor Free
28. Registered Organization:
29. Registered Owner: Donis
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

30.
31. *----> Task List <----*
32. 0 System Process
33. 4 System
34. 788 smss.exe
35. 908 csrss.exe
36. 932 winlogon.exe
37. 976 services.exe
38. 988 lsass.exe
39. 1152 svchost.exe
40. 1220 svchost.exe
41.
42. *----> Module List <----*
43. (0000000000400000 - 000000000041a000: C:\codew\Crash\Debug\Crash.exe
44. (0000000010200000 -
45. 0000000010320000:
C:\WINDOWS\WinSxS\x86_Microsoft.VC80.DebugCRT_1fc8b3b9a1e18e3b_8.0.
46. 50727.7_x-ww_ec5d0b23\MSVCR80D.dll
47. (00000000629c0000 - 00000000629c9000: C:\WINDOWS\system32\LPK.DLL
48. (0000000074d90000 - 0000000074dfb000: C:\WINDOWS\system32\USP10.dll
49. (0000000076390000 - 00000000763ad000: C:\WINDOWS\system32\IMM32.DLL
50. (0000000077b40000 - 0000000077b62000: C:\WINDOWS\system32\Apphelp.dll
51. (0000000077c00000 - 0000000077c08000: C:\WINDOWS\system32\VERSION.dll
52. (0000000077c10000 - 0000000077c68000: C:\WINDOWS\system32\msvcrt.dll
53. (0000000077d40000 - 0000000077dd0000: C:\WINDOWS\system32\USER32.dll
54.
55. *----> State Dump for Thread Id 0xb5c <----*
56.
57. eax=00390000 ebx=0012f6fc ecx=00001000 edx=7c90eb94 esi=0000007c
edi=00000000
58. eip=7c90eb94 esp=0012f6e0 ebp=0012f9e8 iopl=0 nv up ei pl nz
na pe nc
59. cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000
efl=00000202
60.
61. *----> Stack Back Trace <----*
62. ChildEBP RetAddr Args to Child
63. 0012f9e8 102116d1 0012fa5c 00000002 00000000 ntdll!KiFastSystemCallRet
64. 0012fa0c 004119a2 c0000005 0012fa5c 1021c2b4 MSVCR80D!XcptFilter+0x61
65. 0012fa18 1021c2b4 00000000 00000000 00000000
Crash!__tmainCRTStartup+0x1f2
66. 0012ffb8 0041179d 0012fff0 7c816d4f 023dd680
MSVCR80D!seh_longjmp_unwind4+0x2e
67. 0012ffc0 7c816d4f 023dd680 7c90e1fe 7ffdd000 Crash!wmainCRTStartup+0xd
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Memory Management
Traditionally, memory-related issues have been the impetus to a vast majority of bugs. Win32 processes,
including managed applications that run in the Windows environment, own several assets. Of those assets,
virtual memory is one of the most important. Win32 processes normally own four gigabytes of virtual
memory, where the operating system resides in the upper two gigabytes. The upper two gigabytes are
shared and protected. There is no reason to load the operating system for each instance of a Win32
process. The lower two gigabytes are private memory in which the application code, heaps, static data area,
stack, and other aspects of the application are loaded. This memory is private and protected from access by
other processes. Virtual Memory Manager (VMM), which is the kernel-level component of the NT Executive,
guards private memory from incidental or deliberate external modifications.

The managed heap is created in the private memory of a managed application. There are several families of
APIs that allocate memory from the available virtual memory, including the Heap APIs such as HeapCreate,
HeapAlloc, and HeapFree. The Memory Mapped family of APIs include CreateFileMapping, MapViewOfFile,
UnmapViewOfFile, and related functions. The Virtual APIs include VirtualAlloc, VirtualFree, and others.
Internally, the Heap and Memory Mapped File APIs decompose to Virtual APIs.

Initially, the garbage collector (GC) calls VirtualAlloc with the MEM_RESERVE flag and reserves a block of
memory. It then requests memory from the reserved area with successive calls to VirtualAlloc, but with the
MEM_COMMIT flag. When committing memory, the first parameter of VirtualAlloc is the base address to a
block of committed memory. The GC keeps the ending address of the previous memory allocation. With that
information, it can calculate the base address of the next block of committed memory, which is stacked
upon the previous allocation. This is a quick and efficient method of allocating memory. VirtualAlloc can be
called with a null first parameter, which requires the VMM search for an appropriate location to commit
memory, which is expensive. This is the syntax of VirtualAlloc:
 LPVOID VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize,
 DWORD flAllocationType, DWORD flProtect)

The following is a stack trace and shows VirtualAlloc being called in a managed program. The first argument
(0x00b54000) is the location of the allocation. This is where the memory is being committed.

0:000> kb
ChildEBP RetAddr Args to Child
0012e674 79e74391 00b54000 00001000 00001000 KERNEL32!VirtualAlloc
0012e6b4 79e74360 00b54000 00001000 00001000 mscorwks!EEVirtualAlloc+0x104
0012e6c8 79e74348 7a38b1b0 00b54000 00001000
mscorwks!CExecutionEngine::ClrVirtualAlloc+0x15
0012e6e0 79e8b7a4 00b54000 00001000 00001000 mscorwks!ClrVirtualAlloc+0x1b
0012e718 79e9f940 000000a8 00000001 00010000
mscorwks!UnlockedLoaderHeap::GetMoreCommittedPa
ges+0x90

0012e750 79e7f89f 000000a4 00000004 0012e794


mscorwks!UnlockedLoaderHeap::UnlockedAllocAlign
edMem_NoThrow+0x6c
0012e764 79e7f853 000000a4 00000004 0012e794
mscorwks!UnlockedLoaderHeap::UnlockedAllocAlign
edMem+0x15
0012e7a4 79e85010 0012e7d0 000000a4 00000004
mscorwks!LoaderHeap::RealAllocAlignedMem+0x40
0012e7f0 79e84eca 7a389bec 00000094 00000000 mscorwks!Stub::NewStub+0xc1
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

0012e834 79e8733c 7a389bec 00000000 00000000 mscorwks!StubLinker::Link+0x59

Reference Tree

The GC does not perform reference counting. Some memory models maintain a reference count on each
memory object. When the count drops to zero, the object is immediately removed from memory. Overhead
attributed to reference counting, especially for objects that are never reclaimable, is considerable. There are
two benefits to the reference counting model. First, the cost of garbage collection is distributed across the
life of the application. Second, it is proactive. Memory is reclaimed prior to being needed.

In managed code, a reference tree is erected when garbage collection is initiated, which avoids expensive
reference counting. References no longer in the tree are assumed collectable and the memory for those
objects is reclaimed. Memory is then consolidated and outstanding references are updated. This phase of
memory management prevents fragmentation of the managed heap. The model described ignores finalization
for the moment. The tree is not cached between garbage collection cycles. Rebuilding the tree is one reason
why garbage collection is expensive. However, garbage collection is performed only when needed, which is a
considerable efficiency.

An object is rooted when another object holds a reference to it. Conversely, root objects are not referenced
by another object, including static, global, and local objects. C# does not support global objects. The root
objects are the base of the object tree. The branches of the tree emerge from the root objects, as shown in
Figure 13-8.

Memory Walkthrough
In this tutorial, the Store application is explored again. Three transactions are added and the root reference of
each transaction is displayed.
1. Start the Store application and add three transactions.
2. Attach to the Store application with WinDbg.
3. Transactions are instances of the Item class. Display information on the Item class using the
!name2ee command:
4.
5. 0:004> !name2ee store.exe Store.Item
6. Module: 00d40c14 (Store.exe)
7. Token: 0x02000002
8. MethodTable: 00d442dc
9. EEClass: 00db21c4
10. Name: Store.Item
11.
12. With the MethodTable address, you can list the address of each transaction item. This is
information is obtained with the dumpheap command:
13.
14. 0:004> !dumpheap -mt 00d442dc
15. Address MT Size
16. 013a03b8 00d442dc 20
17. 013b409c 00d442dc 20
18. 013bca10 00d442dc 20
19. total 3 objects
20. Statistics:
21. MT Count TotalSize Class Name
22. 00d442dc 3 60 Store.Item
23. Total 3 objects
24. Check the root of each object using the !gcroot command. This is a partial listing from the first
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Item object:
25.
26. 0:004> !gcroot 013a03b8
27. Note: Roots found on stacks may be false positives. Run "!help gcroot"
for
28. more info.
29. ebx:Root:01392b60(System.Windows.Forms.Application+ThreadContext)->
30. 01392214(Store.Form1)->
31. 01392454(System.Collections.Generic.List`1[[Store.Item, Store]])->
32. 013d5f2c(System.Object[])->
33. 013a03b8(Store.Item)
34. Scan Thread 0 OSTHread ee4
35. Scan Thread 2 OSTHread c48
36. DOMAIN(001483A8):HANDLE(WeakLn):9f1088:Root:013a074c(System.Windows.For
ms.NativeMethod
37. s+WndProc)->
38. 0139ec94(System.Windows.Forms.Control+ControlNativeWindow)->
39. 0139ebc4(System.Windows.Forms.CheckBox)->
40. 0139d6f8(Store.Transaction)->
41. 013a03b8(Store.Item)
42. Are you curious about composition of the Item object? The items objects are shown as 20 bytes.
What do those 20 bytes contain? Here is the source code for the Item class:
43.
44. public class Item: IDisposable
45. {
46. public Item()
47. {
48. ++nextPropId;
49. propItemId = nextPropId;
50. }
51.
52. public enum eProducts
53. {
54. Computer = 1,
55. Laptop = 2,
56. Printer = 4,
57. Software = 8
58. };
59.
60. private eProducts propProducts=0;
61.
62. public eProducts Products
63. {
64. get
65. {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

66. return propProducts;


67. }
68. set
69. {
70. propProducts = value;
71. }
72. }
73.
74. static private int nextPropId=0;
75. private int propItemId;
76. public int ItemId
77. {
78. get
79. {
80. return propItemId;
81. }
82. }
83.
84. public void Dispose()
85. {
86. --nextPropId;
87. }
88.
89. private float[] buffer = new float[100];
90. }

That was easy because the source code was available. What if the source code is not available? This is the
normal case on a production machine. The !dumpclass command dumps the class. It uses the EEClass
address, which is provided with !name2ee command. Actually, !dumpclass provides information that may be
more valuable than the source code. You also receive state information. In the following listing, we are told
that the static count is 3, which is the correct value at this moment.

0:004> !dumpclass 00db21c4


Class Name: Store.Item
mdToken: 02000002 (C:\store\Store.exe)
Parent Class: 790fa034
Module: 00d40c14
Method Table: 00d442dc
Vtable Slots: 5
Total Method Slots: 9
Class Attributes: 100001
NumInstanceFields: 3
NumStaticFields: 1
MT Field Offset Type VT Attr Value Name
00d44224 4000001 8 System.Int32 0 instance propProducts
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

790fe920 4000003 c System.Int32 0 instance propItemId


79129180 4000004 4 System.Single[] 0 instance buffer
790fe920 4000002 24 System.Int32 0 static 3 nextPropId

Generations

The managed heap is organized into three generations and a large object heap. Generations are numbered
0, 1, and 2. New objects are placed in a generation or large object heap. Younger and smaller objects are
found in the earlier generations, whereas older and larger objects are found in the later generations and the
large object heap. This is efficiency by proximity. Objects that are apt to message other objects are kept
close together in memory. This decreases page faults, which are costly, and the amount of physical memory
required at any time.

Garbage collection in .NET is often described as nondeterministic, which means that memory recovery
cannot be predicted. Garbage collection occurs when memory commits exceed the memory reserved for a
particular generation. Because only a portion of the managed heap is being collected, this is more efficient.
When an application starts, objects are allocated on Generation 0 first. Eventually, the memory available to
Generation 0 is exceeded, which triggers garbage collection. If enough memory is reclaimed during garbage
collection, the pending allocation is performed on Generation 0. If enough memory cannot be reclaimed,
Generation 0 objects are promoted to Generation 1. This continues until Generation 0 and 1 are replete with
objects. At that time, Generation 0 and 1 objects are promoted to Generation 1 and 2, respectively. By
design, the older and larger objects tend to migrate toward the higher generations, whereas younger and
smaller object are found in lower generations.

Memory on the managed heap is allocated top-down. The new objects are at the higher addresses.
Generation 0 is at a higher address than Generation 1. 256 kilobytes, 2 megabytes, and 10 megabytes are
reserved for Generation 0, 1, and 2, respectively. These thresholds may be adjusted. The GC changes these
thresholds based on the pattern of allocations in the managed application.

As the name implies, the large object heap hosts large objects. Objects greater than 85 kilobytes (KB) in
size are considered large objects. Instead of promoting these objects from one generation to another, which
is costly, large objects are immediately placed on the large object heap at allocation.

Generations Walkthrough
This time the Store application has an Add Transactions button and an Add Large Transactions button. The
Add Large Transactions button adds large transactions, which are instances of the LargeItem class. The
LargeItem class inherits from the Item class and adds additional fields, such as the largeStuff field. The
largeStuff field is greater than 85 KB and qualifies as a large object. The objective of this walkthrough is to
determine the generation of each Item, LargeItem and largeStuff instance.
1. Start the Store application. Add three regular transactions and four large transactions.
2. Launch WinDbg and attach to the Store application.
3. There should be three instances of the Item class in memory. Retrieve the method table address
of the Item class with the !name2ee command. Then dump the Items instances using the
!dumpheap -mt command:
4.
5. 0:004> !name2ee Store.exe Store.Item
6. Module: 00d40c14 (Store.exe)
7. Token: 0x02000005
8. MethodTable: 00d4431c
9. EEClass: 00db22f4
10. Name: Store.Item
11. 0:004> !dumpheap -mt 00d4431c
12. Address MT Size
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

13. 013a8bd0 00d4431c 20


14. 013aabb0 00d4431c 20
15. 013aadd8 00d4431c 20
16. 013adffc 00d4431c 20
17. 013b513c 00d4431c 20
18. 013c1a4c 00d4431c 20
19. total 6 objects
20. Statistics:
21. MT Count TotalSize Class Name
22. 00d4431c 6 120 Store.Item
23. Total 6 objects
24. Unexpectedly, there are six instances, not three. Has a bug been uncovered?! This issue will be
explored further later.
25. Use the !name2ee command to obtain the method table address of the LargeItem. Dump the
LargeItem objects. As expected, there are four objects:
26.
27. 0:004> !dumpheap -mt 00d460a8
28. Address MT Size
29. 013ab03c 00d460a8 5016
30. 013ae5a4 00d460a8 5016
31. 013be020 00d460a8 5016
32. 013ca900 00d460a8 5016
33. total 4 objects
34. Statistics:
35. MT Count TotalSize Class Name
36. 00d460a8 4 20064 Store.LargeItem
37. Total 4 objects
38. There should be four largeStuff fields—one for each LargeItem object. The easiest way to locate
them by using is the !dumpheap -stat command. The objects are sorted by size, with the larger
objects at the bottom of the list:
39.
40. 0:004> !dumpheap -stat
41. total 16356 objects
42. Statistics:
43. MT Count TotalSize Class Name
44. 7b481adc 1 12 System.Windows.Forms.OSFeature
45. 7b47fd04 1 12 System.Windows.Forms.FormCollection
46. 7b47efec 1 12 System.Windows.Forms.Layout.DefaultLayout
47. 7ae86e80 134 5896 System.Drawing.BufferedGraphics
48. 790f8230 374 5984 System.WeakReference
49.
50. 79124ec4 41 8136 System.Collections.Hashtable+bucket[]
51. 790fd688 341 8184 System.Version
52. 79116738 250 9000
System.Collections.Hashtable+HashtableEnumerator
53. 79124d8c 5 10596 System.Byte[]
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

54. 79110f78 523 12552 System.Collections.Stack


55. 7ae868e8 1049 12588 System.Drawing.KnownColor
56. 00d460a8 4 20064 Store.LargeItem
57. 7b47e850 522 33408 System.Windows.Forms.Internal.DeviceContext
58. 7910acbc 2104 42080 System.SafeGCHandle
59. 79124ba8 642 57496 System.Object[]
60. 00152760 14 77744 Free
61. 790fa860 7067 407316 System.String
62. 00e80838 4 16000128 System.Single[,]
63. The last item in the report is a two-dimensional array of Single types. This is the largeStuff field.
There are four instances shown. The first column of the command is the method table address.
Dump the largeStuff instances using the !dumpheap -mt command:
64.
65. 0:004> !dumpheap -mt 00e80838
66. Address MT Size
67. 02396da8 00e80838 4000032
68. 027676c8 00e80838 4000032
69. 02b37fe8 00e80838 4000032
70. 02f08918 00e80838 4000032
71. total 4 objects
72. Statistics:
73. MT Count TotalSize Class Name
74. 00e80838 4 16000128 System.Single[,]
75. Total 4 objects
76. Finally, list the memory range for Generations 0, 1, and 2 and the large object heap. This is
accomplished with the !eeheap -gc command:
77.
78. 0:004> !eeheap -gc
79. Number of GC Heaps: 1
80. generation 0 starts at 0x013d2488
81. generation 1 starts at 0x013af93c
82. generation 2 starts at 0x01391000
83. ephemeral segment allocation context: none
84. segment begin allocated size
85. 0016bf58 7a74179c 7a76248c 0x00020cf0(134384)
86. 001687e0 7b45baa0 7b471f0c 0x0001646c(91244)
87. 00154b20 790d6314 790f575c 0x0001f448(128072)
88. 01390000 01391000 013ff3ac 0x0006e3ac(451500)
89. Large object heap starts at 0x02391000
90. segment begin allocated size
91. 02390000 02391000 032d9248 0x00f48248(16024136)
92. Total Size 0x100cb98(16829336)
93. ------------------------------
94. GC Heap Size 0x100cb98(16829336)

Based on the addresses of the Item, LargeItem, and largeStuff instances, Table 13-8 maps each object to
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

the managed heap. None of the instances resides in Generation 0.


Table 13-8:
Item,
LargeItem,
and
largeStuff
Instances

Ite Ad
m dr
ess

No N/
obj A
ect
s

Ge 0x
ne 01
rat 3d
ion 24
0 88
St
art
s

Lar 0x0
geI 13
te ca
m4 90
0

Ite 0x0
m6 13
c1
a4
c

Lar 0x0
geI 13
te be
m3 02
0

Ite 0x0
m5 13
b5
13
c

Ge 0x
ne 01
rat 3af
ion 93
1 c
St
art
s
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-8:
Item,
LargeItem,
and
largeStuff
Instances

Ite Ad
m dr
ess

Lar 0x0
geI 13
te ae
m2 5a
4

Lar 0x0
geI 13
te ab
m1 03
c

Lar 01
geI 3a
te e5
m2 a4

Ite 0x0
m3 13
aa
dd
8

Ite 0x0
m2 13
aa
bb
0

Ite 0x0
m1 13
a8
bd
0

Ge 0x
ne 01
rat 39
ion 10
2 00
St
art
s

lar 02f
ge 08
Stu 91
ff 4 8
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-8:
Item,
LargeItem,
and
largeStuff
Instances

Ite Ad
m dr
ess

lar 02
ge b3
Stu 7fe
ff 3 8

lar 02
ge 76
Stu 76
ff 2 c8

lar 02
ge 39
Stu 6d
ff 1 a8

lar 02
ge 76
Stu 76
ff 2 c8

La 0x
rg 02
e 39
obj 10
ect 00
he
ap

It is time to diagnose the earlier bug. Actually, there is no bug. The issue is nondeterministic collection. In
the Store application, each transactions is initially an Item object. A LargeItem object is then initialized with
the Item transaction. At that point, the Item object is no longer required, but the memory is not reclaimed.
Therefore, there is a shadow item in memory for every LargeItem, which is the reason for the extra Item
instances. At the next garbage collection, those items will be removed from memory. For demonstration
purposes, there is a version of the Store application that forces garbage collection. It has a Collect Memory
button that calls GC.Collect and removes the extra Item instances. When using this Store application, dump
the Item instances before and after clicking the Collect Memory button to confirm that GC.Collect is
reclaiming the extra objects. In general, calling GC.Collect is not recommended because it is an expensive
operation.

Finalization

The finalization process has been ignored until now. It plays a vital role in garbage collection. Finalization
also affects the performance and effectiveness of garbage collection. In C#, finalization is linked to class
destructors. For C++ programmers, .NET presents an entirely different methodology for destructors.

Object.Finalize is the universal destructor in .NET. In C#, Finalize calls the class destructor. Destructors are
called deterministically in C++. However, CLR calls destructors nondeterministically during garbage
collection. Do not invoke destructors directly. Destructors are called as part of the garbage-collection
process and are not called in a guaranteed sequence. In addition, you should clean up for only unmanaged
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

resources in the destructor. For deterministic garbage collection, implement the IDisposable interface.

Destructors add processing overhead to an object. The overhead is incurred even before object is collected.
The GC adds references for objects with destructors to the Finalization queue when the object is created.
Thus, the extra overhead starts at the beginning of the object's lifetime.

Objects that have destructors but no outstanding references require at least two garbage collections to be
reclaimed. During the first garbage-collection cycle, references to reclaimable objects are transferred from
the Finalization queue to the FReachable queue, which is serviced by a dedicated thread. These objects are
added to the list of objects already waiting on the FReachable queue to have their destructors called. The
Finalization thread is responsible for invoking destructors on objects and then removing that object from the
FReachable queue. When that happens, the object can be reclaimed and removed from memory during the
next garbage collection.

The !finalizequeue command reports on objects waiting to have their destructors called. These are the
objects on the FReachable queue.

Performance Monitor

The Performance Monitor has several counters that are helpful when debugging managed applications. Table
13-9 itemizes some of the more useful memory-related counters.
Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

#G Th
C e
Ha nu
ndl mb
es er
of
GC
ha
ndl
es
to
ext
ern
al
res
our
ce
s,
su
ch
as
win
do
ws
an
d
file
s.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

# Tot
Byt al
es nu
in mb
All er
He byt
ap es
s allo
cat
ed
for
Ge
ner
ati
on
0,
1,
2,
an
d
the
lar
ge
obj
ect
he
ap.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

# Th
Ind e
uc pe
ed ak
GC nu
mb
er
of
tim
es
gar
ba
ge
coll
ect
ion
wa
s
ind
uc
ed
be
ca
us
e
of
GC
.Co
llec
t.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

# Th
of e
Pin nu
ne mb
d er
Obj of
ect pin
s ne
d
obj
ect
s
dis
cov
ere
d
dur
ing
the
las
t
gar
ba
ge
coll
ect
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

# A
of co
Sin unt
ks of
Blo sy
ck nc
s blo
in ck
Us ent
e rie
s.
(Th
e
sy
nc
blo
ck
is
dis
cu
ss
ed
in
the
se
cti
on
on
de
bu
ggi
ng
thr
ea
ds.
)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

#G Th
en e
0 nu
Col mb
lec er
tio of
ns tim
es
tha
t
Ge
ner
ati
on
0
ha
s
be
en
gar
ba
ge
coll
ect
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

#G Th
en e
1 nu
Col mb
lec er
tio of
ns tim
es
tha
t
Ge
ner
ati
on
1
ha
s
be
en
gar
ba
ge
coll
ect
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

#G Th
en e
2 nu
Col mb
lec er
tio of
ns tim
es
tha
t
Ge
ner
ati
on
2
ha
s
be
en
gar
ba
ge
coll
ect
ed.

# Th
Tot e
al tot
Co al
m nu
mit mb
ted er
Byt of
es virt
ual
me
mo
ry
co
m
mit
ted
by
the
GC
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

# Th
Tot e
al tot
Re al
ser nu
ve mb
Byt er
es of
virt
ual
me
mo
ry
res
erv
ed
by
the
GC
.

Ge Ma
n xi
0 mu
He m
ap nu
Siz mb
e er
of
allo
cat
ed
byt
es
for
Ge
ner
ati
on
0.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

Ge Ma
n xi
1 mu
He m
ap nu
Siz mb
e er
of
allo
cat
ed
byt
es
for
Ge
ner
ati
on
1.

Ge Ma
n xi
2 mu
He m
ap nu
Siz mb
e er
of
allo
cat
ed
byt
es
for
Ge
ner
ati
on
2.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

Lar Nu
ge mb
Obj er
ect of
He byt
ap es
Siz cur
e ren
tly
allo
cat
ed
for
the
lar
ge
obj
ect
he
ap.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

%T Th
im e
e per
in ce
GC nta
ge
of
tim
e
sp
ent
in
gar
ba
ge
coll
ect
ion
,
whi
ch
is
up
dat
ed
at
ea
ch
gar
ba
ge
coll
ect
ion
cy
cle
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

All Th
oc e
ate nu
d mb
Byt er
es/ of
Se byt
c es
allo
cat
ed
per
se
co
nd,
whi
ch
is
up
dat
ed
at
ea
ch
gar
ba
ge
coll
ect
ion
cy
cle
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

Fin Th
aliz e
ati nu
on mb
Sur er
vivo of
rs obj
ect
tha
t
sur
vive
d
gar
ba
ge
coll
ect
ion
an
d
wai
tin
g
for
de
str
uct
ors
to
be
call
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

Ge Th
n e
0 ma
He xi
ap mu
Siz m
e nu
mb
er
byt
es
allo
cat
ed
for
Ge
ner
ati
on
0.

Ge Th
n e
0 nu
Pro mb
mo er
ted of
Byt byt
es/ es
Se per
c se
co
nd
pro
mo
ted
fro
m
Ge
ner
ati
on
0
to
1.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

Ge Th
n e
1 cur
He ren
ap t
Siz nu
e mb
er
of
byt
es
in
Ge
ner
ati
on
1.

Ge Th
n e
1 nu
Pro mb
mo er
ted of
Byt byt
es/ es
Se per
c se
co
nd
pro
mo
ted
fro
m
Ge
ner
ati
on
1
to
2.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

Ge Th
n e
2 cur
He ren
ap t
Siz nu
e mb
er
of
byt
es
in
Ge
ner
ati
on
2.

Pro Th
mo e
ted nu
Fin mb
aliz er
ati of
on- byt
Me es
mo pro
ry mo
fro ted
m to
Ge Ge
n0 ner
ati
on
1
be
ca
us
e
of
pe
ndi
ng
fina
lize
rs.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

Pro Th
mo e
ted nu
Fin mb
aliz er
ati of
on- byt
Me es
mo pro
ry mo
fro ted
m to
Ge Ge
n1 ner
ati
on
2
be
ca
us
e
of
pe
ndi
ng
fina
lize
rs.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

Pro Tot
mo al
ted byt
Me es
mo for
ry obj
fro ect
m s
Ge tha
n0 t
wer
e
pro
mo
ted
to
Ge
ner
ati
on
1.
Thi
s
do
es
not
incl
ud
e
the
obj
ect
s
wai
tin
g
on
pe
ndi
ng
fina
lize
rs.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 13-9:
Performance
Monitor
Counters

Na De
me scr
ipti
on

Pro Tot
mo al
ted byt
Me es
mo for
ry obj
fro ect
m s
Ge tha
n1 t
wer
e
pro
mo
ted
to
Ge
ner
ati
on
2.
Thi
s
do
es
not
incl
ud
e
the
obj
ect
s
wai
tin
g
on
pe
ndi
ng
fina
lize
rs.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Threads
Multithread applications have multiple threads. Each thread represents a path of execution and owns
resources, such as stack, thread local storage, local variables, and thread environment block. Proper use of
threads can enhance the performance of an application, whereas poor implementation can hinder
performance.

Creating threads is not difficult. Managing threads is the real challenge. Thread synchronization, which is the
management of threads, entails several activities, including preventing race conditions and controlling access
to resources. Threads are like children that require corralling.

Improperly implemented threads can lead to a high utilization or low utilization condition. High utilization is
characterized by one or more threads consuming at or near 100-percent CPU utilization. Other threads are
starved for time, which makes the application appear to hang or behave incorrectly. Low utilization is the
reverse. The process and contained threads are receiving minimal or no CPU usage.

There are two primary reasons for high utilization:


 Threads in tight loop that usurp all CPU resources
 Active high-priority threads that prevent lower-priority threads from receiving attention from the CPU

There is an assortment of reasons for low utilization:


 Threads waiting for resources that never become available. Threads in that state are suspended
indefinitely and receive little CPU time.
 Threads mutually blocked on each other. This deadlock suspends both threads indefinitely, and
both receive little CPU time.
 A low-priority thread in a sea of high priority threads has little opportunity to sail. It is accorded
minimal CPU time.
 Threads with an erroneously high suspend counts are not resumed when planned. For this
reason, the thread continues to receive no CPU time.

The previous items highlight some of the reasons for high and low utilization. There are plenty more.
However, high and low utilization are not the only issues. Multithreaded and simultaneous access to
non-thread-safe resources is another cause for application failures. Actually, the list of potential
transgressions from multithreading is almost endless. Threading is fertile ground for debugging.

For brevity, this section focuses on monitors and mutexes. Synchronization problems from semaphores,
events, and reader-writer locks are not discussed. Monitors synchronize access to a single resource. The
resource could be an object, data structure, or even an algorithm—anything that requires singular access.
Monitors are limited to synchronizing threads within the same process. A mutex also synchronizes access
to a single resource. However, mutexes have additional power and flexibility. For example, mutexes can
synchronize threads across processes.

Monitors are the most frequently used synchronization device. For that reason, the CLR tracks monitors for
efficient access. Instances of objects have an additional field called the syncblock index, which is an index
into the syncblock table where monitors are tracked. The syncblock index of an object defaults to zero.
When an object is assigned to a monitor, the syncblock index is updated to point to an entry in the
syncblock table. Otherwise, the syncblock index remains 0. In .NET 2.0, a syncblock entry is not created for
every object associated with a monitor. If the monitor is not already associated with a syncblock, a thinlock
is created instead. The command !syncblk -all lists the outstanding syncblocks, !dumpheap -thinlock
reports the thinlocks.

Markers for thread synchronization can be found on the call stack. Finding AwareLock.Enter,
WaitHandle.WaitAll, and WaitForMultipleObjects in the call stack are indications of thread synchronization
activity.
 AwareLock.Enter This method is called when an object is bound to a monitor. If the following
breakpoint is hit, that thread is entering a monitor:

 bp mscorwks!AwareLock::Enter
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 WaitHandle.WaitAll Except for monitors, most synchronization objects in .NET are derived from
the WaitHandle class. Look for method calls from this class on the managed call stack, including
WaitOne and WaitAll, as a sign of pending synchronization.
 WaitForMultipleObjects Most waits on synchronization objects, managed or unmanaged,
dissolve in a WaitForMultipleObjects API, which is the workhorse of thread synchronization. This
is the syntax of the WaitForMultipleObjects API:
o DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE*
o lphandles, BOOL bWaitAll, DWORD dwMilliseconds)

Threads Commands

The first step for debugging threads in WinDbg and SOS is to use the thread commands. In WinDbg, the
tilde (~) is the thread command; in SOS, the command is !threads.

This is sample output from the WinDbg thread command:

0:000> ~
. 0 Id: f7c.f80 Suspend: 1 Teb: 7ffdd000 Unfrozen
1 Id: f7c.f9c Suspend: 1 Teb: 7ffdc000 Unfrozen
2 Id: f7c.fa0 Suspend: 1 Teb: 7ffdb000 Unfrozen
3 Id: f7c.fa4 Suspend: 1 Teb: 7ffda000 Unfrozen
4 Id: f7c.de0 Suspend: 1 Teb: 7ffd9000 Unfrozen

Listed in order, the columns are thread number, process identifier, thread identifier, suspend count, address
of thread environment block, and status of the thread.

Here is output from the SOS threads command:

0:000> !threads
ThreadCount: 4
UnstartedThread: 1
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count
APT Exception
0 1 f80 001501f8 6020 Disabled 013c2cf0:013c32bc 001483a8 0 STA
2 2 fa0 00153e40 b220 Enabled 00000000:00000000 001483a8 0 MTA
(Finalizer)
4 3 de0 0018b898 b020 Disabled 013b4cdc:013b52bc 001483a8 2 MTA
XXXX 4 0 0018e750 9400 Enabled 00000000:00000000 001483a8 0 Ukn

The information on managed threads includes the following:

 ID Unmanaged thread number

 OSID Managed thread number

 ThreadObject Address of related thread object


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 State State of the thread

 Preemptive GC Whether a thread can be preempted for garbage collection

 AppDomain Address of the AppDomain that hosts the thread

 Lock Count Lock count

 APT Apartment model

Threads Walkthrough
Multithread capabilities have been added to the Store application. Two buttons have been added. The
Enumerate button writes the transactions to the forward.txt file. The Reverse Enumerate button writes the
transactions, in reverse order, to the reverse.txt file. Each button handler creates and starts a thread to
accomplish the reporting tasks.
1. Close all instances of the Store application.
2. Start the Store program and add three transactions. Click the Enumerate button to write the
transactions to the forward.txt file. Close the Store program and open the forward.txt file, which is
found to be empty. It should contain three transactions!
3. Try again. Reopen the Store application and add three transactions. However, upon clicking the
Enumerate button an unhandled exception occurs. What is the problem? You need to investigate.
4. Start the Store application yet again. Retrieve the process identifier using the tlist command.
However, notice that there are two Store applications running. Apparently a previous version is still
running in the background. This kind of problem is typical of a hung thread, which keeps an
application alive after the user closes the main window.
5. Use ADPlus to obtain a dump of the earlier Store application. This is the command:
6.
7. adplus -hang -o c:\dumps -p 2696
8. Open the resulting dump file in WinDbg.
9. Load the SOS debugger extension and list out the managed threads. For readability, some of the
columns have been removed from this listing:
10.
11. 0:000> .load sos
12. 0:000> !threads
13. ThreadCount: 3
14. UnstartedThread: 0
15. BackgroundThread: 2
16. PendingThread: 0
17. DeadThread: 0
18. Hosted Runtime: no
19.
20. PreEmptive GC Alloc
Lock
21. ID OSID ThreadOBJ State GC Context
Domain Count
22. 0 1 a90 001501f8 2016220 Enabled 013dbe2c:013dc990
001483a8 0
23. 2 2 9c8 00153e40 b220 Enabled 00000000:00000000
001483a8 0
24. 4 3 3e0 00190718 b020 Disabled 013d63b0:013d6990
001483a8 2

Thread 4 seems to be the culprit. It is the only thread with a positive lock count. What is the thread waiting
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

for? This question is answered with the !dumpheap -thinlock command:

0:000> !dumpheap -thinlock


Address MT Size
01392440 00d443e8 24 ThinLock owner 3 (00199a78) Recursive 0
01392468 790fa098 12 ThinLock owner 3 (00199a78) Recursive 0

From the preceding listing, both thinlocks are owned by Thread 4. The address of the Thread 4 object is
0x00199a78, which could be nested locks. Dump the method tables of the thinlocks to uncover what Thread
4 is waiting for:

0:000> !dumpmt 00d443e8


EEClass: 79126bb0
Module: 790c2000
Name: System.Collections.Generic.List`1[[Store.Item, Store]]
mdToken: 02000287
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
BaseSize: 0x18
ComponentSize: 0x0
Number of IFaces in IFaceMap: 6
Slots in VTable: 30
0:000> !dumpmt 790fa098
EEClass: 790fa034
Module: 790c2000
Name: System.Object
mdToken: 02000002
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 14

What is known? When the program hung, Thread 4 had outstanding locks on an Item and Object instance.
No other thread is holding a lock, which narrows the problem to Thread 4. Here is the source code for Thread
4:

private void Forward()


{
lock (items)
{
lock (syncObj)
{
StreamWriter sw = new StreamWriter("forward.txt");
IEnumerator<Item> enumerator = items.GetEnumerator();
while (true)
{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

while (true)

{
if (enumerator.MoveNext())
{
Item current = enumerator.Current;
string message = current.ItemId + " Product Mask: "
+ ((int)current.Products).ToString();
sw.WriteLine(message);
}
else
{
break;
}
}
sw.Close();
}
}
}

Review the code—I hope that the problem is obvious. The lock statement is a shortcut to calling the
Monitor.Enter method. After acquiring the locks, the program enters an infinite loop, which was shown
previously. Because execution never continues past the loop where the locks are released, the locks are still
being held. Remove the extraneous while(true) loop and retry the program. Before recompiling the
application, you have to kill the hung process. The forward.txt file should be created and contain transactions.

Threads Walkthrough 2
The Store application appears to be working, but not in all circumstances. Delete the forward.txt and
reverse.txt files. End any current sessions of the Store application. Start a new session of the Store
application and add a couple of transactions.
1. Click the Reverse Enumerate button followed by the Enumerate button. Close the application and
check for the forward.txt and reverse.txt files. Neither file is created. Why not?
2. Restart the Store application. Add two new transactions. Click the Reverse Enumerate button
followed by the Enumerate button.
3. Start WinDbg and attach to the Store application.
4. List the available threads with the !threads command. Threads 4 and 5 have a positive lock count.
Both threads are waiting for something:
5.
6. 0:006> !threads
7. ThreadCount: 4
8. UnstartedThread: 0
9. BackgroundThread: 1
10. PendingThread: 0
11. DeadThread: 0
12. Hosted Runtime: no
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

13. PreEmptive GC Alloc


Lock
14. ID OSID ThreadOBJ State GC Context Domain
Count
15. 0 1 e54 001501f8 6020 Enabled 013e7afc:013e7b68 001483a8
0
16. 2 2 d84 00153e40 b220 Enabled 00000000:00000000 001483a8
0
17. 4 3 2e0 00191f60 200b020 Enabled 013d9bec:013dbb68 001483a8
1
18. 5 4 ccc 00190b98 200b020 Enabled 013dfb9c:013e1b68 001483a8
1
19.

The !syncblk command reports the syncblock entries. Thread 5 is using an Item instance as a
monitor. Thread 4 is using an Object instance as a monitor. This confirms Threads 4 and 5 as the
potential source of the problem. The other threads are not using monitors:

0:006> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner
2 00174854 3 1 00190b98 ccc 5 01392440
System.Collections.Generic.List`1[[Store.Item, Store]]
21 001747f4 3 1 00191f60 2e0 4 01392468
System.Object
-----------------------------
Total 44
CCW 0
RCW 0
ComClassFactory 0
Free 0
20. Perform a stack trace on Threads 4 and 5. Notice the inclusion of the AwareLock::Enter method,
which is a marker of thread synchronization. Also note that the top of the call stack is populated
with WaitForMultipleObjects methods, which means the thread is currently blocked on something:
21.
22. 0:004> kb
23. ChildEBP RetAddr Args to Child
24. 0358f4a0 7c90e9ab 7c8094f2 00000001 0358f4cc ntdll!KiFastSystemCallRet
25. 0358f4a4 7c8094f2 00000001 0358f4cc 00000001
ntdll!ZwWaitForMultipleObjects+0xc
26. 0358f540 79f4aa60 00000001 00174868 00000000
KERNEL32!WaitForMultipleObjectsEx+0x12c
27. 0358f5a8 79f16d92 00000001 00174868 00000000
mscorwks!WaitForMultipleObjectsEx_SO_TOLE
28. RANT+0x6f
29. 0358f5c8 79f16d03 00000001 00174868 00000000
mscorwks!Thread::DoAppropriateAptStateWai
30. t+0x3c
31. 0358f64c 79f16b9e 00000001 00174868 00000000
mscorwks!Thread::DoAppropriateWaitWorker+
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

32. 0x144
33. 0358f69c 79f4a9d9 00000001 00174868 00000000
mscorwks!Thread::DoAppropriateWait+0x40
34. 0358f6f8 79ebc06e ffffffff 00000001 00000000
mscorwks!CLREvent::WaitEx+0xf7
35. 0358f708 7a0fd093 ffffffff 00000001 00000000
mscorwks!CLREvent::Wait+0x17
36. 0358f794 7a0fd28f 00191f60 ffffffff 00191f60
mscorwks!AwareLock::EnterEpilog+0x94
37. 0358f7b0 79f0fe6a 8a20e59b 0358f888 01392214
mscorwks!AwareLock::Enter+0x61
38. Look at the parameters for WaitForMultiple objects. Thread 4 is waiting for a single
synchronization object, which is the first parameter. The second parameter is an address, which
is a pointer to an array of handles. Dump that parameter to find the handle to the synchronization
object:
39.
40. 0:004> dd 00174868
41. 00174868 00000658 0000000d 00000000 00000000
42. 00174878 00000000 00000000 00000000 00000000
43. 00174888 00000000 00000000 00000000 80000023
44. The handle to the synchronization object is 0x00000658. Use the !handle command to obtain
more information on that handle. It is an event handle:
45.
46. 0:004> !handle 00000658
47. Handle 658
48. Type Event
49.
50. Repeat steps 1 through 7 for Thread 5. The result should be similar.

The problem has been isolated to Threads 4 and 5. Threads 4 and 5 are started in the Forward and
Reverse handlers. Here is the source code for these methods. Both methods have nested locks.
However, the locks in the Forward and Reverse methods are in reverse order, which is causing a
deadlock.

private void Forward()


{
lock (items)
{
lock (syncObj)
{
StreamWriter sw = new StreamWriter("forward.txt");
IEnumerator<Item> enumerator = items.GetEnumerator();

while (true)
{
// other code
}
sw.Close();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}
}

Object syncObj= new Object();

private void Reverse()


{
lock (syncObj)
{
Thread.Sleep(5000);
lock (items)
{
StreamWriter sw = new StreamWriter("reverse.txt");
items.Reverse();
IEnumerator<Item> enumerator = items.GetEnumerator();
while (true)
{
// other code
}
items.Reverse();
sw.Close();
}
}
51. Reverse the order of the locks in either method, which resolves the problem. Restart the Store
application and test.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Exceptions
Have you ever been presented with a memory exception? See Figure 13-9. Of course, I am sure this
exception occurred while you were using an application that someone else wrote. As a kind gesture, you
volunteered to help diagnose the problem and make an unstable application robust.

Figure 13-9: Typical dialog box that reports an exception

Managed exceptions start life as native exceptions. To raise an exception, the CLR calls
mscorwks!RaiseTheException. RaiseTheException then calls RaiseException, which is a system-level API.
RaiseException assigns all managed exceptions the E0434F4D exception code. Because all managed
exceptions are raised with this same exception code, it is difficult to distinguish between managed
exceptions. Fortunately, the first parameter of the RaiseTheException function call is the managed exception
object. You can dump that object to ascertain the specific exception objection.

Exception Walkthrough
The Exception application is modified to raise an exception when the Add Transactions button is clicked.
The object of this walkthrough is to determine the type of exception.
1. Start the Store application. Open WinDbg and attach to that program.
2. Set a breakpoint on the RaiseException API and resume the application:
3.
4. 0:004> bp Kernel32!RaiseException; g
5. Click the Add Transaction button. The exception is raised and the breakpoint is hit in WinDbg.
Display the call stack.
6. Use the !dumpobj command to dump the first parameter of RaiseTheException, which is the
managed exception object. You now have the details of the exception, including the exception
type.

There are two other ways to trap managed exceptions.


 sxe clr This command breaks on all unhandled managed exceptions. You can then perform a
back trace for the details of the exception, which exist on the call stack. This is an alternative to
breaking on RaiseTheException API.
 !soe exceptiontype This is the Stop On Exception command and an SOS command. A
breakpoint is set on the type of exception specified. Before issuing the command, switch to the
thread on which the exception is expected.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Symbols
Until now, it is has been assumed that debug symbol files have aligned perfectly. Admittedly, that is a major
assumption. However, the advent of symbol stores and servers makes me optimistic that your symbols are
aligning without the obligatory drama. Having the correct debug symbols files for the environment and
application make the debugging experience infinitely easier. With symbol files, function names, parameter
names, local variables, source code line, and data to resolve, frame pointer omissions (FPOs) are available.
Without symbol files, little of this valuable information is available, which makes your debugging quest much
more difficult.

Debug symbol files are versioned. Different versions of debug symbol files are available for separate Windows
environments. Windows 98, Windows 2000, Windows XP, and other Windows operating environments do not
have identical symbols. Service packs may also have different symbols. Because of the large assortment of
symbol combinations, obtaining the correct symbols for an environment becomes a trial-and-error process—
which is further complicated when performing postmortem analysis. The dump may have originated on
another machine that has a different operating system, which requires having the symbols for the
environment on the source machine available on your machine. Things are getting complicated very quickly.
A more direct approach is needed, and the solutions are symbol servers and symbol stores.

Symbol servers orchestrate the downloading of required symbols from a symbol store. The symbol server
assumes the responsibility of finding the correct symbols; a symbol store is a repository of related debug
symbol files. Symbol servers consult with the symbol store to download the correct versions of the debug
symbol files. Microsoft publishes a public symbol store for developers, which can be accessed here:
 http://msdl.microsoft.com/download/symbols

You can download symbols directly instead of using symbol servers. However, the approaches are not
mutually exclusive. Symbol packages for different Windows environments are downloadable from this
location:
 http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx

Symsrv Symbol Server

Symsrv.dll is the symbol server distributed with Debugging Tools for Windows, and it must be installed in the
same directory as the debugger. Symsrv contacts the listed symbol stores and downloads debug symbol
files into a downstream directory. Files can be transferred over http and https.

This is the generic syntax to download debug symbol files with a symbol server:
 Symsrv*ServerDLL*DownstreamStore*SymbolStore

The following command leverages the symsrv.dll symbol server. The symbol server is instructed to contact
the Microsoft Public Symbol Store to download missing or correct versions of symbol files. The symbols are
transferred to c:\ symbols, which is the downstream store:
 Symsrv*Symsrv*c:\symbols*http://msdl.microsoft.com/download/symbols

Because symsrv.dll is the most prevalent symbol server, an abbreviated syntax is available that is specific
for that server:
 srv*DownstreamStore*SymbolStore

The following command uses the abbreviated syntax and is identical to the previous expanded command that
used the symsrv.dll symbol server:
 srv*c:\symbols*http://msdl.microsoft.com/download/symbols

As shown in the following syntax, symbol servers can have multiple downstream servers. If the symbol file is
not in DownstreamStore 1, it is downloaded from DownstreamStore 2. Furthermore, if the file is not in
DownstreamStore 2, DownstreamStore 3 is contacted. If the file is found there, it is downloaded from
DownstreamStore 3 into DownstreamStore 2 and then DownstreamStore 2 into DownstreamStore 1. This pattern
continues until the debug symbol is found or the symbol stores are exhausted.

srv*DownstreamStore 1*DownstreamStore 2* DownstreamStore n*SymbolStore


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

WinDbg and Visual Studio .NET read the _NT_SYMBOL_PATH environment variable for the default path for
the symbol server. Use the System tool in Control Panel to create or modify the _NT_SYMBOL_PATH
environment variable.

Application Symbols

The Microsoft Public Symbol Store downloads the symbols for the environment. You also need the symbols
for your application. Symbol files are not always distributed with release versions of a product, so a
production server might not have the required symbol files. It is imperative that the debug symbol files for the
release product be maintained somewhere, such as a private symbol store, for debugging if needed.

Visual Studio .NET creates a symbol file (PDB) for both debug and release versions of the product. It is
important to retain the symbol files for each version of the debug and release product. Because clients may
have older versions of your product, the debug symbol files for those versions must also be retained and
available.

WinDbg
In WinDbg, the symbol path can be set via the user interface or the command line. From the user interface,
select the Symbol File Path menu item from the File menu. From the command line, the .sympath directive
can display or set the symbol path. When the symbol path is changed, the .reload directive resynchronizes
and potentially downloads additional symbol files.

The !sym noisy command helps diagnose errors in loading debug symbol files. This command displays
detailed information on each symbol that should be downloaded, which is helpful for resolving symbol
problems. The !sym quiet command, which is the default, suppresses the extra binding data.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Memory Management
Memory management was introduced in this chapter. Concepts such as root objects, reference trees,
generations, and finalization queues were reviewed. The next chapter expands the conversation to include
the disposable pattern, weak references, unsafe pointers, and other topics related to memory management.

Understanding the managed paradigm to memory management is particularly important to C- and Cbased
programmers. C programmers are accustomed to managing their own memory with minimal assistance from
the environment. For them, memory management in .NET represents a different mindset, which includes
adopting new best practices for allocating, managing, and releasing memory. Some C developers perceive
the managed memory model as confining, when actually it is liberating.

Although the CLR provides memory management, developers have some sway in the process, which
includes pinned pointer, memory stress, forcing garbage collection, and allocation patterns. These topics are
introduced in the next chapter.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Part V: Advanced Concepts


Chapter List

Chapter 14: Memory Management

Chapter 15: Unsafe Code


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 14: Memory Management


Overview
Memory management is an essential aspect of every program except the most trivial of applications. There
are different classifications of memory. Registers, static data area (SDA), stack, thread local storage, heap,
virtual, and file storage are some of the categories of memory. Registers hold data that require quick and
efficient memory access. Critical system information, such as the instruction and stack pointer, are stored in
registers. Static and global values are automatically stored in the SDA. Stacks are thread-specific and hold
the context information (stack frames) of current functions. Local variables, parameters, return values, the
instruction pointer of the calling function, and other function-related information is placed on the stack.
Thread local storage (TLS) is also thread-specific storage. The TLS table is 64 slots of 32-bit values that
contain thread-specific data. TLS slots frequently hold pointers to blocks of data that belong to the thread. A
heap is memory allocated at run time from the virtual memory of an application and controlled by the heap
manager. An application can have more than one heap. Large objects are commonly placed on the heap,
whereas small objects are located on the stack. Virtual memory is raw memory that developers directly
manipulate at run time with minimal assistance from the environment. Virtual memory is ideal for collections
of disparate-sized data stored in noncontiguous memory addresses, such as a link list.

Developers of managed applications can directly affect the stack and managed heap. The other forms of
memory, such as registers and virtual memory, are largely unavailable except through interoperability. Value
type instances, local values, are created on the stack. Instances of reference types, objects, are created on
the managed heap. Lifetimes of local values are confined by scope. When a local value loses scope, it is
removed from the stack. For example, the local variables and parameters of a function are removed from
memory when the function is exited. The lifetime of an object, which resides on the managed heap, is
controlled by the garbage collector (GC), which is an element of the Common Language Runtime (CLR). The
GC periodically performs garbage collection to cleanse memory of unused objects.

The policies and best practices of the GC and garbage collection are the primary focus of this chapter.
Although garbage collection is not language-specific, the tradition of C-based developers, as related to
memory management, is somewhat different from other developers—particularly Microsoft Visual Basic and
Java developers. The memory model employed in Visual Basic and Java is cosmetically similar to the
managed environment. However, the memory model of previous C-based languages is dissimilar to this
environment. These differences make this chapter especially important.

Developers in C-based languages are accustomed to deterministic garbage collection, in which developers
explicitly set the lifetime of an object. The malloc/free and new/delete statement combinations create and
destroy objects that reside on a heap. Managing the memory of a heap required programmer discipline,
which proved insufficient for guaranteeing consistently robust code. Memory leaks and other problems were
common. These leaks could eventually destabilize the application and cause complete application failure.
Instead of each developer individually struggling with these issues, the managed environment has the GC,
which is omnipresent and controls the lifetime of objects located on the managed heap.

The GC offers nondeterministic garbage collection. Developers explicitly allocate memory for objects.
However, the GC determines when garbage collection is performed and unused objects are vanquished from
memory.

When memory for an object is allocated at run time, the GC returns a reference to that object. The new
operator requests that an instance of a type (an object) is placed on the managed heap. A reference is an
indirect pointer to that object. This indirection helps the GC transparently manage the managed heap,
including the relocation of pointers when necessary.

In .NET, unused objects are eventually removed from memory. When is an object unused? Reference
counting is not performed in the managed environment. Reference counting was common to Component
Object Model (COM) components. When the reference count became zero, the related COM component
was considered no longer relevant and removed from memory. There were many problems in this model.
First, this required careful synchronization of the AddRef and Release methods. Breakdown of
synchronization could sometimes cause memory leakage and exceptions. Second, reference counting was
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

expensive. Reference counting was applied to collectable and noncollectable components. Finally, programs
incurred the overhead of reference counting, even when there was no memory stress on the application. For
this reason, reference counting was deservedly abandoned for a more efficient model that addresses the
memory concerns of modern applications. When there is memory stress in the managed environment,
garbage collection occurs, and an object graph is built. Objects not on the graph become candidates for
collection.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Unmanaged Resources
Objects that incorporate unmanaged resources have a managed and unmanaged context, which affects
memory management and garbage collection.

For example, the unmanaged resource of a managed object might consume copious amount of unmanaged
memory. This cannot be ignored. Managed and unmanaged memories are allocated from the same pool of
virtual memory. Corrective action must be taken when the pool is drained, regardless of the source.
Developers can compensate for unmanaged resources in .NET Framework 2.0 and take corrective action to
prevent out of memory occurrences. You can no longer hide an unmanaged elephant behind a managed
object. A managed wrapper class for a bitmap is one example. The wrapper class is relatively small, and the
memory associated with the managed object is trivial. However, the bitmap is the elephant. A bitmap
requires large amounts of memory, which cannot be ignored. If ignored, creating several managed bitmaps
could unexpectedly cause your application to be trampled by a stampede of elephants.

The availability of an unmanaged resource can be discrete. When consumed in a managed application,
discrete resources must be tracked to prevent overconsumption. The overconsumption of unmanaged
resources can have an adverse affect on the managed application, including the potential of resource
contention or raising an exception. For example, a device can support three simultaneous connections.
What happens when the fourth connection is requested? In the managed environment, you should be able to
handle this scenario gracefully.

The lifetime of an unmanaged resource is a separate consideration apart from the lifetime of the managed
object that hosts that resource. Equating the lifetimes can delay the release of sensitive resources. This
delay can result in resource contention, poor user responsiveness, or application failure. For example, the
FileStream class is a wrapper for a native resource: a physical file. The FileStream instance, which is a
managed component, is collected nondeterministically. Therefore, the lapse between when the file is no
longer needed and the managed component is collected could be substantial. This could prevent access to
the file from within and outside your application. When the file is no longer required, the ability to release the
file deterministically is imperative. You need the ability to say "Close the file now." The Disposable pattern
provides this ability to managed developers and separates the lifetime of managed components and
unmanaged resources.

Garbage Collection Overview

This section is an overview of garbage collection. A detailed explanation of the mechanics of garbage
collection is presented in Chapter 13, "Advanced Debugging," and not repeated here. Two assumptions
guide the implementation of garbage collection in the managed environment. The first assumption is that
objects are more likely to communicate with other objects of a similar size. The second assumption is that
smaller objects are short-lived objects, whereas larger objects are long-lived objects. For these reasons, the
GC attempts to organize objects based on size and age.

In the managed environment, garbage collection is nondeterministic. With the exception of the GC.Collect
method, which is discouraged, developers cannot explicitly initiate garbage collection. The managed heap is
partitioned into generations, which are Generations 0, 1, and 2. The initial sizes of the generations are about
256 kilobytes, 2 megabytes, and 10 megabytes, respectively. As the application executes, the GC
fine-tunes the thresholds based on the pattern of memory allocations. Garbage collection is prompted when
the threshold for Generation 0 is exceeded. At that time, nonrooted objects are removed from memory.
Objects that survive garbage collection are promoted from Generation 0 to 1. Generation 0 is now empty. The
generations are then compacted and references updated. If during garbage collection Generation 0 and 1
exceed their thresholds, both are collected. Surviving objects are promoted from Generation 0 to 1 and from
Generation 1 to 2. Afterward, Generation 0 is empty again, generations are compacted, and references are
updated. In fewer instances, all three generations will exceed thresholds and require collection. The later
generations contain larger objects, which live longer. Because the short-lived objects reside primarily on
Generation 0, most garbage collection is focused in this generation. Generations allow the garbage
collection to implement a partial cleanup of the managed heap at a substantial performance benefit.

Objects larger than 85 kilobytes are considered large objects and are treated differently from other objects.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Large objects are placed on the large object heap, not on a generation. Large objects are generally long-lived
components. Placing large objects on the large object heap eliminates the need to promote these objects
between generations, thereby conserving resources and reducing the number of overall collection cycles. The
large object heap is collected with Generation 2, so large objects are collected only during a full
garbage-collection cycle.

When garbage collection is performed, the GC builds an object graph to determine which objects are not
rooted and can be discarded. The object graph is a graph of live objects. First the GC populates the object
graph with root references. The root references of an application are global, static, and local references.
Local references include references that are locals and function parameters. The GC then adds to the graph
those objects reachable from a root reference. An embedded object of a local is an example of an object
reachable from a root reference. Of course, the embedded object could contain other objects. The GC
extrapolates all the reachable objects to compose the branches of the object graph. Objects can appear
once in the object graph, which avoids circular references and other problems. Objects not in the graph are
not rooted and are considered candidates for garbage collection.

Objects that are not rooted can hold outstanding references to other objects. In this circumstance, the entire
branch is disconnected from a rooted object and can be collected. (See Figure 14-1.)

Figure 14-1: Object graph with nonrooted objects

The Rooted application demonstrates how nonrooted objects are collected. In the application, the Branch
class contains the Leaf class, which contains the Leaf2 class. The Branch class is used as a field in the
Form1 class. When an instance of the Branch class is created, it is rooted through the Form class. Leaf and
Leaf2 instances are rooted through the Branch instances. (See Figure 14-2.)

Figure 14-2: Object graph of the Rooted application

In the following code, a modal message box is displayed in the finalizer. This is done for demonstration
purposes only and generally considered bad practice.

public class Branch


{
~Branch()
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

{
MessageBox.Show("Branch d'tor");
}
public Leaf e= new Leaf();
}

public class Leaf


{
~Leaf()
{

MessageBox.Show("Leaf d'tor");
}
public Leaf2 e2= new Leaf2();
}

public class Leaf2


{
~Leaf2()
{
MessageBox.Show("Leaf2 d'tor");
}
}

The user interface of the Rooted application allows users to create the Branch, which includes Leaf
instances. (See Figure 14-3.) You can then set the Branch or any specific Leaf to null, which interrupts the
path to the root object. That nullified object is collectable. Objects that are rooted through the nullified object
are also now collectable. For example, if the Leaf instance is set to null, the Branch instance is not
collectable; it is before the Leaf reference in the object graph. However, Leaf2 object is immediately a
candidate for collection. After setting the Branch or Leaf objects to null, garbage collection can occur. If it
doesn't occur, click the Collect Memory button to force garbage collection.

Figure 14-3: Rooted application

As mentioned, garbage collection occurs when the memory threshold of Generation 0 is exceeded. Other
events, which are described in the following list, can prompt garbage collection:
 When the threshold of Generation 0 is exceeded, garbage collection is triggered. Certain
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

activities, such as frequent allocations, can accelerate garbage collection cycles.


 Garbage collection is conducted when the extents of memory pressure are reached. The
GC.AddMemoryPressure method applies pressure to the managed heap for an unmanaged
resource.
 The limit of an unmanaged resource is reached. HandleCollector sets limits for unmanaged
resources.
 Garbage collection can be forced with the GC.Collect method. This behavior is not recommended
because forcing garbage collection is expensive. Nonetheless, this is sometimes necessary.
 Garbage collection also occurs when overall system memory is low.

Certain suppositions are made for garbage collection in the managed environment. For example, small
objects are generally short-lived. Coding contrary to these assumptions can be costly. Although it makes for
an interesting theoretical experiment, this is not recommended for production applications. Defining a basket
of short-lived but larger objects is an example of coding against assumptions of managed garbage collection,
which would force frequent and full collections. Full collections are particularly expensive. Defining a
collection of near-large objects—objects that are slightly less than 85 kilobytes—is another example. These
objects would apply immediate memory pressure. Because they are probably long-lived, you have the
overhead of eventually promoting the near-large objects to Generation 2. It would be more efficient to pad the
objects with a buffer, forcing them into large object status, in which the objects are directly placed onto the
large object heap. You must remain cognizant of the underlying principal of garbage collection. Implement
policies that enhance, not exasperate, garbage collection in the managed environment.

One such policy is to limit boxing. Constant boxing of value types can cause garbage collection more often.
Boxing creates a copy of the value type on the managed heap. Most value types are small. For this reason,
the resulting object placed on the managed heap could be larger than the original value. This is yet another
reason that boxing is inefficient and should be avoided when possible. This is particularly a problem with
collection types. The best solution is to use generic types.

This introduction to garbage collection omits the topic of finalization, which is discussed in complete detail
later in this chapter.

GC Flavors

There are two flavors of the garbage collection: Workstation GC is optimized for a workstation or
single-processor system, whereas Server GC is fine-tuned for a server machine that has multiple processors.
Workstation GC is the default; Server GC is never the default—even with a multiprocessor system. Server
GC can be enabled in the application configuration file. If your application is hosted by a server application,
that application might select the Server GC.

Workstation GC can have concurrent garbage collection enabled or disabled. Concurrent is a single thread
concurrently servicing the user interface and garbage collection. The thread simultaneously responds to
events of the user interface while also conducting garbage collection responsibilities. The alternative is
noncurrent. When garbage collection is performed, other responsibilities, such as servicing the user
interface, are deferred.

Workstation GC with Concurrent Garbage Collection


Workstation GC with concurrent garbage collection is the default. It is ideal for desktop applications, in
which the user interface must remain responsive. When garbage collection occurs, it will not subjugate the
user interface. Concurrent applies only to full garbage collection, which is the collection of Generation 2.
When Generation 2 is collected, Generation 0 and 1 are also collected. Partial garbage collection of
Generation 0 or 1 is an expeditious activity. The potential impact on the user interface is minimal, and
concurrent garbage collection is not merited.

The following are the garbage collection steps for Workstation GC with concurrent processing:
1. Garbage collection is triggered.
2. All managed threads are paused.
3. Perform garbage collection. If garbage collection is completed, proceed to step 5.
4. Interrupt garbage collection. Resume threads for a short time to respond to user interface
requests. Return to step 3.
5. Resume threads.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Threads are suspended at a secure point. The CLR maintains a table of secure points for use during garbage
collection. If a thread is suspended at an nonsecure point, the thread is hijacked until a secure point is
reached or the current function returns.

Workstation GC Without Concurrent Garbage Collection

Workstation GC without concurrent garbage collection is selected when Server GC is chosen on a


single-processor machine. With this option, priority is placed on garbage collection in lieu of the user
interface.

Here are the garbage collection steps for Workstation GC without concurrent processing:
1. Garbage collection is triggered.
2. All managed threads are paused.
3. Garbage collection is conducted.
4. Managed threads resume.

Server GC

Server GC is designed for multiprocessor machines that are commonly deployed as servers, such as Web,
application, and database servers. In the server environment, emphasis is on throughput and not the user
interfaces. The Server GC is fine-tuned for scalability. For optimum scalability, garbage collection is not
handled on a single thread. The Server GC allocates a separate managed heap and thread for every
processor. Garbage collection is not conducted on the thread that requests the allocation.

Here are the garbage collection steps with Server GC:


1. A GC thread performs an allocation.
2. Garbage collection is triggered.
3. Managed threads are suspended.
4. Garbage collection is performed.
5. Managed threads are resumed.

Configuring GC Flavor
Workstation GC with concurrent garbage collection can be enabled or disabled in an application
configuration file. Because concurrent is the default, the configuration file is used primarily to disable
concurrent garbage collection. This is set in the gcConcurrent tag, as shown in the following code:

<configuration>
<runtime>
<gcConcurrent enabled="false"/>
</runtime>
</configuration>

Server GC is also stipulated in the application configuration file. Remember, Server GC is never the default—
even in a multiprocessor environment. Select the Server GC using the gcServer tag, which is exhibited in the
following code:

<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>

You can also use the .NET Framework Configuration Tool (mscorcfg.msc) to select the appropriate GC. This
tool is installed in the Administrative Tools of the Control Panel. Open the .NET Framework Configuration tool
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

and select the Applications icon, which is presented in the left pane. Click the Add An Application To
Configure link in the Applications window. From the Configure An Application dialog box, browse and select
the target application. The application window will appear. In that window, click the View The Application's
Properties link. The application's Properties dialog box will appear. From the two options, you can select the
appropriate Garbage Collection mode in this window. Figure 14-4 shows the application properties dialog box
and the garbage collection options.

Figure 14-4: Application properties in the .NET Framework Configuration tool


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Finalizers
Resources of an object are cleaned up in a Finalize method. Before an object is removed from memory, the
Finalize method is called to release collateral resources. As a group, Finalize methods are called finalizers.
Every object inherits the Finalize method from the System.Object type. This is the syntax of the Finalize
method:
 Object.Finalize syntax:
o protected virtual void Finalize()

Finalizers are not called programmatically; they are called automatically during the garbage collection cycle.
Garbage collection is nondeterministic, which means that the finalizer may not be called immediately. This
means that unmanaged resources, such as files, database connections, and devices, might not be released
in a timely manner. This delay in relinquishing resources can have adverse side effects on this and possibly
other applications.

Instead of a Finalize method, C# has a destructor. Coding a Finalize method explicitly causes a compiler
error. Destructor methods are preceded with a tilde and share the name of the class.

Destructor syntax:
 ~Classname()

The destructor syntax has the following limitations:


 Destructors do not have modifiers.
 Destructors are protected and virtual by default.
 Destructors have no parameters.
 Destructors cannot be overloaded.
 Destructors do not have a return type. The implied return type of a destructor is void.

The C# compiler converts destructors to Finalize methods. Here is a simple destructor:

~ZClass() {
--propCount;
}

The C# compiler emits a Finalize method for the ZClass. The Finalize method supplants the destructor in
Microsoft intermediate language (MSIL) code. Figure 14-5 shows the ZClass. Notice the Finalize method and
the absence of the Destructor method.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 14-5: View of the ZClass

The C# compiler generated the following MSIL code for the ZClass destructor (for clarity, extraneous code
has been removed from the listing):

.method family hidebysig virtual instance void


Finalize() cil managed
{
.maxstack 2
.try
{
IL_0001: ldsfld uint8 Donis.CSharpBook.ZClass::propCount
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: conv.u1

IL_0009: stsfld uint8 Donis.CSharpBook.ZClass::propCount


IL_000f: leave.s IL_0019

}
finally
{
IL_0011: ldarg.0
IL_0012: call instance void [mscorlib]System.Object::Finalize()
IL_0018: endfinally
}
IL_0019: nop
IL_001a: ret
}

The Finalize method provided by the C# compiler contains a termination handler. The try block contains the
code of the destructor. In this circumstance, the count is decremented. The termination handler calls the
Finalize method of the base class. Because the call is in a termination handler, the finalizer of the base
class is called even if an unhandled exception is raised in the destructor. This means that calls to the
Finalize method propagate through the class hierarchy even when an exception is raised. This also means
that developers should never attempt to directly call the destructor of the base class. The manifested Finalize
method automatically assumes this responsibility.

The following code defines a class hierarchy, in which each class in the hierarchy has a destructor. This
demonstrates that the destructors are called bottom-up automatically. The destructor in the XClass throws
an unhandled exception. Despite the error condition, the base destructors are called anyway. This confirms
that the Finalize method of the base class is called in a termination handler:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
XClass obj=new XClass();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

public class ZClass{

~ZClass() {
Console.WriteLine("ZClass d'tor");
}

public class YClass: ZClass{

~YClass() {
Console.WriteLine("YClass d'tor");
}

public class XClass: YClass{

~XClass() {
Console.WriteLine("XClass d'tor");
throw new Exception("D'tor exception");
}

Many have lamented the decision to associate finalizers with destructors. C++ developers are familiar with
destructors. They are an integral part of the C++ language. This familiarity creates a level of expectation,
which is only partially honored in C#. There are credible differences between C++ and C# destructors,
including the following:
 C++ destructors can be called deterministically, whereas C# destructors are called
nondeterministically.
 C++ destructors can be virtual or nonvirtual, whereas C# destructors are implicitly virtual.
 C++ destructors execute on the same thread that created the object, whereas C# destructors
execute on a dedicated finalizer thread.
 C++ destructors cannot be suppressed at run time, whereas C# destructors can be suppressed.

For the remainder of this chapter, C# destructors are referred to as finalizers to distinguish between C# and
C++ destructors.

As mentioned, finalizers are called nondeterministically. In code, you cannot call them directly. When are
finalizers called?
 During the garbage collection process
 When the AppDomain of an object is unloaded
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 When the GC.Collect method is called


 When the CLR is shutting down

Knowing the specific reason for finalization can be helpful. For example, if finalization is part of normal
garbage collection, you might choose to recycle the object. However, if the application domain is being
unloaded, recycling a dead object would be pointless. You can confirm that finalization is initiated by an
application unload or a CLR shutdown. The AppDomain .IsFinalizingForUnload method, which is an instance
method, returns true if the application domain is unloading and finalization has begun on objects in that
domain. Otherwise, the method returns false. The Environment.HasShutdownStarted property is a static
property that returns true if the CLR is shutting down or the application domain is unloading. Otherwise, the
property returns false.

The Recycle application recycles an instance of the ZClass type. When the object is being finalized, the
Environment.HasShutdownStarted property is checked. If false, the reference to the object is re-established,
which ends finalization. This resurrects the object (more about resurrection later). If the property is true, the
object is not recycled. There is no reason to recycle an object if the current application domain is unloading
or the CLR is shutting down. This is the ZClass type from the Recycle application:

public class ZClass


{
public ZClass()
{
++propCount;
_count = propCount;
}

~ZClass()
{
++propCount;
++_count;
AppDomain current = AppDomain.CurrentDomain;
if (!Environment.HasShutdownStarted)
{
Form1.obj = this;
GC.ReRegisterForFinalize(this);
}
}

private static int propCount = 0;


private int _count;
public int Count
{
get
{
return _count;
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

At application shutdown, finalizers have a limited amount of time to complete their tasks. This prevents an
indefinite shutdown. Each Finalize method has two seconds to complete. If the time allotment is exceeded,
that finalizer is terminated. The remaining finalizers then continue to execute. As a group, the Finalize
methods have 40 seconds to complete all finalization chores. When this time limit is exceeded, the
remaining finalizers are skipped. Forty seconds is nearly an eternity in processing time and should be
sufficient to complete even the most extensive housecleaning of an application.

In the following application, you can adjust the duration of the finalizer and view the results. A number
between 1 and 10 provides the best comparative results. Specify the value as a command-line argument:

using System;
using System.Threading;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(string [] args){
Shutdown.ZTime=int.Parse(args[0]);
ZClass [] obj=new ZClass[500];
for(int count=0;count<500;++count) {
obj[count]=new ZClass();
}
}
}

public class Shutdown {


static public int ZTime=0;
}

public class ZClass{

public ZClass() {
++globalcount;
localcount=globalcount;
}

private int localcount=0;


private static int globalcount=0;

~ZClass() {
for(int i=0; i< Shutdown.ZTime; ++i) {
Thread.Sleep(50);
}
Console.WriteLine(localcount+" "+
"ZClass d'tor");
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

Finalizer Thread
The finalizer thread calls finalizers on objects waiting in the FReachable queue. After the finalizer is called,
the object is removed from the FReachable queue and deleted from memory during the next garbage
collection cycle. The finalizer thread executes the finalizer asynchronously. There is one finalizer thread that
services all finalizers of the application, which creates a potential bottleneck. For this reason, finalizers
should be short and simple. A long finalizer can delay the finalization of the remaining objects on the
FReachable queue. In addition, this extends the lifetime of objects pending finalization and increases
memory pressure on the managed heap. This causes more garbage collection, which is always expensive.

Finalizer Considerations
When implementing finalizers, there are several considerations. These considerations should help developers
implement finalizers correctly. Some of these considerations emphasize that finalizers should be avoided
whenever possible. For example, you should never implement an empty finalizer. In the C++ language, an
empty destructor is harmless. In C#, an empty destructor (finalizer) is costly, as explained in this section.

Finalizers are expensive As mentioned, finalizers are expensive. At least two garbage collection cycles
are required to collect a finalizable object that is not rooted. During the first garbage collection, the finalizable
object is moved from the Finalizable queue to the FReachable queue. After the finalizer has been called, the
memory of the object is reclaimed in a future garbage collection. The lifetime of objects referenced by the
finalizable object are equally extended. They must wait for the finalizable object to be reclaimed before being
released themselves. Additional object retention increases memory pressure, which causes additional
garbage collection. Needless garbage collection is particularly expensive. The finalizable objects are
promoted to later generations, which make a full garbage collection more likely. Full garbage collection is
much more expensive than collecting only Generation 0. Actually, the extra expense of defining a finalizable
object starts at its allocation. When a finalizable object is created, a reference to the object must be added
to the Finalizable queue. Objects without finalizers avoid this additional expense.

Finalizers are not guaranteed Finalizers are not always called. Some of the reasons why a finalizer might
not be called have already been mentioned. One such reason is the shutdown of the CLR by a host
application. At that time, finalizers must run in an allotted amount of time. You can also programmatically
suppress a finalizer with the GC.SuppressFinalize method. An asynchronous exception, such as a thread
abort exception, can cause a finalizer not to run.

Multithreading Finalizable objects are multithreaded. Object code and the finalizer execute on different
threads. For this reason, certain activities should be avoided in the finalizer. Most notably, never access
thread-local storage associated with the object in the finalizer. Because the thread context has changed,
using thread local storage in the finalizer is inappropriate.

The TLS sample application contains the following code that uses thread local storage. This is a Windows
Forms application. A reference to a StreamWriter object is placed into the TLS table for each thread. Various
threads accessing the same TMonitor object will own a different StreamWriter reference in the TLS table.
Therefore, each thread will write status messages to a different file. In the sample application, two threads
are accessing a TMonitor instance. In the destructor of the TMonitor type, a StreamWriter is retrieved from
TLS and closed. Which StreamWriter is closed? Is this the StreamWriter of the first or second thread? The
answer is neither. The destructor is running on the finalizer thread, which is unrelated to the other threads.
This thread has no StreamWriter reference, and an error is reported. In Microsoft Visual Studio 2005,
Console.WriteLine in a Windows Forms application displays in the Output window:

class TMonitor
{
public void WriteFile()
{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

StreamWriter sw = Thread.GetData(Form1.Slot)
as StreamWriter;
if (sw == null)
{
sw = new StreamWriter(string.Format(
@"C:\{0}File.txt",
Thread.CurrentThread.Name),
true);
Thread.SetData(Form1.Slot, sw);
}
sw.WriteLine(DateTime.Now.ToLongTimeString());
}

~TMonitor()
{
StreamWriter sw = Thread.GetData(Form1.Slot)
as StreamWriter;
if (sw != null)
{
sw.Close();
}
else
{
Console.WriteLine("Error in destructor");
}
}
}

The preceding application is for demonstration purposes only. In a finalizer, you should not reference other
managed objects.

One finalizer thread There is a single finalizer thread that services the FReachable queue. It calls pending
finalizers of finalizable objects. The finalizer thread is different from other threads that might be accessing the
object methods. Do not change the context of the finalization thread. This is not your thread. Changing the
context of the finalization thread can have an adverse effect on the finalization process.

Finalizers and virtual functions Do not call virtual functions from finalizers. This can cause unexpected
behavior such as inadvertent leaks and resources not being cleaned up. If overridden, there is no assurance
that the derived class will provide the appropriate implementation. This is especially true for classes
published in a class library, in which the developer of the derived class may have limited knowledge of the
base class.

Look at the following sample code:

using System;

namespace Donis.CSharpBook{
public class Starter{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static void Main(){


YClass obj=new YClass();
}
}

public class ZClass {

protected virtual void CloseResource() {


Console.WriteLine("Closing ZClass resource.");
}

~ZClass() {
CloseResource();
}
}

public class YClass: ZClass {

protected override void CloseResource() {


Console.WriteLine("Closing YClass resource.");
}

~YClass() {
CloseResource();
}

}
}

In the preceding code, the finalizer in the ZClass calls the CloseResource method, which is a virtual method.
YClass is derived from ZClass and overrides the CloseResource method. An instance of the derived class is
created in the Main method. At garbage collection, the following messages are displayed:

Closing YClass resource.


Closing YClass resource.

Yes, CloseResource of the derived class is called twice, which creates a couple of problems. First, an
exception could be raised on the second attempt to close the resource. Second, the ZClass resource is not
removed and leaks.

Order of finalization Garbage collection is not performed in a guaranteed sequence. For this reason, do
not access another managed object in the finalizer. There is no assurance that the other managed object
has not been collected and removed from memory.

In the following code, the ZClass has a StreamWriter field. In the finalizer, the StreamWriter is closed.
Normally, this is perfectly acceptable behavior, but not in a finalizer. When the application exits, an
exception is raised in the finalizer. The StreamWriter object was collected before the current object.
Therefore, an exception is raised when an instance method of the StreamWriter class is called in the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

finalizer.

public class ZClass


{
public ZClass()
{

sw = new StreamWriter("test.txt");
}

~ZClass()
{
sw.Close();
}

private StreamWriter sw;


}

Resurrection Zombies do exist. Yikes! Like any object, finalizable objects are created on the managed
heap. When there are no outstanding references to the object, a finalizable object is submitted for garbage
collection. At that time, the object is dead. However, the object is resurrected to be placed in the FReachable
queue. After the finalizer is called, the object is removed from the FReachable queue. It is removed from
memory during the next garbage collection. At that time, the object is dead again.

You can intentionally, or more likely inadvertently, resurrect an object permanently during the finalization
process. At that time, the object is resurrected without the finalizer attached. Therefore, the resurrected
object is not completely returned to the live status. The object is a zombie. Zombies pose a distinct problem
because of their dangling finalizers. Because the finalizer is not called, proper cleanup is not performed when
the zombie is later collected. The result could be a memory leak, a resource not being released, or other
related problems. You can manually reconnect the finalizer with the GC.ReRegisterForFinalize method.
Afterward, the object is normal and is no longer a zombie.

Another problem with resurrection is that the original finalizer has executed. This could render the object
unusable because needed resources might have been relinquished.

During finalization, a common cause of accidental resurrection is the creation of a new reference to the
current object. At that moment, the object is resurrected. Despite being resurrected, the finalizer of the
object runs to completion. In the following code, the current object is directly referenced in the finalizer. An
indirect reference is more likely. Referencing another managed object in a finalizer can have a domino effect
and should be avoided. That object might access another managed object, which might reference another
object and so on until someone references the current object. Voilà—resurrection has occurred. This is a
compelling reason to avoid referencing managed objects in a destructor.

using System;
using System.IO;

namespace Donis.CSharpBook{

public class Starter{


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static void Main(){


obj=new ZClass();
obj.TimeStamp();

obj=null;
GC.Collect();
GC.WaitForPendingFinalizers();
obj.TimeStamp();
}

public static ZClass obj;


}

public class ZClass {

public ZClass() {
sw=new StreamWriter("test.txt");
}

public void TimeStamp() {


sw.WriteLine(DateTime.Now.ToLongTimeString());
}

~ZClass() {
Starter.obj=this;
sw.Close();
sw=null;
}

static private StreamWriter sw;


}
}

The first statement in the ZClass destructor resurrects the object. It assigns the object reference to a static
field of the Starter class. Because there is again an outstanding reference, the object is resurrected. The
underlying file of the StreamWriter instance is then closed. In Main, an instance of the ZClass is created.
The instance is assigned to a static field of the Starter class. Afterward, the reference is assigned null, and
garbage collection is forced. This kills and then resurrects the object. The next call on the object raises an
exception because the underlying file has been closed in the previous finalization.

The following code corrects the problem and successfully resurrects the object. The first statement confirms
whether the CLR is shutting down. If true, the managed application is exiting. In that circumstance, there is
no reason to resurrect the object while the application domain is being unloaded. At that time, static objects
are submitted to garbage collection. For that reason, the static object (sw) is accessible only when the
application domain is not being unloaded. In the if block, the object is resurrected and the finalizer is
reattached.

~ZClass() {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

if(Environment.HasShutdownStarted==false) {
Starter.obj=this;
sw.Close();
sw=null;
GC.ReRegisterForFinalize(this);
}
}

The TimeStamp method of the previous code must also be updated. The finalizer sets the sw object, which
is a StreamWriter instance, to null. This is checked in the revised TimeStamp method. If null, the sw
reference is reinitialized. The file resource is then available again for writing:

public void TimeStamp() {


if(sw==null) {
sw=new StreamWriter("test.txt",true);
}
sw.WriteLine(DateTime.Now.ToLongTimeString());
sw.Flush();
}

This is the entire code of the revised application:

using System;
using System.IO;

namespace Donis.CSharpBook{

public class Starter{

public static void Main(){


obj=new ZClass();
obj.TimeStamp();
obj=null;
GC.Collect();
GC.WaitForPendingFinalizers();
obj.TimeStamp();
}

public static ZClass obj;


}

public class ZClass {

public ZClass() {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

sw=new StreamWriter("test.txt", true);


}

public void TimeStamp() {


if(sw==null) {
sw=new StreamWriter("test.txt",true);
}
sw.WriteLine(DateTime.Now.ToLongTimeString());
sw.Flush();
}

~ZClass() {
if(Environment.HasShutdownStarted==false) {
Starter.obj=this;
sw.Close();
sw=null;

GC.ReRegisterForFinalize(this);
}
}

static private StreamWriter sw;

}
}

Finalizers and reentrancy A finalizer is reentrant. The best example of this is complete resurrection, in
which the finalizer is reattached. In that circumstance, the finalizer is called at least twice. When a finalizer
is called more than once, resurrection is the likely culprit. Redundant calls on a finalizer should not cause a
logic error or an exception.

Deep object graph A deep object graph can make garbage collection more expensive. Roots and branches
of the object graph can be anchored with a finalizable object. As mentioned, the lifetime of a finalizable
object is extended to encompass at least two garbage collections. All objects, even nonfinalizable objects,
along the path of the finalizable object have their lives similarly extended. Therefore, one finalizable object
can keep several other objects from being garbage collected. Deeper graphs by definition have longer
branches and can extend the problem.

Finalizer race condition The finalizer can execute at the same time as other functions of the finalizable
object. Because the finalizer executes on a dedicated thread, other functions of the finalizable object could
be running when finalization starts. This can cause a race condition to occur between normal operations and
the finalization. Standard thread-synchronization techniques can protect against a finalization race condition.

In the following code, MethodA is called on a ZClass instance. MethodA has a built-in delay. Shortly
thereafter, the object is set to null and collected. The finalizer then runs simultaneously with MethodA. The
race has begun! The results are usually unpredictable.

public class Starter{

public static void Main(){


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Thread t=new Thread(


new ThreadStart(MethodA));
obj=new ZClass();
t.Start();
obj=null;
GC.Collect();
}

private static void MethodA() {


obj.MethodB();
}

private static ZClass obj;


}

public class ZClass {

public void MethodB() {


Console.WriteLine("ZClass.MethodB Started");
Thread.Sleep(1500);
Console.WriteLine("ZClass.MethodB Finished");
}

~ZClass() {
Console.WriteLine("ZClass.~ZClass Started");
// D'tor operation
Console.WriteLine("ZClass.~ZClass Finished");
}
}

Constructors An exception in the constructor does not deter the object from being finalized. The finalizer is
called regardless of the success of the constructor, which can create an interesting dilemma in which an
object that is unsuccessfully constructed is still finalized. Cleanup of a partially constructed object can pose
risks.

The following code demonstrates the problems that can occur when an exception is raised in a constructor.
The exception is caught by the exception handler in Main. At that time, the object exists but is not correctly
initialized. Despite the earlier exception in the constructor, the finalizer is called as the application exits.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
try {
ZClass obj=new ZClass();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
catch {
}
}
}

public class ZClass {

public ZClass() {
Console.WriteLine("ZClass c'tor");
throw new Exception("Error");
}

~ZClass() {
Console.WriteLine("ZClass d'tor");
}
}
}

The following code resolves the problem of a partially constructed finalizable object. If the constructor does
not complete successfully, GC.SuppressFinalize prevents the finalizer from being called later. In addition, a
flag is maintained that indicates the state of the object. The bPartial flag is set to true if the constructor fails,
which is checked in instance methods. If the flag is true, the methods raise an exception because the object
might not be stable.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
try {
ZClass obj=null;
obj=new ZClass();
if(obj!=null){
obj.MethodA();
}
}
catch(Exception ex) {
Console.WriteLine(ex.Message);
}
}
}

public class ZClass {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public ZClass() {
try {
Console.WriteLine("ZClass c'tor");
throw new Exception("Error");
}
catch {
GC.SuppressFinalize(this);
bPartial=true;
}
}

public void MethodA() {


if(bPartial) {
throw new Exception("Partial construction error");
}
Console.WriteLine("ZClass.MethodA");
}

~ZClass() {
Console.WriteLine("ZClass d'tor");
}

private bool bPartial=false;

}
}

Console and finalization You can safely use the Console class in a finalizer. The Console class is
exempted from the rule about not using managed classes in finalizers. It is especially written for use during
finalization.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

IDisposable.Dispose
The Dispose method is an alternative to a finalizer. Contrary to finalizers, Dispose methods are deterministic
and can freely access managed types. Finalizers are nondeterministic, which delays invocation. This can
prevent resources from being released in a timely manner and create resource contention. For example, an
unreleased file handle can block or cause errors in other threads waiting on that handle. Dispose methods
are deterministic and sometimes referred to as explicit garbage collection. You can call the Dispose method
to release an expendable resource, such as immediately closing a file handle. Accessing managed objects
in a finalizer is unadvisable. Garbage collection is undeterminable, and that object may no longer exist. This
requirement greatly limits the scope and functionality of a finalizer. The Dispose method does not
necessarily have these limitations because garbage collection may not be occurring.

The Dispose method is defined in the IDisposable interface of the System namespace. Disposable objects
should inherit and implement the IDisposable interface, in which the Dispose method is the only member.
You then call the Dispose method as a normal method to start deterministic garbage collection. Although
possible, you should not implement the Dispose method separate of the IDisposable interface. The
IDisposable interface is an important marker that confirms the presence of a disposable object. There are
statements and behaviors, such as the using statement, that require this marker.

The following code demonstrates a simple implementation of the Dispose method:

public class Starter{


public static void Main(){
ZClass disposableobject=new ZClass();
disposableobject.Dispose();
disposableobject=null;
}
}

public class ZClass: IDisposable {


public ZClass() {
// Allocate resources
}

public void Dispose() {


// Release resources
}
}

In the preceding code, the Dispose method is not guaranteed to run. Raising an exception prior to the
Dispose method call could cause the method to be skipped and result in resource leakage. To protect
against this possibility, place the Dispose method call in a finally block. This assures that the Dispose
method is called whether or not an exception is raised in the try block. This is an updated version of the
previous code, in which the Dispose method is placed in a finally block:

public static void Main(){


ZClass disposableobject=null;

try {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

disposableobject=new ZClass();
}
finally {
disposableobject.Dispose();
disposableobject=null;
}
}

The using block is the short form of the preceding code. A new object is defined in the using statement.
When the using block exits, the Dispose method is called automatically on the declared object of the using
statement:

public static void Main(){


using(ZClass disposableobject=
new ZClass())
{
// use object
}
}

The C# compile substitutes a try and a finally block for the using statement and block. This is some of the
MSIL code emitted for the using block:

IL_0006: stloc.0
.try
{
IL_0007: nop
IL_0008: nop
IL_0009: leave.s IL_001b
} // end .try
finally
{
// partial listing…

IL_0014: callvirt instance void [mscorlib]System.IDisposable::Dispose()


IL_0019: nop
IL_001a: endfinally
} // end handler

Multiple objects of the same type can be declared in the using statement. Delimit the objects with commas.
All objects declared in the statement are accessible in the using block. When the using block exits, the
Dispose method is called on each of the declared objects from the using statement. In the following code,
two objects of the same type are declared in the using statement:

using System;

namespace Donis.CSharpBook{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class Starter{


public static void Main(){
using(ZClass obj1=new ZClass(),

obj2=new ZClass()) {
}
}
}

public class ZClass: IDisposable {


public void Dispose() {
Console.WriteLine("ZClass.Dispose");
}
}

You can also declare objects of different types for a using block—simply stack multiple using statements. In
the following code, three objects are scoped to the using block. One object is the XClass type, whereas two
objects are ZClass types. All three are disposed at the end of the using block.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
using(XClass obj3=new XClass())
using(ZClass obj1=new ZClass(),
obj2=new ZClass()) {
}
}
}

public class ZClass: IDisposable {


public void Dispose() {
Console.WriteLine("ZClass.Dispose");
}
}

public class XClass: IDisposable {


public void Dispose() {
Console.WriteLine("XClass.Dispose");
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Class can contain both a Dispose method and a finalizer. You can relinquish both managed and unmanaged
resources in the Dispose method, whereas the finalizer can clean up only the unmanaged resources. When
a Dispose method is not called as planned, the finalizer is an effective safety net. Finalizers are called
automatically and cannot be forgotten. If not called earlier, finalizers of disposable objects are called at CLR
shutdown. Finalization should not be performed on a disposed object. A second iteration of cleanup could
have unexpected results. For this reason, developers typically suppress the finalizer in the Dispose method.
The GC.SuppressFinalize method is called in the Dispose method to suppress the finalizer. Performance is
improved because future finalization of the object is eliminated.

In the following code, the ZClass has both a Dispose and finalizer method. Note that GC.SuppressFinalize is
invoked in the Dispose method.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
using(ZClass obj1=new ZClass()) {
}
}
}

public class ZClass: IDisposable {


public void Dispose() {
Console.WriteLine("Disposing resources");
GC.SuppressFinalize(this);
}

~ZClass() {
Console.WriteLine("ZClass.ctor");
// Cleanup unmanaged resources
}
}
}

This section reviewed the simple implementation of the Dispose method, which is sufficient for sealed
classes. However, inheritable classes require the more complex Disposable pattern.

Thread Local Storage Example


Earlier in this chapter, an unworkable Thread Local Storage application was presented. The following code
shows the corrected version that uses the Dispose method. For the TMonitor class, the Dispose method is
called from each thread that is using the class.

class TMonitor: IDisposable


{
public void WriteFile()
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

{
StreamWriter sw = Thread.GetData(Form1.Slot)
as StreamWriter;
if (sw == null)
{
sw = new StreamWriter(string.Format(
@"C:\{0}File.txt",
Thread.CurrentThread.Name),
true);
Thread.SetData(Form1.Slot, sw);
}
sw.WriteLine(DateTime.Now.ToLongTimeString());
}

public void Dispose()


{
StreamWriter sw = Thread.GetData(Form1.Slot)
as StreamWriter;
Thread.SetData(Form1.Slot, null);
if (sw != null)
{
sw.Close();
MessageBox.Show("sw closed");
}
}
}

Disposable Pattern

The Disposable pattern provides a template for implementing the Dispose method and finalizer in a base and
derived class. The Disposable pattern, shown in the following code, should be implemented if the base class
does not presently possess resources:

using System;
using System.Threading;

namespace Donis.CSharpBook{

public class Base: IDisposable {

public void Dispose() {


Dispose(true);
GC.SuppressFinalize(this);
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

protected virtual void Dispose(bool disposing) {


if (disposing) {
// Release managed resources
}
// Release unmanaged resources
}

~Base() {
Dispose (false);
}
}

public class Derived: Base {


protected override void Dispose(bool disposing) {
if (disposing) {
// Release managed resources.
}
// Release unmanaged resources
base.Dispose(disposing);
}
}
}

We will focus first on the base class, which implements the IDisposable interface and contains two Dispose
methods.

The one-argument Dispose method, which is a protected method, has a single argument. The disposing
argument indicates whether the method is being called during deterministic or nondeterministic garbage
collection. If called during nondeterministic garbage collection, the disposing argument is set to false.
Otherwise, the argument is true. When the argument is false, only unmanaged releases are releasable in the
method. When true, both managed and unmanaged resources can be released.

Both the no-argument Dispose method and the finalizer delegate to the one-argument Dispose method. The
no-argument Dispose method is public and called explicitly for deterministic garbage collection. This Dispose
method delegates to the one-argument destructor with the disposing flag set to true. It also suppresses
finalization of this object in future garbage collection. The finalizer delegates to the one-argument destructor
with the disposing flag set to false. This limits cleanup to unmanaged resources, which is appropriate during
normal garbage collection.

The no-argument Dispose method is not a virtual method, whereas the one-argument Dispose method is
virtual. The no-argument Dispose method should not be overridden in the derived class. This method should
always delegate to the most derived one-argument Dispose method. Any other behavior would seriously
break the disposable pattern.

In the derived class, override the one-argument Dispose method to clean up managed and unmanaged
resources of the derived class. Do not override or hide the no-argument Dispose method of the base class.
Finally, the one-argument Dispose method in the derived class should call the same method in the base
class, affording that class the opportunity to release its resources.

In the derived class, do not implement a finalizer. The base class implementation of the finalize method will
correctly call the most derived dispose method. Disposal then propagates from the most derived class to all
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

ascendants. Therefore, resource cleanup is performed in the correct order.

Disposable Pattern Considerations

There are several factors to consider when implementing a simple dispose or the more complex Disposable
pattern. This section lists many of the factors that should be considered when implementing a Dispose
method.

Redundant Dispose Method


In the following code, the Dispose method is called twice. Calling the Dispose method multiple times should
be secure. Set a flag the first time Dispose is called. Check the flag in future invocations to confirm that the
object is disposed. If the object is disposed, do not dispose it again. Alternatively, you might be able to
confirm the disposability of an object from the state of the object. It is a good practice to confirm the
disposed status at the beginning of other member methods. If the object is disposed, revive the object and
execute the method or throw the ObjectDisposedException.

public static void Main(){


using(ZClass disposableobject=
new ZClass())
{
disposableobject.Dispose();
}
}

The following code demonstrates a resilient Dispose method, which can be called multiple times. The
ReverseReader type is a thin wrapper for a StreamReader. It inverts information read from the StreamReader.
ReserveReader contains a StreamReader field. It is initialized in the class constructor and closed in the
Dispose method. If the StreamReader is null, the object is presumed disposed. This is checked in the
Dispose method. If the object is already disposed, the Dispose method simply returns. When the object is
disposed, the other ReverseReader method throws the ObjectDisposedException exception. After the using
block, a second Dispose method is called, which proves to be harmless. A second call to the ReadLine
method is commented. If uncommented, an exception would be raised.

using System;
using System.IO;

namespace Donis.CSharpBook{
public class Starter{

public static void Main(){


using(ReverseReader input=new
ReverseReader("text.txt")) {
string result=input.ReadLine();
while(result!=null) {
Console.WriteLine(result);
result=input.ReadLine();
}
input.Dispose();
// input.ReadLine();
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

public class ReverseReader:IDisposable {

public ReverseReader(string filename) {


file=new StreamReader(filename);
}

public string ReadLine() {


if(file==null) {

throw new ObjectDisposedException(


"ReadLine object");
}
if(file.Peek()<0) {
return null;
}
string temp=file.ReadLine();
char [] tempArray=temp.ToCharArray();
Array.Reverse(tempArray);
return new string(tempArray);
}

public void Dispose() {


if(file==null) {
return;
}
else {
file.Close();
file=null;
}
}

private StreamReader file=null;


}

Close Method
Instead of the Dispose method, some classes expose another method for deterministic cleanup. Although
this should not be done as a general practice, the exception is when another method is more intuitive than
the Dispose method. For example, the FileStream class exposes the Close method. (Close is the traditional
term for releasing a file.) The alternative method should delegate to the Dispose method. Do not implement
the disposable routine more than once. Both the Dispose and alternative methods are available to the clients
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

for deterministic garbage collection. The correct implementation is demonstrated with the StreamWriter.Close
method, as shown in the following code. StreamWriter.Close delegates to TextWriter.Dispose for
deterministic garbage collection. TextWriter.Dispose is inherited by the StreamWriter class. The Close
method suppresses the finalizer, which is standard behavior of a deterministic method. Both the Close and
Dispose method are available on the StreamWriter class. You should clearly document any alternate method
for deterministic garbage collection.

.method public hidebysig virtual instance void


Close() cil managed
{
// Code size 14 (0xe)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: callvirt instance void System.IO.TextWriter::Dispose(bool)
IL_0007: ldarg.0
IL_0008: call void System.GC::SuppressFinalize(object)
IL_000d: ret
} // end of method StreamWriter::Close

Thread-Safe Dispose Method


The Dispose method is not implicitly thread-safe. As a public method, Dispose is callable for multiple
threads simultaneously. Thread synchronization is required for thread-safeness. The lock statement, as
demonstrated in the following code, is the convenient means of supporting simultaneous access to the
Dispose method.

public class ZClass: IDisposable {

public void Dispose() {


lock(this) {
}
}
}

Reusable Objects
The Disposable pattern accommodates reusable objects. Unless the object is nondisposed, it can be
recycled. Do not recycle an object implicitly. Automatically recycling an object on the assignment operator
or a function call is not recommended. Expose a method that explicitly recycles the object. There is no
convention for naming this method. However, an Open method is always a good choice. This method should
have the dual purpose of initializing instances created with a default constructor. Recyclable objects should
also expose a property that confirms the status of the object as alive or disposed.

The following code is a revision of the ReverseReader class, which was presented earlier in this chapter. This
version is recyclable. It has a default and one-argument constructor. The one-argument constructor
delegates to the Open method. You can call the Open method to initialize or recycle a ReverseReader
instance. The Active property returns the status of the object. If true, the object is active.

public class ReverseReader:IDisposable {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public ReverseReader() {
}

public ReverseReader(string filename) {


Open(filename);
}

public bool Open(string filename) {


if(file!=null) {
return false;
}
file=new StreamReader(filename);
return true;
}

public string ReadLine() {


if(file==null) {

throw new ObjectDisposedException(


"ReadLine object");
}
if(file.Peek()<0) {
return null;
}
string temp=file.ReadLine();
char [] tempArray=temp.ToCharArray();
Array.Reverse(tempArray);
return new string(tempArray);
}

public void Dispose() {


if(file==null) {
return;
}
else {
file.Close();
file=null;
}
}

public void Close() {


Dispose();
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

private StreamReader file=null;

public bool Active {


get {
return !(file==null);
}
}
}

Disposing Inner Objects

A disposable class should dispose the disposable fields contained in the type. Call the Dispose method of
those fields in the Dispose method of the class. After disposing, set the disposable fields to null. Of course,
the inner objects dispose the disposable objects they contain. In this way, the Dispose method is transitive.

The proper disposal of inner objects is shown in the following code:

public class ZClass: IDisposable{

public ZClass() {
inner=new YClass();
}

public void Dispose() {


Console.WriteLine("ZClass.Dispose");
inner.Dispose();

inner=null;
}

private YClass inner=null;

public class YClass: IDisposable{


public void Dispose() {
Console.WriteLine("YClass.Dispose");
}
}

An object should not dispose any object not fully within its control, which can cause some unwanted side
affects. In the following code, the _inner field is initialized with a property. The _inner field is a disposable
type. Two instances of the containing class are created. One is created before the using block, and the other
is created in the using statement. The _inner field of both objects is initialized to the same instance.
Therefore, neither object has full control of the object. When the using block is exited, the inner object is
disposed in the second object. However, the other object remains active. When the remaining active object
attempts to access the inner object, an exception is raised.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ZClass obj1=new ZClass();
obj1.Inner=new YClass();
using(ZClass obj2=new ZClass()) {
obj2.Inner=obj1.Inner;
}
obj1.MethodA(); // exception
obj1.Dispose();
obj1=null;
}
}

class ZClass: IDisposable{

public ZClass() {
}

public void Dispose() {


Console.WriteLine("ZClass.Dispose");
_inner.Dispose();
}

public void MethodA() {


Console.WriteLine("ZClass.MethodA");
_inner.MethodA();
}

public YClass Inner {


set {
_inner=value;
}
get {
return _inner;
}
}

private YClass _inner=null;


}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

class YClass: IDisposable{


public void Dispose() {
Console.WriteLine("YClass.Dispose");
disposed=true;
}

public void MethodA() {


if(disposed) {
throw new ObjectDisposedException(
"YClass disposed");
}
Console.WriteLine("YClass.MethodA");
}

private bool disposed=false;

}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Weak Reference
Weak references are one of my favorite features of the .NET Framework. A weak reference accords an object
less persistence than a strong reference. A strong reference is a conventional reference and created with the
new operator. As long as there is a strong reference pointing to the object, the object persists in memory. If
not, the object becomes a candidate for removal and is collected in a future garbage collection. Conversely,
a weak reference to an object is insufficient to retain that object in memory. A weak reference can be
collected as memory is needed. You must confirm that weakly referenced objects have not been collected
before use.

Weak references are not ideal for objects that contain information that is expensive to rehydrate. Information
read from a persistent source such as a file or data store is preferred. You can simply reread the file or
request the dataset again. Rehydrating a dataset can be light or heavy based on several factors, including
the location of the dataset.

The central type for establishing weak references is, appropriately, the WeakReference type. These are the
steps for creating and using a weak reference:

A weak reference usually starts life as a strong reference:

XNames objTemp = new XNames();

Create a WeakReference type. In the constructor, initialize the weak reference with the strong reference.
Afterward, set the strong reference to null. An outstanding strong reference prevents the weak reference from
controlling the lifetime of the object:

XNames objTemp = new XNames();


weaknames=new WeakReference(objTemp);
objTemp = null;

Before using the object, request a strong reference to the object from the weak reference.
WeakReference.Target returns a strong reference to the weak object. If WeakReference.Target is null, the
object has been collected and is no longer in memory. In this circumstance, the object needs to be
rehydrated:

if (weaknames.Target == null)
{
// do something
}

The following class reads a list of names from a file:

class XNames
{
public XNames()
{
StreamReader sr=new StreamReader("names.txt");
string temp = sr.ReadToEnd();
_Names = temp.Split('\n');
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

private string [] _Names;

public IEnumerator<string> GetEnumerator()


{
foreach(string name in _Names)
{
yield return name;
}
}
}

The preceding code is from the Weak application. It uses the XNames class to display the names from a file
in a list box. The Weak application is shown in Figure 14-6.

Figure 14-6: Weak application

In the Weak application, a weak reference is created and initiated with an instance of the XNames class.
The code in the Fill List button enumerates the names of the XNames instance to populate the list box.
Before using the instance, the status of the instance must be confirmed. Is it collected or not? The Apply
Pressure button applies memory pressure to the application that eventually forces the weakly referenced
object to be collected. When this occurs, the content in the list box is removed. You must then refill the list
box using the Fill List button.

This is the code from the form class of the Weak application that pertains to weak references:

public partial class Form1 : Form


{
public Form1()
{
InitializeComponent();
}
private void btnFill_Click(object sender, EventArgs e)
{
if (weaknames.Target == null)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

{
DialogResult result=MessageBox.Show(
"Rehydrate?",
"Names removed from memory.",
MessageBoxButtons.YesNo);
if (result == DialogResult.No)
{
return;
}
else
{
weaknames.Target = new XNames();
}
}
foreach(string name in (XNames)weaknames.Target)
{
lblNames.Items.Add(name);
}
}

private WeakReference weaknames;

private void Form1_Load(object sender, EventArgs e)


{
XNames objTemp = new XNames();
weaknames=new WeakReference(objTemp);
objTemp = null;
}

private void btnApply_Click(object sender, EventArgs e)


{
objs.Add(new ZClass());
if (weaknames.Target == null)
{
lblNames.Items.Clear();
}
}

List<ZClass> objs = new List<ZClass>();


}

internal class ZClass


{
public long[] array = new long[7500];
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Weak Reference Internals

Weak references are tracked in short weak reference and long weak reference tables. Weak references are
not created on the managed heap, but are entries in the short weak reference or long weak reference tables.
Both tables are initially empty.

Each entry in the short weak reference table is a reference to a managed object on the heap. When garbage
collection occurs, objects referenced in the short weak reference table that are not strongly rooted are
collectable. The related slot in the table is set to null. References to finalizable objects that are being
collected are moved from the finalization to the FReachable queue.

Entries in the long weak reference table are evaluated next. Long weak references are weak references that
track an object through finalization. This allows the resurrection of a weakly referenced object. Objects
referenced in the long weak reference table that are not strongly rooted are collectable.

Weak Reference Class

Table 14-1 lists the important members of the WeakReference class.


Table 14-1:
WeakReferen
ce Class

Me De
mb scr
er ipti
Na on
me

We Th
ak e
Ref on
ere e-a
nc rgu
e(o me
bje nt
ct co
tar nst
get ruc
) tor
initi
aliz
es
the
we
ak
ref
ere
nc
e
wit
h
the
tar
get
obj
ect
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 14-1:
WeakReferen
ce Class

Me De
mb scr
er ipti
Na on
me

We Th
ak e
Ref two
ere -ar
nc gu
e(o me
bje nt
ct co
tar nst
get ruc
, tor
bo initi
ol aliz
tra es
ck the
Re we
sur ak
rec ref
tio ere
n) nc
e
wit
h
the
tar
get
obj
ect
. If
tra
ck
Re
sur
rec
tio
n
is
tru
e,
the
obj
ect
is
als
o
tra
ck
ed
thr
ou
gh
fina
liza
tio
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 14-1:
WeakReferen
ce Class

Me De
mb scr
er ipti
Na on
me

IsA Thi
live s
is
a
pro
per
ty
an
d
get
s
wh
eth
er
or
not
the
tar
get
obj
ect
ha
s
be
en
coll
ect
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 14-1:
WeakReferen
ce Class

Me De
mb scr
er ipti
Na on
me

Tar Thi
get s
is
an
obj
ect
pro
per
ty
an
d
get
s
or
set
s
the
obj
ect
bei
ng
ref
ere
nc
ed.

Critical Finalization Objects

Conditions can prevent a finalizer from running, and critical cleanup code might not execute. Resource
leakage and other problems can occur when critical finalization code is abandoned. .NET Framework 2.0
introduces critical finalizable objects to ensure that critical finalizers run. The CLR is more diligent about
executing finalizers in critical finalizer objects. Conditions that can prevent a normal finalizer from running,
such as a forcible thread abort or an unload of the application domain, do not affect a critical finalizer. This is
especially an issue in environments that host the CLR, such as Microsoft SQL Server 2005. A CLR host can
asynchronously interrupt a managed application, which can strand important finalizers.

During garbage collection, critical finalizers run after the normal finalizers.

Critical finalizer objects are derived from the CriticalFinalizerObject, which is located in the System.Runtime
namespace. The finalizer runs uninterrupted in a Constrained Execution Region (CER).

Constrained Execution Region

CER is a region of reliable code that is guaranteed to run. Even an asynchronous exception will not prevent
the region from executing to completion. Within the CER, developers are constrained to certain actions. This
is a shortlist of some of the actions that should be avoided in a CER:
 Boxing
 Unsafe code
 Locks
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

 Serialization
 Calling unreliable code
 Actions likely to cause an asynchronous exception

In a CER, the CLR delays an asynchronous exception until the region is exited. The CLR performs a variety
of checks and does some preparation to ensure that code in the CER runs uninterrupted.

The RuntimeHelpers.PrepareConstrainedRegions static method places a subsequent catch, finally, or fault


handler in a constrained region. The RuntimeHelpers class is in the System .Runtime.CompilerServices
namespace. The PrepareConstrainRegions method call should immediately precede the try statement. The
code in the try block is not reliable and can be interrupted. However, the related handler is within the CER
and is uninterruptible.

Developers must make reliability assurances for code in a constrained region. The CLR does not strictly
enforce the reliability constraints within the CER. Instead, the CLR relies on developer commitment, which is
a reliability contract. Reliability contracts state the level of compliance for a method, class, or assembly. Set
a reliability contract with the ReliabilityContractAttribute. This attribute is found in the
System.Runtime.ConstrainedExecution namespace. The Reliability-ContractAttribute constructor has two
parameters. The first parameter is the ConsistencyGuarantee property, which indicates the potential scope
of corruption if an asynchronous exception occurs during execution. For example,
Consistency.MayCorruptAppDomain means that an asynchronous exception can leave the application
domain in an unreliable state. The second parameter is the Cer property, which is a completion guarantee for
code in a CER region. Cer.Success is the highest guarantee and promises that the code will successfully
complete when running in a CER, assuming valid input.

Here is an example of a CER region:

[ReliabilityContract(Consistency.WillNotCorruptState,
Cer.Success)]
class ZClass {

void MethodA() {
RuntimeHelpers.PrepareConstrainedRegions();
try {
}
finally {
// CER Region
}
}

Stephen Toub authored a detailed and informative article on CERs called "Keep Your Code Running with the
Reliability Features of the .NET Framework." It can be found at the following link:
http://msdn.microsoft.com/msdnmag/issues/05/10/reliability/default.aspx

Safe Handles
As a convenience, partial implementation of the CriticalFinalizerObject type is found in the
System.Runtime.InteropServices namespace. The implementation creates a critical finalizer, which contains
a CER. CriticalHandle, SafeHandle, SafeHandleMinusOneIsInvalid, and
Safe-HandleZeroOrMinusOneIsInvalid are derived from CriticalFinalizerObject and are adequate for most
purposes. These classes are found in the Microsoft.Win32.SafeHandles namespace. Safe-Handle
implements reference counting, whereas CriticalHandle does not support reference counting. Both classes
are essentially safe wrappers for kernel handles and ensure that kernel handles are properly closed in the
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

future. The classes are abstract and require minimal implementation in the derived type. The .NET
Framework class library (FCL) provides a complete implementation of the CriticalHandle and SafeHandle
classes in the Microsoft.Win32.SafeHandles namespace. SafeWaitHandle is one implementation. It is a
wrapper for a wait handle and indirectly extends the SafeHandle class.

In the following code, the PipeHandle class is a safe wrapper for a pipe handle. It also exposes the
CreatePipe and the CloseHandle application programming interfaces (APIs) using interoperability. Because
the method is called in a CER, a reliability contract is placed on the CloseHandle method. PipeHandle
derives from the SafeHandleMinusOneIsInvalid class for the behavior of a critical finalizer object. The finalizer
of the base class automatically calls the ReleaseHandle method. The ReleaseHandle of the derived type,
PipeHandle, also has a reliability contract.

In the AnonymousPipe constructor, two PipeHandle instances are initialized, which are a read and write
handle. The handle values are also displayed. The PipeHandle and AnonymousPipe classes are included in
the Pipe application found on the companion CD-ROM. In the sample code, the application domain hosting
the PipeHandle instances can be forcibly unloaded. Because the instances are critical finalizer objects, their
destructors are called despite the unloading of the application domain:

public sealed class PipeHandle :


SafeHandleMinusOneIsInvalid
{

private PipeHandle()
: base(true)
{

[ReliabilityContract(Consistency.WillNotCorruptState,
Cer.Success)]
protected override bool ReleaseHandle()
{
return CloseHandle(handle);
}

[DllImport("kernel32.dll")]
extern public static bool CreatePipe(
out PipeHandle hReadPipe,
out PipeHandle hWritePipe,
IntPtr securityAttributes,
int nSize);

[ReliabilityContract(Consistency.WillNotCorruptState,
Cer.Success)]
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr handle);

}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public class AnonymousPipe


{

public AnonymousPipe()
{

PipeHandle.CreatePipe(out readHandle, out writeHandle,


IntPtr.Zero, 10);
MessageBox.Show((readHandle.DangerousGetHandle())
.ToInt32().ToString());

MessageBox.Show((writeHandle.DangerousGetHandle())
.ToInt32().ToString());
}

private PipeHandle readHandle = null;


private PipeHandle writeHandle = null;
}

Managing Unmanaged Resources

Managed code often relies on unmanaged resources. The unmanaged resource is typically accessible
through a managed wrapper. The MyDevice program is an unmanaged application that emulates a hardware
device. DeviceWrapper is a managed wrapper for the MyDevice unmanaged resource. This is the code for the
DeviceWrapper class:

public sealed class MyDevice


{
static private int count = 0;

public MyDevice()
{
obj = new MyDeviceLib.DeviceClass();
++count;
}

private MyDeviceLib.DeviceClass obj;

public void Open()


{
obj.OpenDevice();
}

public void Close()


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

{
obj.CloseDevice();
}

public void Start()


{
obj.StartCommunicating();
}

public void Stop()


{
obj.StopCommunicating();
}

~MyDevice()
{
// resource released
--count;
}
}

Memory Pressure
The wrapper for an unhandled resource can hide the true memory cost of an object. Incorrect accounting of
unhandled memory in the managed environment can cause unexpected out of memory exceptions.

.NET 2.0 introduces memory pressure, which accounts for unmanaged memory in the managed
environment. This prevents a wrapper to an unmanaged resource from hiding an elephant in the closet.
Memory pressure forces garbage collection sooner, which collects unused instances of the wrapper class.
The wrapper releases the unmanaged resource to reduce the memory pressure on both managed and
unmanaged memory.

The GC.AddMemoryPressure method adds artificial memory pressure on the managed heap for an
unmanaged resource, whereas the GC.RemoveMemoryPressure method removes memory pressure. Both
methods should be integrated into the wrapper class of the unmanaged resource. Call AddMemoryPressure
and RemoveMemoryPressure in the constructor and Dispose method, respectively. Each instance of the
MyDevice unmanaged resource allocates 40,000 bytes of memory on the unmanaged heap. In the following
code, the constructor and destructor for the MyDevice wrapper now account for the unmanaged memory:

public MyDevice()
{
GC.AddMemoryPressure(40000);
obj = new MyDeviceLib.DeviceClass();
++count;
}

~MyDevice()
{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

GC.RemoveMemoryPressure(40000);
// resource released
--count;
}

Handles
Some native resources are available in limited quantities. Exhausting the resource can hang the application,
crash the environment, or cause other adverse reactions. The availability of a limited resource should be
tracked. When the resource is exhausted, corrective action should occur. Some limited kernel resources,
such as a window, are assigned handles. The HandleCollector class is introduced in .NET Framework 2.0 to
manage handles to limited kernel resources. Despite the name, the HandleCollector class is not limited to
tracking kernel handles. You can use the HandleCollector class to manage any resource that has limited
availability. The HandleCollector class is found in the System.Runtime.InteropServices namespace.

The HandleCollector class has a three-argument constructor that configures the important properties of the
type. The arguments are the name: initial threshold and maximum threshold. The initial threshold sets the
minimal requirement for starting garbage collection. The maximum threshold sets the limit where garbage
collection is forced. When the availability is exceeded, garbage collection is triggered. Hopefully, this will
collect managed wrappers that are holding unmanaged resources and replenish native resources. Using the
constructor, create a static instance of the HandleCollector in the managed wrapper of the unmanaged
resource. In the constructor, call HandleCollector.Add. In the finalizer, call HandleCollector.Remove.

The following code shows the MyDevice class revised for the HandleCollector class. The MyDevice
unmanaged resource supports an initial threshold of three simultaneous connections and a maximum of five.
You can test the effectiveness of the wrapper in the UseResource application by clicking the Connect button
and monitoring the message boxes.

public sealed class MyDevice


{
static private HandleCollector track=
new HandleCollector("devices", 3,5);

static private int count = 0;

public MyDevice()
{
GC.AddMemoryPressure(40000);
track.Add();
obj = new MyDeviceLib.DeviceClass();
++count;
MessageBox.Show("Device count: " + count.ToString());
}

private MyDeviceLib.DeviceClass obj;


public void Open()
{
obj.OpenDevice();
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public void Close()


{
obj.CloseDevice();
}

public void Start()


{
obj.StartCommunicating();
}

public void Stop()


{
obj.StopCommunicating();
}

~MyDevice()
{
GC.RemoveMemoryPressure(40000);

track.Remove();
// resource released
--count;
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

GC Class
Developers use the GC class as an interface to the GC in .NET. You can manipulate and monitor garbage
collection with the GC class. Some GC commands affect the normal operation of the garbage collection.
Garbage collection usefully performs best without developer interference. Table 14-2 lists the static members
of the GC class.
Table 14-2: GC Class

Member Name Description

MaxGeneration This property is an integer property and gets the maximum number of
generations.

AddMemoryPressure This method forces the GC to recognize memory allocations for unmanaged
resources.

Collect This method forces garbage collection on a specific generation. There are
two overloads of the method. The no-argument Collect performs garbage
collection for all the generations. The one-argument Collect has a parameter
that specifies the oldest generation to be collected.

CollectionCount This method returns the number of garbage collection cycles for the
specified generation.

GetGeneration This method returns the generation of the specified object.

GetTotalMemory This method returns the total number of bytes thought to be allocated for the
managed heap. You can wait on garbage collection and finalization by
setting the Boolean parameter to true.

KeepAlive This method keeps alive the specified object from the beginning of the
current routine to where the KeepAlive method is called.

RemoveMemoryPressure This method removes some of the memory pressure set aside for
unmanaged resources.

ReRegisterForFinalize This method reattaches a finalizer to a resurrected object.

SuppressFinalize This method suppresses future finalization of the specified object.

WaitForPendingFinalizers This method suspends the current thread until the Finalization queue is
empty.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Nonsecure Code
The final chapter, which is the next chapter, pertains to unsafe code, which is an ominous name. What
developer wants to purposely write unsafe code? In .NET, unsafe code really means potentially unsafe code,
which is code or memory that exists outside the normal controls of the CLR. For this reason, developers
should approach unsafe code with caution.

Developers have access to raw pointers in C#, which are called pinned pointers. They are Cstyle pointers.
You can use pointer operators, such as * and &, with these pointers. Pointers should be avoided because
they interrupt the normal operation of the GC. How-ever, not secure pointers are sometimes necessary. For
example, porting algorithms that rely heavily on pointers is one situation in which not secure pointers are
beneficial.

Managed developers must sometime call unmanaged routines. Although the breadth of the .NET FCL is
expanding quickly, there is considerable system behavior that still resides out-side its realm. In addition,
many third-party routines are not managed—particularly legacy applications. Finally, some code will never
be managed for performance or other reasons. Interoperability allows managed developers to build bridges
back to managed code. You can call unmanaged code from a managed routine. Conversely, you can call
managed code from unmanaged routines.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 15: Unsafe Code


Overview
Unsafe code can access unmanaged memory, which is outside the realm of the Common Language
Runtime (CLR). Conversely, safe code is limited to accessing the managed heap. The managed heap is
controlled by the CLR under the auspices of the garbage collector (GC). Code that addresses the managed
heap is intrinsically safer. The CLR automatically releases unused objects, performs type verification, and
conducts other checks on managed memory. Developers can focus on core application development instead
of administrative tasks such as memory management. For this reason, safe code improves user productivity
and satisfaction.

Pointers to unmanaged memory are available in unsafe code. Like unmanaged memory, pointers are also
outside the realm of the CLR. Pointers point to a fixed location in unmanaged memory, whereas reference
types point to a moveable location in managed memory. The CLR manages reference types, which includes
controlling the lifetime of objects and calling cleanup code. Developers do not delete memory allocated for
reference types and are not overly involved in the intricacies of memory management. In C and C++
application development, developers were preoccupied with memory management. Despite this, improper
management of pointers is a primary contributor to unsafe code in the unmanaged environment, including
memory leaks, access of invalid memory, deletion of pointers, and fence post errors. Abstracting the
nuances of pointer management and manipulation with reference types has made managed code
considerably safer. However, when needed, you can exempt yourself from secure code and access pointers
directly.

When is unsafe code appropriate? Not often. Unsafe code is provided within C# as the exception, not the
rule. There are specific circumstances in which unsafe code is recommended:
 Unmanaged code often relies heavily on pointers. When porting this sort of code to C#, unsafe
code is a possible solution. Most nontrivial C and C++ programmers heavily leverage pointers.
 Implementing a software algorithm, in which pointers are integral to the design, might necessitate
unsafe code.
 Calling an unmanaged function might require function pointers.
 Pointers might be required when working with binary memory resident data structures.
 Unmanaged pointers might improve performance and efficiencies in certain circumstances.

Code in an unmanaged module is also considered unsafe. Code in an unmanaged module is shielded from
the CLR. Therefore, no code verification, stack tracing, or other checking is performed on the unmanaged
code, which makes the code less safe.

Developers sometimes need to call unmanaged code from managed applications. Although the Microsoft
.NET Framework class library (FCL) contains most of the code needed for .NET application development, the
FCL umbrella does not encompass everything. You might need to call functions (APIs) in operating system
libraries for behavior outside the FCL. In addition, proprietary and vendor software might not be available as
managed code. Alternatively, you can call managed code from an unmanaged module, such as during a
callback. Managed code might also be exposed to unmanaged clients.

Platform invocation services (PInvoke) is the bridge between managed and unmanaged execution. The bridge
is bidirectional. From managed code, PInvoke is responsible for locating, loading, and executing a function in
an unmanaged module. Marshaling is the primary concern of cross-platform calls and the responsibility of
the Interop marshaler. Marshaling converts parameters and return types between unmanaged and managed
acceptable formats. Fortunately, marshaling is not always required, which avoids unnecessary overhead.
Certain types, such as blittable types, do not require transformation and are the same in managed and
unmanaged memory.

You can also build bridges between managed code and COM components, which contain unmanaged code.
The Runtime Callable Wrapper (RCW) helps managed code call COM components. The COM Callable
Wrapper (CCW) portrays a managed component as a COM component. This makes the managed
component indirectly accessible to COM clients. COM components are also available via PInvoke. However,
the CCW and RCW are more convenient and are the recommended solutions in most scenarios. COM
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

interoperability is not a topic for this book. COM Programming with Microsoft .NET, by John Paul Mueller and
Julian Templeman (Microsoft Press, 2003), is an excellent resource for additional information on COM
interoperability and .NET.

Unsafe code is also not trusted code. Code access security does not extend to unsafe code. Type
verification, which helps prevent buffer overrun attacks, is not performed. Code verification is not performed.
Therefore, the reliability of the code is undetermined. These are some of the reasons why unsafe code is not
trusted. Because it is not trusted, elevated permissions are required to call unsafe code from managed code.
Applications that rely on unsafe code might not execute successfully in every deployment situation and
should be thoroughly tested in all potential scenarios. Managed code requires the
SecurityPermission.UnmanagedCode permission to call unsafe code. The
SuppressUnmanagedCodeSecurityAttribute attribute disables the stack walk that confirms the
SecurityPermission.UnmanagedCode permission in callers. This attribute is a free pass for other managed
code to call unsafe code. It is a convenient option, but also dangerous.

Managed applications that include unsafe code must be compiled with the unsafe option. The C# compiler
option is simply /unsafe. In Microsoft Visual Studio 2005, this option is found in the project properties. The
project properties are accessible from Solution Explorer. Open the context menu on the project name and
choose the Properties menu item. In the Build window, choose the Allow unsafe code option, as shown in
Figure 15-1.

Figure 15-1: The Build window with the unsafe compiler option
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Unsafe Keyword
The unsafe keyword sets the perimeter of an unsafe context and prevents the inadvertent placement of
unsafe code. Code within the unsafe context can be unsafe, which allows unmanaged pointers to be
declared and used in expressions. The unsafe keyword can be applied to a class, struct, interface, or
delegate. When it is applied to a type, all the members of that type are also considered unsafe. You can
also apply the unsafe keyword to specific members of a type. If applied to a function member, the entire
function operates in the unsafe context.

In the following code, the ZStruct contains two fields that are pointers. Each is annotated with the unsafe
keyword.

public struct ZStruct {


public unsafe int *fielda;
public unsafe double *fieldb;
}

In this example, ZStruct is marked as unsafe. The unsafe context extends to the entire struct, which
includes the two fields. Both fields are unsafe.

public unsafe struct ZStruct {


public int *fielda;
public double *fieldb;
}

You can also create an unsafe block using the unsafe statement. All code encapsulated by the block is in
the unsafe context. The following code has an unsafe block and method. Within the unsafe block in the Main
method, MethodA is called and passed an int pointer as a parameter. MethodA is an unsafe method. It
assigns the int pointer to a byte pointer, which now points to the lower byte of the int value. The value at that
lower byte is returned from MethodA. For an int value of 296, MethodA returns 40.

public static void Main(){


int number=296;
byte b;
unsafe {
b=MethodA(&number);
}
Console.WriteLine(b);
}

public unsafe static byte MethodA(int *pI) {


byte *temp=(byte*) pI;

return *temp;
}

The unsafe status of a base class is not inherited by a derived class. Unless explicitly designated as unsafe,
a derived class is safe. In an unsafe context, the derived class can use unsafe members of the base class
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

that are accessible.

In the following code, a compile error occurs in the derived type. The fieldb member of YClass requires an
unsafe context, which is not inherited from the ZClass base class. Add the unsafe keyword explicitly to
fieldb, and the code will compile successfully.

public unsafe class ZClass {


protected int *fielda;
}

public class YClass: ZClass {


protected int *fieldb; // compile error
}

Pointers

Unsafe code is mostly about direct access to pointers, which point to a fixed location in memory. Because
the location is fixed, the pointer is reliable and can be used for dereferencing, pointer math, and other
traditional pointer type manipulation. Pointers are outside the control of the GC. The developer is responsible
for managing the lifetime of the pointer, if necessary.

C# does not automatically expose pointers. Exposing a pointer requires an unsafe context. In C#, pointers
are usually abstracted using references. The reference abstracts a pointer to memory on the managed heap.
That reference and related memory is managed by the GC and subject to relocation. A moveable pointer
underlies a reference, which is why references are not available for direct pointer manipulation. Pointer
manipulation on a moveable address would yield unreliable results.

This is the syntax for declaring a pointer:


 unmanagedtype* identifier;
 unmanagedtype* identifier=initializer;

You can declare multiple pointers in a single statement using comma delimiters. Notice that the syntax is
slightly different from C or C++ languages:

int *pA, pB, pC; // C++: int *pA, *pB, *pC;

The unmanaged types (a subset of managed types) are sbyte, byte, short, ushort, int, uint, long, ulong, char,
float, double, decimal, bool, and enum. Some managed types, such as string, are not included in this list.
You can create pointers to user-defined structs, assuming that they contain all unmanaged types as fields.
Pointer types do not inherit from System.Object, so they cannot be cast to or from System.Object.

Void pointers are allowed but dangerous. This is a typeless pointer that can emulate any other pointer type.
Any pointer type can be implicitly cast to a void pointer. This unpredictability makes void pointers
extraordinarily unsafe. Except for void pointers, pointers are moderately type-safe. Although you cannot
implicitly cast between different pointer types, explicitly casting between most pointer types is always
allowed. As expected, the following code would cause a compiler error because of the pointer mismatch.
This assignment could be forced with an explicit cast to another pointer type. In that circumstance, the
developer assumes responsibility for the safeness of the pointer assignment.

int val=5;
float* pA=&val;

You can initialize a pointer with the address of a value or with another pointer. In the following code, both
methods of initializing a pointer are shown:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public unsafe static void Main() {


int ival=5;
int *p1=&ival; // dereference
int *p2=p1; // pointer to pointer
}

In the preceding code, the asterisk (*) is used to declare a pointer. The ampersand (&) is used to
dereference a value. Table 15-1 describes the various symbols that are used with pointers.
Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Poi For
nte poi
r nte
de rs,
cla the
rati ast
on eri
(*) sk
sy
mb
ol
ha
s
two
pur
po
se
s.
Th
e
firs
t
is
to
de
cla
re
ne
w
poi
nte
r
vari
abl
es.

int
*pA;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Poi Th
nte e
r se
der co
efe nd
ren pur
ce po
(*) se
of
the
ast
eri
sk
is
to
der
efe
ren
ce
a
poi
nte
r.
Poi
nte
rs
poi
nt
to
an
ad
dre
ss
in
me
mo
ry.
Der
efe
ren
cin
g
a
poi
nte
r
ret
urn
s
the
val
ue
at
tha
t
ad
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Ad Th
dre e
ss am
of per
(&) sa
nd
sy
mb
ol
ret
urn
s
the
me
mo
ry
loc
ati
on
of
a
vari
abl
e,
whi
ch
is
a
fixe
d
val
ue.
Th
e
foll
owi
ng
co
de
ret
urn
s
the
me
mo
ry
ad
dre
ss
of
an
int.
It
is
us
ed
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Me Arr
mb ow
er not
ac ati
ce on
ss der
(->) efe
ren
ce
s
me
mb
ers
of
a
typ
e
fou
nd
at
a
me
mo
ry
loc
ati
on.
For
ex
am
ple
,
yo
u
ca
n
ac
ce
ss
me
mb
ers
of
a
str
uct
usi
ng
arr
ow
not
ati
on
an
d
a
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Poi A
nte poi
r nte
ele r
me ele
nt me
([]) nt
is
an
offs
et
fro
m
the
me
mo
ry
ad
dre
ss
of
a
poi
nte
r.
For
ex
am
ple
,
p[2
]
is
an
offs
et
of
two
.
Off
set
s
are
inc
re
me
nte
d
by
the
siz
e
of
the
poi
nte
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Poi A
nte poi
r nte
to r
a to
poi a
nte poi
r nte
(**) r
poi
nts
to
a
loc
ati
on
in
me
mo
ry
tha
t
co
nta
ins
the
ad
dre
ss
of
a
poi
nte
r.
Alt
ho
ug
h
rar
ely
us
eful
,
yo
u
ca
n
ext
en
d
the
ch
ain
of
poi
nte
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Poi Poi
nte nte
r r
ad ad
diti diti
on on
(+) ad
ds
the
siz
e
of
the
poi
nte
r
typ
e
to
the
me
mo
ry
loc
ati
on.

ZStru
ct
obj=n
ew
ZStru
ct(5)
;
int
*pA=&
obj.f
ielda
;
pA=pA
+2;
//
Add
eight
to
point
er
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Poi Poi
nte nte
r r
su su
btr btr
act act
ion ion
(-) su
btr
act
s
fro
m
the
poi
nte
r
the
siz
e
of
the
poi
nte
r
typ
e.

ZStru
ct
obj=n
ew
ZStru
ct(5)
;
int
*pA=&
obj.f
ielda
;
pA=pA
-3;
//
Subtr
act
twelv
e
from
point
er
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Poi Poi
nte nte
r r
inc inc
re re
me me
nt nt
(++ inc
) re
me
nts
the
poi
nte
r
by
the
siz
e
of
the
poi
nte
r
typ
e.

ZStru
ct
obj=n
ew
ZStru
ct(5)
;
int
*pA=&
obj.f
ielda
;
++pA;
//
incre
ment
point
er
by
four
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Poi Poi
nte nte
r r
de de
cre cre
me me
nt nt
(--) de
cre
me
nts
the
poi
nte
r
by
the
siz
e
of
the
poi
nte
r
typ
e.

ZStru
ct
obj=n
ew
ZStru
ct(5)
;
int
*pA=&
obj.f
ielda
;
--pA;
//
decre
ment
point
er
by
four
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-1:
Pointer
Symbols

Sy De
mb scr
ol ipti
on

Rel Th
ati e
on rel
al ati
sy on
mb al
ols op
era
tor
s,
su
ch
as
<
>
>=
<=
!=
==,
ca
n
be
us
ed
to
co
mp
are
poi
nte
rs.
Th
e
co
mp
ari
so
n
is
ba
se
d
on
me
mo
ry
loc
ati
on
an
d
not
poi
nte
r
typ
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Pointer Parameters and Return

A pointer is a legitimate variable. As such, a pointer can be used as a variable in most circumstances,
including as a parameter or return type. When used as a return type, ensure that the lifetime of the pointer is
the same as or exceeds that of the target. For example, do not return a pointer to a local variable from a
function—the local variable loses scope outside of the function and the pointer is then invalid.

In the following code, a pointer is used as both a parameter and return type. MethodA accepts a pointer as a
parameter. It then returns the same pointer. After the method call, both pB and pA point to the same location
in memory. They are aliases. Therefore, Console.WriteLine displays the same number when the values at
the pointers are displayed.

using System;

namespace Donis.CSharpBook{
public class Starter{
public unsafe static void Main() {
int val=5;
int *pA=&val;
int *pB;
pB=MethodA(pA);
Console.WriteLine("*pA = {0} | *pB = {0}",
*pA, *pB);
}

public unsafe static int *MethodA(int *pArg) {


*pArg+=15;
return pArg;
}
}

The ref or out modifiers can be applied to pointer parameters. Without the modifiers, the memory location is
passed by pointer. The pointer itself is passed by value on the stack. In the function, you can dereference
the pointer and change values at the memory location. These changes will persist even after the function
exits. However, changes to the pointer itself are discarded when the function exists. With the ref or out
modifier, a pointer parameter is passed by reference. In the function, the pointer can be changed directly.
Those changes continue to persist even after the function exits.

In the following code, both MethodA and MethodB have a pointer as a parameter. MethodA passes the
pointer by value, whereas MethodB passes the pointer by reference. In both methods, the pointer is
changed. The change is discarded when MethodA exists. When MethodB exits, the change persists.

using System;

namespace Donis.CSharpBook{
public class Starter{
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public unsafe static void Main() {


int val=5;
int *pA=&val;
Console.WriteLine("Original: {0}", (int) pA);
MethodA(pA);
Console.WriteLine("MethodA: {0}", (int) pA);
MethodB(ref pA);
Console.WriteLine("MethodB: {0}", (int) pA);
}

public unsafe static void MethodA(int *pArg) {


++pArg;
}

public unsafe static void MethodB(ref int *pArg) {


++pArg;
}

Fixed
What is wrong with the following code?

int [] numbers={1,2,3,4,5,6};
int *pI=numbers;

The problem is that the numbers variable is an array, which is a reference type. The code will not compile.
References are moveable types and cannot be converted to pointers. Because objects are moveable, you
cannot obtain a reliable pointer. Conversely, structs are value types and are placed on the stack and outside
of the control of the GC. Struct values have a fixed address and are easily converted into pointers. In the
preceding code, if the type were changed from an array to a struct, it would compile successfully. With the
fixed statement, you pin the location of a moveable type—at least temporarily. Pinning memory for an
extended period of time can interfere with efficient garbage collection.

Here is the code revised with the fixed statement. This code compiles successfully.

int [] numbers={1,2,3,4,5,6};
fixed(int *pI=numbers) {
// do something
}

The fixed statement pins memory for the span of a block. In the block, the memory is unmovable and is
exempt from garbage collection. You can access the pinned memory using the pointer declared or initialized
in the fixed statement, which is a read-only pointer. When the fixed block exits, the memory is unpinned.
Multiple pointers can be declared in the fixed statement. The pointers are delimited with commas, and only
the first pointer is prefixed with the asterisk (*):
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

int [] n1={1,2,3,4};
int [] n2={5,6,7,8};
int [] n3={9,10,11,12};
fixed(int *p1=n1, p2=n2, p3=n3) {
}

This is a more complete example of using the fixed statement:

using System;

namespace Donis.CSharpBook{
public class Starter{

private static int [] numbers={5,10,15,20,25,30};

public unsafe static void Main(){


int count=0;
Console.WriteLine(" Pointer Value\n");
fixed(int *pI=numbers) {
foreach(int a in numbers){
Console.WriteLine("{0} : {1}",
(int)(pI+count), *((int*)pI+count));
++count;
}
}
}
}
}

In the following code, ZClass is a class and a moveable type. The fixed statement makes the ZClass object
fixed in memory. A pointer to the integer member is then obtained.

public class Starter{


public unsafe static void Main() {
ZClass obj=new ZClass();
fixed(int *pA=&obj.fielda) {
}
}
}

public class ZClass {


public int fielda=5;
}

stackalloc
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The stackalloc command allocates memory dynamically on the stack instead of the heap. The lifetime of the
allocation is the duration of the current function, which provides another option for allocating memory at run
time. The stackalloc command must be used within an unsafe context. It can be used to initialize only local
variables. The CLR will detect buffer overruns caused by the stackalloc command.

Here is the syntax for stackalloc:


 type * stackalloc type[expression]

The stackalloc command returns an unmanaged type. The expression should evaluate to an integral value,
which is the number of elements to be allocated. The base pointer of the memory allocation is returned. This
memory is fixed and not available for garbage collection. It is automatically released at the end of the
function. These are the particulars of the stackalloc command.

The following code allocates 26 characters on the stack. The subsequent for loop assigns alphabetic
characters to each element. The final loop displays each character.

using System;

namespace Donis.CSharpBook{
public unsafe class Starter{
public static void Main(){
char* pChar=stackalloc char[26];
char* _pChar=pChar;
for(int count=0;count<26;++count) {
(*_pChar)=(char)(((int)('A'))+count);
++_pChar;
}
for(int count=0;count<26;++count) {
Console.Write(pChar[count]);
}
}
}
}

Platform Invoke

You can call unmanaged functions from managed code using platform invoke (PInvoke). Managed and
unmanaged memory might be laid out differently, which might require marshaling of parameters or the return
type. In .NET, marshaling is the responsibility of the Interop marshaler.

Interop Marshaler
The Interop marshaler is responsible for transferring data between managed and unmanaged memory. It
automatically transfers data that is similarly represented in managed and unmanaged environments. For
example, integers are identically formatted in both environments and automatically marshaled between
managed and unmanaged environments. Types that are the same in both environments are called blittable
types. Nonblittable types, such as strings, are managed types without an equivalent unmanaged type and
must be marshaled. The Interop marshaler assigns a default unmanaged type for many nonblittable types. In
addition, developers can explicitly marshal nonblittable types to specific unmanaged types with the
MarshalAsAttribute type.

DllImport
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The DllImportAttribute imports a function exported from an unmanaged library, and the unmanaged library
must export a function. DllImportAttribute is in the System.Runtime .InteropServices namespace.
DllImportAttribute has several options that configure the managed environment to import the function. The
library is dynamically loaded, and the function pointer is initialized at run time. Because the attribute is
evaluated at run time, most configuration errors are not found at compile time; they are found later.

This is the syntax of the DllImportAttribute:


 [DllImport(options)] accessibility static extern returntype functionname(parameters)

Options are used to configure the import. The name of the library is the only required option. The name of the
library should include the fully qualified path if it is not found in the path environment variable. Accessibility is
the visibility of the function, such as public or protected. Imported functions must be static and extern. The
remainder is the managed signature of the function.

The following code imports three functions to display the vertical and horizontal size of the screen. GetDC,
GetDeviceCaps, and ReleaseHandle are Microsoft Win32 APIs. The imported functions are configured and
exposed in the API class, which is a static class.

using System;
using System.Runtime.InteropServices;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
IntPtr hDC=API.GetDC(IntPtr.Zero);
int v=API.GetDeviceCaps(hDC, API.HORZRES);
Console.WriteLine("Vertical size of window {0}mm.", v);
int h=API.GetDeviceCaps(hDC, API.HORZRES);
Console.WriteLine("Horizontal size of window {0}mm.", h);
int resp=API.ReleaseDC(IntPtr.Zero, hDC);
if(resp!=1) {
Console.WriteLine("Error releasing hdc");
}
}
}

public static class API {


[DllImport("user32.dll")] public static extern

IntPtr GetDC(IntPtr hWnd);

[DllImport("user32.dll")] public static extern


int ReleaseDC(IntPtr hWnd, IntPtr hDC);

[DllImport("gdi32.dll")]public static extern


int GetDeviceCaps(IntPtr hDC, int nIndex);

public const int HORZSIZE=4; // horizontal size in pixels


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public const int VERTSIZE=6; // vertical size in pixels


public const int HORZRES=8; // horizontal size in millimeters
public const int VERTRES=10; // vertical size in millimeters
}
}

In the preceding code, the name of the library was the option used. There are several other options, which
are described in the following sections.

EntryPoint This option explicitly names the imported function. Without this option, the name is implied from
the managed function signature. When the imported name is ambiguous, the EntryPoint option is necessary.
You can then specify a different name for the entry point and the managed function.

In the following code, MessageBox is being imported. However, the managed name for the function is
ShowMessage.

using System;
using System.Runtime.InteropServices;

namespace Donis.CSharpBook{
public class Starter{
public static void Main() {
string caption="Visual C# 2005";
string text="Hello, world!";
API.ShowMessage(0, text, caption, 0);
}
}

public class API {


[DllImport("user32.dll", EntryPoint="MessageBox")]
public static extern int ShowMessage(int hWnd,
string text, string caption, uint type);
}
}

CallingConvention This option sets the calling convention of the function. The default calling convention is
Winapi, which maps to the standard calling convention in the Win32 environment. The calling convention is
set with the CallingConvention enumeration. Table 15-2 lists the members of the enumeration.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-2:
CallingConve
ntion
Enumeration

Me De
mb scr
er ipti
on

Cd Th
ecl e
call
er
re
mo
ves
the
par
am
ete
rs
fro
m
the
sta
ck,
whi
ch
is
the
call
ing
co
nve
nti
on
for
fun
cti
on
s
tha
t
hav
e
a
vari
abl
e-l
en
gth
arg
um
ent
list
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-2:
CallingConve
ntion
Enumeration

Me De
mb scr
er ipti
on

Fa Thi
stC s
all call
ing
co
nve
nti
on
is
not
su
pp
ort
ed.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-2:
CallingConve
ntion
Enumeration

Me De
mb scr
er ipti
on

Std Th
Cal e
l call
ed
me
tho
d
re
mo
ves
the
par
am
ete
rs
fro
m
the
sta
ck.
Thi
s
call
ing
co
nve
nti
on
is
co
m
mo
nly
us
ed
for
AP
Is
an
d
is
the
def
aul
t
for
call
ing
un
ma
na
ge
d
fun
cti
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-2:
CallingConve
ntion
Enumeration

Me De
mb scr
er ipti
on

Thi Th
sC e
all firs
t
par
am
ete
r
of
the
fun
cti
on
is
the
thi
s
poi
nte
r
foll
ow
ed
by
the
co
nve
nti
on
al
par
am
ete
rs.
Th
e
thi
s
poi
nte
r
is
ca
ch
ed
in
the
EC
X
reg
ist
er
an
d
us
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-2:
CallingConve
ntion
Enumeration

Me De
mb scr
er ipti
on

Wi Def
nA aul
pi t
call
ing
co
nve
nti
on
of
the
cur
ren
t
pla
tfor
m.
For
Wi
n3
2
env
iro
nm
ent
,
thi
s
is
the
Std
Cal
l
call
ing
co
nve
nti
on.
For
Wi
nd
ow
s
CE
.N
ET,
CD
ecl
is
the
def
aul
t.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The following code imports the printf function, which is found in the C Runtime Library. The printf function
accepts a variable number of parameters and supports the CDecl calling convention.

using System;
using System.Runtime.InteropServices;

namespace Donis.CSharpBook{
public class Starter{
public static void Main() {
int val1=5, val2=10;
API.printf("%d+%d=%d", val1, val2, val1+val2);
}
}

public class API {


[DllImport("msvcrt.dll", CharSet=CharSet.Ansi,
CallingConvention=CallingConvention.Cdecl)]
public static extern int printf(string formatspecifier,
int lhs, int rhs, int total);
}

ExactSpelling This option stipulates that the exact spelling of the function name is used to resolve the
symbol. Names are not always what they seem. For example, the function names of many Win32 APIs are
actually macros that map to the real API, which is an A or W suffixed method. The A version is the ANSI
version, whereas the W (wide) version is the Unicode version of the function. The ANSI versus Unicode
extrapolation pertains mostly to Win32 APIs that have string parameters. For example, the supposed
CreateWindow API is a macro that maps to either the CreateWindowW or CreateWindowA API. For the
DllImportAttribute, the version selected is determined in the CharSet option. If ExactSpelling is false, the
function name is treated as the actual name and not translated. The default is false.

The following code imports the GetModuleHandleW function specifically. ExactSpelling is true to prevent
mapping to another name.

using System;
using System.Runtime.InteropServices;

namespace Donis.CSharpBook{
public class Starter{
public static void Main() {
int hProcess=API.GetModuleHandleW(null);
}
}

public class API {


[DllImport("kernel32.dll", ExactSpelling=true)]
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static extern int GetModuleHandleW(string filename);


}

PreserveSig This option preserves the signature of the method when resolving the symbol. COM functions
usually return an HRESULT, which is the error status of the call. The real return is the parameter decorated
with the [out, retval] Interface Definition Language (IDL) attribute. In managed code, the HRESULT is
consumed and the [out,retval] parameter is the return. To resolve a COM function, that managed signature
cannot be preserved; it should be mapped to a COM signature. Conversely, the signature of non-COM
functions should be preserved. PreserveSig defaults to true.

The following code demonstrates the PreserveSig option with a fictitious COM function:

public class API {


[DllImport("ole32.dll", PreserveSig=false)]
public static extern int SomeFunction ();
}

The signature is not preserved and would become the following:

HRESULT SomeFunction([out, retval] int param)

SetLastError This option requests that the CLR cache the error code of the named Win32 API. Most Win32
APIs return false if the function fails. False is minimally descriptive, so developers can call GetLastError for
an integer error code. GetLastError must be called immediately after the failed API; if not, the next API might
reset the error code. In managed code, call Marshal.GetLastWin32Error to retrieve the error code. The
Marshal type is in the System.Runtime .InteropServices namespace. SetLastError defaults to false.

In the following code, CreateDirectory and FormatMessage are imported in the API class. CreateDirectory
creates a file directory; FormatMessage converts a Win32 error code into a user-friendly message. For
CreateDirectory, the SetLastError option is set to true. In Main, CreateDirectory is called with an invalid path.
The "c*" drive is probably an incorrect drive on most computers. The resulting error code is stored in the resp
variable, which is then converted into a message in the FormatMessage API. FormatMessage returns the
user-friendly messages as an out parameter.

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace Donis.CSharpBook{
public class Starter{
public static void Main() {
bool resp=API.CreateDirectory(@"c*:\file.txt",
IntPtr.Zero);
if(resp==false) {
StringBuilder message;
int errorcode=Marshal.GetLastWin32Error();
API.FormatMessage(
API.FORMAT_MESSAGE_ALLOCATE_BUFFER |
API.FORMAT_MESSAGE_FROM_SYSTEM |
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

API.FORMAT_MESSAGE_IGNORE_INSERTS,
IntPtr.Zero, errorcode,
0, out message, 0, IntPtr.Zero);
Console.WriteLine(message);
}
}
}

public class API {


[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CreateDirectory(
string lpPathName, IntPtr lpSecurityAttributes);

[DllImport("kernel32.dll", SetLastError=false)]
public static extern System.Int32 FormatMessage(
System.Int32 dwFlags,
IntPtr lpSource,
System.Int32 dwMessageId,
System.Int32 dwLanguageId,
out StringBuilder lpBuffer,
System.Int32 nSize,
IntPtr va_list);

public const int FORMAT_MESSAGE_ALLOCATE_BUFFER=256;


public const int FORMAT_MESSAGE_IGNORE_INSERTS=512;
public const int FORMAT_MESSAGE_FROM_STRING=1024;
public const int FORMAT_MESSAGE_FROM_HMODULE=2048;
public const int FORMAT_MESSAGE_FROM_SYSTEM=4096;
public const int FORMAT_MESSAGE_ARGUMENT_ARRAY=8192;
public const int FORMAT_MESSAGE_MAX_WIDTH_MASK=255;
}
}

CharSet
This option indicates the proper interpretation of strings in unmanaged memory, which can affect the
ExactSpelling option. CharSet is also an enumeration with three members. The default is CharSet.Ansi. Table
15-3 lists the members of the CharSet enumeration.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-3:
CharSet
Enumeration

Va De
lue scr
ipti
on

Ch Stri
arS ng
et. s
An sh
si oul
d
be
ma
rsh
ale
d
as
AN
SI.

Ch Stri
arS ng
et. s
Uni sh
co oul
de d
be
ma
rsh
ale
d
as
Uni
co
de.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-3:
CharSet
Enumeration

Va De
lue scr
ipti
on

Ch Th
arS e
et. ap
Aut pro
o pri
ate
co
nve
rsi
on
is
de
cid
ed
at
run
tim
e
de
pe
ndi
ng
on
the
cur
ren
t
pla
tfor
m.

The following code marshals string for unmanaged memory as ANSI. The ExactSpelling option defaults to
false, and the GetModuleHandleA API is called.

using System;
using System.Runtime.InteropServices;

namespace Donis.CSharpBook{
public class Starter{
public static void Main() {
int hProcess=API.GetModuleHandle(null);
}
}

public class API {


[DllImport("kernel32.dll", CharSet=CharSet.Ansi)]
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static extern int GetModuleHandle(string filename);


}
}

BestFitMapping This option affects the Unicode-to-ANSI mapping of text characters passed from managed
to unmanaged functions running in the Windows 98 or Windows Me environment. If true, best fit mapping is
enabled. When there is not a direct character match, the Unicode character is mapped to the closest match
in the ANSI code page. If no match is available, the Unicode character is mapped to a "?" character. The
default is true.

ThrowOnUnmappableChar The ThrowOnUnmappableChar option can request an exception when an


unmappable character is found in the Unicode-to-ANSI translation for Windows 98 and Windows Me. If true,
an exception is raised when a Unicode character cannot be mapped to ANSI, and the character is converted
to a "?" character. If false, no exception is raised. See the BestFitMapping option for additional details on
Unicode-to-ANSI mapping.

Blittable Types
Blittable types are identically represented in managed and unmanaged memory. Therefore, no conversion is
necessary from the Interop marshaler when marshaling between managed and unmanaged environments.
Because conversion can be expensive, blittable types are more efficient than nonblittable types. For this
reason, when possible, parameters and return types should be blittable types, which include System.Byte,
System.SByte, System.Int16, System.UInt16, System.Int32, System.UInt32, System.Int64, System.IntPtr,
System.UIntPtr, System.Single, and System.Double. Vectors of blittable types are also considered blittable.
Formatted value types that contain only blittable types are also considered blittable.

Nonblittable types have different representation in managed and unmanaged memory. Some nonblittable
types are automatically converted by the Interop marshaler, whereas others require explicit marshaling.
Strings and user-defined classes are examples of nonblittable types. A managed string can be marshaled as
a variety of unmanaged strings: LPSTR, LPTSTR, LPWSTR, and so on. Classes are nonblittable unless
formatted. A formatted class marshaled as a formatted value type is blittable.

Formatted Type
A formatted type is a user-defined type in which the memory layout of the members is explicitly specified.
Formatted types are prefixed with the StructLayoutAttribute, which sets the layout of the members as
described in the LayoutKind enumeration. Table 15-4 lists the members of the LayoutKind enumeration.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-4:
LayoutKind
Enumeration

Va De
lue scr
ipti
on

Lay Th
out e
Kin CL
d.A R
uto set
s
the
loc
ati
on
of
me
mb
ers
in
un
ma
na
ge
d
me
mo
ry.
Th
e
typ
e
ca
nn
ot
be
ex
po
se
d
to
un
ma
na
ge
d
co
de.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-4:
LayoutKind
Enumeration

Va De
lue scr
ipti
on

Lay Me
out mb
Kin ers
d.S are
eq sto
ue red
nti in
al co
nti
gu
ou
s
(se
qu
ent
ial)
an
d
tex
tua
l
ord
er
in
un
ma
na
ge
d
me
mo
ry.
If
de
sir
ed,
set
pa
cki
ng
wit
h
the
Str
uct
Lay
out
Att
rib
ute
.Pa
ck
opt
ion
.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-4:
LayoutKind
Enumeration

Va De
lue scr
ipti
on

Lay Thi
out s
Kin val
d.E ue
xpli allo
cit ws
the
dev
elo
per
to
sti
pul
ate
the
ord
er
of
the
fiel
ds
in
me
mo
ry
usi
ng
Fie
ldO
ffs
etA
ttri
but
e.
Thi
s
val
ue
is
us
eful
for
rep
res
ent
ing
a
C
or
C+
+
uni
on
typ
e
in
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

In the following code, the API class contains the GetWindowRect unmanaged API. This function returns the
location of the client area in the screen. The parameters of GetWindowRect are a window handle and a
pointer to a Rect structure, which is also defined in the API class. The Rect structure, which is initialized
inside the function, is a formatted value type and is blittable. By default, value types are passed by value. To
pass by pointer, the out modifier is assigned to the Rect parameter.

public class API


{
[DllImport("user32.dll")]

public static extern bool GetWindowRect(


IntPtr hWnd,
out Rect windowRect);

[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
}

Here is the code that uses the GetWindowRect API and the Rect structure:

API.Rect client = new API.Rect();


API.GetWindowRect(this.Handle, out client);
string temp=string.Format("Left {0} : Top {1} : "+
"Right {2} : Bottom {3}", client.left,
client.top, client.right, client.bottom);
MessageBox.Show(temp);

The following code is a version of the API class that defines a Rect class instead of a structure. Because the
Rect class has the StructLayout attribute, it is a formatted type. Classes are passed by reference by default.
The out modifier required for a structure is not necessary for a class.

class API2
{
[DllImport("user32.dll")]
public static extern bool GetWindowRect(
IntPtr hWnd,
Rect windowRect);

[StructLayout(LayoutKind.Sequential)]
public class Rect
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

{
public int left;
public int top;
public int right;
public int bottom;
}
}

This is the code to call the GetWindowRect API using the Rect class:

API2.Rect client = new API2.Rect();


API2.GetWindowRect(this.Handle, client);
string temp = string.Format("Left {0} : Top {1} : " +
"Right {2} : Bottom {3}", client.left,
client.top, client.right, client.bottom);
MessageBox.Show(temp);

Unions are fairly common in C and C++ code. A union is a type in which the members share the same
memory location. This preserves memory by overlaying data in shared memory. C# does not offer a union
type. In managed code, emulate a union in unmanaged memory with the LayoutKind.Explicit option of
StructLayoutAttribute. Set each field of the union to the same offset, as shown in the following code:

[StructLayout(LayoutKind.Explicit)]
struct ZStruct {
[FieldOffset(0)] int fielda;
[FieldOffset(0)] short fieldb;
[FieldOffset(0)] bool fieldc;
}

Directional Attributes
Directional attributes explicitly control the direction of marshaling. Parameters can be assigned InAttribute,
OutAttribute, or both attributes to affect marshaling. This is equivalent to [in], [out], and [in,out] of the IDL.
InAttribute and OutAttribute are also represented by keywords in C#. Table 15-5 lists the attributes and
related keywords.
Table 15-5:
Directional
Attributes and C#
Keywords

Ke Att ID
yw rib L
or ute
d

Not InA [in]


ava ttri
ilab but
le e
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-5:
Directional
Attributes and C#
Keywords

Ke Att ID
yw rib L
or ute
d

Ref InA [in,


ttri out
but ]
e
an
d
Ou
tAt
trib
ute

Ou Ou [ou
t tAt t]
trib
ute

The default directional attribute depends on the type of parameter and any modifiers.

StringBuilder
Strings are immutable and dynamically sized. An unmanaged API might require a fixed-length and modifiable
string. In addition, some unmanaged APIs initialize the string with memory allocated at run time. A string
type should not be used in these circumstances. Instead, use the StringBuilder class, which is found in the
System.Text namespace. StringBuilders are fixed-length and not immutable. Furthermore, you can initialize
the StringBuilder with memory created in the unmanaged API.

In the following code, the GetWindowText unmanaged API is imported twice. (This code, which is from the
GetWindowText application, is included on the CD-ROM for this book.) GetWindowText retrieves the text
from the specified window. For an overlapped window, this is text from the title bar. The second parameter of
GetWindowText is a string, which is initialized with the window text during the function call. The first version
of GetWindowText in the API class has a string parameter, whereas the version in the API2 class has a
StringBuilder parameter. The GetWindowText application is a Windows Forms application that has two
buttons. The first button calls API.GetWindowText. The second button calls API2.GetWindowText.

Because of the string parameter in API.GetWindowText, an exception is raised because the API attempts to
change that parameter. The second button invokes API2.GetWindowText successfully.

public class API


{
[DllImport("user32.dll")]
public static extern int GetWindowText(
IntPtr hWnd, ref string lpString, int nMaxCount);
}

public class API2


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

{
[DllImport("user32.dll")]
public static extern int GetWindowText(
IntPtr hWnd, StringBuilder lpString, int nMaxCount);
}

This is the code from the button-click handlers of the form:

private void btnGetText_Click(object sender, EventArgs e)


{
string windowtext=null;
API.GetWindowText(this.Handle, ref windowtext,
10);
MessageBox.Show(windowtext);
}

private void btnGetText2_Click(object sender, EventArgs e)


{
StringBuilder windowtext=new StringBuilder();
API2.GetWindowText(this.Handle, windowtext,
25);
MessageBox.Show(windowtext.ToString());
}

Unmanaged Callbacks
Some unmanaged APIs accept a callback as a parameter, which is a function pointer. The API invokes the
function pointer to call a function in the managed caller. Callbacks are typically used for iteration. For
example, the EnumWindows unmanaged API uses a callback to iterate top-level window handles.

.NET abstracts function pointers with delegates, which are type-safe and have a specific signature. In the
managed signature, substitute a delegate for the callback parameter of the unmanaged signature.

These are the steps to implement a callback for an unmanaged function:


1. Find the unmanaged signature of the callback function.
2. Define a matching managed signature for the callback function.
3. Implement a function to be used as the callback. The function should contain the response to the
callback.
4. Create a delegate, which is initialized with the callback function.
5. Invoke the unmanaged API using the delegate for the callback parameter.

The following code imports the EnumWindows unmanaged API. The first parameter of EnumWindows is a
callback. EnumWindows enumerates top-level windows. The callback function is called at each iteration and
is given the current window handle. In this code, APICallback is a delegate and provides a managed
signature for the callback.

class API
{
[DllImport("user32.dll")]
public static extern bool EnumWindows(
APICallback lpEnumFunc,
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

System.Int32 lParam);

public delegate bool APICallback(int hWnd, int lParam);


}

EnumWindows is called in the click handler of a Windows Forms application, where GetWindowHandle is
the callback function. GetWindowHandle is called for each iterated window handle. The function adds each
window handle to a list box:

private void btnHandle_Click(object sender, EventArgs e)


{
API.EnumWindows(new API.APICallback(GetWindowHandle), 0);
}

bool GetWindowHandle(int hWnd, int lParam)


{
string temp = string.Format("{0:0000000}", hWnd);
listBox1.Items.Add(temp);
return true;
}

Explicit Marshaling
Explicit marshaling is sometimes required to convert nonblittable parameters and fields, and returns types to
proper unmanaged types. Marshaling is invaluable for strings, which have several possible representations in
unmanaged memory. Strings default to LPSTR. Use the MarshalAsAttribute to explicitly marshal a managed
type as a specific unmanaged type. The UnmanagedType enumeration defines the unmanaged types
available to the MarshalAsAttribute. Table 15-6 lists the members of the UnmanagedType enumeration.
Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

An Le
siB ngt
Str h-p
refi
xe
d
AN
SI
stri
ng
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

As Dy
An na
y mi
c
typ
e
for
whi
ch
the
typ
e
of
the
val
ue
is
set
at
run
tim
e

Bo Fo
ol ur-
byt
e
Bo
ole
an
val
ue

BS Le
tr ngt
h-p
refi
xe
d
Uni
co
de
stri
ng
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

By Ma
Val rsh
Arr als
ay an
arr
ay
by
val
ue;
Siz
eC
on
st
set
s
the
nu
mb
er
of
ele
me
nts

By Inli
Val ne
TS fixe
tr d-l
en
gth
ch
ara
cte
r
arr
ay
tha
t
is
a
me
mb
er
of
a
str
uct
ure
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

Cur CO
ren M
cy cur
ren
cy
typ
e

Cu A
sto cu
m sto
Ma m
rsh ma
ale rsh
r ale
r
to
be
us
ed
wit
h
Ma
rsh
alA
sAt
trib
ute
.M
ars
hal
Ty
pe
or
Ma
rsh
alA
sAt
trib
ute
.M
ars
hal
Ty
pe
Ref
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

Err HR
or ES
UL
T

Fu C-s
nct tyl
ion e
Ptr fun
cti
on
poi
nte
r

I1 On
e-b
yte
int
eg
er

I2 Tw
o-b
yte
int
eg
er

I4 Fo
ur-
byt
e
int
eg
er

I8 Eig
ht-
byt
e
int
eg
er
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

IDi IDi
sp sp
atc atc
h h
poi
nte
r
for
CO
M

Int CO
erf M
ac int
e erf
ac
e
poi
nte
r

IUn IUn
kn kn
ow ow
n n
int
erf
ac
e
poi
nte
r
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

LP Poi
Arr nte
ay r
to
the
firs
t
ele
me
nt
of
an
un
ma
na
ge
d
arr
ay

LP Nul
Str l-te
rmi
nat
ed
AN
SI
stri
ng

LP Poi
Str nte
uct r
to
an
un
ma
na
ge
d
str
uct
ure
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

LP Pla
TS tfor
tr m-
de
pe
nd
ent
stri
ng

LP Uni
W co
Str de
stri
ng

R4 Fo
ur-
byt
e
floa
tin
g
poi
nt
nu
mb
er

R8 Eig
ht-
byt
e
floa
tin
g
poi
nt
nu
mb
er
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

Saf Saf
eAr e
ray arr
ay
in
whi
ch
the
typ
e,
ran
k,
an
d
bo
un
ds
are
defi
ne
d

Str Ma
uct rsh
als
for
ma
tte
d
val
ue
an
d
ref
ere
nc
e
typ
es
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

Sy Pla
sIn tfor
t m-
de
pe
nd
ent
int
eg
er
(32
bit
s
in
Wi
n3
2
env
iro
nm
ent
)

Sy Pla
sUI tfor
nt m-
de
pe
nd
ent
un
sig
ne
d
int
eg
er
(32
bit
s
in
Wi
n3
2
env
iro
nm
ent
)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

TB Le
Str ngt
h-p
refi
xe
d,
pla
tfor
m-
de
pe
nd
ent
stri
ng

U1 On
e-b
yte
un
sig
ne
d
int
eg
er

U2 Tw
o-b
yte
un
sig
ne
d
int
eg
er

U4 Fo
ur-
byt
e
un
sig
ne
d
int
eg
er
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-6:
UnmanagedT
ype
Enumeration

Me De
mb scr
er ipti
on

U8 Eig
ht-
byt
e
un
sig
ne
d
int
eg
er

Var Tw
ian o-b
tBo yte
ol VA
RI
AN
T_
BO
OL
typ
e

VB Mi
By cro
Ref sof
Str t
Vis
ual
Ba
sic
-sp
ecif
ic

GetVersionEx is imported in the following code. The function is called in Main to obtain information on the
current operating system. GetVersionEx has a single parameter, which is a pointer to an OSVERSIONINFO
structure. The last field in the structure is szCSDVersion, which is a universally unique identifier (UUID). A
UUID is a 128-byte array. The MarshalAs attribute marshals the field as a 128-character array. Each
character is one byte long.

using System;
using System.Runtime.InteropServices;

namespace Donis.CSharpBook{

public class Starter{


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public static void Main() {


API.OSVERSIONINFO info=new API.OSVERSIONINFO();
info.dwOSVersionInfoSize=Marshal.SizeOf(info);
bool resp=API.GetVersionEx(ref info);
if(resp==false) {
Console.WriteLine("GetVersion failed");
}
Console.WriteLine("{0}.{1}.{2}",
info.dwMajorVersion,
info.dwMinorVersion,
info.dwBuildNumber);
}
}

public class API {

[DllImport("kernel32.dll")] public static extern


bool GetVersionEx(ref OSVERSIONINFO lpVersionInfo);

[StructLayout(LayoutKind.Sequential)]
public struct OSVERSIONINFO {
public System.Int32 dwOSVersionInfoSize;
public System.Int32 dwMajorVersion;
public System.Int32 dwMinorVersion;
public System.Int32 dwBuildNumber;
public System.Int32 dwPlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
public String szCSDVersion;

}
}

Fixed-Size Buffers
In the previous code, the MarshalAs attribute defined a fixed-size field of 128 characters or bytes. As an
alternative to the MarshalAs attribute, C# 2.0 introduces fixed-size buffers using the fixed keyword. The
primary purpose of this keyword is to embed aggregate types, such as an array, in a struct. Fixed-size
buffers are accepted in structs but not in classes.

There are several rules for using fixed-size buffers:


 Fixed-size buffers are available only in unsafe context.
 Fixed-size buffers can represent only one-dimensional arrays (vectors).
 The array must have a specific length.
 Fixed-size buffers are allowed only in struct types.
 Fixed-sized buffers are limited to bool, byte, char, short, int, long, sbyte, ushort, uint, ulong, float,
or double types.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

This is the syntax of the fixed-sized buffer:


 attributes accessibility modifier fixed type identifier [expression]

The following code rewrites the OSVERSIONINFO structure that used the MarshalAs attribute. This version
uses the fixed keyword for the szCSDVersion field.

public class API {


[StructLayout(LayoutKind.Sequential)]
unsafe public struct OSVERSIONINFO {
public System.Int32 dwOSVersionInfoSize;
public System.Int32 dwMajorVersion;
public System.Int32 dwMinorVersion;
public System.Int32 dwBuildNumber;
public System.Int32 dwPlatformId;
public fixed char szCSDVersion[128];
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Summary
Although pointers are not normally available in C#, developers can choose to use pointers at their discretion.
Pointers are available in the context of unsafe code, which requires the unsafe keyword. You can create
pointers to unmanaged types, such as the int, float, and char types. In addition, unsafe code must be
compiled with the unsafe compiler option.

You cannot create pointers to moveable memory. Managed memory is moveable and managed by the
garbage collector (GC). The fixed statement pins managed memory within a block. Pinned memory is fixed.
While pinned, memory is not accessible to the GC.

The DllImportAttribute, which describes an unmanaged function that is exported from a library, has various
options to configure the importing of a function. The Interop marshaler marshals parameters and returns
values between managed and unmanaged memory during the function call. Blittable types do not require
conversion. Nonblittable types require conversion to unmanaged memory. Developers can explicitly marshal
nonblittable types using the MarshalAs attribute.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Appendix A: Operator Overloading


Overview
Developers add operator overloading to user-defined types to describe how that type works with common
operators. A feature of built-in types is the automatic support of most operators. Built-in types, such as int,
float, and long-value types, behave intuitively with mathematical, logical, and conditional operators. As
expected, the plus, minus, and multiply operators implicitly perform addition, subtraction, and multiplication
when applied to these types. This intrinsic knowledge of operators makes using built-in types convenient.
You might want to use user-defined types as conveniently. Unfortunately, the C# compiler cannot interpret
user-defined classes in the context of most of the standard operators. For example, how does the compiler
interpret zclass+zclass? The compiler cannot perform this interpretation without help from the class
developer. This assistance is offered through operator overloading, which describes an operator in the
context of a particular type. Overload several operators in a user-defined type to provide the same
transparency found in most built-in types for operators.

User-defined types that represent numerical systems or perform mathematical operations benefit the most
from operator overloading. A fraction, complex number, summation, hexadecimal numerical system, and
other similar types that have well-established behavior are improved with operator overloading.

You can also describe type conversion of user-defined types using operator overloading. Conversion
operators can convert or cast a user-defined type to another type, which can be a built-in type or another
user-defined type. With some exceptions, you can cast from one built-in type to another built-in type. For
example, you can implicitly cast from a short to a long value. You can also cast explicitly from a long to a
short value. However, what does it mean to cast a ZClass instance to an int value? This is another situation
in which developer input is essential. Developers overload conversion operators to instruct the compiler in the
conversions of user-defined types.

Operator overloading should be intuitive and is never required. Do not stray from the underlying intent of the
operator. For example, the plus operator should perform some type of addition. System.String overloads the
operator+ to concatenate strings. Concatenation and addition are similar concepts. If the implementation of
the operator+ within the string type truncated characters, that would be nonintuitive and more confusing than
helpful. Operator overloading can be overused and is not appropriate in all circumstances. The operator+ is a
reasonable addition to a string class. However, an operator-, although available, would be nonsensical.
Remember, the overloaded operator must be intuitive to everyone, not just to you. Confirm with peers your
perception of intuitive behavior. An alternative to operator overloading is simply implementing a named
method: Add method instead of an operator+ and Subtract method instead of overloading the operator-.
There is the added benefit that named methods are called overtly, whereas operator functions are called
tacitly.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Mathematical and Logical Operators


Mathematical and logical operators can be unary or binary operators, and most binary and unary operators
can be overloaded in a user-defined type. The sole ternary operator, which is the conditional operator, cannot
be overloaded. This is the complete description of mathematical and logical operators that cannot be
overloaded in a user-defined type:
 Dot operator (identifier.member)
 Call operator (methodname())
 Assignment operators (=, +=, /=, %=, and so on)
 Conditional operators (&&, ||, and ?:)
 Check and unchecked operators
 new operator
 typeof operator
 as and is operators
 Array operator ([])
 Pointer operators

The compound assignment operators, such as += and /=, are implicitly overloaded using the individual
operators. For example, the += and /= operators are implicitly overloaded by overloading the + and /
operators.

In addition, developers cannot use operator overloading to define new operators. For example, you could not
define a ^^ operator, which does not otherwise exist.

There are some notable differences between usage in the C++ and C# languages. In C++, you can overload
the assignment, new, and array operators. This is not allowed in C#. This may be an issue when porting
code from C++ to C#. Instead of overloading the assignment operator, implement the ICloneable interface.
The garbage collector (GC) is responsible for managing dynamic memory. For that reason, the new operator
cannot be overloaded in managed code.

The array operator is commonly overloaded in C++ to create a secure array, where fence post errors are
usually checked. Fencepost errors are automatically detected by the CLR, which eliminates one of the
primary reasons to overload the array operator.

Overloading an operator redefines the behavior of that operator in an expression. However, you cannot
change the syntax, precedence, or associativity of an operator with operator overloading. Overloading an
operator does not change the core principles of using the operator. Assume that the division operator is
overloaded in a user-defined type. The syntax for employing the division operator remains obj1/obj2.
Precedence is also preserved. In obj1+obj2/obj3-obj4, the division operation is performed before a plus or
minus operator, but after the increment or decrement operator. Multiple division operations, as in
obj1/obj2+obj3/obj4 are evaluated from left to right, which maintains the normal associativity.

Implementation

Overloaded operators are implemented as static and public functions. Other modifiers, such as virtual and
sealed, are not allowed. The unary operator has a single operand, whereas the binary operator has two
operands. Parameters of an overloaded operator cannot be ref or out.

Here is the syntax for overloading a unary or binary operator method:


 public static type operator unary(classtype operand)
 public static type operator binary(type lhsoperand, type rhsoperand)

For a unary operator method, the operand is the same type as the containing class. For a binary operator
method, at least one of the parameters must be the containing type. This allows the type to appear as lhs,
rhs, or both lhs and rhs in the expression. In the obj+5 expression, the object instance is passed as the lhs
operand to the operator+ method. The object instance is passed as the rhs operand in the 5+obj expression.
The return type is any value type but not void.

The following is an example of the implementation and use of an overloaded operator. The ZClass is a simple
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

class and wrapper for two integer fields. The operator+ method is overloaded to add two ZClass instances.
Because the operator+ method is part of the class, it has access to the private members of that class. This
is convenient when accessing parameters of that type within the operator method. In this code, the operator+
is called implicitly in the expression: obj1+obj2. You cannot call an operator function explicitly.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ZClass obj1=new ZClass(5,10);
ZClass obj2=new ZClass(15,20);
ZClass obj3=obj1+obj2;

Console.WriteLine(obj3.Total);
}
}

class ZClass {

public ZClass(int _fielda, int _fieldb) {


fielda=_fielda;
fieldb=_fieldb;
}

public static ZClass operator+(ZClass lhs, ZClass rhs) {


return new ZClass(lhs.fielda+rhs.fielda,
lhs.fieldb+rhs.fieldb);
}

public int Total {


get {
return fielda+fieldb;
}
}

protected int fielda, fieldb;


}
}

Operator methods are available in a derived class. At least one operand of the operator function remains the
base type. However, you can freely substitute the derived instance with the base type operand and access
the base type members. The return type can also be a base type, which might pose problems. As a return,
assigning a base instance to a derived type causes a run-time error. In addition, the derived type can replace
operator methods of the base class. Simply implement the operator function again in the derived class. The
implementation in the derived class overloads the base operator method.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

In the following code, YClass derives from the ZClass class and inherits operator+, fielda, and fieldb. (
ZClass.operator+ was shown in the previous code.) YClass also implements an operator-function. In Main,
both the operator+ and operator-functions are used. The operator+ on the YClass returns a ZClass instance,
which is the base type. You cannot explicitly cast this result to a YClass without raising a run-time
exception.

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
YClass obj1=new YClass(5,10);
YClass obj2=new YClass(15,20);
ZClass obj3=obj1+obj2;
Console.WriteLine(obj3.Total);
YClass obj4=obj1-obj2;
Console.WriteLine(obj4.Total);
}
}

// Partial listing

public class YClass:ZClass {

public YClass(int _fielda, int _fieldb)


:base(_fielda, _fieldb) {
}

public static YClass operator-(YClass lhs, YClass rhs) {


return new YClass(lhs.fielda-rhs.fielda,
lhs.fieldb-rhs.fieldb);
}
}
}

You can overload an operator member function. The general rules of overloading apply, and each overloaded
operator member function must have a unique signature. Implicit conversion of operands to other types can
limit the necessity for some operator overloading. Operators are typically overloaded to use the containing
type as an lhs or rhs.

In the following code, the operator+ is overloaded three times:

public static ZClass operator+(ZClass lhs, ZClass rhs) {


return new ZClass(lhs.fielda+rhs.fielda,
lhs.fieldb+rhs.fieldb);
}

public static ZClass operator+(ZClass lhs, int rhs) {


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

return new ZClass(lhs.fielda+rhs,


lhs.fieldb+rhs);
}

public static ZClass operator+(int lhs, ZClass rhs) {


return new ZClass(lhs+rhs.fielda,
lhs+rhs.fieldb);
}

All three operator member functions are used in the following code:

obj3=obj1+obj2;
obj1=obj1+10;
obj2=20+obj2;

Operator overloading is not stipulated in the Common Language Specification (CLS) and therefore not
guaranteed in all managed languages. It is good practice to implement a parallel named method for each
operator member function. The named method should call the operator member function as demonstrated in
the following code:

public class ZClass {

public ZClass(int _fielda, int _fieldb) {


fielda=_fielda;

fieldb=_fieldb;
}

public static ZClass operator+(ZClass lhs, ZClass rhs) {


return new ZClass(lhs.fielda+rhs.fielda,
lhs.fieldb+rhs.fieldb);
}

public ZClass Add(ZClass rhs) {


return this+rhs;
}

public int Total {


get {
return fielda+fieldb;
}
}

protected int fielda, fieldb;


}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

The semantics of overloading certain mathematical and logical operators are unique. Special rules must be
followed when overloading these operators in a type.

Increment and Decrement Operators

The Increment (++) and Decrement (--) operators have special semantics. These are unary operators, where
the operand and return type must be the containing class or a derivative. To maintain the underlying behavior,
the Increment and Decrement operator should return a modified instance of the current object, which is the
operand. You can (but should not) return an entirely new instance. Remember, overloaded operators should
preserve the underlying meaning of the operator. Finally, overloading the Increment or Decrement operator
revises both the prefix and postfix usage of the operator.

Here is sample code showing an overloading of both the Increment and Decrement operators:

public class ZClass {

public ZClass(int _fielda, int _fieldb) {


fielda=_fielda;
fieldb=_fieldb;
}

public static ZClass operator++(ZClass curr) {


++curr.fielda;
++curr.fieldb;
return curr;
}

public static ZClass operator--(ZClass curr) {


--curr.fielda;

--curr.fieldb;
return curr;
}

public int Total {


get {
return fielda+fieldb;
}
}

public int fielda, fieldb;


}

LeftShift and RightShift Operators

The LeftShift and RightShift operators normally perform a binary shift. Both are binary operators. When
overloading these operators, the first operand must be the same type as the containing class. The second
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

operand must be an int, which is the amount of the shift. The return type can be anything except void. The
LeftShift and RightShift operators are not paired operator methods. You can implement them independently
of each other. However, I would recommend implementing both because the methods are logically related:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ZClass obj1=new ZClass(5,10);
ZClass obj2=obj1<<2;
Console.WriteLine(obj2.Total);
}
}

public class ZClass {


public ZClass(int _fielda, int _fieldb) {
fielda=_fielda;
fieldb=_fieldb;
}

public static ZClass operator<<(ZClass curr, int shift) {


int newa=curr.fielda<<shift;
int newb=curr.fieldb<<shift;
return new ZClass(newa, newb);
}

public static ZClass operator>>(ZClass curr, int shift) {


int newa=curr.fielda>>shift;
int newb=curr.fieldb>>shift;
return new ZClass(newa, newb);
}

public int Total {


get {
return fielda+fieldb;
}
}

public int fielda, fieldb;


}
}

Operator True and Operator False


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

True and false are logical operators and are used in conditional expressions and sometimes in assignments.
They are paired operator methods, which require both functions of the pair to be implemented. If either the
operator true or operator false method is overloaded, both must be implemented. Both operators are unary
operators, in which the current object is the operand. The operand must be the containing class type or a
derivative, and the return type should be bool. Add operator true and operator false methods to classes that
have a false or true representation. This representation is typically interpreted from the state of the object.
When an object is used as a Boolean expression, the operator true method is called. The operator false
method is called in other circumstances, such as an && expression. Operator overloading and the &&
operator are discussed later in this appendix.

This is sample code of an operator true and operator false. The operator true is used in the Main method at
the if statement.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ZClass obj1=new ZClass(5,5);
if(obj1) {
Console.WriteLine("obj1 is true");
}
else {
Console.WriteLine("obj1 is false");
}
}
}

public class ZClass {

public ZClass(int _fielda, int _fieldb) {


fielda=_fielda;
fieldb=_fieldb;
}

public static bool operator true(ZClass curr) {


Console.WriteLine("ZClass.operator true");
return curr.fielda==curr.fieldb;
}

public static bool operator false(ZClass curr) {

Console.WriteLine("ZClass.operator false");
return curr.fielda!=curr.fieldb;
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public int Total {


get {
return fielda+fieldb;
}
}

protected int fielda, fieldb;


}
}

Paired Operators

In addition to operator true and operator false, the relational operators are paired operators. Paired operators
enforce a practical guideline—which is that related operators should be overloaded to maintain consistency.
For example, because they are logically related, you should overload both the operator== and operator!=
methods. This is the complete list of paired relational operators, which are discussed in the following
sections:
 operator== and operator!=
 operator<= and operator>=
 operator< and operator>
 operator| and operator&

Operator== and Operator!=


The overloaded operator== method should delegate to the Equals method, which ensures that the operator==
and the Equals method exhibit consistent behavior. If not, the definition of equality for an instance will vary
based on circumstances, which would be minimally confusing. The operator== and operator!= methods are
paired methods. When overloading these operators, you must also implement the Equals method in the
same class. The Equals method is inherited from System.Object:

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ZClass obj1=new ZClass(5,10);
ZClass obj2=new ZClass(5,10);
ZClass obj3=new ZClass(5,15);
if(obj1==obj2) {
Console.WriteLine("obj1 and obj2 are equal.");
}

else {
Console.WriteLine("obj1 and obj2 are not equal.");
}
if(obj1==obj3) {
Console.WriteLine("obj1 and obj3 are equal.");
}
else {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine("obj1 and obj3 are not equal.");


}
}
}

public class ZClass {

public ZClass(int _fielda, int _fieldb) {


fielda=_fielda;
fieldb=_fieldb;
}

public static ZClass operator+(ZClass lhs, ZClass rhs) {


return new ZClass(lhs.fielda+rhs.fielda,
lhs.fieldb+rhs.fieldb);
}

public static bool operator==(ZClass lhs, ZClass rhs) {


return lhs.Equals(rhs);
}

public static bool operator!=(ZClass lhs, ZClass rhs) {


return !lhs.Equals(rhs);
}

public override bool Equals(object o) {


return this.GetHashCode()==o.GetHashCode();
}

public override int GetHashCode(){


return fielda+fieldb;
}

public int Total {


get {
return fielda+fieldb;
}
}

protected int fielda, fieldb;


}
}

Operator|| and Operator&&


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Actually, operator|| and operator&& cannot be overloaded directly. These are the logical and and or
operators, respectively. Instead, operator|, operator&, operator true, and operator false combine to overload
operator|| and operator&&. The bitwise operators are normally operator| and operator&. If a user-defined type
is used in an && or || expression, the four mentioned operator functions must be overloaded in that type.

Because of short-circuiting, an && or || expression is sometimes partially evaluated. If the lhs of an &&
expression is false, the entire expression is false. This means the rhs can be ignored. For || expressions, the
entire expression is true if the lhs is true. When that occurs, the rhs of the || expression can be ignored.
Potential short-circuiting complicates the overloading of the && and || operators. Several steps are required
to evaluate the && or || operators for a user-defined type.

Following are the steps for evaluating the && operator, where the expression is lhs && rhs. (Let us assume
that lhs and rhs are the same type as the containing class.)
1. The overloaded operator false method is called. If the method returns true, the expression
short-circuits because the first part of the && expression is confirmed to be false.
2. If short-circuiting, the expression evaluates to type.operator true(lhs).
3. If the expression does not short-circuit, the overloaded operator& is called:
result=type.operator&(lhs, rhs).
4. Finally, type.operator true(result) is called. This method returns the final result of the lhs && rhs
expression when short-circuiting does not occur.

Following are the steps for evaluating the || operator, where the expression is lhs || rhs:
1. The overloaded operator true method is called. If the method returns true, the expression
short-circuits. The expression short-circuits because the first part of the || expression is confirmed
to be true.
2. If short-circuiting, the expression evaluates to type.operator true(lhs).
3. If the expression does not short-circuit, the overloaded operator | is called:
result=type.operator|(lhs, rhs).
4. Finally, type.operator true(result) is called. This method returns the final result of the lhs || rhs
expression when short-circuiting does not occur.

For the operator& and operator| methods, the operand and return must be the same type.

In the following code, ZClass is overloaded to support the && and || expression. All four required methods are
implemented: operator true, operator false, operator&, and operator|. The overloaded methods of the ZClass
type display messages for auditing program flow. In Main, ZClass instances are used in a || expression.
Because the operator true is hard-coded to return false, the expression will never short-circuit.

using System;

namespace Donis.CSharpBook{
public class Starter{

public static void Main(){


ZClass obj1=new ZClass(5,10);
obj1.name="obj1";
ZClass obj2=new ZClass(15,20);
obj2.name="obj2";
if(obj1 || obj2) {
Console.WriteLine("expression evaluated to true");
}
}

class ZClass {
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public ZClass(int _fielda, int _fieldb) {


fielda=_fielda;
fieldb=_fieldb;
}

public static ZClass operator &(ZClass obj1,ZClass obj2) {


Console.WriteLine("operator &");
ZClass result= new ZClass(obj1.fielda&obj2.fielda,
obj1.fieldb&obj2.fieldb);
result.name="result";
return result;
}

public static ZClass operator |(ZClass obj1,ZClass obj2) {


Console.WriteLine("operator |");
ZClass result= new ZClass(obj1.fielda|obj2.fielda,
obj1.fieldb|obj2.fieldb);
result.name="result";
return result;
}

public static bool operator true(ZClass obj) {


Console.WriteLine("operator true({0})",obj.name);
return false;
}

public static bool operator false(ZClass obj) {


Console.WriteLine("operator false({0})",obj.name);
return true;
}

public int Total {


get {
return fielda+fieldb;
}
}

public string name;


protected int fielda, fieldb;
}
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Conversion Operators
Implementing conversion operators facilitates the implicit or explicit casting of user-defined types to built-in
types or even other user-defined types. Developers implement a conversion operator to explain to the
compiler how to interpret a user-defined type in the context of another type. Like mathematical and logical
operators, the primary reason for implementing conversion operators is convenience. It is never required. You
could as easily expose ToType methods, such as ToInt, ToFloat, or ToDecimal.

An implicit cast is considered a secure cast, whereas explicit casting is required for casting that is not
secure. For built-in types, a secure cast is available when there is no potential loss of precision or accuracy.
When there is potential loss of precision or accuracy, an explicit cast is required. For example, an int can be
assigned to long implicitly. Eight bytes are reserved for a long value and four bytes are reserved for an int
value. The int value will be promoted to a long. The promotion occurs silently—no warning or notice. The
reverse, in which a long is assigned to an int, requires an explicit cast. This is exhibited in the following code:

int a=5;
long b=10;
b=a; // implicit cast
a=(int) b; // explicit cast

C# does not support conversion constructors. A conversion constructor is a one-argument constructor used
to create an instance of a type from a different type. Conversion constructors are supported in C++ but are
not allowed in C#. Conversion constructors were convenient—too convenient. Conversion constructors were
sometimes called transparently when a compiler error for mismatched types was more appropriate.

You cannot overload the cast operator directly. Instead, overload the cast operator selectively with
conversion operator methods. This is the syntax of a conversion operator:
 public static implicit operator returntype(classtype obj)
 public static explicit operator returntype(type obj)

For the conversion operator syntax, there are many similarities when compared with mathematical and
relational operators. Conversion operators must be public and static. Other modifiers, such as virtual and
sealed, are syntax errors. Conversion operators that are implicit do not require casting, whereas explicit
conversion operators require casting for use. I recommend explicit casting in all circumstances. Implicit
casting allows the conversion function to be called transparently and sometimes inadvertently, which may
cause undetected side effects. With explicit casting, developers affirmatively state their intentions through
casting. Either the return or operand of the conversion operator must be the same as the containing type. If
converting to the containing type, the return type should be the containing class. Notice that the return type
is after the operator keyword, not before. When converting from the containing type, the operand should be
the same type as the containing class.

Here is sample code of implicit and explicit conversion methods. The ZClass has two conversion operators.
The first conversion operator converts ZClass to an int. The second conversion operator converts a YClass to
a ZClass.

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ZClass obj1=new ZClass(5,10);
int ival=obj1;
YClass obj2=new YClass(5);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

// ZClass obj3=obj2; [ error ]


ZClass obj3=(ZClass) obj2;
}
}

public class ZClass {

public ZClass(int _fielda, int _fieldb) {


fielda=_fielda;
fieldb=_fieldb;
}

public static implicit operator int(ZClass curr) {


return curr.fielda+curr.fieldb;
}

public static explicit operator ZClass(YClass curr) {


return new ZClass(curr.field/2, curr.field/2);
}

public int fielda, fieldb;


}

public class YClass {

public YClass(int _field) {


propField=_field;
}

private int propField;


public int field {
get {
return propField;
}
set {
propField=value;
}
}
}
}

Conversion operators are often overloaded to provide the illusion of a user-defined type, which can support a
variety of casts. In the following code, the conversion operator is overloaded several times to allow the
conversion of ZClass instances to a variety of types:
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

using System;

namespace Donis.CSharpBook{

public class ZClass {

public ZClass(int _fielda, int _fieldb) {


fielda=_fielda;
fieldb=_fieldb;
}

public static explicit operator int(ZClass curr) {


return curr.fielda+curr.fieldb;
}

public static explicit operator float(ZClass curr) {


return (float) (curr.fielda+curr.fieldb);

public static explicit operator short(ZClass curr) {


return (short) (curr.fielda+curr.fieldb);
}

// and so on

public int fielda, fieldb;


}
}

Operator String

The operator string operator is a special conversion operator that converts a user-defined type to a string.
This appears to overlap with the ToString method, which is inherited from System.Object. Actually, every
type is also automatically provided an operator string method, which simply calls the polymorphic ToString
method. Look at the following code. If a class has both a ToString and operator string method, which method
is called in the Console.WriteLine?

using System;

namespace Donis.CSharpBook{
public class Starter{
public static void Main(){
ZClass obj=new ZClass();
Console.WriteLine(obj);
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

}
}

public class ZClass {

public static implicit operator string(ZClass curr) {


return "Zlass.operator string";
}

public override string ToString() {


return "ZClass.ToString";
}

}
}

The preceding program displays ZClass.operator string. The operator string is called for the
Console.WriteLine operand. Why? Unlike the default operator string, the custom operator string does not call
ToString. In most circumstances, calling ToString in the operator string is the best practice, which
eliminates the necessity of implementing a custom operator string. The default operator string already has
this behavior. You simply override the ToString method with the proper string representation of the type.
Inconsistencies and confusion can occur when the operator string and ToString have disparate
implementations.
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Practical Example
Until now, simple examples have been provided to demonstrate operator overloading and conversion
operators. The following code contains a more practical example. Summation notation iterates and totals an
expression in a specified range. Figure A-1 offers three examples of summation notation.

Figure A-1: Examples of summation notation

Summation is not a predefined type in C#. The following class defines the Summation type. It contains
several methods:
 The Summation class has three constructors. The two- and three-argument constructors delegate
to the four-argument constructor and set unspecified parameters a default value.
 The Calculate method calculates the result of the summation.
 The class has two operator+ methods, which allow instances of the class to be either lhs or rhs in
the binary expression. Each operator+ method extends the iteration by adding to the stop value of
the summation. A new instance with an updated number of iterations is returned.
 The operator++ method extends the number of iterations by one. The current object is then
returned.
 The class has an operator int conversion constructor. This method converts a Summation object
into an int value, which is the result of the operation.
 There are two string functions: ToString returns the result of the operation; ToNotationString
displays summation notation and shows the parameters of the operation.

Here is the code for the class:

public class Summation {

public Summation(int _start, int _stop) :


this(_start, _stop, 1, 1) {
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

public Summation(int _start, int _stop,


int _product) :
this(_start, _stop, _product, 1) {
}

public Summation(int _start, int _stop,


int _product, int _power) {
start=_start;
stop=_stop;
product=_product;
power=_power;
Calculate();
}

private void Calculate() {


propResult=0;
int temp;
for(int count=start;count <= stop;
++count) {

temp=(int)Math.Pow(count, power);
temp=temp*product;
propResult+=temp;
}
}

public static Summation operator+(Summation sum, int val) {


return new Summation(sum.start, sum.stop+val,
sum.product, sum.power);
}

public static Summation operator+(int val, Summation sum) {


return new Summation(sum.start, sum.stop+val,
sum.product, sum.power);
}

public static Summation operator++(Summation sum) {


++sum.stop;
sum.Calculate();
return sum;
}

public static explicit operator int(Summation sum) {


return sum.propResult;
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

private int propResult;


public int Result {
get {
return propResult;
}
}

public override string ToString() {


return propResult.ToString();
}

public string ToNotationString() {


string line1="\n "+stop.ToString();
string line2="\n\neeeee";
string line4="\nee "+
(product==1?"":product.ToString())+"i";
string line3="\ne"+new string(' ',line4.Length-2);
line3+=(power==1?"":power.ToString());
string line5="\ne";
string line6="\neeeee";
string line7="\n\n i="+start.ToString();
return line1+line2+line3+line4+line5+line6+line7;
}

private int start;


private int stop;
private int product;
private int power;
}

The following code tests the Summation type. The ingredients of the summation are read from the command
line. In order, provide the start, stop, product, and power for the summation as command-line arguments. The
number of iterations is between the start and stop value. In Main, the summation notation is displayed
followed by the result. The number of iterations is then increased using the operator++. The new results are
then displayed:

public static void Main(string [] argv){


Summation sum=
new Summation(int.Parse(argv[0]),
int.Parse(argv[1]),
int.Parse(argv[2]),
int.Parse(argv[3]));
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Console.WriteLine();
Console.WriteLine(sum.ToNotationString());
Console.WriteLine("\n[Result = {0}]",
sum.Result);

++sum;
int isum=(int)sum;
Console.WriteLine();
Console.WriteLine(sum.ToNotationString());
Console.WriteLine("\n\n[Result = {0}]", isum);
}
}
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Operator Overloading Internals


Internally, Microsoft intermediate language (MSIL) does not understand operator methods. For that reason,
the C# compiler converts operator methods into normal functions. Figure A-2 presents a view of the
Summation class from the previous section. Although there are no operator methods, there are replacement
functions such as op_Addition and op_Explicit.

Figure A-2: View of the Summation class

Table A-1 lists the replacement methods for mathematical and logical operators.
Table A-1: Replacement Methods for Mathematical and Logical Operators
Open table as spreadsheet

Operator Replacement Method

operator+ op_Addition

operator- op_Subtraction

operator* op_Multiply

operator++ op_Increment

operator-- op_Decrement

operator/ op_Division

operator% op_Modulus

operator& op_BitwiseAnd

operator| op_BitwiseOr

operator^ op_ExclusiveOr

operator false op_False

operator true op_True

operator>> op_RightShift

operator<< op_LeftShift

operator! op_LogicalNot

operator~ op_OnesComplement

Table A-2 lists the replacement methods for relational operators.


Table A-2: Replacement Methods for Relational Operators

Operator Replacement Method

operator> op_GreaterThan
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table A-2: Replacement Methods for Relational Operators

Operator Replacement Method

operator< op_LessThan

operator>= op_GreaterThanOrEqual

operator<= op_LessThanOrEqual

operator== op_Equality

operator!= op_Inequality

Conversion operators are implemented as op_Explicit and op_Implicit methods. The methods are overloaded
for every combination of explicit or implicit conversion operator provided in the contained type. The following
class has two explicit operators and one implicit conversion operator:

public class ZClass{

public static explicit operator int(ZClass obj) {


return 0;
}

public static explicit operator float(ZClass obj) {


return (float) 0;

}
public static implicit operator double(ZClass obj) {
return 0;
}
}

Figure A-3 is an internal view of the application. There are two overloaded op_Explicit methods and a single
op_Implicit method.

Figure A-3: View of ZClass


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
Symbols
/* and */ (block comments), 10
: (colon punctuator), 9
, (comma punctuator), 9
- (Decrement) operator overloading, 632
/* (delimited comments), 10
*/ (delimited comments), 10
/// (documentation comments), 10–12
. (dot punctuator), 9
++ (Increment) operator overloading, 632
/* and */ (multiline comments), 10
; (semicolon punctuator), 8
// (single-line comments), 10
/// (single-line documentation comments), 10–12
~ (tilde) command, 514
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
A
abstract
classes, 106, 112
indexers, 106
keyword, 106
members, 106
methods, 106
overview, 106
properties, 106
static members, 106
access modifiers, 98–99
accessibility
classes, 46
constructors, 63
delegates, 298
destructors, 68
enumerations, 78
fields, 53
members, 49
methods, 56
nested types, 73
Activator class, 378
activity traces, 479
additional information
Constrained Execution Region (CER) information, 593
Debugging Tools for Windows, 500
Microsoft Press Technology Updates Web page, xxiii
Microsoft Public Symbol Store, 548
support for this book, xxiv
AddMemoryPressure method, 596
Address Breakpoint dialog box, 456
ADPlus
crash mode, 525
hang mode, 526
overview, 503, 525
walkthrough, 526
anonymous methods
delegate keyword, 313
generic anonymous methods, 318
limitations, 318
local variables, 316
naming, 315
nested classes, 317
outer variables, 316–318
overview, 313–316
private nested classes, 317
private static methods, 317
static methods, 317
syntax, 314
AppDomain.UnhandledException, 349–350
application exceptions
overview, 338–340
serializing, 346
applications
exceptions. See application exceptions
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

symbols, 549
thread local storage (TLS), 580
trapping unhandled exceptions, 347
Application.ThreadException, 348–349
arithmetic instructions
conversion operations, 430
exception handling, 431–432
list of, 429–430
overview, 429
array covariance, 213
Array.AsReadOnly method, 199
Array.Clone method, 200
Array.CreateInstance method, 201–202
Array.FindAll method, 202–203
ArrayList collection
IList interface, 215
members, 215–219
overview, 215
Array.Resize method, 203
arrays
accessing elements, 428
array covariance, 213
casting between, 213
conversion, 213–214
delegates, 300
elements, 188, 191
function returns, 213–214
indexers, compared to, 209
jagged arrays. See jagged arrays
multidimensional arrays. See multidimensional arrays
nested arrays, 193
overview, 186, 187, 428
parameters, 213–214
params keyword, 211–212
reference types vs. value types, 188
single-dimensional arrays. See single-dimensional arrays
syntax, 189–191, 428
System.Array. See System.Array
System.MulticastDelegate class, 301–302
value types vs. reference types, 188
Array.SyncRoot property, 204
as operator
overview, 128
syntax, 130
ASP.NET debugging, 499
assemblies
Assembly Binding Log Viewer Tool (fuslogvw.exe), 368
loading, 367–369
Reflection trees, 366
Type objects, 366
Assembly Binding Log Viewer Tool (fuslogvw.exe), 368
assembly directives
overview, 406
syntax, 407
association, 151
asynchronous delegate diagram
delegate internals, 312
overview, 311
asynchronous invocation
BeginInvoke method, 307–309
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

EndInvoke method, 309–310


IAsyncResult object, 308
overview, 307
Attribute suffix, 391
attributes
anatomy of, 391–392
Attribute suffix, 391
AttributeTargets flags, 393
combining, 390
creating custom, 392–396
directional attributes, 620
generics, 238
GetCustomAttribute method, 396, 397
GetCustomAttributes method, 396–397
inheritance, 130–131
instance constructors, 393
interfaces, 112
MarshalAs attribute, 624
members, 49
metadata, 356
overview, 389–390
parameter types, list of, 393–394
position parameters, 391
predefined, 390
programmer-defined custom attributes, 390
pseudo-custom attributes, 390
reflection, 396–398
syntax, 391
target types, 391
AttributeTargets flags, list of, 393
AutoRecover, 143
Autos window, 468
AwareLock.Enter, 541
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
B
base types, 83
BeginInvoke method, 307–309
BestFitMapping, 617
binary operators
details, 22
overview, 22
Binder class
abstract methods, 375
BindingFlags parameter, 375
overview, 375
sample code, 377–378
syntax, 375
binders, 375
binding, dynamic, 373–374
BindingFlags enumeration, 371
BindingFlags parameter, 375
BitArray collection
members, 219–220
overview, 219
BitVector32
collection, 232
bitwise enumerations, 79
blittable types, 611, 618
Blob heap, 358
block comments (/* and */), 10
blocks, 16
Boolean operators
list of, 23
overview, 23
bound parameters, 243
boxing
collections, 233
garbage collection overview, 559
IEnumerator interface, 278
overview, 419
branching
calling methods, 425–427
comparative branching instructions, 424
compare instructions, 423
overview, 423
Breakpoint Condition dialog box, 457
Breakpoint Filter dialog box, 458
Breakpoint Hit Count dialog box, 457
breakpoints
breakpoints memory commands, 516–518
Breakpoints window, 455–459, 464
code stepping, 461–463
function breakpoints, 453–455
memory commands, 516–518
overview, 453
symbols, 461
tracepoints, 459–461
When Breakpoint Is Hit dialog box, 460
Breakpoints window
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Address Breakpoint dialog box, 456


Breakpoint Condition dialog box, 457
Breakpoint Filter dialog box, 458
Breakpoint Hit Count dialog box, 457
condition command, 456
File Breakpoint dialog box, 456
filter command, 458–459
hit count command, 457
location command, 456
overview, 455–456, 464
toolbar, 459
when hit command, 459
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
C
call instructions, list of, 426
Call Stack window, 471–472
callbacks
overview, 291
unmanaged callbacks, 621–622
calling methods, 425
CallingConvention, 613–614
casting
arrays, 213
generic types, 256–257
IEnumerator interface, 278
inheritance, 125–130
reflection, 380
catch statements, 329–330
CCW. See COM Callable Wrappers (CCWs)
<![CDATA ]> elements, 168
CDATA syntax, 168
CDB. See Windows Console Debugger (CDB)
CER. See Constrained Execution Region (CER)
change tracking, 159
characters
escape characters, 19–20
overview, 18
verbatim characters, 20–21
CharSet, 617
Class Designer, 145
class diagrams
association, 151
inheritance, 149
overview, 145–149
toolbox, 148–149
walkthrough, 151–154
class directives, 409–412
class hierarchies
association, 151
Class Designer, 145
class diagrams, 145–149, 151–154
Class View window, 144
Error List window, 156
inheritance, 149–151
Object Browser window, 144–145
overview, 143
Class View window, 144
classes
abstract, 106
accessibility, 46
Activator, 378
Binder, 375
Console, 576
declaration syntax, 46
delegates, 297–298
Employee, 96
EventArgs, 321
Exception. See System.Exception
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

GC, 598
HandleCollector, 596–597
hierarchies. See class hierarchies
inheritance. See inheritance
member access syntax, 48
members, list of, 48
members overview, 48
modifiers, 46
nested. See nested classes
overview, 44, 45, 46–47
partial, 74–76
private nested, 317
refinement, 81
sealed, 107
SourceSwitch, 479, 480
static, 50
StringBuilder, 620–621
Summation, 643
System.Exception. See System.Exception
TraceListener, 482
TraceSource. See TraceSource
types. See types
WeakReference, 591
ClickOnce deployment
Manifest Generation and Editing (MageUI) tool, 183
manifests, 183
modes of deployment, 182
overview, 135, 182
Publish Wizard, 185–186
publishing applications, 185–186
Close method, 584
closed constructed types
overview, 243
static members, 260
this references, 246
CLR Debugger (DbgClr), 503
Code Editor
change tracking, 159
color formatting, 158
font formatting, 158
IntelliSense, 156–158
overview, 156
profiles, 160
source code formatting, 159
Surround With feature, 158
Code elements, 168
code expansion, 162
code samples. See sample C# programs
Code Snippet Schema Reference, 166
code snippets
<![CDATA ]> elements, 168
Code elements, 168
code expansion, 162
Code Snippet Schema Reference, 166
Code Snippets Manager, 165–166
CodeSnippets elements, 166
copying, 161
creating, 166–171
Declarations elements, 167
default snippets, 163–164
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Header elements, 166


Imports elements, 167
inserting, 162–163
IntelliSense, 162
for keyword, 163
Literal elements, 167
Object elements, 167
overview, 160–161
pasting, 161
References elements, 167
Reflection namespace, 170
Snippet elements, 167
StringBuilder type, 168
Code Snippets Manager, 165–166
code stepping
Next Statement command, 462
overview, 461
step commands, 462
CodeSnippets elements, 166
collections
ArrayList, 215–219
BitArray, 219–220
BitVector32, 232
boxing, 233
generics, 237, 266–267
Hashtable, 222–225
HybridDictionary, 232
metadata, 371
NameValueCollection, 232
OrderedDictionary, 232
overview, 186, 187, 214
Queue, 226–230
SortedList, 228–230
specialized, 232–233
Stack, 231–232
StringCollection, 232
StringDictionary, 232
types, 215
colon punctuators, 9
colors, formatting, 158
COM Callable Wrappers (CCWs)
accessing managed code through, 345
unsafe code, 602
COM interoperability exceptions
COM Callable Wrappers (CCWs), 345
COM exceptions, 341–343
generating COM exceptions, 343–345
IErrorInfo to COMException mapping, 342
overview, 341
Combine method, 302
COMException class, 342
comma punctuators, 9
comments
block (/* and */), 10
delimited (/* and */), 10
delimited documentation tags, 12–13
documentation (///), 10–12
feedback or questions, xxiv
multiline (/* and */), 10
overview, 10
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

single-line (//), 10
single-line documentation (///), 10–12
common exception model, 327
Common Language Runtime (CLR)
exception handling, 325
MSIL programming, 401
Common Language Specification (CLS), 631
Community menu, 137
companion Web site, xxiv
comparative branching instructions, 424
compare instructions, 423
complex iterations, 290
composition, 83–87
compound operators
list of, 22–23
overview, 22
concurrent garbage collection
overview, 559
Workstation GC, 560
condition command, 456
conditional preprocessor directives, 14
configuration files, 488–489
Configuration Manager, 442–443
consistency, 92
Console class, 576
constants, 52
Constrained Execution Region (CER)
overview, 592–593
safe handles, 593–594
Web site, 593
constraints
constructors, 255
default constructor, 255
derivation, 248–252
integer, 251
interface, 252–253
list of, 247
overview, 246–247
recursive, 250
reference type, 254
restrictions, 252
value type, 254
value types, 251
constructed types, 243
constructors
accessibility, 63
constraints, 255
default, 255
delegates, 298
EventTypeFilter, 484
finalizers, 575–576
generics, 238
instance, 393
overloading, 64
overview, 63, 108
private, 63
sheet generic type, 241
singletons, 67
SourceFilter, 484
SourceSwitch, 480
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

static, 66
syntax, 63, 109
System.Exception, 336
this references, 110
containment, 83
contravariance, 299–300
conversion operations, 430
conversion operator overloading
operator string operator, 641–642
overview, 639–641
sample code, 640–641
summation notation, 642–645
CorDbg. See Managed Debugger (MDbg)
core language features
blocks, 16
characters, 18
comments, 10
escape characters, 19–20
generic types, 17
keywords, 25–29
line terminators, 9
nullable types, 18
numeric suffixes, 18–19
operators, 21–24
overview, 7
preprocessor directives, 13–16
primitives, 29
punctuators, 8–9
symbols and tokens overview, 7
tabs, 8
Unicode characters, 18
verbatim characters, 20–21
white space, 8
counters, list of, 538–539
covariance
arrays, 213
delegates, 299–300
CreateDelegate method, 381
cross-language inheritance, 89
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
D
data members
constants, 52
fields, 52–54
overview, 51
Data menu, 141–142
Data Source Configuration Wizard, 141
data tips, 450
DataSet Visualizer, 452–453
DbgClr (CLR Debugger), 503
Debug configuration, 441
Debug Source Files window, 449
Debug toolbar, 464
debug windows
Autos window, 468
Breakpoints window, 464
Call Stack window, 471–472
Disassembly window, 474
Immediate window, 468–471
Locals window, 468
Memory window, 474
Modules window, 472–473
Output window, 464
overview, 464
Processes window, 473
Registers window, 475–476
Script Explorer window, 465
Threads window, 472
Watch window, 465–468
DebuggableAttribute, 501–503
DebuggableBrowsableState, 493
DebuggerBrowsableAttribute, 493–495
DebuggerDisplayAttribute
DebuggableBrowsableState, 493
DebuggerBrowsableAttribute, 493–495
DebuggerTypeProxyAttribute, 495–496
overview, 492–493
DebuggerTypeProxyAttribute, 495–496
debugging
ADPlus, 503, 525–526
advanced debugging overview, 498, 499–501
ASP.NET applications, 499
attaching debuggers to running processes, 439–440
class library projects, 441
CLR Debugger (DbgClr), 503
Configuration Manager, 442–443
console application projects, 440–441
Debug configuration, 441–442
DebuggableAttribute, 501–503
DebuggableBrowsableState, 493
DebuggerBrowsableAttribute, 493–495
DebuggerDisplayAttribute. See DebuggerDisplayAttribute
debuggers overview, 503
DebuggerTypeProxyAttribute, 495–496
Debugging Tools for Windows Web site, 500
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Dr. Watson. See Dr. Watson


dump files, 496–498, 525
exception handling. See exception handling
Exceptions dialog box, 351–352
invasive vs. noninvasive, 500
Managed Debugger. See Managed Debugger (MDbg)
memory. See memory
metadata. See metadata
overview, 438
Performance Monitor, 503, 538–539
reflection. See reflection
Release configuration, 441–442
settings overview, 443
setup, 441–443
Son of Strike. See Son of Strike (SOS)
symbols, 547–549
threads. See threads
tracing. See tracing
Visual Studio 2005. See debugging with Visual Studio 2005
Visual Studio Debugger, 503
WinDbg. See Windows Debugger (WinDbg)
Windows Console Debugger. See Windows Console Debugger (CDB)
Windows Forms projects, 438
Debugging Tools for Windows Web site, 500
debugging with Visual Studio 2005
ADPlus, 503, 525–526
advanced debugging overview, 498, 499–501
Autos window, 468
breakpoints. See breakpoints
Call Stack window, 471–472
CLR Debugger (DbgClr), 503
controls for debugging sessions, 437–438
data tips, 450
DataSet Visualizer, 452–453
Debug pane of the Project Property pages, 449
Debug Source Files window, 449
Debug toolbar, 464
debug windows, 464
DebuggableBrowsableState, 493
DebuggerBrowsableAttribute, 493–495
DebuggerDisplayAttribute. See DebuggerDisplayAttribute
debuggers overview, 503
DebuggerTypeProxyAttribute, 495–496
Disassembly window, 474
Dr. Watson. See Dr. Watson
dump files, 496–498, 525
Edit And Continue window, 445–446
exception handling. See exception handling
Exceptions dialog box, 351–352
General window, 443–445
Immediate window, 468–471
Just-In-Time Debugging window, 446–448
Locals window, 468
Managed Debugger. See Managed Debugger (MDbg)
memory. See memory
Modules window, 472–473
Output window, 464
overview, 436, 437
Performance Monitor, 503, 538–539
Processes window, 473
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Registers window, 475–476


Script Explorer window, 465
settings for projects, 449–450
settings overview, 443
Son of Strike. See Son of Strike (SOS)
symbols, 547–549
threads. See threads
Threads window, 472
tracing. See tracing
transferring from action to break mode, 438
user interface, 450–453
Visual Studio Debugger, 503
visualizers, 451
Watch window, 465–468
WinDbg. See Windows Debugger (WinDbg)
Windows Console Debugger. See Windows Console Debugger (CDB)
XML Visualizer, 451
Declarations elements, 167
declarative preprocessor directives, 13
Decrement (-) operator overloading, 632
deep object graphs, 574
default constructor constraints, 255
delegate inference, 299
delegate keyword
anonymous methods, 313
overview, 296
delegates
accessibility, 298
arrays, 300
asynchronous delegate diagram, 311–312
asynchronous invocation, 307–310
callbacks, 291
classes, 297–298
combining, 302
constructors, 298
contravariance, 299–300
covariance, 299–300
CreateDelegate method, 381–382
creating, 298–300
defining, 297–298
delegate inference, 299
DynamicInvoke method, 382
exceptions, 312
function pointers, 295
generics, 306–307
internals, 312
invocation lists, 298
invoking, 300
late binding delegates, 380–382
members, 306
methods, 306
multicast delegates, 298, 301
overview, 291, 295–297, 380
properties, 306
removing, 302
syntax, 298
System.MulticastDelegate class, 301–302
delimited comments (/* and */), 10
delimited documentation tags, 12–13
derivation constraints
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

generic methods, 249


generic types, 249
integer constraints, 251
nodes, 250
overview, 248
restrictions, 252
type parameters, 248, 250, 251
derived types, 83
deserialization, 263
destructors
accessibility, 68
Finalize method, 563
finalizers, 562
Object.Finalize, 538
overview, 68, 108–111
syntax, 68
diagnostic directives, 15
directional attributes, 620
directives
assembly, 406–409
class, 409–412
method, 412–413
overview, 406
Windows Debugger (WinDbg), 518–519
Disassembly window, 474
display memory commands, 515–516
Disposable pattern
Close method, 584
considerations, 582
Dispose method, 582–583
overview, 581–582
reusable objects, 585
thread-safe Dispose method, 585
Dispose method
Close method, 584
Disposable pattern considerations, 582
Disposable pattern overview, 581–582
disposing inner objects, 586–587
finalizers, 577
finally block, 577
multiple calls, 582–583
overview, 577
sample code, 577
thread safe, 585
DllImport
CallingConvention, 613–614
EntryPoint, 613
ExactSpelling, 614–615
overview, 612–613
PreserveSig, 615
SetLastError, 615–616
DllImportAttribute, 612
documentation comments (///), 10–12
dot punctuators, 9
downcasting, 278
downloading code samples for this book, xxiv
Dr. Watson
configuring, 528
overview, 503, 527
walkthrough, 528
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

drwtsn32.exe. See Dr. Watson


dual iteration, 287–288
dump files
ADPlus, 525–526
overview, 496–498, 525
dynamic binding
overview, 373
sample code, 374
syntax, 373, 374
dynamic invocation
binders, 375–378
overview, 373
DynamicInvoke method, 382
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
E
Edit And Continue window, 445–446
Employee class, list of, 96
EndInvoke method, 309–310
entry points, 35–36
EntryPoint, 613
enumerable objects, 270
enumerations
accessibility, 78
BindingFlags, 371
bitwise, 79
MemberTypes, 370
overview, 46, 77–79, 269
syntax, 78
System.Enum methods, 79
enumerators
generic, 278
IEnumerator interface, 278
nested classes, 287
overview, 267, 271–272
sample code (basic), 273–275
sample code (static collections), 275–276
sample code (versioned collections), 276
states, 272–273
equivalence compared to identity, 80–81
error handling. See also exception handling
MSIL programming, 431–432
validating object states, 72
Error List window, 156
Error objects, mapping COMException class to, 342
escape characters, 19–20
evaluation stacks, 405–406
EventArgs class, 321
events
EventArgs class, 321
exception handling, 323
overriding, 101
overview, 291, 295–296, 319
publishers, 320
publishing, 319–320
raising, 321
sealed, 107
subscribe, 320–321
syntax, 319
EventTypeFilter constructors, 484
ExactSpelling, 614–615
Exception Assistant, 351
exception clauses, 431
exception handling. See also error handling
AppDomain.UnhandledException, 349–350
Application.ThreadException, 348–349
catch statements, 329–330
COM Callable Wrappers (CCWs), 345
COM interoperability exceptions, 341–345
common exception model, 327
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Common Language Runtime (CLR), 325


delegates, 312
events, 323
Exception Assistant, 351
Exception Information Table, 333
exception translation, 340
Exceptions dialog box, 351–352
finally statements, 332
managing exceptions in Visual Studio, 351–352
metadata, 352
multicast delegates, 312
nested try blocks, 333–334
overview, 325–326, 546–547
Portable Executable Common Object File Format (PE COFF), 352
propagating exceptions, 330–331
reflection, 352
remote exceptions, 345–347
rethrowing exceptions, 330
sample code, 326
serializing application exceptions, 346
structured exception handling, 327
System.Exception constructors, 336
System.Exception functions, 336
System.Exception methods, 336
System.Exception overview, 335
System.Exception properties, 337
termination handlers, 332
try blocks, 326
try statements, 327–328
unhandled exceptions, 347–350
walkthrough, 547
Exception Information Table, 333
exception translation, 340
Exceptions dialog box, 351–352
explicit interface member implementation, 115–117
explicit marshaling, 622–624
expressions
debugging with Visual Studio 2005, 466–468
order of precedence, 38
overview, 38
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
F
FCL (Framework Class Library), 31
features, core language
blocks, 16
characters, 18
comments, 10
escape characters, 19–20
generic types, 17
keywords, 25–29
line terminators, 9
nullable types, 18
numeric suffixes, 18–19
operators, 21–24
overview, 7
preprocessor directives, 13–16
primitives, 29
punctuators, 8–9
symbols and tokens overview, 7
tabs, 8
Unicode characters, 18
verbatim characters, 20–21
white space, 8
feedback, questions, or comments, xxiv
fields
accessibility, 53
declaration syntax, 52
overview, 52
private fields, 53
read-only fields, 53
volatile fields, 54
File Breakpoint dialog box, 456
filter command, 458–459
filters, 483
finalization
critical finalization objects, 592
finalizers, 569–570
garbage collections, 537
overview, 537–538
Finalize method
destructors, 563
syntax, 562
termination handler, 564
finalizers
considerations, 567
Console class, 576
constructors, 575–576
critical finalization objects, 592
deep object graphs, 574
destructors, 562
Dispose method, 577
expense, 568
multithreading, 568–569
order of finalization, 569–570
overview, 562–566
race conditions, 574
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

reentrancy, 574
resurrection, 571–573
running guarantees, 568
threads, 567, 569
virtual functions, 569–570
zombies, 571
finally statements
Dispose method, 577
overview, 332
fixed-size buffers, 624–625
fixed statement, 609–610
fonts, formatting, 158
for keyword, 163
formatted types, 618–620
Framework Class Library (FCL), 31
functions
breakpoints, 453–455
call performance, 383
members, 51
operators, 261–263
overloading, 62–63
overview, 54–55
parameters, 58–61
pointers, 295
static members, 261–263
System.Exception, 336
fuslogvw.exe (Assembly Binding Log Viewer Tool), 368
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
G
garbage collections
boxing, 559
concurrent garbage collection, 559–560
finalization, 537
finalizers. See finalizers
GC class, 598
generations, 534
overview, 555–560
reference tree, 531
garbage collector (GC)
flavors, 559–560, 561–562
garbage collection overview, 555
GC class, 598
overview, 530
Server GC, 559, 560–562
Workstation GC, 559, 560
GC. See garbage collector (GC)
GC class, 598
General window debugging options, 443–445
generations
garbage collections, 534, 555
overview, 534
walkthrough, 534–537
generic enumerable objects, 279
generic enumerators
IEnumerable<T> interface, 279
IEnumerator<T> interface, 279–280
overview, 278
sample code (versioned collections), 281
generic methods
derivation constraints, 249
overloaded methods, 244–245
overview, 243
prototypical generic method, 243
suitability, 238
syntax, 244
this reference for generic types, 246
type inference, 244
generic types
casting, 256–257
closed constructed types, 243
constructed types, 243
derivation constraints, 249
inheritance, 257–260
interfaces, 266–267
MSIL view, 265
nested types, 259–260
nodes, 250
open constructed types, 243
overview, 17, 233
serialization, 263
static members, 260
suitability, 238
syntax, 242
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

this references, 246


type parameters, 239–242
generics
anonymous methods, 318
attributes, 238, 389–392
collections, 237, 266–267
compared to parameterized templates, 265
compared to parametric polymorphism, 265
constraints. See constraints
constructors, 238
creating generic types, 387
delegates, 306–307
enumerators, 267
GetGenericArguments method, 386
GetGenericTypeDefinition method, 385
GetType method, 384
indexers, 238
inheritance polymorphism, 236
internals, 265–266
IsGeneric Boolean property, 383
IsGenericMethod property, 383
IsGenericTypeDefinition Boolean property, 383
MakeGenericType method, 387
multiple parameters, 241
nested parameters, 242
operators, 251
overview, 233, 235, 383
parametric polymorphism, 238
predefined attributes, 390
programmer-defined custom attributes, 390
properties, 238
pseudo-custom attributes, 390
reflection security, 388
StackInt class, 235
static members, 265–266
typeof operator, 384
types. See generic types
GetCustomAttribute method, 396, 397
GetCustomAttributes method, 396–397
GetGenericArguments method, 386
GetGenericTypeDefinition method, 385
GetInvocationList method, 303
GetType method, 384
global methods, 412
global namespaces
compared to nonglobal namespaces, 33
overview, 32
GUID heap, 358
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
H
HandleCollector class, 596–597
handles, 596–597
Hashtable collection
IDictionaryEnumerator enumerator, 225
members, 222–224
overview, 222
Header elements, 166
heaps
Blob, 358
GUID, 358
String, 358
Userstring, 358
Hello World applications
metadata validation, 360
overview, 403–405
sample C# programs, 30–31
sample MSIL programs, 403–405
hit count command, 457
HybridDictionary collection, 232
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
I
IAsyncResult object properties, 308
ICloneable interface
Object.MemberwiseClone method, 95
overview, 207
ICollection interface, 207
IDE. See integrated development environment (IDE)
IDE Navigator, 142
identifiers, 24
identity compared to equivalence, 80–81
IDictionaryEnumerator enumerator, 225
IDisposable interface
Close method, 584
Disposable pattern considerations, 582
Disposable pattern overview, 581–582
Dispose method. See Dispose method
disposing inner objects, 586–587
overview, 577–580
reusable objects, 585
IEnumerable interface, 207
IEnumerable<T> interface
generic enumerable objects, 279
Yield statements, 284
IEnumerator interface, 278
IEnumerator<T> interface, 279–280
IErrorInfo to COMException mapping, 342
ILASM. See Intermediate Language Assembler (ILASM)
ILDASM. See Intermediate Language Disassembler (ILDASM)
IList interface
ArrayList collection, 215
members, 208
overview, 208
Immediate window
aliases, 470–471
IntelliSense, 469
limitations, 469
navigating, 469
overview, 468
implements keyword, 421
Imports elements, 167
Increment (++) operator overloading, 632
indexers
abstract, 106
arrays, compared to, 209
generics, 238
overloading, 210
overview, 208
properties, compared to, 208–209
sample code, 209
sealed, 107
syntax, 209
inheritance. See also classes
abstract, 106–107
access modifiers, 98–99
attributes, 130–131
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

base types, 83
casting, 125–130
class diagrams, 149
class hierarchies, 149–151
class refinement, 81
composition, 83
constructors, 108–111
containment, 83
cross-language inheritance, 89
derived types, 83
destructors, 108–111
Employee class, 96
generic types, 257–260
implementing, 98–99
interfaces. See interfaces
MSIL programming, 420–421
nested types, 259–260
new modifier, 102–105
operators, 128–130
overload vs. override, 100
override keyword, 99
overriding events, 101
overriding methods, 258–259
overriding overview, 99–101
overview, 83
polymorphism. See polymorphism
sample code, 88–89
sealed, 107–108
syntax, 98
System.Object, 90
terminology, 87
virtual keyword, 99
Visual Studio 2005, 149–151
inheritance polymorphism, 236
instance constructors, 393
instance fields, 52
instance members, 50
instructions, MSIL
arithmetic instructions, 429–433
boxing, 419
branching, 423–427
call instructions, 426
comparative branching instructions, 424
compare instructions, 423
list of, 433
load method, 415–417
overview, 414
short forms, 414–415
store method, 415–417
integer constraints, 251
integrated development environment (IDE)
adding references, 141
AutoRecover, 143
Community menu, 137
creating projects, 137–138
Data menu, 141–142
Data Source Configuration Wizard, 141
IDE Navigator, 142
managing windows, 142
overview, 136
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Solution Explorer, 138–141


Start Page, 136–137
IntelliSense
Immediate window, 469
inserting code snippets, 162
overview, 156–158
interface constraints, 252
interfaces
abstract classes, compared to, 112
attributes, 112
constraints, 252–253
explicit interface member implementation, 115–117
generic types, 266–267
ICloneable, 207
ICollection, 207
IEnumerable, 207
IList, 208
implementing, 113–114
overview, 111–113, 421–422
polymorphism, 123
reimplementation, 119
syntax, 112
System.Array, 189
Intermediate Language Assembler (ILASM)
overview, 403
roundtripping, 436
Intermediate Language Disassembler (ILDASM)
command-line options, 362–363
elements, 362
metadata, 359, 360–364
Interop marshaler, 611
introduction to Microsoft Visual C# 2005, 3–4, xxi–xxii
invocation
asynchronous, 307
dynamic, 373–378
lists for multicast delegates, 298, 303–306
Invoke method, 300
is operator, 128
IsGeneric Boolean property, 383
IsGenericMethod property, 383
IsGenericTypeDefinition Boolean property, 383
ItemGroup elements, 177
iterative statements, 41–44
iterator blocks, 285
iterators
internals, 286–287
iterator blocks, 285–286
nested classes, 286
overview, 269–270, 283
sample code (complex iterations), 290
sample code (dual iteration), 287–288
sample code (overview), 287
sample code (reverse iteration), 288
sample code (temporary collections), 289
Yield statements, 284–285
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
J
jagged arrays
overview, 187, 194
sample code, 194
syntax, 194
JIT. See just-in-time (JIT) compilers; just-in-time (JIT) debugging
jitters, 401
just-in-time (JIT) compilers, 401
just-in-time (JIT) debugging
DebuggableAttribute, 501–503
Microsoft Error Reporting dialog box, 504
Modules window, 447–448
Native window, 447
overview, 446, 504–506
Symbols window, 447–448
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
K
keywords
abstract, 106
delegate, 296
delegate keyword, 313
implements, 421
interface, 421–422
for keyword, 163
list of, 25
override, 99
overview, 25
params, 211–212
return, 57
struct, 254
tracepoints, 461
unsafe, 603
virtual, 99
Knowledge Base articles, xxiv
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
L
language origins, 4–6
late binding delegates, 380
LayoutKind enumeration, 618
LeftShift operator overloading, 633
line directives, 16
line terminators, 9
links
code samples for this book, xxiv
Constrained Execution Region (CER) information, 593
Debugging Tools for Windows, 500
Microsoft Knowledge Base articles, xxiv
Microsoft Press Technology Updates Web page, xxiii
Microsoft Public Symbol Store, 548
support for this book, xxiv
listeners
managing, 483
overview, 481
predefined, 481–482
TraceListenerCollection, 483
Literal elements, 167
load method, 415–417
local variables
anonymous methods, 316
overview, 36, 55
scope, 55–56
syntax, 55
Locals window, 468
location command, 456
logical operators. See mathematical and logical operator overloading
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
M
MageUI (Manifest Generation and Editing) tool, 183
main entry points, 35–36
MakeGenericType method, 387
Managed Debugger (MDbg)
commands, 511–512
overview, 503, 506–507
walkthrough, 507–510
managed heap
generations, 534
overview, 530
manifest, 355
Manifest Generation and Editing (MageUI) tool, 183
MarshalAs attribute, 624
marshaling, explicit, 622–624
mathematical and logical operator overloading
C++ vs. C# languages, 628
Decrement (-) operators, 632
implementing, 629–632
Increment (++) operators, 632
LeftShift operators, 633
operator false, 634
operator true, 634
operator|| and operator&&, 636–637
operator== and operator!=, 635
overview, 628–629
paired operators, 635–637
replacement methods, 646
RightShift operators, 633
MDbg. See Managed Debugger (MDbg)
member functions
constructors, 63
destructors, 68
function code, 54–55
function overloading, 62–63
local variables, 55–56
methods, 56
nested types, 73
overview, 54
parameters, 58–61
partial classes, 74–76
properties, 69–72
returns, 57–58
members
abstract, 106
accessibility, 49
ArrayList collection, 215–219
attributes, 49
BitArray collection, 219–220
class members, overview, 48
data members, 51
delegates, 306
function members, 51
Hashtable collection, 222–224
instance members overview, 50
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

LayoutKind enumeration, 618


modifiers, 49
Queue collection, 226–227
sealed, 108
SortedList collection, 228–230
static members overview, 50
System.Array, 196–199
UnmanagedType enumeration, 623
WeakReference class, 591
MemberTypes enumeration, 370
memory
breakpoints memory commands, 516–518
Constrained Execution Region (CER), 592–594
counters, 538–539
destructors, 538
display memory commands, 515–516
Dispose method. See Dispose method
dump files. See dump files
finalization, 537–538
finalizers. See finalizers
garbage collection overview, 555–559
garbage collector (GC), 530
GC class, 598
GC flavors, 559–560
generations, 534–537
HandleCollector class, 596–597
handles, 596–597
IDisposable interface. See IDisposable interface
managed heap, 530
managing, 530, 550, 553–554
Memory window, 474
Object.Finalize, 538
Performance Monitor, 538–539
pressure, 596
reference tree, 531–533
thread local storage (TLS), 553, 568, 580
unmanaged resources. See unmanaged resources
Virtual Memory Manager (VMM), 530
VirtualAlloc, 530
walkthrough, 531–533
weak references. See weak references
Memory window, 474
metadata
attributes, 356
collections, 371
exception handling, 352
heaps, 358
Intermediate Language Disassembler (ILDASM), 359, 360–364
manifest, 355
overview, 355
PEVerify, 359
pure time, 360
streams, 358
tables, 357
tokens, 357–358
validation, 359–360
method directives, 412–413
methods
abstract, 106
accessibility, 56
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

AddMemoryPressure, 596
anonymous. See anonymous methods
BeginInvoke, 307–309
calling, 425–427
Close, 584
Combine, 302
CreateDelegate, 381–382
Dispose. See Dispose method
DynamicInvoke, 382
EndInvoke, 309–310
Finalize, 562
function parameters, 58–61
generic. See generic methods
GetCustomAttribute, 396, 397
GetCustomAttributes, 396–397
GetGenericArguments, 386
GetGenericTypeDefinition, 385
GetInvocationList, 303
GetType, 385
global, 412
inheritance, 258–259
Invoke, 300
load, 415–417
MakeGenericType, 387
MulticastDelegate type, 306
Object.Equals, 92
Object.GetHashCode, 93
Object.GetType, 93
Object.MemberwiseClone, 94–95
Object.ReferenceEquals, 95
Object.ToString, 94
overriding, 258–259
overview, 56
private static, 317
RemoveMemoryPressure, 596
return types, 57–58
sealed, 107
static, 317
store, 415–417
syntax, 56
System.Array, 199–203
System.Enum, 79
System.Exception, 336
System.Object, 91
TraceSource, 476–477
Microsoft Build Engine (MSBuild)
command-line switches, 180
ItemGroup elements, 177
items, 177
overview, 135, 176
project files, 179–180
properties, 177
reserved properties, 177
syntax, 180
Target elements, 178
tasks, 178–179
walkthrough, 180–181
Microsoft Error Reporting dialog box, 504
Microsoft intermediate language programming. See MSIL programming
Microsoft Knowledge Base articles, xxiv
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Microsoft Press Technology Updates Web page, xxiii


Microsoft Public Symbol Store Web site, 548
Microsoft Visual Studio 2005. See Visual Studio 2005
modifiers
list of, 47
members, 49
overview, 46
Modules window, 472–473
monitors, 540
MSBuild. See Microsoft Build Engine (MSBuild)
MSIL programming
arithmetic instructions, 429–433
arrays, 428
assembly directives, 406–409
boxing, 419
branching, 423–427
class directives, 409–412
Common Language Runtime (CLR), 401
complex tasks, 417
debugging with Visual Studio 2005 overview, 436
directives, 406
evaluation stacks, 405–406
exception clauses, 431
generic types, 265
Hello World application, 403–405
ILASM. See Intermediate Language Assembler (ILASM)
inheritance, 420–421
instructions, 414–417
interfaces, 421–422
Intermediate Language Assembler. See Intermediate Language Assembler (ILASM)
Just-in-time (JIT) compilers, 401
managing types, 417–418
method directives, 412–413
miscellaneous operations, 432
overview, 399, 401–403, 406
process execution, 433–436
roundtripping, 434–436
scoped exceptions, 432
structures, 422
multicast delegates
arrays of delegates, 301
exception handling, 312
invocation lists, 303
overview, 298
MulticastDelegate type, 306
multidimensional arrays
array hierarchy, 193
four-dimensional array example, 193
nested arrays, 193
overview, 187, 191
sample code, 193
syntax, 192
multiline comments (/* and */), 10
mutexes, 540
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
N
namespaces
Framework Class Library (FCL), 31
global, 32
global vs. nonglobal, 33
overview, 31
Reflection, 170
Reflection namespace, 364
NameValueCollection collection, 232
nested arrays, 193
nested classes
anonymous methods, 317
enumerators, 287
iterators, 286
nested parameters, 242
nested try blocks, 333–334
nested types
accessibility, 73
generic types, 259–260
inheritance, 259–260
overview, 73
syntax, 73
new keyword, 102
new modifier
overview, 102–105
polymorphism, 124–125
Next Statement command, 462
nodes, 250
nonblittable types, 611–612, 618
nonglobal namespaces compared to global namespaces, 33
nonsecure code. See unsafe code
nullable types, 18, 37
numeric suffixes, 18–19
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
O
Object Browser window, 144–145
Object elements, 167
Object.Equals method
consistency, 92
overview, 92
reflexivity, 92
symmetry, 92
transitivity, 92
Object.Finalize, 538
Object.GetHashCode method, 93
Object.GetType method, 93
Object.MemberwiseClone method, 94–95
Object.ReferenceEquals method, 95
objects
disposing inner, 586–587
enumerable, 270
reusable, 585
System.Object. See System.Object
Object.ToString method, 94
open constructed types, 243
operator false, 634
operator overloading
Common Language Specification (CLS), 631
conversion operators. See conversion operator overloading
Decrement (-) operators, 632
implementing, 629–632
Increment (++) operators, 632
internals, 645–647
LeftShift operators, 633
mathematical and logical operators. See mathematical and logical operator overloading
operator false, 634
operator string operator, 641–642
operator true, 634
operator|| and operator&&, 636–637
operator== and operator!=, 635
overview, 627–628
paired operators, 635–637
relational operators, 646
RightShift operators, 633
Summation class, 643
summation notation, 642–645
Summation type, 643
operator string operator, 641–642
operator true, 634
operator|| and operator&&, 636–637
operator== and operator!=, 635
operators
binary, 22
Boolean, 23
compound, 22–23
conversion. See conversion operator overloading
Decrement (-) operators, 632
expressions, 38
functions, 261–263
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

generics, 251
identifiers, 24
Increment (++) operators, 632
inheritance, 128–130
is operator, 128
LeftShift, 633
logical. See mathematical and logical operator overloading
mathematical. See mathematical and logical operator overloading
as operator, 128
operator false, 634
operator string, 641–642
operator true, 634
operator|| and operator&&, 636–637
operator== and operator!=, 635
overloading. See operator overloading
overview, 21
pointer, 24
relational, 646
RightShift, 633
static members, 261–263
ternary, 24
unary, 21
OrderedDictionary collection, 232
origins of language, 4–6
outer variables, 316–318
Output window, 464
overloading
constructors, 64
functions, 62–63
indexers, 210
methods, 244–245
operators. See operator overloading
overriding, compared to, 100
override keyword, 99
overriding
events, 101
methods, 258–259
overloading, compared to, 100
overview, 99
overview, 3–4, xxi–xxii
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
P
paired operators, 635–637
parameterized templates compared to generics, 265
parameters
arrays, 213–214
bound parameters, 243
functions, 58–61
multiple parameters for generics, 241
params keyword, 211–212
pointers, 608–611
type parameters, 239
parametric polymorphism
compared to generics, 265
overview, 238
params keyword, 211–212
partial classes, 74–76
PE COFF (Portable Executable Common Object File Format), 352
performance, function call, 383
Performance Monitor, 503, 538–539
PEVerify
arguments, 359
metadata validation, 359
options, 359–360
syntax, 359
pinned pointers, 599
PInvoke. See Platform invocation services (PInvoke)
Platform invocation services (PInvoke)
BestFitMapping, 617
CharSet, 617
directional attributes, 620
DllImport, 612–616
explicit marshaling, 622–624
fixed-size buffers, 624–625
formatted types, 618–620
Interop marshaler, 611
LayoutKind enumeration, 618
MarshalAs attribute, 624
overview, 602, 611
StringBuilder class, 620–621
ThrowOnUnmappableChar, 617
unmanaged callbacks, 621–622
pointer operators
list of, 24
overview, 24
sample code, 24
pointers
exposing, 605
fixed statement, 609–610
initializing, 605
parameters, 608–611
pinned, 599
raw, 599
return types, 608–611
stackalloc command, 610–611
symbols, 606–607
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

syntax, 605
unsafe code, 604–607
void, 605
polymorphism
advantages, 120
inheritance, 236
interfaces, 123
new modifier, 124–125
overview, 119–123
parametric, 238
requirements, 121
Portable Executable Common Object File Format (PE COFF), 352
position parameters, 391
predefined attributes, 390
preprocessor directives
conditional, 14
declarative, 13
diagnostic, 15
line, 16
overview, 13
region, 15
PreserveSig, 615
Preview Changes dialog box, 172
primitives
list of, 29–30
overview, 29
private constructors, 63
private fields, 53
private nested classes, 317
private static methods, 317
process execution, 433–436
Processes window, 473
profiles, 160
program samples, 30–31
programmer-defined custom attributes, 390
propagating exceptions, 330–331
properties
abstract, 106
error handling, 72
generics, 238
IAsyncResult object, 308
indexers, compared to, 208–209
IsGeneric Boolean, 383
IsGenericMethod, 383
IsGenericTypeDefinition Boolean, 383
Microsoft Build Engine (MSBuild), 177
MulticastDelegate type, 306
overview, 69–72
read-only, 72
sealed, 107
SourceSwitch, 480
syntax, 70
System.Array, 203–204
System.Exception, 337
TraceListener class, 482
TraceSource, 478
validating object states, 72
write-only, 72
pseudo-custom attributes, 390
Public Symbol Store Web site, 548
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Publish Wizard, 185–186


publishers, 320
punctuators
colon, 9
comma, 9
dot, 9
overview, 8
semicolon, 8
pure time, 360
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
Q
questions, comments, or feedback, xxiv
Queue collection
members, 226–227
overview, 226
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
R
raw pointers, 599
RCW (Runtime Callable Wrapper), 602
read-only fields, 53
read-only properties, 72
rectangular arrays. See multidimensional arrays
recursive constraints, 250
refactoring
operations, 172
overview, 171
Preview Changes dialog box, 172
Refactoring menu, 172
walkthrough, 173–176
Refactoring menu, 172
reference tree, 531–533
reference types
constraints, 254
overview, 45
user-defined types, 254
References elements, 167
refinement of classes, 81
reflection
Activator class, 378
assembly loading, 367–369
attributes, 389–392, 396–398
binders, 375–378
casting, 380
creating generic types, 387
dynamic invocation, 373–378
exception handling, 352
function call performance, 383
GetCustomAttribute method, 396, 397
GetCustomAttributes method, 396–397
GetGenericArguments method, 386
GetGenericTypeDefinition method, 385
GetType method, 384
IsGeneric Boolean property, 383
IsGenericMethod property, 383
IsGenericTypeDefinition Boolean property, 383
late binding delegates, 380–382
MakeGenericType method, 387
overview, 355, 364, 383
predefined attributes, 390
programmer-defined custom attributes, 390
pseudo-custom attributes, 390
sample code, 372, 379–380
security, 388
type creation, 378–380
Type objects, 365–367
typeof operator, 384
Reflection namespace
code snippets, 170
overview, 364
Reflection trees, 366
ReflectionPermission flags, 388
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

reflexivity, 92
region directives, 15
Registers window, 475–476
relational operators, replacement methods, 646
Release configuration
overview, 441
settings, 442
remote exceptions, 345–347
RemoveMemoryPressure method, 596
resources for this book
Constrained Execution Region (CER) information, 593
Debugging Tools for Windows, 500
links to code samples for this book, xxiv
Microsoft Knowledge Base articles, xxiv
Microsoft Press Technology Updates Web page, xxiii
Microsoft Public Symbol Store, 548
support for this book, xxiv
resurrection, 571–573
rethrowing exceptions, 330
return keyword, 57
return statements, 285
return types
methods, 57–58
pointers, 608–611
reusable objects, 585
reverse iteration, 288
RightShift operator overloading, 633
roundtripping, 434–436
Runtime Callable Wrapper (RCW), 602
Runtime Debugger (CorDbg). See Managed Debugger (MDbg)
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
S
safe handles, 593–594
sample C# programs
Binder class, 377–378
complex iterations, 290
conversion operator overloading, 640–641
Dispose method, 577
dual iteration, 287–288
dynamic binding, 374
enumerators (basic), 273–275
enumerators (static collections), 275–276
enumerators (versioned collections), 276
exception handling, 326
four-dimensional array sample code, 193
generic enumerators (versioned collections), 281
GetGenericArguments method, 386
GetGenericTypeDefinition method, 385
GetType method, 385
Hello World application, 30–31, 360
indexers, 209
inheritance, 88–89
iterator examples (complex iterations), 290
iterator examples (dual iteration), 287–288
iterator examples (overview), 287
iterator examples (reverse iteration), 288
iterator examples (temporary collections), 289
jagged arrays, 194
links to code samples for this book, xxiv
multidimensional arrays, 193
reflection, 372
reverse iteration, 288
sheet collections, 239
temporary collections, 289
tracing, 480, 485–486, 489–491
type creation, 379–380
type parameters, 239
sample MSIL programs, 403–405
scoped exceptions, 432
Script Explorer window, 465
sealed
classes, 107
events, 107
indexers, 107
members, 108
methods, 107
overview, 107
properties, 107
static members, 107
security, 388
selection statements, 38–41
semicolon punctuators, 8
serialization, 263
serializing application exceptions, 346
Server GC
configuring GC flavor, 561–562
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

overview, 559, 560–561


SetLastError, 615–616
sheet collections, 239
sheet generic type, 241
short-form instruction syntax, 414–415
single-dimensional arrays
overview, 187
syntax, 189
single-line comments (//), 10
single-line documentation comments (///), 10–12
singletons, 67
Snippet elements, 167
snippets. See code snippets
Solution Explorer
overview, 138–139
project types, 140–141
special-purpose project templates, 140
Web project types, 140
Son of Strike (SOS)
commands, 522–523
overview, 504, 519–520
thread commands, 541
walkthrough part I, 520–523
walkthrough part II, 523–524
SortedList collection
members, 228–230
overview, 228
SOS. See Son of Strike (SOS)
source code formatting, 159
SourceFilter constructors, 484
SourceLevels, 479
SourceSwitch
constructors, 480
overview, 479
properties, 480
specialized collections
list of, 232–233
overview, 232
Stack collection
members, 231–232
overview, 231
stack trace commands, 514–515
stackalloc command, 610–611
StackInt class, 235
stacks, evaluation, 405–406
Start Page, 136–137
statements
fixed, 609–610
iterative, 41–44
selection, 38–41
Yield, 284–285
static classes, 50
static collections, 275–276
static constructors, 66
static fields, 52
static members
abstract, 106
closed constructed types, 260
deserialization, 263
generic types, 260
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

generics internals, 265–266


operator functions, 261–263
overview, 50
sealed, 107
serialization, 263
static classes, 50
static methods, 317
step commands, 518–519
store method, 415–417
streams, 358
String heap, 358
StringBuilder class, 620–621
StringBuilder type, 168
StringCollection collection, 232
StringDictionary collection, 232
struct keyword, 254
structured exception handling
catch statements, 329–330
Exception Information Table, 333
finally statements, 332
nested try blocks, 333–334
overview, 327
propagating exceptions, 330–331
rethrowing exceptions, 330
termination handlers, 332
try statements, 327–328
structures
MSIL programming, 422
overview, 45, 76–77
syntax, 76
subscribers, 320–321
Summation class, 643
summation notation, 642–645
Summation type, 643
Surround With feature, 158
switches, 479
symbol servers
overview, 548
Symsrv symbol server, 548–549
symbol stores, 548
symbols and tokens
blocks, 16
breakpoints, 461
characters, 18
comments, 10
debugging, 547–549
escape characters, 19–20
generic types, 17
keywords, 25–29
line terminators, 9
list of, 8
metadata, 357–358
nullable types, 18
numeric suffixes, 18–19
operators, 21–24
overview, 7
pointers, 606–607
preprocessor directives, 13–16
primitives, 29
punctuators, 8–9
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

tabs, 8
TRACE symbol, 476
Unicode characters, 18
verbatim characters, 20–21
white space, 8
symmetry, 92
Symsrv symbol server, 548–549
syntax
anonymous methods, 314
arrays, 189–191, 428
assembly directives, 407
attributes, 391
BeginInvoke method, 308
Binder class, 375
calling methods, 425
CDATA, 168
class declarations, 46
class member access, 48
constants, 52
constructors, 63, 109
CreateDelegate method, 381
delegates, 298
destructors, 68
DllImportAttribute, 612
dynamic binding, 373, 374
DynamicInvoke method, 382
EndInvoke method, 310
enumerations, 78
events, 319
field declarations, 52
Finalize method, 562
fixed-size buffers, 625
generic methods, 244
generic types, 242
GetGenericArguments method, 386
GetGenericTypeDefinition method, 385
GetInvocationList method, 303
indexers, 209
inheritance, 98
instance members, 50
instructions, MSIL, 414–415
interfaces, 112
is operator, 129
jagged arrays, 194
local variables, 55
methods, 56
Microsoft Build Engine (MSBuild), 180
multidimensional arrays, 192
nested types, 73
as operator, 130
PEVerify, 359
pointers, 605
properties, 70
single-dimensional arrays, 189
stackalloc command, 611
structures, 76
UnhandledExceptionEventHandler, 350
VirtualAlloc, 530
WaitForMultipleObjects, 541
system requirements, xxii–xxiii
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Sys tem.Array. See also arrays


Array.AsReadOnly method, 199
Array.Clone method, 200
Array.CreateInstance method, 201–202
Array.FindAll method, 202–203
Array.Resize method, 203
Array.SyncRoot property, 204
comparable elements, 205–207
ICloneable interface, 207
ICollection interface, 207
IEnumerable interface, 207
IList interface, 208
indexers, 208–210
interfaces, 189
members, 196–199
methods, 199–203
overview, 189, 196
properties, 203–204
System.Enum methods, list of, 79
System.Exception
application exceptions, 338–340
COM Callable Wrappers (CCWs), 345
COM interoperability exceptions, 341–345
constructors, 336
exception translation, 340
functions, 336
methods, 336
overview, 335
properties, 337
System.MulticastDelegate class
combining delegates, 302
overview, 301
removing delegates, 302
System.Object
members, 91
methods, 91
Object.Equals method, 92
Object.GetHashCode method, 93
Object.GetType method, 93
Object.MemberwiseClone method, 94–95
Object.ReferenceEquals method, 95
Object.ToString method, 94
overview, 90
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
T
tables, metadata, 357
tabs, 8
Target elements, 178
technology updates, xxiii
templates, parameterized, 265
temporary collections, 289
termination handlers, 332, 564
ternary operators, 24, 628
this references
closed constructed types, 246
constructors, 110
generic types, 246
overview, 50–51
XClass type, 246
thread local storage (TLS)
application, 568, 580
overview, 553
thread-safe Dispose method, 585
threads
AwareLock.Enter, 541
commands, 541–542
finalizers, 567, 569
monitors, 540
mutexes, 540
overview, 539–541
Son of Strike (SOS), 541
WaitForMultipleObjects, 541
WaitHandle.WaitAll, 541
walkthrough, 542–546
Windows Debugger (WinDbg), 541
Threads window, 472
ThrowOnUnmappableChar, 617
tilde (~) command, 514
Tlist, 513
TLS. See thread local storage (TLS)
tokens. See symbols and tokens
TRACE symbol, 476
TraceListener class properties, 482
TraceListenerCollection, 483
TraceOptions, 483
tracepoints
keywords, 461
overview, 459–461
TraceSource
members, 476
methods, 476–477
overview, 476
properties, 478
sample code, 485–486
tracing
activity traces, 479
configuration files, 488–489
EventTypeFilter, 484
filters, 483
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

levels, 478–479
listeners, 481–482
overview, 476
sample code, 480, 485–486, 489–491
source levels, 479–480
SourceFilter, 484
SourceSwitch, 479
switches, 479
TraceListener class, 482
TraceListenerCollection, 483
TraceOptions values, 483
TraceSource. See TraceSource
transitivity, 92
trapping unhandled exceptions, 347
try blocks
exception handling, 326
nested try blocks, 333–334
try statements, 327–328
type inference, 244
Type methods, 371
Type objects
assemblies, 366
browsing information, 370
MemberTypes enumeration, 370
metadata collections, 371
obtaining, 365–367
overview, 365
typeof operator, 366
type parameters
closed constructed types, 243
derivation constraints, 248, 250, 251
multiple parameters, 241
open constructed types, 243
overview, 239
sample code, 239
sheet generic type, 241
typeof operator, 366, 384
types
blittable, 611, 618
browsing information, 370
classes. See classes
collections, 215
creating, 378–380
creating generic, 387
DebuggerBrowsableAttribute, 493–495
DebuggerDisplayAttribute. See DebuggerDisplayAttribute
DebuggerTypeProxyAttribute, 495–496
EventTypeFilter, 484
formatted, 618–620
generic. See generic types
managing, 417–418
MemberTypes enumeration, 370
metadata collections, 371
nested, 73
nonblittable, 611–612, 618
nullable, 18, 37
overview, 45
reference, 45
sample code, 379–380
SourceFilter, 484
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

SourceLevels, 479
StringBuilder, 168
Summation, 643
TraceListenerCollection, 483
TraceSource. See TraceSource
user-defined, 627
value, 45
WeakReference, 588
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
U
unary operators
list of, 21
overview, 21
unboxing, 278
unhandled exceptions
AppDomain.UnhandledException, 349–350
Application.ThreadException, 348–349
Exception Assistant, 351
overview, 347–348
trapping, 347
UnhandledExceptionEventHandler, 350
Unicode characters, 18
unmanaged callbacks, 621–622
unmanaged resources
boxing, 559
garbage collection overview, 555–559
generations, 555
handles, 596–597
managing, 595–597
memory pressure, 596
overview, 554–555
UnmanagedType enumeration, 623
unsafe code
appropriate uses, 601
blittable types, 611, 618
CharSet, 617
directional attributes, 620
DllImport, 612–616
explicit marshaling, 622–624
fixed-size buffers, 624–625
fixed statement, 609–610
formatted types, 618–620
Interop marshaler, 611
LayoutKind enumeration, 618
MarshalAs attribute, 624
nonblittable types, 611–612, 618
overview, 598–599, 601–603, 625
Platform invocation services. See Platform invocation services (PInvoke)
pointer parameters and return, 608–611
pointers, 604–607
Runtime Callable Wrapper (RCW), 602
stackalloc command, 610–611
StringBuilder class, 620–621
summary, 625
unmanaged callbacks, 621–622
void pointers, 605
unsafe keyword, 603
untrusted code. See unsafe code
URLs. See Web sites
user-defined types
operator overloading, 627
reference type constraints, 254
Userstring heap, 358
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
V
validation, 359–360
value types
constraints, 251, 254
overview, 45
variables
local, 36
outer, 316–318
vectors. See single-dimensional arrays
verbatim characters, 20–21
versioned collections
sample code (enumerators), 276
sample code (generic enumerators), 281
virtual functions, 569–570
virtual keyword, 99
Virtual Memory Manager (VMM), 530
VirtualAlloc, 530
Visual Studio 2005
adding references, 141
association, 151
AutoRecover, 143
building, 176
change tracking, 159
Class Designer, 145
class diagrams, 145–149, 151–154
class hierarchies. See class hierarchies
Class View window, 144
ClickOnce deployment, 135, 182–186
Code Editor, 156–160
code snippets. See code snippets
color formatting, 158
Community menu, 137
creating projects, 137–138
Data menu, 141–142
Data Source Configuration Wizard, 141
debugging. See debugging with Visual Studio 2005
deploying, 176
Error List window, 156
Exception Assistant, 351
Exceptions dialog box, 351–352
font formatting, 158
IDE Navigator, 142
inheritance, 149–151
integrated development environment. See integrated development environment (IDE)
IntelliSense, 156–158
managing exceptions in, 351–352
managing windows, 142
Microsoft Build Engine. See Microsoft Build Engine (MSBuild)
Object Browser window, 144–145
overview, 131, 135–136
profiles, 160
project types, 140–141
refactoring, 171–176
Solution Explorer, 138–141
source code formatting, 159
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

special-purpose project templates, 140


Start Page, 136–137
Surround With feature, 158
Web project types, 140
Visual Studio Debugger, 503
visualizers, 451
VMM (Virtual Memory Manager), 530
void pointers, 605
volatile fields, 54
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
W
WaitForMultipleObjects, 541
WaitHandle.WaitAll, 541
Watch window
expressions, 466–468
overview, 465
weak references
Constrained Execution Region (CER), 592–594
critical finalization objects, 592
internals, 591
overview, 588–590
WeakReference class, 591
WeakReference type, 588
WeakReference class, 591
WeakReference type, 588
Web sites
companion for this book, xxiv
Constrained Execution Region (CER) information, 593
Debugging Tools for Windows, 500
Microsoft Knowledge Base articles, xxiv
Microsoft Press Technology Updates Web page, xxiii
Microsoft Public Symbol Store, 548
support for this book, xxiv
When Breakpoint Is Hit dialog box, 460
when hit command, 459
white space, 8
WinDbg. See Windows Debugger (WinDbg)
Windows Console Debugger (CDB), 503
Windows Debugger (WinDbg)
application symbols, 549
breakpoints memory commands, 516–518
commands list, 513–514
commands overview, 513
directives, 518–519
display memory commands, 515–516
overview, 500, 503, 512
stack trace commands, 514–515
step commands, 518–519
thread commands, 541
tilde (~) command, 514
Tlist, 513
Windows Forms projects
attaching debuggers to running processes, 439–440
class library projects, 441
console application projects, 440–441
debugging, 438
Workstation GC
concurrent garbage collection, with, 560
concurrent garbage collection, without, 560
overview, 559
write-only properties, 72
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Index
X–Y–Z
XClass type, 246
XML Visualizer, 451
Yield statements
IEnumerable<T> interface, 284
iterator blocks, 285
overview, 284
zombies, 571
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

List of Figures
Chapter 1: Introduction to Visual C# Programming
Figure 1-1: Evolution of programming languages from inception to C#

Figure 1-2: The Build pane of the Project Settings window

Figure 1-3: Global vs. non-global namespaces

Chapter 2: Types
Figure 2-1: Figure diagramming the scope and visibility of a local variable

Figure 2-2: ZClass depicted in ILDASM

Chapter 3: Inheritance
Figure 3-1: A basket of marbles

Figure 3-2: Organized baskets of marbles

Figure 3-3: Nouns from the Personnel scenario

Figure 3-4: Nouns grouped by relationships

Figure 3-5: The result of MemberwiseClone

Chapter 4: Introduction to Visual Studio 2005


Figure 4-1: Visual Studio 2005 Start Page

Figure 4-2: New Project dialog box

Figure 4-3: Solution Explorer window

Figure 4-4: Project Designer window

Figure 4-5: Solution Explorer as a tabbed window

Figure 4-6: Data Source Configuration Wizard

Figure 4-7: IDE Navigator

Figure 4-8: AutoRecover window

Figure 4-9: Microsoft Visual Studio Recovered Files dialog box

Figure 4-10: Class View window

Figure 4-11: Object Browser window

Figure 4-12: Class diagram that contains a single class

Figure 4-13: Class Details window

Figure 4-14: Class Diagram toolbox


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-15: Add New Interface Dialog box

Figure 4-16: Class inheritance in the class diagram

Figure 4-17: Interface inheritance in the class diagram

Figure 4-18: Rerouted inheritance line

Figure 4-19: Association relationship

Figure 4-20: IEmployee interface details

Figure 4-21: Class diagram of the Personnel library

Figure 4-22: Error List window

Figure 4-23: Parameter info for Console.WriteLine

Figure 4-24: IntelliSense for a generic type

Figure 4-25: Add Using smart tag menu

Figure 4-26: Fonts and Colors window

Figure 4-27: Source Formatting window

Figure 4-28: Change tracking of code

Figure 4-29: Import And Export Settings Wizard dialog box

Figure 4-30: Toolbox with code

Figure 4-31: Code snippet of the for keyword

Figure 4-32: Customized code snippet

Figure 4-33: Code Snippets Manager

Figure 4-34: Reflect Method snippet

Figure 4-35: Preview Changes dialog box

Figure 4-36: Airline Seats application

Figure 4-37: Rename dialog box

Figure 4-38: Preview Changes—Rename dialog box

Figure 4-39: Extract Interface dialog box

Figure 4-40: Encapsulate Field dialog box

Figure 4-41: Application manifest—Name window

Figure 4-42: Application manifest—Files window

Figure 4-43: Application manifest—Permissions Required window

Figure 4-44: Deployment manifest—Deployment Options window

Figure 4-45: Deployment manifest—Update Options window

Figure 4-46: Publish Wizard—step 1


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 4-47: Publish Wizard—step 2

Figure 4-48: Publish Wizard—step 3

Chapter 5: Arrays and Collections


Figure 5-1: Array of reference types versus value types

Figure 5-2: A command line and the results from running the application

Chapter 6: Generics
Figure 6-1: MSIL view of a generic type

Chapter 7: Iterators
Figure 7-1: A view of the ZClass type, which includes the nested enumerator classes

Figure 7-2: A view of a nested class and fields

Chapter 8: Delegates and Events


Figure 8-1: Asynchronous processing of a delegate

Figure 8-2: C# manifested delegate class

Figure 8-3: Disassembly showing wrapper delegates and anonymous methods

Figure 8-4: Disassembly of nested class for an anonymous method that uses outer variables

Figure 8-5: Disassembly of the event class

Chapter 9: Exception Handling


Figure 9-1: Execution sequence of exception handling

Figure 9-2: Life cycle of an exception

Figure 9-3: The Exception Assistant

Figure 9-4: The Exceptions dialog box

Chapter 10: Metadata and Reflection


Figure 10-1: Layout of a metadata token

Figure 10-2: Simple.exe displayed in ILDASM

Figure 10-3: Diagram of the Reflection tree

Figure 10-4: The Conditional attribute in MSIL code

Chapter 11: MSIL Programming


Figure 11-1: A depiction of the evaluation stack, function parameters, and local variables

Figure 11-2: The dumpbin command with the imports option


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 12: Debugging with Visual Studio 2005


Figure 12-1: Attach To Process window

Figure 12-2: Debug Location toolbar

Figure 12-3: Configuration Manager

Figure 12-4: The General window for setting general debugging options

Figure 12-5: Edit And Continue debug settings

Figure 12-6: Just-In-Time Debugging window

Figure 12-7: Symbols window

Figure 12-8: Modules window

Figure 12-9: Find Symbols dialog box

Figure 12-10: Debug Source Files window

Figure 12-11: Debug pane of the Project Property pages

Figure 12-12: XML Visualizer uncovers a problem

Figure 12-13: XML Visualizer of myxml

Figure 12-14: Dataset Visualizer

Figure 12-15: New Breakpoint dialog box

Figure 12-16: Setting a breakpoint on MethodA

Figure 12-17: Choose Breakpoints dialog box

Figure 12-18: Breakpoint in the Call Stack window

Figure 12-19: Breakpoints window

Figure 12-20: Address Breakpoint Dialog Box

Figure 12-21: File Breakpoint Dialog Box

Figure 12-22: Conditional Breakpoint dialog box

Figure 12-23: Breakpoint Hit Count dialog box

Figure 12-24: Breakpoint Filter dialog box

Figure 12-25: Breakpoints window toolbar

Figure 12-26: When Breakpoint Is Hit dialog box

Figure 12-27: Print a message selected in the When Breakpoint Is Hit dialog box

Figure 12-28: Breakpoint and current line

Figure 12-29: Repositioned current line

Figure 12-30: Debug toolbar

Figure 12-31: Output window


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 12-32: Script Explorer window

Figure 12-33: Watch window with two parameters

Figure 12-34: Watch window with locala, localb, fielda, and fieldb values

Figure 12-35: DumpType.GetReflection expression in the Watch window

Figure 12-36: Results in the Text Visualizer

Figure 12-37: Autos window

Figure 12-38: Find in Files window

Figure 12-39: Call Stack window

Figure 12-40: Call Stack window with Enable Just My Code disabled

Figure 12-41: Threads window

Figure 12-42: Memory window

Figure 12-43: Disassembly window

Figure 12-44: Registers window

Figure 12-45: View of the ZClass and YClass instances before applying DebuggerDisplayAttribute

Figure 12-46: View of ZClass and YClass types in the debugger window after applying the
DebuggerDisplayAttribute type

Figure 12-47: View of ZClass and YClass types before applying the DebuggerBrowsableAttribute type

Figure 12-48: View of ZClass and YClass types after applying DebuggerBrowsableAttribute

Figure 12-49: Call Stack window for a dump

Figure 12-50: Modules window for a dump

Figure 12-51: Son of Strike in the Immediate window

Chapter 13: Advanced Debugging


Figure 13-1: Microsoft Error Report dialog box

Figure 13-2: Just-in-Time Debugging dialog box

Figure 13-3: View of the .NETFramework key and DbgManagedDebugger value

Figure 13-4: Just-In-Time pane

Figure 13-5: The user interface of the Store application

Figure 13-6: Step buttons on the Debugging toolbar

Figure 13-7: Store application and the Transaction dialog box

Figure 13-8: Main window of Dr. Watson

Figure 13-9: Typical dialog box that reports an exception

Chapter 14: Memory Management


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Figure 14-1: Object graph with nonrooted objects

Figure 14-2: Object graph of the Rooted application

Figure 14-3: Rooted application

Figure 14-4: Application properties in the .NET Framework Configuration tool

Figure 14-5: View of the ZClass

Figure 14-6: Weak application

Chapter 15: Unsafe Code


Figure 15-1: The Build window with the unsafe compiler option

Appendix A: Operator Overloading


Figure A-1: Examples of summation notation

Figure A-2: View of the Summation class

Figure A-3: View of ZClass


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

List of Tables
Chapter 1: Introduction to Visual C# Programming
Table 1-1: C# Symbols and Tokens

Table 1-2: Description of Suffixes

Table 1-3: Predefined Escape Sequences

Table 1-4: Unary Operators

Table 1-5: Binary Operators

Table 1-6: List of Compound Operators

Table 1-7: List of Boolean Operators

Table 1-8: List of Pointer Operators

Table 1-9: Overview of C# Keywords with Explanations

Table 1-10: Primitives in C#

Table 1-11: Order of Precedence for Expressions

Chapter 2: Types
Table 2-1: Class Modifier Table

Table 2-2: Type Members

Table 2-3: Accessibility

Table 2-4: Modifiers

Table 2-5: Important System.Enum Methods

Chapter 3: Inheritance
Table 3-1: Inheritance Terminology

Table 3-2: System.Object Methods

Table 3-3: Member Accessibility

Chapter 4: Introduction to Visual Studio 2005


Table 4-1: Project Types

Table 4-2: Web Project Types

Table 4-3: Special-Purpose Project Templates

Table 4-4: Default Code Snippets

Table 4-5: Refactoring Operations


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 4-6: Reserved Properties

Table 4-7: Default Tasks

Table 4-8: MSBuild Switches

Chapter 5: Arrays and Collections


Table 5-1: Interfaces Implemented at System.Array

Table 5-2: System.Array Members

Table 5-3: System.Array Properties

Table 5-4: List Members

Table 5-5: Collection Types

Table 5-6: ArrayList Members

Table 5-7: BitArray Members

Table 5-8: Hashtable Members

Table 5-9: Queue Members

Table 5-10: SortedList Members

Table 5-11: Stack Members

Table 5-12: Specialized Collections

Chapter 6: Generics
Table 6-1: Inheritance Table for Generic Types

Table 6-2: Combination of Overriding Generic Methods

Table 6-3: Generic Types and Interfaces

Chapter 7: Iterators
Table 7-1: Enumerator States

Chapter 8: Delegates and Events


Table 8-1: Delegate Members

Table 8-2: IAsyncResult Properties

Chapter 9: Exception Handling


Table 9-1: Exception Methods

Table 9-2: Exception Properties

Table 9-3: COM Exception Table

Table 9-4: IErrorInfo to COMException Mapping


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Chapter 10: Metadata and Reflection


Table 10-1: Metadata Tables

Table 10-2: Metadata Streams

Table 10-3: PEVerify Options

Table 10-4: Elements of ILDASM

Table 10-5: ILDASM Options

Table 10-6: MemberTypes Enumeration

Table 10-7: Type Methods That Return Metadata Collections

Table 10-8: Abstract Methods of the Binder Class

Table 10-9: ReflectionPermission Flags

Chapter 11: MSIL Programming


Table 11-1: Hello World MSIL Code

Table 11-2: Assembly Directives

Table 11-3: Class Directives

Table 11-4: Directives Included in the Method Block

Table 11-5: Load Instructions

Table 11-6: Store Instructions

Table 11-7: Compare Instructions

Table 11-8: Comparative Branching

Table 11-9: Call Instructions

Table 11-10: Syntax for Defining Arrays

Table 11-11: Arithmetic Instructions

Table 11-12: Exception Clauses

Table 11-13: Miscellaneous MSIL Instructions

Chapter 12: Debugging with Visual Studio 2005


Table 12-1: Control of a Debugging Session

Table 12-2: General Debugging Options

Table 12-3: Hit Count Options

Table 12-4: Filter Contexts

Table 12-5: Tracepoint Keywords

Table 12-6: Breakpoint Symbols


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 12-7: Navigating the Immediate Window

Table 12-8: Command Aliases

Table 12-9: Modules Window Columns

Table 12-10: Processes Window Columns

Table 12-11: Registers

Table 12-12: TraceSource Methods

Table 12-13: TraceSource Properties

Table 12-14: Trace Levels

Table 12-15: Activity Traces

Table 12-16: Source Level

Table 12-17: SourceSwitch Properties

Table 12-18: Trace Listeners

Table 12-19: TraceListener Properties

Table 12-20: TraceOptions Values

Table 12-21: DebuggableBrowserState Values

Chapter 13: Advanced Debugging


Table 13-1: MDbg Commands

Table 13-2: Basic WinDbg Commands

Table 13-3: Stack Trace Commands

Table 13-4: Common Display Memory Commands

Table 13-5: Common Display Memory Commands

Table 13-6: WinDbg Directives

Table 13-7: Son of Strike Commands

Table 13-8: Item, LargeItem, and largeStuff Instances

Table 13-9: Performance Monitor Counters

Chapter 14: Memory Management


Table 14-1: WeakReference Class

Table 14-2: GC Class

Chapter 15: Unsafe Code


Table 15-1: Pointer Symbols

Table 15-2: CallingConvention Enumeration


ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html

Table 15-3: CharSet Enumeration

Table 15-4: LayoutKind Enumeration

Table 15-5: Directional Attributes and C# Keywords

Table 15-6: UnmanagedType Enumeration

Appendix A: Operator Overloading


Table A-1: Replacement Methods for Mathematical and Logical Operators

Table A-2: Replacement Methods for Relational Operators

You might also like