WordPress Shortcode

Link

Accelerated C# 2008 - APress

Programming is exhilarating. It is a breathtaking venture through problems of the mind accented
…

Programming is exhilarating. It is a breathtaking venture through problems of the mind accentedby beautiful vistas as solutions are discovered. Throughout the process, a programmer’s view of theproblems he solves and the solutions to these problems is formed through the lens of the languagethat he uses and thinks in. So, it is important for a programmer to become intimately familiar withthat language.The problems that developers work on are as varied as the developers themselves. They rangefrom medical applications to insurance software, from multimedia applications to data miningtools. The evolution of C# really is about the evolution of the problems that developers face. As theproblems become ever more complex, the language becomes simpler and more powerful to dealwith the complexity.C# began its life as a way to describe reusable components that run in a variety of executionenvironments. During this phase, it solidified its role as a great language for describing the architectureof components and systems while embracing and extending its roots as a C-like language. Oneof the major contributions it added was a fully object-oriented type system that unifies the conceptsof primitive and complex types and garbage collection.While the first version of C# was a major accomplishment, the second release became thedefining moment for the language. The type system became much richer with the inclusion ofgenerics. The language also began to provide features like iterators and anonymous methods thatencourage simpler and more elegant designs. These features enabled more flexible and powerfulframeworks to be developed.The third version of C# really breaks new ground. It blurs the line between code and data. Itintroduces declarative query syntax. It empowers programmers through functional features. All ofthese additions enable programmers to deal with the difficulties of data whether in-memory, in adatabase, or from a web server. Programmers will find that these features put the fun back in programming.In this book, Trey Nash provides a refreshingly clear explanation of the C# language. He notonly understands C#, but he is also able to guide the reader through the process of learning to excelin the language. He makes the journey to understanding enjoyable through thought-provokingexamples while taking the time to motivate each feature and demonstrate common and best practices.I am confident that the reader will write better code by reading this book.

15.
Foreword
P rogramming is exhilarating. It is a breathtaking venture through problems of the mind accented
by beautiful vistas as solutions are discovered. Throughout the process, a programmer’s view of the
problems he solves and the solutions to these problems is formed through the lens of the language
that he uses and thinks in. So, it is important for a programmer to become intimately familiar with
that language.
The problems that developers work on are as varied as the developers themselves. They range
from medical applications to insurance software, from multimedia applications to data mining
tools. The evolution of C# really is about the evolution of the problems that developers face. As the
problems become ever more complex, the language becomes simpler and more powerful to deal
with the complexity.
C# began its life as a way to describe reusable components that run in a variety of execution
environments. During this phase, it solidified its role as a great language for describing the architec-
ture of components and systems while embracing and extending its roots as a C-like language. One
of the major contributions it added was a fully object-oriented type system that unifies the con-
cepts of primitive and complex types and garbage collection.
While the first version of C# was a major accomplishment, the second release became the
defining moment for the language. The type system became much richer with the inclusion of
generics. The language also began to provide features like iterators and anonymous methods that
encourage simpler and more elegant designs. These features enabled more flexible and powerful
frameworks to be developed.
The third version of C# really breaks new ground. It blurs the line between code and data. It
introduces declarative query syntax. It empowers programmers through functional features. All of
these additions enable programmers to deal with the difficulties of data whether in-memory, in a
database, or from a web server. Programmers will find that these features put the fun back in pro-
gramming.
In this book, Trey Nash provides a refreshingly clear explanation of the C# language. He not
only understands C#, but he is also able to guide the reader through the process of learning to excel
in the language. He makes the journey to understanding enjoyable through thought-provoking
examples while taking the time to motivate each feature and demonstrate common and best prac-
tices. I am confident that the reader will write better code by reading this book.
Wes Dyer
C# Compiler and Language Design Teams
Microsoft Corporation
xvii

16.
About the Author
■TREY NASH currently develops software at a market-leading security soft-
ware company. Prior to that, he called Macromedia Inc. home for five
years. At Macromedia, he worked on a cross-product engineering team for
several years, designing solutions for a wide range of products throughout
the company, including Flash and Fireworks. He specialized in
COM/DCOM using C/C++/ATL until the .NET revolution. He’s been glued
to computers ever since he scored his first, a TI-99/4A, when he was a mere
13 years old. He astounded his parents by turning a childhood obsession
into a decent paying career, much to their dismay. Trey received his bache-
lor of science and his master of engineering degrees in electrical
engineering from Texas A&M University. When he’s not sitting in front of a
computer, you can find him working in his garage, honing his skills in card magic (strange but true),
playing his piano, brushing up on a foreign language (Russian and Icelandic are the current
favorites), or playing ice hockey.
xix

17.
About the Technical Reviewer
■SHAWN WILDERMUTH is a Microsoft MVP (C#), MCSD.NET, MCT and is the
founder of Wildermuth Consulting Services, LLC, a company that is dedi-
cated to delivering architecture, mentoring, and software solutions in the
Atlanta, Georgia area. He is also a speaker on the INETA Speaker’s Bureau
and has spoken at several national conferences on a variety of subjects. He is
currently teaching Silverlight across the country during his Silverlight Tour
(http://www.silverlight-tour.com).
Shawn is also the author of several books, including Pragmatic
ADO.NET for Addison-Wesley, and is also the co-author of four Microsoft
Certification Training Kits for Microsoft Press, as well as the upcoming book,
Prescriptive Data Architectures.
He has been writing articles for a number of years for a variety of magazines and web sites,
including MSDN, MSDN Online, DevSource, InformIT, Windows IT Pro, The ServerSide, ONDotNet
and Intel’s Rich Client series. Shawn has enjoyed building data-driven software for more than 20
years. He can be reached at his web site at http://www.wildermuthconsulting.com.
xxi

18.
Acknowledgments
W riting a book is a long and arduous process, during which I have received tons of great support,
which I greatly appreciate, from friends and family. The process would have been much more diffi-
cult, and arguably much less fruitful, without their support.
I would like to specifically call out the following individuals for their contribution to the first
edition of this work. I would like to thank (in no particular order) David Weller, Stephen Toub, Rex
Jaeschke, Vladimir Levin, Jerry Maresca, Chris Pels, Christopher T. McNabb, Brad Wilson, Peter
Partch, Paul Stubbs, Rufus Littlefield, Tomas Restrepo, John Lambert, Joan Murray, Sheri Cain,
Jessica D’Amico, Karen Gettman, Jim Huddleston, Richard Dal Porto, Gary Cornell, Brad Abrams,
Ellie Fountain, Nicole Abramowitz and the entire Apress crew, and finally, Shelley Nash.
During the development of the second edition, I would like to call out the following individuals
for their help and support (again in no particular order): Shawn Wildermuth, Sofia Marchant, Jim
Compton, Dominic Shakeshaft, Wes Dyer, Kelly Winquist, and Laura Cheu.
If I have left anyone out, it is purely my mistake and not one I intended. I could not have done
it without all of your support. Thank you all!
xxiii

19.
Introduction
V isual C# .NET (C#) is relatively easy to learn for anyone familiar with another object-oriented
language. Even someone familiar with Visual Basic 6.0, who is looking for an object-oriented lan-
guage, will find C# easy to pick up. However, although C#, coupled with the .NET Framework,
provides a quick path for creating simple applications, you still need a wealth of information and
must understand how to use it correctly in order to produce sophisticated, robust, fault-tolerant C#
applications. In Accelerated C# 2008 I teach you what you need to know and explain how best to use
your knowledge so that you can quickly develop true C# expertise.
Idioms and design patterns are invaluable for developing and applying expertise, and I show
you how to use many of them to create applications that are efficient, robust, fault tolerant, and
exception safe. Although many of these patterns are familiar to C++ and Java programmers, some
are unique to .NET and its Common Language Runtime (CLR). The following chapters show you
how to apply these indispensable idioms and design techniques to seamlessly integrate your C#
applications with the .NET runtime, focusing on the new capabilities of C# 3.0.
Design patterns document best practices in application design that many different program-
mers have discovered and rediscovered over time. In fact, the .NET Framework itself implements
many well-known design patterns. Similarly, over the past three versions of the .NET Framework
and the past two versions of C#, many new idioms and best practices have come to light. You will
see these practices detailed throughout this book. Also, it is important to note that the invaluable
tool chest of techniques is evolving constantly.
With the arrival of C# 3.0, you can easily incorporate functional programming techniques using
lambda expressions, extension methods, and Language Integrated Query (LINQ). Lambda expres-
sions make it easy to declare and instantiate function delegates at one point. Additionally, with
lambda expressions, it’s trivial to create functionals, which are functions that accept functions as
arguments and typically return another function. Even though you could implement functional
programming techniques in C# (albeit with some difficulty), the new language features in C# 3.0
foster an environment where functional programming can flourish interweaved with the typical
imperative programming style of C#. LINQ allows you to express data query operations (which are
typically functional in nature) using a syntax that is native to the language. Once you see how LINQ
works, you will realize you can do much more than simple data query; you can use it to implement
complex functional programs.
.NET and the CLR provide a unique and stable cross-platform execution environment. C# is
only one of the languages that target this powerful runtime. You will find that many of the tech-
niques explored in this book are also applicable to any language that targets the .NET runtime.
For those of you who have significant C++ experience and are familiar with such concepts as
C++ canonical forms, exception safety, Resource Acquisition Is Initialization (RAII), and const
correctness, this book explains how to apply these concepts in C#. If you’re a Java or Visual Basic
programmer who has spent years developing your toolbox of techniques and you want to know
how to apply them effectively in C#, you’ll find out how to do that here.
As you’ll see, it doesn’t take years of trial-and-error experience to become a C# expert. You sim-
ply need to learn the right things and the right ways to use them. That’s why I wrote this book for you.
xxv

20.
xxvi ■INTRODUCTION
About This Book
I assume that you already have a working knowledge of some object-oriented programming lan-
guage, such as C++, Java, or Visual Basic .NET. Since C# derives its syntax from both C++ and Java, I
don’t spend much time covering C# syntax, except where it differs starkly from C++ or Java. If you
already know some C#, you may find yourself skimming or even skipping Chapters 1 through 3.
Chapter 1, “C# Preview,” gives a quick glimpse of what a simple C# application looks like, and it
describes some basic differences between the C# programming environment and the native
C++ environment.
Chapter 2, “C# and the CLR,” expands on Chapter 1 and quickly explores the managed environ-
ment within which C# applications run. I introduce you to assemblies, the basic building
blocks of applications into which C# code files are compiled. Additionally, you’ll see how meta-
data makes assemblies self-describing.
Chapter 3, “C# Syntax Overview,” surveys the C# language syntax. I introduce you to the two
fundamental kinds of types within the CLR: value types and reference types. I also describe
namespaces and how you can use them to logically partition types and functionality within
your applications.
Chapters 4 through 13 provide in-depth descriptions of how to employ useful idioms, design
patterns, and best practices in your C# programs and designs. I’ve tried hard to put these chap-
ters in logical order, but inevitably one chapter may reference a technique or topic covered in a
later chapter.
Chapter 4, “Classes, Structs, and Objects,” provides details about defining types in C#. You’ll
learn more about value types and reference types in the CLR. I also touch upon the native sup-
port for interfaces within the CLR and C#. You’ll see how type inheritance works in C#, as well
as how every object derives from the System.Object type. This chapter also contains a wealth of
information about the managed environment and what you must know in order to define
types that are useful in it. I introduce many of these topics in this chapter and discuss them in
much more detail in later chapters.
Chapter 5, “Interfaces and Contracts,” details interfaces and the role they play in the C# lan-
guage. Interfaces provide a functionality contract that types may choose to implement. You’ll
learn the various ways that a type may implement an interface, as well as how the runtime
chooses which methods to call when an interface method is called.
Chapter 6, “Overloading Operators,” details how you may provide custom functionality for the
built-in operators of the C# language when applied to your own defined types. You’ll see how to
overload operators responsibly, since not all managed languages that compile code for the CLR
are able to use overloaded operators.
Chapter 7, “Exception Handling and Exception Safety,” shows you the exception-handling
capabilities of the C# language and the CLR. Although the syntax is similar to that of C++,
creating exception-safe and exception-neutral code is tricky—even more so than creating
exception-safe code in native C++. You’ll see that creating fault-tolerant, exception-safe code
doesn’t require the use of try, catch, or finally constructs at all. I also describe some of the
new capabilities added to the .NET 2.0 runtime that allow you to create more fault-tolerant
code than was possible in .NET 1.1.

21.
■INTRODUCTION xxvii
Chapter 8, “Working with Strings,” describes how strings are a first-class type in the CLR and
how to use them effectively in C#. A large portion of the chapter covers the string-formatting
capabilities of various types in the .NET Framework and how to make your defined types
behave similarly by implementing IFormattable. Additionally, I introduce you to the globaliza-
tion capabilities of the framework and how to create custom CultureInfo for cultures and
regions that the .NET Framework doesn’t already know about.
Chapter 9, “Arrays, Collection Types, and Iterators,” covers the various array and collection
types available in C#. You can create two types of multidimensional arrays, as well as your own
collection types while utilizing collection-utility classes. You’ll see how to define forward,
reverse, and bidirectional iterators using the new iterator syntax introduced in C# 2.0, so that
your collection types will work well with foreach statements.
Chapter 10, “Delegates, Anonymous Functions, and Events,” shows you the mechanisms used
within C# to provide callbacks. Historically, all viable frameworks have always provided a
mechanism to implement callbacks. C# goes one step further and encapsulates callbacks into
callable objects called delegates. Additionally, C# 2.0 allows you to create delegates with an
abbreviated syntax called anonymous functions. Anonymous functions are similar to lambda
functions in functional programming. Also, you’ll see how the framework builds upon dele-
gates to provide a publish/subscribe event notification mechanism, allowing your design to
decouple the source of the event from the consumer of the event.
Chapter 11, “Generics,” introduces you to probably the most exciting feature added to C# 2.0
and the CLR. Those familiar with C++ templates will find generics somewhat familiar, though
many fundamental differences exist. Using generics, you can provide a shell of functionality
within which to define more specific types at run time. Generics are most useful with collection
types and provide great efficiency compared to the collections used in previous .NET versions.
Chapter 12, “Threading in C#,” covers the tasks required in creating multithreaded applications
in the C# managed virtual execution environment. If you’re familiar with threading in the
native Win32 environment, you’ll notice the significant differences. Moreover, the managed
environment provides much more infrastructure for making the job easier. You’ll see how dele-
gates, through use of the I Owe You (IOU) pattern, provide an excellent gateway into the
process thread pool. Arguably, synchronization is the most important concept when getting
multiple threads to run concurrently. This chapter covers the various synchronization facilities
available to your applications.
Chapter 13, “In Search of C# Canonical Forms,” is a dissertation on the best design practices for
defining new types and how to make them so you can use them naturally and so consumers
won’t abuse them inadvertently. I touch upon some of these topics in other chapters, but I dis-
cuss them in detail in this chapter. This chapter concludes with a checklist of items to consider
when defining new types using C#.
Chapter 14, “Extension Methods,” covers a feature new to C# 3.0. Since you can invoke exten-
sion methods, like instance methods, on a type they extend, they can appear to augment the
contract of types. But they are much more than that. In this chapter, I show you how extension
methods can begin to open up the world of functional programming in C#.
Chapter 15, “Lambda Expressions,” covers another new feature C# 3.0. You can declare and
instantiate delegates using lambda expressions using a syntax that is brief and visually descrip-
tive. Although anonymous functions can serve the same purpose just mentioned, they are
much more verbose and less syntactically elegant. However, in C# 3.0, you can convert lambda
expressions into expression trees. That is, the language has a built-in capability to convert code
into data structures. By itself, this capability is useful, but not nearly as useful as when coupled
with Language Integrated Query (LINQ). Lambda expressions, coupled with extension meth-
ods, really bring functional programming full circle in C#.

22.
xxviii ■INTRODUCTION
Chapter 16, “LINQ: Language Integrated Query,” is the culmination of all of the new features of
C# 3.0. Using LINQ expressions via the new C# 3.0 LINQ-oriented keywords, you can seam-
lessly integrate data queries into your code. LINQ forms a bridge between the typically
imperative programming world of C# programming and the functional programming world of
data query. LINQ expressions can be used to manipulate normal objects as well as data origi-
nating from SQL databases, Datasets, and XML, just to name a few.

23.
CHAPTER 1
C# Preview
S ince this is a book for experienced object-oriented developers, I assume that you already have
some familiarity with the .NET runtime. Essential .NET Volume 1: The Common Language Runtime
by Don Box (Boston, MA: Addison-Wesley, 2002) is an excellent book specifically covering the .NET
runtime. Additionally, it’s important to look at some of the similarities and differences between C#
and C++, and then go through an elementary “Hello World!” example for good measure. If you
already have experience building .NET applications, you may want to skip this chapter. However,
you may want to read the section “Overview of What’s New in C# 3.0.”
Differences Between C# and C++
C# is a strongly typed object-oriented language whose code visually resembles C++ (and Java). This
decision by the C# language designers allows C++ developers to easily leverage their knowledge to
quickly become productive in C#. C# syntax differs from C++ in some ways, but most of the differ-
ences between these languages are semantic and behavioral, stemming from differences in the
runtime environments in which they execute.
C#
C# source code compiles into managed code. Managed code, as you may already know, is an
intermediate language (IL) because it is halfway between the high-level language (C#) and the low-
est-level language (assembly/machine code). At run time, the Common Language Runtime (CLR)
compiles the code on the fly by using Just In Time (JIT) compiling. As with just about anything in
engineering, this technique comes with its pros and cons. It may seem that an obvious con is the
inefficiency of compiling the code at run time. This process is different from interpreting, which is
typically used by scripting languages such as Perl and JScript. The JIT compiler doesn’t compile a
function or method each and every time it’s called; it does so only the first time, and when it does,
it produces machine code native to the platform on which it’s running. An obvious pro of JIT com-
piling is that the working set of the application is reduced, because the memory footprint of inter-
mediate code is smaller. During the execution of the application, only the needed code is JIT-com-
piled. If your application contains printing code, for example, that code is not needed if the user
never prints a document, and therefore the JIT compiler never compiles it. Moreover, the CLR can
optimize the program’s execution on the fly at run time. For example, the CLR may determine a way
to reduce page faults in the memory manager by rearranging compiled code in memory, and it
could do all this at run time. Once you weigh all the pros together, you find that they outweigh the
cons for most applications.
1

24.
2 CHAPTER 1 ■ C# PREVIEW
■ Note Actually, you can choose to code your programs in raw IL while building them with the IL Assembler
(ILASM). However, it will likely be an inefficient use of your time. High-level languages can nearly always provide
any capability that you can achieve with raw IL code.
C++
Unlike C#, C++ code traditionally compiles into native code. Native code is the machine code that’s
native to the processor for which the program was compiled. For the sake of discussion, assume
that we’re talking about natively compiled C++ code rather than managed C++ which can be
achieved by using C++/CLI. If you want your native C++ application to run on different platforms,
such as on both a 32-bit platform and a 64-bit platform, you must compile it separately for each.
The native binary output is generally not compatible across platforms.
IL, on the other hand, is compatible across platforms, because it, along with the Common Lan-
guage Infrastructure (CLI) upon which the CLR is built, is a defined international standard.1 This
standard is rapidly gaining traction and being implemented beyond the Microsoft Windows plat-
form.
■Note I recommend you check out the work the Mono team has accomplished toward creating alternate, open
source Virtual Execution Systems (VESs) on other platforms.2
Included in the CLI standard is the Portable Executable (PE) file format for managed modules.
Therefore, you can actually compile a C# program on a Windows platform and execute the output
on both Windows and Linux without having to recompile, because even the file format is standard-
ized.3 This degree of portability is extremely convenient and was in the hearts and minds of the
COM/DCOM designers back in the day, but for various reasons, it failed to succeed across disparate
platforms at this level.4 One of the major reasons for that failure is that COM lacked a sufficiently
expressive and extensible mechanism for describing types and their dependencies. The CLI specifi-
cation solves this nicely by introducing metadata, which I’ll describe in Chapter 2.
CLR Garbage Collection
One of the key facilities in the CLR is the garbage collector (GC). The GC frees you from the burden
of handling memory allocation and deallocation, which is where many software errors can occur.
However, the GC doesn’t remove all resource-handling burdens from your plate, as you’ll see in
1. You can find the CLI standard document Ecma-335 at www.ecma-international.org. Additionally, Ecma-334 is
the standard document for the C# language.
2. You can find the Mono project on the Internet at www.mono-project.com.
3. Of course, the target platform must also have all of the dependent libraries installed. This is quickly becom-
ing a reality, given the breadth of the .NET Standard Library. For example, check out www.go-mono.com/docs/
to see how much coverage the Mono project libraries have.
4. For all the gory details, I recommend reading Don Box and Chris Sells’ Essential .NET, Volume I: The Common
Language Runtime (Boston, MA: Addison-Wesley Professional, 2002). (The title leads one to believe that Vol-
ume II is due out any time now, so let’s hope it’s not titled in the same vein as Mel Brooks’ History of the
World: Part I.)

25.
CHAPTER 1 ■ C# PREVIEW 3
Chapter 4. For example, a file handle is a resource that must be freed when the consumer is finished
with it, just as memory must be freed in the same way. The GC handles only memory resources
directly. To handle resources other than memory, such as database connections and file handles,
you can use a finalizer (as I’ll show you in Chapter 13) to free your resources when the GC notifies
you that your object is being destroyed. However, an even better way is to use the Disposable pat-
tern for this task, which I’ll demonstrate in Chapters 4 and 13.
■Note The CLR references all objects of reference type indirectly, similar to the way you use pointers and refer-
ences in C++, except without the pointer syntax. When you declare a variable of a reference type in C#, you
actually reserve a storage location that has a type associated with it, either on the heap or on the stack, which
stores the reference to the object. So when you copy an object reference in one variable into another variable, you
end up with two variables referencing the same object. All reference type instances live on the managed heap. The
CLR manages the location of these objects, and if it needs to move them around, it updates all the outstanding ref-
erences to the moved objects to point to the new location. Also, value types exist in the CLR, and instances of them
live on the stack or as a field of an object on the managed heap. Their usage comes with many restrictions and
nuances. You normally use them when you need a lightweight structure to manage some related data. Value types
are also useful when modeling an immutable chunk of data. I cover this topic in much more detail in Chapter 4.
C# allows you to develop applications rapidly while dealing with fewer mundane details than
in a C++ environment. At the same time, C# provides a language that feels familiar to either C++ or
Java developers.
Example of a C# Program
Let’s take a close look at a C# program. Consider the venerable “Hello World!” program that every-
one knows and loves. A console version of it looks like this in C#:
class EntryPoint {
static void Main() {
System.Console.WriteLine( "Hello World!" );
}
}
Note the structure of this C# program. It declares a type (a class named EntryPoint) and a
member of that type (a method named Main). This differs from C++, where you declare a type in a
header and define it in a separate compilation unit, usually a .cpp file. Also, metadata (which
describes all of the types in a module and is generated transparently by the C# compiler) removes
the need for the forward declarations and inclusions as required in C++. In fact, forward declara-
tions don’t even exist in C#.
C++ programmers will find the static Main method familiar, except for the fact that its name
begins with a capital letter. Every program requires an entry point, and in the case of C#, it is the
static Main method. There are some further differences. For example, the Main method is declared
within a class (in this case, named EntryPoint). In C#, you must declare all methods within a type
definition. There is no such thing as a static, free function as there is in C++. The return type for the
Main method may be either of type int or void, depending on your needs. In my example, Main has
no parameters, but if you need access to the command-line parameters, your Main method can
declare a parameter (an array of strings) to access them.

26.
4 CHAPTER 1 ■ C# PREVIEW
■Note If your application contains multiple types with a static Main method, you can select which one to use via
the /main compiler switch.
You may notice that the call to WriteLine seems verbose. I had to qualify the method name
with the class name Console, and I also had to specify the namespace that the Console class lives in
(in this case, System). .NET (and therefore C#) supports namespaces to avoid name collisions in the
vast global namespace. However, instead of having to type the fully qualified name, including the
namespace, every time, C# provides the using directive, which is analogous to Java’s import and
C++’s using namespace. So you could rewrite the previous program slightly, as Listing 1-1 shows.
Listing 1-1. hello_world.cs
using System;
class EntryPoint {
static void Main() {
Console.WriteLine( "Hello World!" );
}
}
With the using System; directive, you can omit the System namespace when calling
Console.WriteLine.
To compile this example, execute the following command from a Windows command prompt:
csc.exe /r:mscorlib.dll /target:exe hello_world.cs
Let’s take a look at exactly what this command line does:
• csc.exe is the Microsoft C# compiler.
• The /r option specifies the assembly dependencies this program has. Assemblies are similar
in concept to DLLs in the native world. mscorlib.dll is where the System.Console object is
defined. In reality, you don’t need to reference the mscorlib assembly because the compiler
will reference it automatically, unless you use the /nostdlib option.
• The /target:exe option tells the compiler that you’re building a console application, which
is the default if not specified. Your other options here are /target:winexe for building a Win-
dows GUI application, /target:library for building a DLL assembly with the .dll extension,
and /target:module for generating a DLL with the .netmodule extension. /target:module
generated modules don’t contain an assembly manifest, so you must include it later into an
assembly using the assembly linker al.exe. This provides a way to create multiple-file
assemblies.
• hello_world.cs is the C# program you’re compiling. If multiple C# files exist in the project,
you could just list them all at the end of the command line.
Once you execute this command line, it produces hello_world.exe, and you can execute it
from the command line and see the expected results. If you want, you can rebuild the code with the
/debug option. Then you may step through the execution inside of a debugger. To give an example of
C# platform independence, if you happen to have a Linux OS running and you have the Mono VES
installed on it, you can copy this hello_world.exe directly over in its binary form and it will run as
expected, assuming everything is set up correctly on the Linux box.

27.
CHAPTER 1 ■ C# PREVIEW 5
Overview of Features Added in C# 2.0
Since its initial release in late 2000, the C# language has evolved considerably. This evolution has
likely been accelerated thanks to the wide adoption of C#. With the release of Visual Studio 2005 and
the .NET Framework 2.0, the C# compiler supported the C# 2.0 enhancements to the language. This
was great news, since C# 2.0 included some handy features that provided a more natural program-
ming experience as well as greater efficiency. This section provides an overview of what those
features are and what chapters of the book contain more detailed information.
Arguably, the meatiest addition to C# 2.0 was support for generics. The syntax is similar to C++
templates, but the main difference is that constructed types created from .NET generics are
dynamic in nature—that is, they are bound and constructed at run time. This differs from C++ con-
crete types created from templates, which are static in the sense that they are bound and created at
compile time.5 Generics are most useful when used with container types such as vectors, lists, and
hash tables, where they provide the greatest efficiency gains. Generics can treat the types that they
contain specifically by their type, rather than by using the base type of all objects, System.Object. I
cover generics in Chapter 11, and I cover collections in Chapter 9.
C# 2.0 added support for anonymous methods. An anonymous method is sometimes referred
to as a lambda function, which comes from functional programming disciplines. C# anonymous
methods are extremely useful with delegates and events. Delegates and events are constructs used
to register callback methods that are called when triggered. Normally, you wire them up to a defined
method somewhere. But with anonymous methods, you can define the delegate’s or event’s code
inline, at the point where the delegate or event is set up. This is handy if your delegate merely needs
to perform some small amount of work for which an entire method definition would be overkill.
What’s even better is that the anonymous method body has access to all variables that are in scope
at the point it is defined.6 I cover anonymous methods in Chapter 10. Lambda expressions, which
are new to C# 3.0, supersede anonymous methods and make for more readable code.
C# 2.0 added support for iterators. Anyone familiar with the C++ Standard Template Library
(STL) knows about iterators and their usefulness. In C#, you typically use the foreach statement to
iterate over an object that behaves as a collection. That collection object must implement the
IEnumerable interface, which includes the GetEnumerator method. Implementing the GetEnumerator
method on container types is typically very tedious. However, when using C# iterators, implement-
ing the GetEnumerator method is a snap. You can find more information regarding iterators in
Chapter 9.
Finally, C# 2.0 added support for partial types. Prior to C# 2.0, you had to define each C# class
entirely in one file (also called a compilation unit). This requirement was relaxed with the support
for partial types. This was great news for those who rely upon code generators to provide skeleton
code. For example, you can use the Visual Studio wizards to generate such useful things as
System.Data.DataSet derived types for accessing data in a database. Prior to C# 2.0, it was problem-
atic if you needed to make modifications to the generated code. You either had to derive from or
contain the generated type in a new type while specializing its implementation, or you had to edit
the generated code. Editing the generated code was risky because you normally lost those changes
when the wizard was forced to regenerate the type for some reason. Partial types solve this problem,
because now you can augment the generated code in a separate file so that your changes aren’t lost
when the wizard regenerates the code. For a great example of how partial types are used, look at the
code automatically generated when you create a Windows Forms application using Visual Studio.
You can find more information regarding partial types in Chapter 4.
5. Using C++/CLI, standardized in Ecma-372 and first made available with Visual Studio 2005, you can use
generics and templates together.
6. This is referred to as either a closure or a variable capture.

28.
6 CHAPTER 1 ■ C# PREVIEW
Overview of What’s New in C# 3.0
C# 3.0 includes some great new features. Most of the new features are stepping stones designed to
support Language Integrated Query (LINQ). Nevertheless, all of them are extremely useful when
used individually outside of the context of LINQ. Many of them allow programmers to employ func-
tional programming techniques more easily.
C# now supports implicitly typed local variables by making use of a new keyword var. It’s
important to note that these variables are not typeless; rather, their type is inferred at compile time.
You can read more about them in Chapter 3.
Have you ever wanted to create a simple type to hold some related data but been annoyed at
having to create an entire new class? In many cases, the new support for anonymous types helps
relieve you of this burden. Using anonymous types, you can define and instantiate a type all in one
compound statement. I cover anonymous types in Chapter 4.
Auto-implemented properties are another helpful new feature to save us some typing and
reduce the potential to introduce bugs. How many times have you simply declared a class to hold a
few pieces of data and been annoyed with the amount of typing required to create property
accessors for that data? After all, doing so follows good encapsulation practices. Thankfully, auto-
implemented properties greatly reduce the amount of typing necessary to define properties on
types. You can read more about them in Chapter 4.
While we’re on the subject of conveniences, C# 3.0 also introduces two new features that help
when instantiating and initializing object instances. Using object and collection initializers, you can
instantiate and initialize either an object or a collection in one compound statement. I cover object
initializers in Chapter 4 and collection initializers in Chapter 9.
C# 2.0 introduced partial class definitions to facilitate using code generators. C# 3.0 adds to that
by introducing partial methods. Using partial methods, a code generator can declare a method sig-
nature, and the consumer of that generated code, the one that creates the rest of the partial class
definition, can choose to implement it or not. You can read more about partial methods in Chapter 4.
Extension methods are one of the most exciting new features. Taken from the surface view, they
are merely static methods that can be called as if they were instance methods. They do not get any
special access into the instance they are operating on, so in that respect, they are just like static
methods. However, the syntax they foster allows us to program in a more functional manner, usu-
ally resulting in clearer and more readable code. I devote the entire Chapter 14 to extension
methods and what you can do with them.
Probably more compelling than extension methods is support for lambda expressions. Lambda
expressions supersede support for anonymous methods. That is, if lambda expressions had existed
in C# 2.0, there would have been no need for anonymous methods at all. However, lambda expres-
sions offer much more than anonymous methods as they can be converted into both delegates and
expression trees. Lambda expressions are covered in Chapter 15.
The granddaddy of all new C# 3.0 features has to be LINQ, which builds upon all of the new
features, especially extension methods, lambda expressions, and anonymous types. It also adds
some new language keywords to allow us to code intuitive query statements, thus seamlessly bridg-
ing the gap between the object-oriented world and the data world. You can use LINQ to access data
from multiple sources. Visual Studio provides the capability to use LINQ on native object collec-
tions, SQL data stores, and XML. Support for many other data sources is coming soon from both
Microsoft and third parties. For example, you’ll be able to use LINQ to connect to Windows Man-
agement Instrumentation (WMI), the Document Object Model (DOM), and the Web. Additionally,
there are implementations in the works to use LINQ against popular web sites such as Google and
Flickr. Chapter 16 is devoted to LINQ.

29.
CHAPTER 1 ■ C# PREVIEW 7
Summary
In this chapter, I’ve touched upon the high-level characteristics of programs written in C#. That is,
all code is compiled into IL rather than the native instructions for a specific platform. Additionally,
the CLR implements a GC to manage raw memory allocation and deallocation, freeing you from
having to worry about one of the most common errors in software development: improper memory
management. However, as with most engineering trade-offs, there are other aspects (read: compli-
cations) of memory and resource management that the GC can introduce in certain situations.
Using the venerable “Hello World!” example, I was able to quickly show the usefulness of name-
spaces as well as the fact that C# is devoid of any kind of inclusion syntax as available in C++.
Instead, all other external types are brought into the compilation unit via metadata, which is a rich
description format of the types contained within an assembly. Therefore, the metadata and the
compiled types are always contained in one neat package.
Generics open up such a huge area of development that you’ll probably still be learning handy
tricks of applying them over the next several years. Some of those tricks can be borrowed from the
C++ template world, but not all of them, since the two concepts are fundamentally different. Itera-
tors and anonymous methods offer a concise way of expressing common idioms such as
enumeration and callback methods, while support for partial type declarations within C# makes it
easier to work with tool-generated code.
C# 3.0 offers many new and exciting features that allow one to employ functional programming
techniques very easily with little overhead. Some of the new features add convenience to program-
ming in C#. LINQ provides a seamless mechanism to bridge to the data storage world from the
object-oriented world.
In the next chapter, I’ll briefly cover more details regarding the JIT compilation process. Addi-
tionally, I’ll dig into assemblies and their contained metadata a bit more. Assemblies are the basic
building blocks of C# applications, analogous to DLLs in the native Windows world.

30.
CHAPTER 2
C# and the CLR
A s mentioned in the previous chapter, managed applications and native applications have many
differences, mainly because managed applications run inside the Microsoft CLR. The CLR is a Vir-
tual Execution System (VES) that implements the CLI. The CLR provides many useful facilities to
managed applications, including a highly tuned GC for memory management, a code access secu-
rity layer, and a rich self-describing type system, among others. In this chapter, I’ll show you how
the CLR compiles, packages, and executes C# programs.
■ Note In-depth coverage of the CLR is outside the scope of this book, because I focus closely on C# concepts
and usage. However, I recommend that you become familiar with the CLR. It’s always best to know and understand
your target platform, and in the case of managed applications such as C#, the platform is the .NET CLR. For fur-
ther, in-depth coverage of the CLR and everything covered in this chapter, see Don Box and Chris Sells’ Essential
.NET, Volume I: The Common Language Runtime (Boston, MA: Addison-Wesley Professional, 2002) and Andrew
Troelsen’s Pro C# 2005 and the .NET 2.0 Platform, Third Edition (Berkeley, CA: Apress, 2005). After that, you may
find many of the other, more specific books on the CLR more informative. For complete coverage of the CLR layer
that provides complete interoperability with native environments such as COM objects and the underlying platform,
I recommend Adam Nathan’s .NET and COM: The Complete Interoperability Guide (Indianapolis, IN: Sams, 2002).
For topics dealing with .NET code access security, I recommend .NET Framework Security by Brian A. LaMacchia,
et al. (Upper Saddle River, NJ: Pearson Education, 2002). Because no developer should ever ignore platform secu-
rity when designing new systems, I recommend Keith Brown’s The .NET Developer’s Guide to Windows Security
(Boston, MA: Addison-Wesley Professional, 2004).
This chapter provides a high-level and cursory description of the mechanisms involved with
compiling C# and loading code for execution. Once the code is loaded, it must be compiled into
native machine code for the platform it’s running on. Therefore, you need to understand the con-
cept of JIT compilation.
9

31.
10 CHAPTER 2 ■ C# AND THE CLR
The JIT Compiler in the CLR
C# is compiled into IL, and IL is what the CLR processes. The IL specification is contained in the CLI
standard. You can see what IL looks like by loading the “Hello World!” application (from the previous
chapter) into the Intermediate Language Disassembler (ILDASM) provided with the .NET SDK.1
ILDASM shows you a tree view of the type data from the assembly, and you can open up individual
methods and see the IL code that the C# compiler generated for them. As shown in Listing 2-1, IL
looks similar to assembly language; in essence, it’s the assembly language of the CLR. It’s called IL
because it acts as an intermediate step between a specific language and a specific platform.
Listing 2-1. HelloWorld.exe Main Method IL
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Hello World!"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method EntryPoint::Main
The CLR is not an interpreter. It doesn’t retranslate the IL code each time it executes it.
Although interpreters provide many flexible solutions (as in the JScript interpreter for the Windows
Scripting Host, for example), they’re generally not efficient runtime platforms. The CLR actually
compiles IL code into machine code before it executes it—called JIT compiling. This process takes
some time, but for each part of a program, it generally means only a one-time performance hit per
process. Once the code is compiled, the CLR holds on to it and simply executes the compiled ver-
sion the next time it’s needed, just as quickly as traditionally compiled code (and sometimes even
more quickly).
Although the JIT compilation phase adds some complexity and has an initial runtime perform-
ance penalty associated with it, the benefits of a JIT compiler coupled with the CLR can outweigh
the time penalty of JIT compiling because
• Managed applications can consume far less memory: In general, IL code has a smaller foot-
print than native code. In other words, the working set of managed applications—that is, the
number of memory pages the application consumes—is normally smaller than native appli-
cations. With a fair amount of work, you can reduce the working set of native applications to
be comparable to managed applications, but with the CLR, you get this for free.
• Only IL code that is executed ever gets JIT-compiled: IL code is generally more compact than
machine code, so keeping the compiled code to a minimum reduces the memory footprint
of the application.
• The CLR can keep track of the frequency of calls: If it sees that a JIT-compiled code section has
not been called in a long time, it can free the space occupied by it. The code will be recom-
piled if it’s called again.
1. You can find ILDASM.exe in the bin directory of the .NET SDK, or if you have Visual Studio 2008 installed, you
can normally find it in the following directory: C:Program FilesMicrosoft SDKsWindowsv6.0A
binildasm.exe. You can launch it easily by invoking it after opening an instance of the Visual Studio 2008
command prompt.

32.
CHAPTER 2 ■ C# AND THE CLR 11
The CLR also may perform optimizations at run time. In native applications, you define the
optimizations at compile time. But, since compilation occurs at run time in the CLR, it can apply
optimizations at any time. It may be the case that a CLR implementation can compile code faster
with fewer optimizations, and it may default to doing it that way. However, for code that it sees get-
ting called frequently, it could recompile such code with more optimizations turned on so that it
executes faster. For example, the CLR efficiency model can be vastly different depending on how
many CPUs are on the target platform or even what architecture family the CPUs belong to. For
native applications, you have to do more manual work—either at run time or compile time—to
accommodate such a situation. But the CLR provides facilities so you can create multi-CPU per-
formance enhancements more readily. Additionally, if the CLR determines that different parts of
code scattered all over the application are called rather frequently, it has the liberty to move them in
memory so that they are all within the same group of memory pages, thus minimizing the number
of page faults and increasing the cache hits as the application runs.
These are only a few of the reasons why the CLR is a flexible platform to target, and why its
benefits quickly outweigh the initial perceived performance hit of JIT compiling.
Assemblies and the Assembly Loader
An assembly is a discrete unit of reusable code within the CLR, similar in nature to a DLL in the
unmanaged world, but that’s where the similarities end. An assembly can consist of multiple mod-
ules all linked together by a manifest, which describes the contents of the assembly. With respect
to the operating system, a module is identical to a DLL. Assemblies can have a version attached to
them so that multiple assemblies with the same name but different versions are identifiable sepa-
rately. Assemblies also contain metadata describing the contained types. When you distribute a
native DLL, you typically include a header file and/or documentation describing the exported
functions. Metadata fulfills this requirement, completely describing the types contained within
the assembly. In short, assemblies are versioned, self-describing units of reuse within the CLR
environment.
As discussed in the previous chapter, when you compile the “Hello World!” program, the result
is an .exe file that is, in fact, an assembly. You can create managed assemblies using any managed
language. Moreover, in most cases, any other managed language can consume managed assem-
blies. Therefore, you can easily create complex systems developed with multiple managed
languages. For example, when creating some low-level types, C++ /CLI may be the most natural lan-
guages to get the job done, but it may make more sense to code the top-level user interface using
either C# or Visual Basic. To provide interoperability between the various languages, the CLI defines
a subset of the type system known as the Common Language Specification (CLS). If you use only
CLS-compliant types in your assemblies, you are guaranteed that any managed language can con-
sume them.
Minimizing the Working Set of the Application
In the “Hello World!” example, the resulting assembly consists of only one file. However, assemblies
can consist of multiple files. These files can include compiled modules, resources, and any other
components listed in the assembly manifest. The assembly manifest is typically included in the
main assembly module and contains essential identification information, including which pieces
belong to the assembly. By using this information, the assembly loader can determine, among other
things, if an assembly is incomplete or has been tampered with. Assemblies are either strongly
named or not strongly named. A strongly named assembly has a hash code built into its manifest
that the loader can use to test the integrity of the assembly. Assemblies can also be digitally signed
in order to identify their producer.

33.
12 CHAPTER 2 ■ C# AND THE CLR
When a C# executable launches, the CLR loads the assembly and starts executing the entry-
point method. Of course, before it can do that, it must JIT-compile the entry-point method. At that
stage, the CLR may have to resolve some external references to be able to JIT-compile the code. For
example, if your Main method creates an instance of a class named Employee, the CLR must find and
load the assembly that contains the Employee type before the JIT compiler can continue. However,
the great thing is that the CLR loads assemblies on demand. So, if you have a type that provides a
method to print a document, and it lives in a separate assembly from the one containing the main
application, but the application never exercises the dependency, then the separate assembly never
gets loaded. This keeps the working set of the application from growing unnecessarily large. There-
fore, when designing applications, it makes sense to segregate less commonly used features into
separate assemblies so that the CLR loads them only when needed. Any time you can trim the work-
ing set of the application, you speed up start-up time as well as shrink the memory footprint of the
running application. The key is to partition your code into cohesive units, or assemblies. There’s no
point in creating multiassembly applications if code executed in common code paths is scattered
across various assemblies, since you’ll lose the benefit of multiple assemblies.
Naming Assemblies
You can name assemblies in two main ways:
• Strongly (fully) named: This assembly has a name that consists of four parts: the short
assembly name, a version number, a culture identifier in ISO format, and a hash token. If an
assembly is named with all four parts, it is considered to be strongly named.
• Partially named: This assembly has a name that’s missing some of the detail in strongly
named assemblies.
To get a good idea of what assembly names look like, open up Windows Explorer and navigate
to your Global Assembly Cache (GAC), which is in the %systemroot%assembly directory. In reality,
the directory structure is very complex, but the GAC Explorer plug-in presents what you see in your
browser. If you navigate to the same directory by using a command prompt, you see the encoded
directory names that the GAC uses to store the assemblies. Do not tamper with this directory struc-
ture, or you may cause serious damage to your GAC. Focusing on the view in Explorer, you can see
the assemblies’ four-part names. If the Culture entry is blank for an assembly, it means that it is cul-
ture-neutral, which is common for assemblies that contain only code. I recommend that you isolate
all of your resources in a separate assembly, so you can tag them as culture-specific and swap them
out easily with a different culture without affecting your code. Similar guidelines have existed in
native Win32 programming for years and greatly facilitate easy localization of your application to
other languages.
The benefit of strongly named assemblies is that they can be registered in the GAC and become
available for use by all applications on the system. Registering an assembly in the GAC is analogous
to registering a COM server in the registry. If the assembly is not strongly named, the application
may only use it locally. In other words, the assembly must reside somewhere in the directory of the
application using it or in a subdirectory thereof. Such assemblies are commonly referred to as
private assemblies.
Loading Assemblies
The assembly loader goes through a detailed process to load an assembly. Part of this process deter-
mines which version of the assembly to load. By using application configuration files, you can give
the loader some hints during version resolution. The CLR can load assemblies on an as-needed
basis, or you can load assemblies explicitly via AppDomain.Load(). The loader looks for partially
named assemblies in the same directory as the running application or in a subdirectory. (Such

34.
CHAPTER 2 ■ C# AND THE CLR 13
assemblies are called local assemblies.) The loader can also reference the GAC when searching for
the assembly—for example, when loading an assembly with its fully qualified name, the loader
searches the GAC before probing the local directories.
Versioning plays a key role at assembly load time, and all assemblies are versioned. Versioning
was built into the CLR loader from the beginning and removes the affliction known as DLL Hell,
where replacing a shared DLL with a newer version breaks applications that use the older version.
You veterans out there who have developed software on Windows throughout the past 15 years or so
definitely have felt this pain. In the CLR, multiple versions of the same assembly can exist simulta-
neously on the same machine without conflicting with each other. Moreover, applications can
choose to default to using the most recent version of an assembly on the machine, or they can spec-
ify the exact version they prefer by applying a version policy in their configuration files.
■ Note Assembly loading and versioning is a fairly complex topic that is outside the scope of this book. Before
loading an assembly, the loader uses various heuristics to determine which version to load. Once it knows the ver-
sion, it passes the information down to the low-level assembly loading method. For more detailed information
regarding assembly loading, reference Don Box and Chris Sells’ Essential .NET, Volume I: The Common Language
Runtime (Boston, MA: Addison-Wesley Professional, 2002).
Metadata
Let’s look closely at the “Hello World!” example back in Listing 1-1 and compare it to what you may
be used to if you come from the native C++ world. First, notice that it doesn’t include any headers.
That’s because C# does not need to include headers. Instead, it uses something much more reliable
and descriptively rich: metadata. By using metadata, managed modules are self-describing. In the
C++ world, to consume a library in your application, you would need two things: a static library or a
DLL, and, normally, a header file. Since they exist as two separate entities that you must treat as a
whole, it’s entirely possible that the header file and the library could get out of sync if you’re not
careful. That could spell disaster. Managed modules, on the other hand, contain all necessary infor-
mation inside the metadata that is contained in the module itself. The unit of reuse in the managed
world is an assembly. So it is the assembly that is, in fact, self-describing.
Metadata is also extensible, allowing you to define new types and attributes that can be con-
tained in the metadata. To top it all off, you can access metadata at run time. For example, at run
time, you can iterate over all the fields of an arbitrary class type without having to know its declara-
tion ahead of time or at compile time. Astute readers may recognize that this power opens up the
possibility of entire programs and types being generated at run time, which is also something that is
impossible with native C++ unless you integrate a full C++ compiler into your application.
Metadata is an extensible description format for describing the contents of assemblies. Also, if
it’s not expressive enough for your needs, you can define new custom “attributes” that are easily
included in the metadata for a type. In the managed world, just about every entity in a program
with a type can have metadata attached to it, including classes, methods, parameters, return values,
assemblies, and so on. You can define custom attributes by deriving from the System.Attribute
class, and then you can easily associate an instance of your custom attribute to just about any entity
in your assembly.
With metadata, you can access and examine type definitions and the attributes attached to
them. Metadata can tell you if a particular object’s class supports a given method before attempting
to call it, or if a given class is derived from another. The process of inspecting metadata is called

35.
14 CHAPTER 2 ■ C# AND THE CLR
reflection. Typically, you start with a System.Type object when you reflect upon types in the assem-
bly. You can get hold of one of these type instances by using the typeof keyword in C#, by calling
System.Assembly.GetType(), and a few other ways. Generally, the typeof keyword is more efficient
because it is computed at compile time, whereas GetType(), although more flexible since you can
pass it an arbitrary string, is executed at run time. Once you have a type object, you can find out if it
is a class, an interface, a struct, or so on, what methods it has, and the number and types of fields it
contains.
■ Note If you’re wondering, “Why metadata?”, COM/DCOM employ some other techniques. If you’ve ever created
COM components, you may be familiar with the Interface Description Language (IDL), which is a platform-
independent description language for interfaces and components. Typically, you provide your consumer with the
COM component packaged in either a DLL or an executable along with the IDL. Again, it serves the same purpose
as the header file for C++ libraries or the documentation for DLL exports. You typically take the IDL and pass it
through an IDL compiler to produce native code that you can then interface with. A Type Library (TLB) serves much
the same purpose as IDL, but it is a binary format that high-level languages, such as Visual Basic, typically con-
sume. Unfortunately, IDL and TLBs don’t overlap entirely. Some things can be described in IDL but not in TLBs, and
vice versa.
Because assemblies are self-describing, the only thing the C# compiler needs in order to
resolve type usages is a list of referenced assemblies as it compiles and builds the program. Once it
has a list of the referenced assemblies, it can access the metadata contained inside them to resolve
the dependencies. It’s a beautiful system, and it removes some typically error-prone mundane
details from the C# coding process.
In the managed world, you no longer have to carry around any extra baggage in the form of
header files or IDL files. I won’t go so far as to say you don’t have to provide any documentation,
because documentation is always useful. But with an assembly, you have a nicely packaged entity
that contains both the code and the descriptions needed to use its contents. If your assembly con-
sists of a single file, as most do, that one file contains everything needed to consume the code in the
assembly.
Cross-Language Compatibility
Because assemblies are self-describing and contain portable IL code, they are easily shared across
multiple languages. Finally, you have a viable solution to put together complex systems, where
some components are coded using one language and others are coded using different languages.
For example, in a complex system used for engineering analysis, you may have a group of C# devel-
opers coding the system infrastructure and a group of engineers developing the mathematical
components. Many engineers still program in languages such as Fortran. That’s OK, because For-
tran compilers are available that emit IL and create managed assemblies. Thus, each development
group can work in a language that is more natural to it and to its problem domains.

36.
CHAPTER 2 ■ C# AND THE CLR 15
Metadata is essential to such sharing. Jim Miller and Susann Ragsdale describe the metadata
format completely in The Common Language Infrastructure Annotated Standard (Boston, MA:
Addison-Wesley Professional, 2003). I recommend that you read this book or the CLI Ecma stan-
dards documents2 to get the best understanding of the CLR and how metadata is generated and
consumed.
Summary
This chapter briefly covered the essentials of how C# is compiled, packaged, and executed.
I discussed how JIT compiling can actually compete with traditionally compiled applications in
performance. One of the requirements for optimizing JIT compilation is an expressive and extensi-
ble type mechanism that the compiler can understand. By packaging IL into assemblies that are
self-documenting, both the CLR and the JIT compiler have all the information they need to manage
code execution. Additionally, you can explicitly load an assembly on demand by providing either its
strong name or a partial name. Assemblies make it possible to run distinct versions of code without
experiencing DLL Hell, and they also provide the basis for developing and sharing components
across languages.
In the next chapter, I’ll lead you on a whirlwind 20,000-foot view of the C# language syntax.
Since I don’t have the space to cover every minute syntactic detail, I recommend that you also refer-
ence the C# language specification as well.
2. The Ecma-334 document covers the Ecma CLI standard, and the Ecma-334 document found at
www.ecma-international.org covers the C# language. ISO/IEC 23271 also covers the CLI, and ISO/IEC 23270
at www.iso.org also covers the C# language. However, the Ecma standards are generally more current, and
you can download them freely.

37.
CHAPTER 3
C# Syntax Overview
T his chapter introduces you to the syntax of the C# language. It’s assumed that you have a reason-
able amount of experience with C++ or Java, since C# shares a similar syntax. This is no accident.
The designers of C# clearly meant to leverage the knowledge of those who have already developed
with C++ and Java, which are arguably the dominant languages in object-oriented (OO) software
development.
I’ve noted nuances and differences that are specific to the C# language. But if you’re familiar
with either C++ or Java, you’ll feel right at home with C# syntax.
C# Is a Strongly Typed Language
Like C++ and Java, C# is a strongly typed language, which means that every variable and object
instance in the system is of a well-defined type. This enables the compiler to check that the opera-
tions you try to perform on variables and object instances are valid. For example, suppose you have
a method that computes the average of two integers and returns the result. You could declare the C#
method as follows:
double ComputeAvg( int param1, int param2 )
{
return (param1 + param2) / 2.0;
}
This tells the compiler that this method accepts two integers and returns a double. Therefore, if
the compiler attempts to compile code where you inadvertently pass an instance of type Apple, it
will complain and stop. Suppose you wrote the method slightly differently:
object ComputeAvg( object param1, object param2 )
{
return ((int) param1 + (int) param2) / 2.0;
}
The second version of ComputeAvg is still valid, but you have forcefully stripped away the type
information. Every object and value in C# implicitly derives from System.Object. The object key-
word in C# is an alias for the class System.Object. So it is perfectly valid to declare these parameters
as type object. However, object is not a numeric type. In order to perform the calculation, you must
first cast the objects into integers. After you’re done, you return the result as an instance of type
object. Although this version of the method can seem more flexible, it’s a disaster waiting to hap-
pen. What if some code in the application attempts to pass an instance of type Apple into
ComputeAvg? The compiler won’t complain, because Apple derives from System.Object, as every
other class does. However, you’ll get a nasty surprise at run time when your application throws an
17

38.
18 CHAPTER 3 ■ C# SYNTAX OVERVIEW
exception declaring that it cannot convert an instance of Apple to an integer. The method will fail,
and unless you have an exception handler in place, it could terminate your application. That’s not
something you want to happen in your code that is running on a production server somewhere.
It is always best to find bugs at compile time rather than run time. That is the moral of this
story. If you were to use the first version of ComputeAvg, the compiler would have told you how
ridiculous it was that you were passing an instance of Apple. This is much better than hearing it
from an angry customer whose ecommerce server just took a dirt nap. The compiler is your friend,
so let it be a good one and provide it with as much type information as possible to strictly enforce
your intentions.
Expressions
Expressions in C# are practically identical to expressions in C++ and Java. The important thing to
keep in mind when building expressions is operator precedence. C# expressions are built using
operands, usually variables or types within your application, and operators. Many of the operators
can be overloaded as well. Operator overloading is covered in Chapter 6. Table 3-1 lists the prece-
dence of the operator groups. Entries at the top of the table have higher precedence, and operators
within the same category have equal precedence.
Table 3-1. C# Operator Precedence
Operator Group Operators Included Description
Primary x.m Member access
X(...) Method invocation
X[...] Array access
X++, x-- Postincrement and
postdecrement
new T(...), new T[...] Object and array creation
typeof(T) Gets System.Type object for T
checked(x), unchecked(x) Evaluates expression in checked and
unchecked environments
Unary +x, -x Identity and negation
!x Logical negation
~x Bitwise negation
++x, --x Preincrement and predecrement
(T) x Casting operation
Multiplicative x*y, x/y, x%y Multiplication, division, and remainder
Additive x+y, x-y Addition and subtraction
Shift x<<y, x>>y Left and right shift
Relational and type testing x<y, x>y, x<=y, x>=y Less than, greater than, less than or
equal to, greater than or equal to
x is T True if x is convertible to T; false
otherwise
x as T Returns x converted to T, or null if
conversion is not possible
Equality x == y, x != y Equal and not equal

39.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 19
Operator Group Operators Included Description
Logical AND x & y Integer bitwise AND, Boolean logical
AND
Logical XOR x ^ y Integer bitwise XOR, Boolean logical
XOR
Logical OR x | y Integer bitwise OR, Boolean logical OR
Conditional AND x && y Evaluates y only if x is true
Conditional OR x || y Evaluates y only if x is false
Null coalescing x ?? y If x is non-null, evaluates to x;
otherwise, y
Conditional x ? y : z Evaluates y if x is true; otherwise,
evaluates z
Assignment x = y Simple assignment
x op= y Compound assignment; could be any
of *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, or |=
■ Note These operators can have different meanings in different contexts. Regardless, their precedence never
changes. For example, the + operator can mean string concatenation if you’re using it with string operands. By
using operator overloading when defining your own types, you can make some of these operators perform what-
ever semantic meaning makes sense for the type. But again, you may never alter the precedence of these
operators except by using parentheses to change the grouping of operations.
Statements and Expressions
Statements in C# are identical in form to those of C++ and Java. A semicolon terminates one-line
expressions. However, code blocks, such as those in braces in an if or a while statement, do not
need to be terminated with a semicolon. Adding the semicolon is optional at the end of a block.
Most of the statements that are available in C++ and Java are available in C#, including variable
declaration statements, conditional statements, control flow statements, try/catch statements, and
so on. However, C# (like Java) has some statements that are not available in C++. For example, C#
provides a try/finally statement, which I discuss in detail in Chapter 7. In Chapter 12, I’ll show
you the lock statement, which synchronizes access to code blocks by using the sync block of an
object. C# also overloads the using keyword, so you can use it either as a directive or a statement.
You can use a using statement in concert with the Disposable pattern I describe in Chapters 4 and
13. The foreach statement, which makes iterating through collections easier, also deserves mention.
You’ll see more of this statement in Chapter 9, when I discuss arrays.
Types and Variables
Every entity in a C# program is an object that lives on either the stack or the managed heap. Every
method is defined in a class or struct declaration. There are no such things as free functions,
defined outside the scope of class or struct declarations, as there are in C++. Even the built-in

40.
20 CHAPTER 3 ■ C# SYNTAX OVERVIEW
value types, such as int, long, double, and so on, have methods associated with them implicitly. So,
in C#, it’s perfectly valid to write a statement such as the following:
System.Console.WriteLine( 42.ToString() );
A statement like this, where a method is invoked on the immediate value 42, will feel unfamil-
iar if you’re used to C++ or Java. But, it emphasizes how everything in C# is an object, even down to
the most basic types. In fact, the built-in type keywords in C# are actually mapped directly into
types in the System namespace that represent them. You can even elect not to use the C# built-in
types and explicitly use the types in the System namespace that they map to (but this practice is dis-
couraged as a matter of style). Table 3-2 describes the built-in types, showing their size and what
type they map to in the System namespace.
Table 3-2. C# Built-In Types
C# Type Size in Bits System Type CLS-Compliant
sbyte 8 System.SByte No
short 16 System.Int16 Yes
int 32 System.Int32 Yes
long 64 System.Int64 Yes
byte 8 System.Byte Yes
ushort 16 System.Uint16 No
uint 32 System.Uint32 No
ulong 64 System.UInt64 No
char 16 System.Char Yes
bool 8 System.Boolean Yes
float 32 System.Single Yes
double 64 System.Double Yes
decimal 128 System.Decimal Yes
string N/A System.String Yes
object N/A System.Object Yes
For each entry in the table, the last column indicates whether the type is compliant with the
Common Language Specification (CLS). The CLS is defined as part of the CLI standard to facilitate
multilanguage interoperability. The CLS is a subset of the Common Type System (CTS). Even though
the CLR supports a rich set of built-in types, not all languages that compile into managed code sup-
port all of them. However, all managed languages are required to support the types in the CLS. For
example, Visual Basic hasn’t supported unsigned types traditionally. So the designers of the CLI
defined the CLS to standardize types in order to facilitate interoperability between the languages. If
your application will be entirely C#-based and won’t create any components consumed from
another language, then you don’t have to worry about adhering to the strict guidelines of the CLS.
But if you work on a project that builds components using various languages, then conforming to
the CLS will be much more important to you.

41.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 21
In the managed world of the CLR, there are two kinds of types:
Value types: Defined in C# using the struct keyword. Instances of value types are the only kind
of instances that can live on the stack. They live on the heap if they’re members of reference
types or if they’re boxed, which I discuss later. They are similar to structures in C++ in the sense
that they are copied by value by default when passed as parameters to methods or assigned to
other variables. Although C#’s built-in value types represent the same kinds of values as Java’s
primitive types, there are no Java counterparts.
Reference types: Defined in C# using the class keyword. They are called reference types because
the variables you use to manipulate them are actually references to objects on the managed
heap. In fact, in the CLR reference-type variables are like value types that reference an object
on the heap. In this way, C# and Java are identical. C++ programmers can think of them as
pointers that you don’t have to dereference to access objects. Some C++ programmers like to
think of these as smart pointers.
Value Types
Value types can live on either the stack or the managed heap. You use them commonly when you
need to represent some immutable data that is generally small in its memory footprint. You can
define user-defined value types in C# by using the struct keyword.
■Note Even though C++ has a struct keyword, the meaning in C# is different in that it’s the only way to create
value types in C#.
User-defined value types behave in the same way that the built-in value types do. When you
create a value during the flow of execution, the value is created on the stack, as shown in this code
snippet:
int theAnswer = 42;
System.Console.WriteLine( theAnswer.ToString() );
Not only is the theAnswer instance created on the stack, but if it gets passed to a method, the
method will receive a copy of it. Value types are typically used in managed applications to represent
lightweight pieces or collections of data, similar to the way built-in types and structs are sometimes
used in C++, and primitive types are used in Java.
Values can also live on the managed heap, but not by themselves. The only way this can hap-
pen is if a reference type has a field that is a value type. Even though a value type inside an object
lives on the managed heap, it still behaves the same as a value type on the stack when it comes to
passing it into a method; that is, the method will receive a copy by default. Any changes made to the
value instance are only local changes to the copy unless the value was passed by reference. The fol-
lowing code illustrates these concepts:
public struct Coordinate //this is a value type
{
public int x;
public int y;
}
public class EntryPoint //this is a reference type

42.
22 CHAPTER 3 ■ C# SYNTAX OVERVIEW
{
public static void AttemptToModifyCoord( Coordinate coord ) {
coord.x = 1;
coord.y = 3;
}
public static void ModifyCoord( ref Coordinate coord ) {
coord.x = 10;
coord.y = 10;
}
static void Main() {
Coordinate location;
location.x = 50;
location.y = 50;
AttemptToModifyCoord( location );
System.Console.WriteLine( "( {0}, {1} )", location.x, location.y );
ModifyCoord( ref location );
System.Console.WriteLine( "( {0}, {1} )", location.x, location.y );
}
}
In the Main method, the call to AttemptToModifyCoord actually does nothing to the location
value. This is because AttemptToModifyCoord modifies a local copy of the value that was made when
the method was called. The location value is passed by reference into the ModifyCoord method.
Thus, any changes made in the ModifyCoord method are actually made on the location value in the
calling scope. It’s similar to passing a value by a pointer in C++. The output from the example is as
follows:
( 50, 50 )
( 10, 10 )
Enumerations
Enumerations (enums) in C# are similar to enumerations in C++, and the defining syntax is almost
identical. At the point of use, however, you must fully qualify the values within an enumeration
using the enumeration type name. All enumerations are based upon an underlying integral type,
which if not specified, defaults to int.
■Note The underlying type of the enum must be an integral type that is one of the following: byte, sbyte,
short, ushort, int, uint, long, or ulong.
Each constant that is defined in the enumeration must be defined with a value within the
range of the underlying type. If you don’t specify a value for an enumeration constant, the value
takes the default value of 0 (if it is the first constant in the enumeration) or 1 plus the value of the
previous constant. This example is an enumeration based upon a long:
public enum Color : long
{

43.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 23
Red,
Green = 50,
Blue
}
In this example, if I had left off the colon and the long keyword after the Color type identifier,
the enumeration would have been of int type. Notice that the value for Red is 0, the value for Green
is 50, and the value for Blue is 51.
To use this enumeration, write code such as the following:
static void Main() {
Color color = Color.Red;
System.Console.WriteLine( "Color is {0}", color.ToString() );
}
If you compile and run this code, you’ll see that the output actually uses the name of the enu-
meration rather than the ordinal value 0. The System.Enum type’s implementation of the ToString
method performs this magic.
Many times, you may use enumeration constants to represent bit flags. You can attach an
attribute in the System namespace called System.FlagsAttribute to the enumeration to make this
explicit. The attribute is stored in the metadata, and you can reference it at design time to deter-
mine whether members of an enumeration are intended to be used as bit flags. Also, you can
reference this attribute in some places at run time—for example, when an enumeration value is
converted to a string. Note that System.FlagsAttribute doesn’t modify the behavior of the values
defined by the enumeration. At run time, however, certain components can use the metadata gen-
erated by the attribute to process the value differently. This is a great example of how you can use
metadata effectively in an aspect-oriented programming (AOP) manner.
■Note AOP, also called aspect-oriented software development (AOSD), is a concept originally developed by
Gregor Kiczales and his team at Xerox PARC. Object-oriented methodologies generally do a great job of partitioning
the functionality, or concerns, of a design into cohesive units. However, some concerns, called crosscutting con-
cerns, cannot be modeled easily with standard OO designs. For example, suppose you need to log entry into and
exit from various methods. It would be a horrible pain to modify the code for each and every method that you need
to log. It would be much easier if you could simply attach a property—or in this case, an attribute—to the method
itself so that the runtime would log the method’s call when it happens. This keeps you from having to modify the
method, and the requirement is applied out-of-band from the method’s implementation. Microsoft Transaction
Server (MTS) was one of the first widely known examples of AOP.
Using metadata, and the fact that you can attach arbitrary, custom attributes to types, methods, properties,
and so on, you can use AOP in your own designs.
Here is an example of a bit flag enumeration:
[Flags]
public enum AccessFlags
{
NoAccess = 0x0,
ReadAccess = 0x1,
WriteAccess = 0x2,
ExecuteAccess = 0x4
}

44.
24 CHAPTER 3 ■ C# SYNTAX OVERVIEW
Here is an example of using the AccessFlags enumeration:
static void Main() {
AccessFlags access = AccessFlags.ReadAccess |
AccessFlags.WriteAccess;
System.Console.WriteLine( "Access is {0}", access );
}
If you compile and execute this example, you’ll see that the Enum.ToString method implicitly
invoked by WriteLine does, in fact, output a comma-separated list of all the bits that are set in this
value.
Reference Types
The garbage collector (GC) inside the CLR manages everything regarding the placement of objects.
It can move objects at any time. When it moves them, the CLR makes sure that the variables that ref-
erence them are updated. Normally, you’re not concerned with the exact location of the object
within the heap, and you don’t have to care if it gets moved around or not. There are rare cases, such
as when interfacing with native DLLs, when you may need to obtain a direct memory pointer to an
object on the heap. It is possible to do that using unsafe (or unmanaged) code techniques, but that
is outside the scope of this book.
■Note Conventionally, the term object refers to an instance of a reference type, whereas the term value refers to
an instance of a value type, but all instances of any type are also derived from type object.
Variables of a reference type are either initialized by using the new operator to create an object
on the managed heap, or they are initialized by assignment from another variable of a compatible
type. The following code snippet points two variables at the same object:
string idTag = "423-XYZ";
string theTag = idTag;
Like the Java runtime, the CLR manages all references to objects on the heap. In C++, you must
explicitly delete heap-based objects at some carefully chosen point. But in the managed environ-
ment of the CLR, the GC takes care of this for you. This frees you from having to worry about
deleting objects from memory and minimizes memory leaks. The GC can determine, at any point in
time, how many references exist to a particular object on the heap. If it determines there are none, it
is free to start the process of destroying the object on the heap. (Chapter 13 discusses at length the
intricacies of this process and the factors that influence it.) The previous code snippet includes two
references to the same object. You initialize the first one, idTag, by creating a string object. You ini-
tialize the second one, theTag, from idTag. The GC won’t collect the string object on the heap until
both of these references are outside any usable scope. Had the method containing this code
returned a copy of the reference to whatever called it, then the GC would still have a reference to
track even when the method was no longer in scope.
■Note For those coming from a C++ background, the fundamental way in which objects are treated in the C++
world is reversed in the C# world. In C++, objects are allocated on the stack unless you create them explicitly with
the new operator, which then returns a pointer to the object on the native heap. In C#, you cannot create objects of a
reference type on the stack. They can only live on the heap. So, it’s almost as if you were writing C++ code, where
you create every object on the heap without having to worry about deleting the objects explicitly to clean up.

45.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 25
Default Variable Initialization
By default, the C# compiler produces what is called safe code. One of the safety concerns is making
sure the program doesn’t use uninitialized memory. The compiler wants every variable to be set to a
value before you use it, so it is useful to know how different types of variables are initialized.
The default value for references to objects is null. At the point of declaration, you can option-
ally assign references from the result of a call to the new operator; otherwise, they will be set to null.
When you create an object, the runtime initializes its internal fields. Fields that are references to
objects are initialized to null, of course. Fields that are value types are initialized by setting all bits of
the value type to zero. Basically, you can imagine that all the runtime is doing is setting the bits of
the underlying storage to 0. For references to objects, that equates to a null reference, and for value
types, that equates to a value of zero.
For value types that you declare on the stack, the compiler does not zero-initialize the memory
automatically. However, it does make sure that you initialize the memory before the value is used.
■Note Since enumerations are actually value types, you should always declare an enumeration member that
equates to zero, even if the name of the member is InvalidValue or None and is otherwise meaningless. If an
enumeration is declared as a field of a class, instances of that class will have the field set to zero upon default ini-
tialization. Declaring a member that equates to zero allows users of your enumeration to deal with this case easily.
Implicitly Typed Local Variables
Because C# is a strongly typed language, every variable declared in the code must have an explicit type
associated with it. When the CLR stores the contents of the variable in a memory location, it also asso-
ciates a type with that location. But sometimes, when writing code for strongly typed languages, the
amount of typing needed to declare such variables can be tedious, especially if the type is a generic
one. For complex types, such as query variables created using Language Integrated Query (LINQ), dis-
cussed in Chapter 16, the type names can be downright unwieldy. Enter implicitly typed variables.
By declaring a local variable using the new var keyword, you effectively ask the compiler to
reserve a local memory slot and attach an inferred type to that slot. At compilation time, there is
enough information available at the point the variable is initialized for the compiler to deduce the
actual type of that variable without your having to tell it the type explicitly. Let’s have a look at what
these look like.
Here you see an example of what an implicitly typed variable declaration looks like:
using System;
using System.Collections.Generic;
public class EntryPoint
{
static void Main() {
var myList = new List<int>();
myList.Add( 1 );
myList.Add( 2 );
myList.Add( 3 );
foreach( var i in myList ) {
Console.WriteLine( i );
}
}
}

46.
26 CHAPTER 3 ■ C# SYNTAX OVERVIEW
The first things you should notice are the keywords in bold that show the usage of the new var
keyword. In the first usage, I have declared a variable named myList, asking the compiler to set the
type of the variable based upon the type from which it is assigned. It’s important to note that an
implicitly typed variable declaration must include an initializer. If you tried to state the following in
code, you would be greeted with the compiler warning CS0818, stating that “Implicitly typed locals
must be initialized”:
var newValue; // emits error CS0818
Similarly, if you try to declare a class field member as an implicitly typed variable, even if it has
an initializer, you will get the compiler error CS0825, stating that “The contextual keyword ‘var’ may
only appear within a local variable declaration.”
Finally, you may be used to declaring multiple variables in one line by separating each identi-
fier with a comma, as in the following two examples:
int a = 2, b = 1;
int x, y = 4;
However, you cannot do this with implicitly typed variables. The compiler gives you the error
CS0819, stating “Implicitly typed locals cannot have multiple declarators.”
■Note Early copies of the C# 3.0 draft standard floating around the Internet indicate that implicitly typed vari-
ables can be initialized using multiple declarators as long as each initializer results in the same type. However, the
pre-release version of the compiler that I am using while writing this book does not support it.
THE COMPLEXITY OF ADDING NEW KEYWORDS TO THE LANGUAGE
Adding new features like implicitly typed variables to the compiler is not as trivial as it may appear at first. That’s
because any time you introduce a new keyword to the language, you have to be concerned about breaking existing
code and not allowing backward compatibility. For example, imagine what would happen if you had a huge code
base written with C# 1.0 or C# 2.0 that had a type, say a class, named var. Now, you are in the process of making
the switch to C# 3.0 and you compile your application using the new compiler. Clearly, you will most likely have
some variable declarations that create instances of your var class. What should the compiler do? This is a very dif-
ficult question to answer.
In my tests with the pre-release version of the compiler I am using as I write this, the compiler does nothing.
But should it do nothing? It could choose to emit a compiler warning stating something like “declared type has
same name as built-in ‘var’ keyword.” But in reality, that’s not necessary, as I’ll show soon. In fact, it’s probably
best that the compiler does not emit a warning. Good development teams use the /WARNASERRORS+ compiler
option to halt compilation if there is a warning in the code. So if the compiler emitted a warning, your application
would fail to compile as you migrated to C# 3.0 and Microsoft would take the blame for being so flagrant as to
ignore backward compatibility.
The bottom line is that if you have a type defined using the name var, you simply cannot use implicitly typed
variables in any C# code where that type’s namespace is imported into the local scope. If you do, you’ll typically get
the CS0029 compiler error, which says in essence that the type you are trying to assign to an implicitly typed vari-
able cannot be implicitly converted to your custom var type. Whew! What a mouthful. For example, the following
code exhibits this behavior:
using System;
using System.Collections.Generic;

47.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 27
public class var
{
}
public class EntryPoint
{
static void Main() {
var myList = new List<int>(); // Won't compile! Error CS0029
}
}
Compiler developers typically take this problem extremely seriously and sometimes won’t even introduce a
new keyword if it could possibly break existing code. However, the C# compiler developers have a trump card. If
you follow the recommended conventions for naming .NET types with an initial capital letter, you’ll never find your-
self in this situation. Additionally, if you use Visual Studio code analysis or FxCop (the stand-alone version of code
analysis) during the development of your application, you will never encounter this problem. These rules and guide-
lines are also covered in detail in Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable
.NET Libraries by Krzysztof Cwalina and Brad Abrams (Boston, MA: Addison-Wesley Professional, 2005). I highly rec-
ommend you read their book if you have not already.
Type Conversion
Many times, it’s necessary to convert instances of one type to another. In some cases, the compiler
does this conversion implicitly whenever a value of one type is assigned from another type that,
when converted to the assigned type, will not lose any precision or magnitude. In cases where pre-
cision could be lost, an explicit conversion is required. For reference types, the conversion rules are
analogous to the pointer conversion rules in C++.
The semantics of type conversion are similar to both C++ and Java. Explicit conversion is repre-
sented using the familiar casting syntax that all of them inherited from C—that is, the type to
convert to is placed in parentheses before whatever needs to be converted:
int defaultValue = 12345678;
long value = defaultValue;
int smallerValue = (int) value;
In this code, the (int) cast is required to be explicit since the underlying size of an int is smaller
than a long. Thus, it’s possible that the value in the long may not fit into the space available to the
int. The assignment from the defaultValue variable to the value variable requires no cast, since a
long has more storage space than an int. If the conversion will lose magnitude, it’s possible that the
conversion may throw an exception at run time. The general rule is that implicit conversions are
guaranteed never to throw an exception, whereas explicit conversions may throw exceptions.
The C# language provides the facilities to define custom implicit and explicit conversion oper-
ators to various types for your user-defined types. Chapter 6 covers these in more detail. The
exception requirements for built-in conversion operators apply to user-defined conversion opera-
tors. Namely, implicit conversion operators are guaranteed never to throw.
Conversion to and from reference types models that of Java and of conversions between point-
ers in C++. For example, a reference to type DerivedType can be implicitly converted to a reference
to type BaseType if DerivedType is derived from BaseType. However, you must explicitly cast a con-
version in the opposite direction. Also, an explicit cast may throw a System.InvalidCastException if
the CLR cannot perform the conversion at run time.

48.
28 CHAPTER 3 ■ C# SYNTAX OVERVIEW
One kind of implicit cast is available in C# that is not easily available in C++, mainly because of
the default value semantics of C++. It is possible to implicitly convert from an array of one reference
type to an array of another reference type, as long as the target reference type is one that can be
implicitly converted from the source reference type and the arrays are of the same dimension. For
example, the following conversion is valid:
public class EntryPoint
{
static void Main() {
string[] names = new string[4];
object[] objects = names; //implicit conversion statement
string[] originalNames =
(string[]) objects; // explicit conversion statement
}
}
Because System.String derives from System.Object and, therefore, is implicitly convertible to
System.Object, this implicit conversion of the string array names into the object array objects vari-
able is valid. However, to go in the other direction, as shown, requires an explicit cast that may
throw an exception at run time if the conversion fails.
Keep in mind that implicit conversions of arguments may occur during method invocation if
arguments must be converted to match the types of parameters. If you cannot make the conver-
sions implicitly, you must cast the arguments explicitly.
Finally, another type of common conversion is a boxing conversion. Boxing conversions are
required when you must pass a value type as a reference type parameter to a method or assign it to
a variable that is a reference type. What happens is that an object is allocated dynamically on the
heap that contains a field of the value’s type. The value is then copied into this field. I cover boxing
in C# extensively in Chapter 4. The following code demonstrates boxing:
public class EntryPoint
{
static void Main() {
int employeeID = 303;
object boxedID = employeeID;
employeeID = 404;
int unboxedID = (int) boxedID;
System.Console.WriteLine( employeeID.ToString() );
System.Console.WriteLine( unboxedID.ToString() );
}
}
At the point where the object variable boxedID is assigned from the int variable employeeID,
boxing occurs. A heap-based object is created and the value of employeeID is copied into it. This
bridges the gap between the value type and the reference type worlds within the CLR. The boxedID
object actually contains a copy of the employeeID value. I demonstrate this point by changing the
original employeeID value after the boxing operation. Before printing out the values, I unbox the
value and copy the value contained in the object on the heap back into another int on the stack.
Unboxing requires an explicit cast in C#, because it can fail with a bad cast exception.

49.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 29
as and is Operators
Because explicit conversion can fail by throwing exceptions, times arise when you may want to test
the type of a variable without performing a cast and seeing if it fails or not. Testing this way is
tedious and inefficient, and exceptions are generally expensive at run time. For this reason, C# has
two operators that come to the rescue, and they are guaranteed not to throw an exception:
• is
• as
The is operator results in a Boolean that determines whether you can convert a given expres-
sion to the given type as either a reference conversion or a boxing or unboxing operation. For
example, consider the following code:
using System;
public class EntryPoint
{
static void Main() {
String derivedObj = "Dummy";
Object baseObj1 = new Object();
Object baseObj2 = derivedObj;
Console.WriteLine( "baseObj2 {0} String",
baseObj2 is String ? "is" : "isnot" );
Console.WriteLine( "baseObj1 {0} String",
baseObj1 is String ? "is" : "isnot" );
Console.WriteLine( "derivedObj {0} Object",
derivedObj is Object ? "is" : "isnot" );
int j = 123;
object boxed = j;
object obj = new Object();
Console.WriteLine( "boxed {0} int",
boxed is int ? "is" : "isnot" );
Console.WriteLine( "obj {0} int",
obj is int ? "is" : "isnot" );
Console.WriteLine( "boxed {0} System.ValueType",
boxed is ValueType ? "is" : "isnot" );
}
}
The output from this code is as follows:
baseObj2 is String
baseObj1 isnot String
derivedObj is Object
boxed is int
obj isnot int
boxed is System.ValueType

50.
30 CHAPTER 3 ■ C# SYNTAX OVERVIEW
As mentioned previously, the is operator considers only reference conversions. This means
that it won’t consider any user-defined conversions that are defined on the types.
The as operator is similar to the is operator, except that it returns a reference to the target type.
Because it is guaranteed never to throw an exception, it simply returns a null reference if the con-
version cannot be made. Similar to the is operator, the as operator only considers reference
conversions or boxing conversions. For example, look at the following code:
using System;
public class BaseType {}
public class DerivedType : BaseType {}
public class EntryPoint {
static void Main() {
DerivedType derivedObj = new DerivedType();
BaseType baseObj1 = new BaseType();
BaseType baseObj2 = derivedObj;
DerivedType derivedObj2 = baseObj2 as DerivedType;
if( derivedObj2 != null ) {
Console.WriteLine( "Conversion Succeeded" );
} else {
Console.WriteLine( "Conversion Failed" );
}
derivedObj2 = baseObj1 as DerivedType;
if( derivedObj2 != null ) {
Console.WriteLine( "Conversion Succeeded" );
} else {
Console.WriteLine( "Conversion Failed" );
}
BaseType baseObj3 = derivedObj as BaseType;
if( baseObj3 != null ) {
Console.WriteLine( "Conversion Succeeded" );
} else {
Console.WriteLine( "Conversion Failed" );
}
}
}
The output from this code is as follows:
Conversion Succeeded
Conversion Failed
Conversion Succeeded
Sometimes you need to test whether a variable is of a certain type and, if it is, then do some
sort of operation on the desired type. You could test the variable for the desired type using the is
operator and then, if true, cast the variable to the desired type. However, doing it that way is ineffi-
cient. The better approach is to follow the idiom of applying the as operator to obtain a reference of
the variable with the desired type, and then test whether the resulting reference is null, which would
mean that the conversion succeeded. That way, you perform only one type lookup operation
instead of two.

51.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 31
Generics
Support for generics is one of the most exciting new additions to the C# language. Using the generic
syntax, you can define a type that depends upon another type that is not specified at the point of
definition, but rather at the point of usage of the generic type. For example, imagine a collection
type. Collection types typically embody things such as lists, queues, and stacks. The collection types
that have been around since the .NET 1.0 days are adequate for containing any type in the CLR,
since they contain Object instances and everything derives from Object. However, all of the type
information for the contained type is thrown away, and the compiler’s power to catch type errors is
rendered useless. You must cast every type reference that you obtain from these collections into the
type you think it should be, and that could fail at run time. Also, the original collection types can
contain a heterogeneous blend of types rather than force the user to insert only instances of a cer-
tain type. You could go about fixing this problem by writing types such as ListOfIntegers and
ListOfStrings for each type you want to contain in a list. However, you will quickly find out that
most of the management code of these lists is similar, or generic, across all of the custom list types.
The key word is generic. Using generic types, you can declare an open (or generic) type and only
have to write the common code once. The users of your type can then specify which type the collec-
tion will contain at the point they decide to use it.
Additionally, using generics involves efficiency gains. The concept of generics is so large that
I’ve devoted Chapter 11 entirely to their declaration and usage. However, I believe it’s important to
give you a taste of how to use a generic type now, since I mention them several times prior to Chap-
ter 11.
■Note The generic syntax will look familiar to those who use C++ templates. However, it’s important to note that
there are significant behavioral differences, which I’ll explain in Chapter 11.
The most common use of generics is during the declaration of collection types. For example,
take a look at the following code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
class EntryPoint
{
static void Main() {
Collection<int> numbers =
new Collection<int>();
numbers.Add( 42 );
numbers.Add( 409 );
Collection<string> strings =
new Collection<string>();
strings.Add( "Joe" );
strings.Add( "Bob" );
Collection< Collection<int> > colNumbers
= new Collection<Collection<int>>();
colNumbers.Add( numbers );

52.
32 CHAPTER 3 ■ C# SYNTAX OVERVIEW
IList<int> theNumbers = numbers;
foreach( int i in theNumbers ) {
Console.WriteLine( i );
}
}
}
This example shows usage of the generic Collection type. The telltale sign of generic type
usage is the angle brackets surrounding a type name. In this case, I have declared a collection of
integers, a collection of strings, and, to show an even more complex generic usage, a collection of
collections of integers. Also, notice that I’ve shown the declaration for a generic interface, namely,
IList<>.
When you specify the type arguments for a generic type by listing them within the angle brack-
ets, as in Collection<int>, you are declaring a closed type. In this case, Collection<int> only takes
one type parameter, but had it taken more, then a comma would have separated the type argu-
ments. When the CLR first encounters this type declaration, it will generate the closed type based
on the generic type and the provided type arguments. Using closed types formed from generics is
no different than using any other type, except that the type declaration uses the special angle
bracket syntax to form the closed type.
Now that you’ve seen a glimpse of what generics look like, you should be prepared for the
casual generic references mentioned prior to Chapter 11.
Namespaces
C#, like C++ and analogous to Java packages, supports namespaces for grouping components logi-
cally. Namespaces help you avoid naming collisions between your identifiers.
Using namespaces, you can define all of your types such that their identifiers are qualified by
the namespace that they belong to. You have already seen namespaces in action in many of the
examples so far. For instance, in the “Hello World!” example from Chapter 1, you saw the use of the
Console class, which lives in the .NET Framework Class Library’s System namespace and whose fully
qualified name is System.Console. You can create your own namespaces to organize components.
The general recommendation is that you use some sort of identifier, such as your organization’s
name, as the top-level namespace, and then more specific library identifiers as nested namespaces.
Namespaces provide an excellent mechanism with which you can make your types more dis-
coverable, especially if you’re designing libraries meant for consumption by others. For example,
you can create a general namespace such as MyCompany.Widgets, where you put the most commonly
used types of widgets. Then you can create a MyCompany.Widgets.Advanced namespace where you
place all of the less commonly used, advanced types. Sure, you could place them all in one name-
space. However, users could become confused when browsing the types and seeing all of the types
they least commonly use mixed in with the ones they use the most.
■Note When picking a name for your namespace, the general guideline suggests that you name it using the for-
mula <CompanyName>.<Technology>.*, such that the first two dot-separated portions of the namespace name
start with your company name followed by your company’s technology. Then you can further subclassify the
namespace. You can see examples of this in the .NET Framework—for example, the Microsoft.Win32 name-
space.

53.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 33
Defining Namespaces
The syntax for declaring a namespace is simple. The following code shows how to declare a name-
space named Acme:
namespace Acme
{
class Utility {}
}
Namespaces don’t have to live in only one compilation unit (i.e., the C# source code file). In
other words, the same namespace declaration can exist in multiple C# files. When everything is
compiled, the set of identifiers included in the namespace is a union of all of the identifiers in each
of the namespace declarations. In fact, this union spans across assemblies. If multiple assemblies
contain types defined in the same namespace, the total namespace consists of all of the identifiers
across all the assemblies that define the types.
It’s possible to nest namespace declarations. You can do this in one of two ways. The first way is
obvious:
namespace Acme
{
namespace Utilities
{
class SomeUtility {}
}
}
Given this example, to access the SomeUtility class using its fully qualified name, you must
identify it as Acme.Utilities.SomeUtility. The following example demonstrates an alternate way of
defining nested namespaces:
namespace Acme
{
}
namespace Acme.Utilities
{
class SomeUtility {}
}
The effect of this code is exactly the same as the previous code. In fact, you may omit the first
empty namespace declaration for the Acme namespace. I left it there only for demonstration pur-
poses to point out that the Utilities namespace declaration is not physically nested within the
Acme namespace declaration.
Any types that you declare outside a namespace become part of the global namespace.
■Note You should always avoid defining types in the global namespace. Such practice is known as “polluting the
global namespace” and is widely considered poor programming practice. This should be obvious since there would
be no way to protect types defined by multiple entities from potential naming collisions.

54.
34 CHAPTER 3 ■ C# SYNTAX OVERVIEW
Using Namespaces
In the “Hello World!” example in Chapter 1, I quickly touched on the options available for using name-
spaces. Let’s examine some code that uses the SomeUtility class I defined in the previous section:
public class EntryPoint
{
static void Main() {
Acme.Utilities.SomeUtility util =
new Acme.Utilities.SomeUtility();
}
}
This practice of always qualifying names fully is rather verbose and might eventually lead to a
bad case of carpal tunnel syndrome. The using namespace directive avoids this. It tells the compiler
that you’re using an entire namespace in a compilation unit or another namespace. What the using
keyword does is effectively import all of the names in the given namespace into the enclosing
namespace, which could be the global namespace of the compilation unit. The following example
demonstrates this:
using Acme.Utilities;
public class EntryPoint
{
static void Main() {
SomeUtility util = new SomeUtility();
}
}
The code is now much easier to deal with and somewhat easier to read. The using directive,
because it is at the global namespace level, imports the type names from Acme.Utilities into the
global namespace. Sometimes when you import the names from multiple namespaces, you may
still have naming conflicts if both imported namespaces contain types with the same name. In this
case, you can import individual types from a namespace, creating a naming alias. This technique is
available via namespace aliasing in C#. Let’s modify the usage of the SomeUtility class so that you
alias only the SomeUtility class rather than everything inside the Acme.Utilities namespace:
namespace Acme.Utilities
{
class AnotherUtility() {}
}
using SomeUtility = Acme.Utilities.SomeUtility;
public class EntryPoint
{
static void Main() {
SomeUtility util = new SomeUtility();
Acme.Utilities.AnotherUtility =
new Acme.Utilities.AnotherUtility();
}
}
In this code, the identifier SomeUtility is aliased as Acme.Utilities.SomeUtility. To prove the
point, I augmented the Acme.Utilities namespace and added a new class named AnotherUtility.
This class must be fully qualified in order for you to reference it, since no alias is declared for it.
Incidentally, it’s perfectly valid to give the previous alias a different name than SomeUtility.
Although giving the alias a different name may be useful when trying to resolve a naming conflict,

55.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 35
it’s generally better to alias it using the same name as the original class name in order to avoid
maintenance confusion in the future.
■Note If you follow good partitioning principles when defining your namespaces, you shouldn’t have to deal with
this problem. It is bad design practice to create namespaces that contain a grab bag of various types covering dif-
ferent groups of functionality. Instead, you should create your namespaces with intuitively cohesive types
contained within them. In fact, many times in the .NET Framework, you’ll see a namespace with some general
types for the namespace included in it, with more advanced types contained in a nested namespace named
Advanced. In many respects, for creating libraries, these guidelines mirror the principle of discoverability applied
when creating intuitive user interfaces. In other words, name and group your types intuitively and make them eas-
ily discoverable.
Control Flow
Like C, C++, and Java, the C# language contains all the usual suspects when it comes to control flow
structure. C# even implements the dastardly goto statement.
if-else, while, do-while, and for
The if-else construct within C# is identical to those in C++ and Java. As a stylistic recommenda-
tion, I’m a proponent of always using blocks in if statements, or any other control flow statement
as described in the following sections, even when they contain only one statement, as in the follow-
ing example:
if( <test condition> ) {
Console.WriteLine( "You are here." );
}
The while, do, and for statements are identical to those in C++ and Java.
switch
The syntax of the C# switch statement is very similar to the C++ and Java switch syntax. The main
difference is that the C# switch doesn’t allow falling through to the next section. It requires a break
(or other transfer of control) statement to end each section. I believe this is a great thing. Countless
hard-to-spot bugs exist in C++ and Java applications because developers forgot a break statement
or rearranged the order of sections within a switch when one of them falls through to another. In
C#, the compiler will immediately complain with an error if it finds a section that falls through to
the next. The one exception to this rule is that you can have multiple switch labels (using the case
keyword) per switch section, as shown in the following code snippet. You can also simulate falling
through sections with the goto statement:
switch( k ) {
case 0:
Console.WriteLine( "case 0" );
goto case 1;
case 1:
case 2:
Console.WriteLine( "case 1 or 2" );
break;
}

56.
36 CHAPTER 3 ■ C# SYNTAX OVERVIEW
Notice that each one of the cases has a form of jump statement that terminates it. Even the last
case must have one. Many C++ and Java developers would omit the break statement in the final sec-
tion because it would just fall through to the end of the switch anyway. Again, the beauty of the “no
fall-through” constraint is that even if a developer maintaining the code at a later date whimsically
decides to switch the ordering of the labels, no bugs can be introduced, unlike in C++ and Java. Typ-
ically, you use a break statement to terminate switch sections, and you can use any statement that
exits the section. These include throw and return, as well as continue if the switch is embedded
within a loop where the continue statement makes sense.
foreach
The foreach statement allows you to iterate over a collection of objects in a syntactically natural
way. Note that you can implement the same functionality using a while loop. However, this can be
ugly, and iterating over the elements of a collection is such a common task that foreach syntax is a
welcome addition to the language. If you had an array (or any other type of collection) of strings, for
example, you could iterate over each string using the following code:
static void Main() {
string[] strings = new string[5];
strings[0] = "Bob";
strings[1] = "Joe";
foreach( string item in strings ) {
Console.WriteLine( "{0}", item );
}
}
Within the parentheses of the foreach loop, you declare the type of your iterator variable. In
this example, it is a string. Following the declaration of the iterator type is the identifier for the col-
lection to iterate over. You may use any object that implements the Collection pattern. Chapter 9
covers collections in greater detail, including what sorts of things a type must implement in order to
be considered a collection. Naturally, the elements within the collection used in a foreach state-
ment must be convertible, using an explicit conversion, to the iterator type. If they’re not, the
foreach statement will throw an InvalidCastException at run time. If you’d like to experience this
inconvenience yourself, try running this modification to the previous example:
static void Main() {
object[] strings = new object[5];
strings[0] = 1;
strings[1] = 2;
foreach( string item in strings ) {
Console.WriteLine( "{0}", item );
}
}
Note, however, that it’s invalid for the code embedded in a foreach statement to modify the
iterator variable at all. It should be treated as read-only. That means you cannot pass the iterator
variable as an out or a ref parameter to a method, either. If you try to do any of these things, the
compiler will quickly alert you to the error of your ways.
break, continue, goto, return, and throw
C# includes a set of familiar statements that unconditionally transfer control to another location.
These include break, continue, goto, return, and throw. Their syntax should be familiar to any
C++ or Java developer (though Java has no goto). Their usage is essentially identical in all three
languages.

57.
CHAPTER 3 ■ C# SYNTAX OVERVIEW 37
Summary
This chapter introduced the C# syntax, emphasizing that C#, like similar object-oriented languages,
is a strongly typed language. For these languages, you want to utilize the type-checking engine of
the compiler to find as many errors as possible at compile time rather than find them later at run
time. In the CLR, types are classified as either value types or reference types, and each category
comes with its own stipulations, which I’ll continue to dig into throughout this book. I also intro-
duced namespaces and showed how they help keep the global namespace from getting polluted
with too many types whose names could conflict. And finally, I showed how control statements
work in C#, which is similar to how they work in C++ and Java.
In the next chapter, I’ll dig deeper into the structure of classes and structs, while highlighting
the behavioral differences of instances thereof.

58.
CHAPTER 4
Classes, Structs, and Objects
E verything is an object! At least, that is the view from inside the CLR and the C# programming lan-
guage. This is no surprise, because C# is, after all, an object-oriented language. The objects that you
create through class definitions in C# have all the same capabilities as the other predefined objects
in the system. In fact, keywords in the C# language such as int and bool are merely aliases to prede-
fined value types within the System namespace, in this case System.Int32 and System.Boolean,
respectively.
■Note This chapter is rather long, but don’t allow it to be intimidating. In order to cater to a wider audience, this
chapter covers as much C# base material as reasonably possible. If you’re proficient with either C++ or Java, you
may find yourself skimming this chapter and referencing it as you read subsequent chapters. Some of the topics
touched upon in this chapter are covered in more detail in later chapters.
The first section of this chapter covers class definitions, which is followed by a section discussing value type
definitions. These are the two most fundamental classifications of types in the .NET runtime. Then you’ll learn
about System.Object (the base type of all types), the nuances of creating and destroying instances of objects,
expressions for initializing objects, and the topic of boxing and unboxing. Anonymous types are new to C# 3.0 and I
have devoted a section to them. Finally, I cover inheritance and polymorphism, and the differences between inheri-
tance and containment with regard to code reuse.
The ability to invent your own types is tantamount to object-oriented systems. The cool thing
is that, since even the built-in types of the language are plain-old CLR objects, the objects you cre-
ate are on a level playing field with the built-in types. In other words, the built-in types don’t have
special powers that you cannot muster in user-defined types. The cornerstone for creating these
types is the class definition. Class definitions, using the C# class keyword, define the internal state
and the behaviors associated with the objects of that class’s type. The internal state of an object is
represented by the fields that you declare within the class, which can consist of references to other
objects, or values. Sometimes, but rarely, you will hear people describe this as the “shape” of the
object, since the instance field definitions within the class define the memory footprint of the
object on the heap.
The objects created from a class encapsulate the data fields that represent the internal state of
the objects, and the objects can tightly control access to those fields. The behavior of the objects is
defined by implementing methods, which you declare and define within the class definition. By
calling one of the methods on an object instance, you initiate a unit of work on the object. That
work can possibly modify the internal state of the object, inspect the state of the object, or anything
else for that matter.
39

59.
40 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
You can define constructors, which the system executes whenever a new object is created. You
can also define a method called a finalizer, which works when the object is garbage-collected. As
you’ll see in Chapter 13, you should avoid finalizers if at all possible. This chapter covers construc-
tion and destruction in detail, including the detailed sequence of events that occur during the
creation of an object.
Objects support the concept of inheritance, whereby a derived class inherits the fields and
methods of a base class. Inheritance also allows you to treat objects of a derived type as objects of its
base type. For example, a design in which an object of type Dog derives from type Animal is said to
model an is-a relationship (i.e., Dog is-a(n) Animal). Therefore, you can implicitly convert references
of type Dog to references of type Animal. Here, implicit means that the conversion takes the form of a
simple assignment expression. Conversely, you can explicitly convert references of type Animal,
through a cast operation, to references of type Dog if the particular object referenced through the
Animal type is, in fact, an object created from the Dog class. This concept, called polymorphism,
whereby you can manipulate objects of related types as though they were of a common type, should
be familiar to you. Computer wonks always try to come up with fancy five-dollar words for things
such as this, and polymorphism is no exception, when all it means is that an object can take on mul-
tiple type identities. This chapter discusses inheritance, as well as its traps and pitfalls.
The CLR tracks object references. This means each variable of reference type actually contains a
reference to an object on the heap (or is null, if it doesn’t currently refer to an object). When you
copy the value of a reference-type variable into another reference-type variable, another reference
to the same object is created—in other words, the reference is copied. Thus, you end up with two
variables that reference the same object. In the CLR, you have to do extra work to create copies of
objects—e.g., you must implement the ICloneable interface or a similar pattern.
All objects created from C# class definitions reside on the system heap, which the CLR garbage
collector manages. The GC relieves you from the task of cleaning up your objects’ memory. You can
allocate them all day long without worrying about who will free the memory associated with them.
The GC is smart enough to track all of an object’s references, and when it notices that an object is no
longer referenced, it marks the object for deletion. Then, the next time the GC compacts the heap, it
destroys the object and reclaims the memory.
■Note In reality, the process is much more complex than this. There are many hidden nuances to how the GC
reclaims the memory of unused objects. I talk about this in the section titled “Destroying Objects” later this chap-
ter. Consider this: The GC removes some complexity in one area, but introduces a whole new set of complexities
elsewhere.
Along with classes, the C# language supports the definition of new value types through the
struct keyword. Value types are lightweight objects that typically don’t live on the heap, but instead
live on the stack. To be completely accurate, a value type can live on the heap, but only if it is a field
inside an object on the heap. Value types cannot be defined to inherit from another class or value
type, nor can another value type or class inherit from them.
Value types can have constructors, but they cannot have a finalizer. By default, when you pass
value types into methods as parameters, the method receives a copy of the value. I cover the many
details of value types, along with their differences from reference types, in this chapter and in
Chapter 13.
That said, let’s dive in and get to the details. Don’t be afraid if the details seem a little over-
whelming at first. The fact is, you can start to put together reasonable applications with C# without
knowing every single detailed behavior of the language. That’s a good thing, because C#, along with
the Visual Studio IDE, is meant to facilitate rapid application development. However, the more

60.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 41
details you know about the language and the CLR, the more effective you’ll be at developing and
designing robust C# applications.
Class Definitions
Class definitions in C# look similar to class definitions in C++ and Java. Let’s look at a simple class
now, so you can get a feel for things. In the following code, I’ve shown the basic pieces for creating a
class definition:
//NOTE: This code is not meant to be compiled as-is
[Serializable]
public class Derived : Base, ICloneable
{
private Derived( Derived other ) {
this.x = other.x;
}
public object Clone() { //implement the IClonable.Clone interface
return new Derived( this );
}
private int x;
}
This class declaration defines a class Derived, which derives from the class Base and also imple-
ments the ICloneable interface.
■Note If this is the first time you’ve encountered the interface concept, don’t worry. Chapter 5 is devoted entirely
to interfaces and contract-based programming.
The access modifier in front of the class keyword controls the visibility of the type from outside
the assembly (I describe assemblies in Chapter 2). The class Derived is publicly accessible, which
means that consumers of the assembly that contains this class can create instances of it. This type
contains a private constructor that is used by the public method Clone, which implements the
ICloneable interface. When a class implements an interface, you are required to implement all of
the methods of the interface.
You can apply attributes to just about any nameable entity within the CLR type system. In this
case, I’ve attached the Serializable attribute to the class to show an example of attribute usage
syntax. These attributes become part of the metadata that describes the type to consumers. In addi-
tion, you can create custom attributes to attach to various entities, such as classes, parameters,
return values, and fields, which easily exercise the capabilities of AOP.
Fields
Fields are the bread and butter that make up the state of objects. Typically, you declare a new class
only if you need to model some new type of object with its own custom internal state, represented
by its instance fields.

61.
42 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
You declare fields with a type, just like all other variables in C. The possible field modifiers are
as follows:
new
public
protected
internal
private
static
readonly
volatile
Many of these are mutually exclusive. Those that are mutually exclusive control the accessibil-
ity of the field and consist of the modifiers public, protected, internal, and private. I discuss these
in more detail in the “Accessibility” section. However, for now, I’ll detail the remaining modifiers.
The static modifier controls whether a field is a member of the type or a member of objects
instantiated from the type. In the absence of the static modifier, a field is an instance field, and thus
each object created from the class has its own copy of the field. This is the default. When decorated
with the static modifier, the field is shared among all objects of a class on a per-application-domain
basis.
Note that static fields are not included in the memory footprint of the object instances. In other
words, objects don’t encapsulate the static fields; rather, types encapsulate the static fields. It would
be inefficient for all instances of the object to contain a copy of the same static variable in their
memory footprint. And worse than that, the compiler would have to generate some sort of code
under the hood to make sure that when the static field is changed for one instance, it would change
the field in all instances. For this reason, the static fields actually belong to the class and not to the
object instances. In fact, when a static field is publicly accessible outside the class, you use the class
name and not the object instance variable to access the field.
■Note Static fields have another important quality: They are global to the application domain within which their
containing types are loaded. Application domains are an abstraction that is similar to the process abstraction
within an operating system, but it’s a more lightweight mechanism. You can have multiple application domains in
one operating system process. If your CLR process contains multiple application domains, each will have a copy of
the class’s static fields. A static field’s value in one application domain can be different from the same static field
in another application domain. Unless you create extra application domains yourself, your application will have
only one application domain: the default application domain. However, it’s important to note this distinction when
working in environments such as ASP.NET, where the concept of the application domain is used as the isolation
mechanism between two ASP.NET applications. In fact, you can easily jump to the conclusion that ASP.NET was the
driving motivation behind the application domain notion.
You can initialize fields during object creation in various ways. One straightforward way of ini-
tializing fields is through initializers. You use these initializers at the point where the field is defined,
and they can be used for either static or instance fields—for example:
private int x = 789;
private int y;
private int z = A.InitZ();
The field x is initialized using an initializer. The notation is rather convenient. Note that this
initialization occurs at run time and not at compile time. Therefore, this initialization statement
could have used something other than a constant. For example, the variable z is initialized by call-
ing a method, A.InitZ. At first, this field initialization notation may seem like a great shortcut,
saving you from having to initialize all of the fields inside the body of the constructor. However, I

62.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 43
suggest that you initialize instance fields within the instance constructor body. I cover static and
instance initialization in all of its gory detail in the “Creating Objects” section later in this chapter,
and you’ll see why initializing fields in the constructor can facilitate code that’s easier to maintain
and debug.
Another field modifier that comes in handy from time to time is the readonly modifier. As you
can guess, it defines the field so that you can only read from it. You can write to it only during object
creation. You can emulate the same behavior with greater flexibility using a read-only property,
which I discuss in the section titled “Properties.” Static readonly fields are initialized in a static con-
structor, while instance readonly fields are initialized in an instance constructor. Alternatively, you
can initialize readonly fields using initializers at the point of their declaration in the class definition,
just as you can do with other fields. Within the constructor, you can assign to the readonly field as
many times as necessary. Only within the constructor can you pass the readonly field as a ref or out
parameter to another function. Consider the following example:
public class A
{
public A()
{
this.y = 456;
// We can even set y again.
this.y = 654;
// We can use y as a ref param.
SetField( ref this.y );
}
private void SetField( ref int val )
{
val = 888;
}
private readonly int x = 123;
private readonly int y;
public const int z = 555;
static void Main()
{
A obj = new A();
System.Console.WriteLine( "x = {0}, y = {1}, z = {2}",
obj.x, obj.y, A.z );
}
}
You should note one important nuance here: The z field is declared using the const keyword. At
first, it may seem that it has the same effect as a readonly field, but it does not. First, a const field
such as this is known and used at compile time. This means that the code generated by the compiler
in the Main routine can be optimized to replace all uses of this variable with its immediate const
value. The compiler is free to use this performance trick, simply because the value of the field is
known at compile time. Also, note that you access the const field using the class name rather than
the instance name. This is because const values are implicitly static and don’t affect the memory
footprint, or shape, of the object instances. Again, this makes sense because the compiler would
optimize away access to that memory slot in the object instance anyway, since it would be the same
for all instances of this object.

63.
44 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
But one more detail is lurking here with regard to the difference between readonly and const
fields. readonly fields are guaranteed to be computed at run time. Therefore, suppose you have one
class with both a readonly field and a const field that lives in assembly A, and code in assembly B
creates and uses an instance of that class in assembly A. Now, suppose you rebuild assembly A at a
later date, and you modify the field initializers for the readonly field and the const field. The con-
sumer in assembly B would see the change in the const field only after you recompile the code in
assembly B. This behavior is expected, because when assembly B was built referencing the initial
incarnation of assembly A, the compiler optimized the use of the const values by inserting the literal
value into the generated IL code. Because of this, you need to be careful when deciding whether to
use a readonly field or a const value and, if you choose to use a readonly field, you need to choose
carefully between using a readonly field or a read-only property, which I introduce in a later section
titled “Properties.” Properties provide greater design-time and maintenance-time flexibility over
readonly fields.
Lastly, the volatile modifier indicates, as its name implies, that the field is sensitive to read
and write timing. Technically, the modifier indicates to the compiler that the field may be accessed
or modified by the operating system or hardware running on that system, or more likely, by another
thread at any time. The latter case is the most typical. Normally, access to a field by multiple threads
only becomes a problem when you don’t use any synchronization techniques, such as when not
using the C# lock statement or OS synchronization objects. When a field is marked as volatile, it
tells the implementation—and by that, I mean the CLR JIT compiler—that it must not apply opti-
mizations to that field’s access. Because it is questionable and error-prone to access fields with
multiple threads without using synchronization techniques, I won’t spend any more time describ-
ing the use of the volatile modifier. The fact is, you’ll rarely ever need it or come into contact with
it unless you’re doing some fancy type of interoperation with a device or something of that nature.
I’ve already covered some of the ways that field initialization can occur within an object
instance during class initialization. I cover many more nuances of field initialization in the “Field
Initialization” section. However, note that C# has rules about default field initialization that are
applied before any field initialization code that occurs in the constructor method’s code block. C#,
by default, creates verifiably type-safe code, which is guaranteed not to use uninitialized variables
and fields. The compiler goes to great lengths to ensure that this requirement is satisfied. For exam-
ple, it initializes all fields, whether they’re instance or static fields, to a default value before any of
your variable initializers execute. The default value for just about anything can easily be represented
by either the value 0 or null. For example, you can initialize an integer or any other similar value
type by setting all of the bits in its storage space to 0. For reference types, you set the initial default
value to null. Again, this is usually the result of the implementation setting all of the bits of the refer-
ence to 0. These default initializations occur before any code executes on the instance or class.
Therefore, it’s impossible to inspect the uninitialized values of an object or a class during initial
construction.
Constructors
Constructors are called when a class is first loaded by the CLR or an object is created. There are two
types of constructors: static constructors and instance constructors. A class can have only one static
constructor, and it can have no parameters. The name of the static constructor must match the
name of the class it belongs to. As with any other class member, you can attach metadata attributes
to the static constructor.
Instance constructors, on the other hand, are called when an instance of a class is created.
They typically set up the state of the object by initializing the fields to a desired predefined state.
You can also do any other type of initialization work, such as connecting to a database and opening
a file. A class can have multiple instance constructors that can be overloaded (i.e., have different
parameter types). As with the static constructor, instance constructor names must match the name
of the defining class. One notable capability of an instance constructor is that of the optional con-

64.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 45
structor initializer clause. Using the initializer, which follows a colon after the parameter list, you
can call a base class constructor or another constructor in the same class through the keywords
base and this, respectively. I have more to say about the base keyword in the section titled “base
Keyword.” Consider the following sample code and the two comments:
class Base
{
public int x = InitX();
public Base( int x )
{
this.x = x; // disambiguates the parameter and the instance variable
}
}
class Derived : Base
{
public Derived( int a )
:base( a ) // calls the base class constructor
{
}
}
Methods
A method defines a procedure that you can perform on an object or a class. If the method is an
instance method, you can call it on an object. If the method is a static method, you can call it only
on the class. The difference is that instance methods have access to the instance fields of the object
instance, whereas static methods don’t have access to instance fields or methods. Static methods
can only access static class members.
Methods can have metadata attributes attached to them, and they can also have optional mod-
ifiers attached. I discuss them throughout this chapter. These modifiers control the accessibility of
the methods, as well as facets of the methods that are germane to inheritance. Every method either
does or does not have a return type. If a method doesn’t have a return type, the declaration must
declare the return type as void. Methods may or may not have parameters.
Static Methods
You call static methods on the class rather than on instances of the class. Static methods only have
access to the static members of the class. You declare a method as static by using the static modi-
fier, as in the following example:
public class A
{
public static void SomeFunction()
{
System.Console.WriteLine( "SomeFunction() called" );
}
static void Main()
{
A.SomeFunction();
SomeFunction();
}
}

65.
46 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
Notice that both methods in this example are static. In the Main method, I first access the
SomeFunction method using the class name. I then call the static method without qualifying it. This
is because the Main and SomeFunction methods are both defined in the same class and are both
static methods. Had SomeFunction been in another class, say class B, I would have had no choice but
to reference the method as B.SomeFunction.
Instance Methods
Instance methods operate on objects. In order to call an instance method, you need a reference to
an instance of the class that defines the method. The following example shows the use of an
instance method:
public class A
{
private void SomeOperation()
{
x = 1;
this.y = 2;
z = 3;
// assigning this in objects is an error.
// A newinstance = new A();
// this = newinstance;
}
private int x;
private int y;
private static int z;
static void Main()
{
A obj = new A();
obj.SomeOperation();
System.Console.WriteLine( "x = {0}, y = {1}, z= {2}",
obj.x, obj.y, A.z );
}
}
In the Main method, you can see that I create a new instance of the A class and then call the
SomeOperation method through the instance of that class. Within the method body of
SomeOperation, I have access to the instance and static fields of the class, and I can assign to them
simply by using their identifiers. Even though the SomeOperation method can assign the static field z
without qualifying it, as I mentioned before, I believe it makes for more readable code if the assign-
ment of static fields is qualified by the class name even in the methods of the same class. Doing so is
helpful for whoever comes after you and has to maintain your code—someone who could even be
you!
Notice that when I assign to y, I do so through the this identifier. You should note a few impor-
tant things about this when used within an instance method body. It is treated as a read-only
reference whose type is that of the class. Using this, you can access the fields of the instance, as I
did when assigning the value of y in the previous code example. Because the this value is read-only,
you may not assign it, which would make it reference a different instance. If you try to do so, you’ll
hear about it when the compiler complains to you and fails to compile your code.

66.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 47
Properties
Properties are one of the nicest mechanisms within C# and the CLR that enable you to enforce
encapsulation better. In short, you use properties for strict control of access to the internal state of
an object.
A property, from the point of view of the object’s client, looks, smells, and behaves just like a
public field. The notation to access a property is the same as that used to access a public field on the
instance. However, a property doesn’t have any associated storage space within the object, as a field
does. Rather, a property is a shorthand notation for defining accessors used to read and write fields.
The typical pattern is to provide access to a private field in a class through a public property. C# 3.0
makes this even easier with its support for auto-implemented properties.
Properties significantly enhance your flexibility as a class designer. For example, if a property
represents the number of table rows in a database table object, the table object can defer the com-
putation of the value until the point where it is queried through a property. It knows when to
compute the value, because the client will call an accessor when it accesses the property.
Declaring Properties
The syntax for declaring properties is straightforward. As with most class members, you can attach
metadata attributes to a property. Various modifiers that are valid for properties are similar to ones
for methods. Other modifiers include the ability to declare a property as virtual, sealed, override,
abstract, and so on. I also cover these in detail in the section titled “Inheritance and Virtual Meth-
ods” later in this chapter.
The following code defines a property, Temperature, in class A:
public class A
{
private int temperature;
public int Temperature
{
get
{
System.Console.WriteLine( "Getting value for temperature" );
return temperature;
}
set
{
System.Console.WriteLine( "Setting value for temperature" );
temperature = value;
}
}
}
public class MainClass
{
static void Main()
{
A obj = new A();
obj.Temperature = 1;
System.Console.WriteLine( "obj.Temperature = {0}",
obj.Temperature );
}
}

67.
48 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
First I defined a property named Temperature, which has a type of int. Each property declara-
tion must define the type that the property represents. That type should be visible to the compiler at
the point where it is declared in the class, and it should have at least the same accessibility as the
property being defined. By that, I mean that if a property is public, the type of the value that the
property represents must at least be declared public in the assembly within which it is defined. In
the example, the int type is an alias for Int32. That class is defined in the System namespace, and it
is public. So, you can use int as a property type in this public class A.
You can also give this property the name Temperature. This is the name with which the clients
will refer to the property as if it were a field. In the example, I merely return the private field
temperature from the internal state of the object instance. This is the universal convention. You
name the private field with a leading lowercase character, while naming the property with a leading
uppercase character. Of course, you’re not obligated to follow this convention, but there is no good
reason not to and C# programmers expect it.
Accessors
In the previous example, you can see that there are two blocks of code within the property block.
These are the accessors for the property, and within the blocks of the accessors, you put the code
that reads and writes the property. As you can see, one is named get and the other is named set. It
should be obvious from their names which does what.
The get block is called when the client of the object reads the property. As you would expect,
this accessor must return a value or an object reference that matches the type of the property decla-
ration. It can also return an object that is implicitly convertible to the type of the property
declaration. For example, if the property type is a long and the getter returns an int, the int will be
implicitly converted to a long without losing precision. Otherwise, the code in this block is just like
a parameterless method that returns a value or reference of the same type as the property.
The set accessor is called when the client attempts to write to the property. Note that there is
no return value. Note also that a special variable named value is available to the code within this
block, and it’s the same type as that of the property declaration. When you write to the property, the
value variable will have been set to the value or object reference that the client has attempted to
assign to the property. If you attempt to declare a local variable named value in the set accessor,
you’ll receive a compiler error. The set accessor is like a method that takes one parameter of the
same type as the property and returns void.
Read-Only and Write-Only Properties
If you define a property with only a get accessor, that property will be read-only. Likewise, if you
define a property with only a set accessor, you’ll end up with a write-only property. And lastly, a
property with both accessors is a read-write property.
You may be wondering why a read-only property is any better or worse than a readonly public
field. At first thought, it may seem that a read-only property is less efficient than a readonly public
field. However, given the fact that the CLR can inline the code to access the property, in the case
where the property simply returns a private field, this argument of inefficiency does not hold. Now,
of course, writing the code is not as efficient. However, because programmers aren’t lazy and C# 3.0
auto-implemented properties make it so simple, that’s really no argument either.
The fact is, in 99% of all cases, a read-only property is more flexible than a readonly public
field. One reason is that you can defer a read-only property’s computation until the point where you
need it (a technique known as lazy evaluation, or deferred execution). So, in reality, it could provide
for more efficient code, when the property is meant to represent something that takes significant
time to compute. If you’re using a readonly public field for this purpose, the computation would
have to happen in the block of the constructor. All the necessary data to make the computation may

68.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 49
not even be available at that point. Or, you may waste time in the constructor computing the value,
when the user of the object may not ever access the value.
Also, read-only properties help enforce encapsulation. If you originally had a choice between a
read-only property and a readonly public field, and you chose the read-only property, you would
have had greater flexibility in future versions of the class to do extra work at the point where the
property is accessed without affecting the client. For example, imagine if you wanted to do some
sort of logging in debug builds each time the property is accessed. The client would effectively be
calling a method implicitly, albeit one of the special property methods, to access the data. The flexi-
bility of things that you can do in that method is almost limitless. Had you accessed the value as a
public readonly field, you wouldn’t call a method or be able to do anything without switching it over
to a property and forcing the client code to recompile. This discussion leads directly into the discus-
sion regarding encapsulation in the later section titled “Encapsulation.”
Auto-Implemented Properties
Many times, you need a type, say a class, that contains a few fields that are treated as a cohesive
unit. For example, imagine an Employee type that contains a full name and an identification number
but, for the sake of example, manages this data using strings as shown below:
public class Employee
{
string fullName;
string id;
}
As written, this class is essentially useless. The two fields are private and must be made accessi-
ble. For the sake of encapsulation, we don’t want to just make the fields public. However, for such a
simple little type, it sure is painful to code up basic property accessors as shown below:
public class Employee
{
public string FullName {
get { return fullName; }
set { fullName = value; }
}
public string Id {
get { return id; }
set { id = value; }
}
string fullName;
string id;
}
What a lot of code just to get a type with a couple of read/write properties!
■Note I’d be willing to bet that there are many developers out there who have simply avoided properties and
used public fields in these kinds of helper types simply because of the typing overhead alone. The problem with
that short-sighted approach is that you cannot do any sort of validation upon setting the field or perform any lazy
evaluation during property access.

69.
50 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
Thankfully, C# 3.0 has a new feature called auto-implemented properties that reduce this bur-
den significantly. Look how the previous Employee type changes after using auto-implemented
properties:
public class Employee
{
public string FullName { get; set; }
public string Id { get; set; }
}
That’s it! Basically, what you’re telling the compiler is, “I want a string property named
FullName and I want it to support get and set.” Behind the scenes the compiler generates a private
field in the class for the storage and implements the accessors for you. The beauty of this is that it’s
just a little more typing than declaring public fields but at the same time, since they are properties,
you can change the underlying implementation without having to modify the public interface of
the type. That is, if you later decided you wanted to customize the accessors for Id, you could do so
without forcing the clients of Employee to recompile.
■Note If you’re curious about the private field that the compiler declares in your type for auto-implemented
properties, you can always look at the field using ILDASM. Using my current implementation, the private field pro-
viding storage for FullName in the Employee class is named <>k__AutomaticallyGeneratedPropertyField0
and is of type string. Notice that the field name is “unspeakable,” meaning that you cannot type it into code and
compile without getting syntax errors. The C# compiler implementers do this on purpose so we don’t use the type
name directly. After all, the name of the field is a compiler implementation detail that is subject to change in the
future.
You can also create a read-only auto-implemented property by inserting the private keyword
as shown below:
public class Employee
{
public string FullName { get; private set; }
public string Id { get; set; }
}
At this point, you may be wondering how the FullName field ever gets set. After all, it’s read-only
and the private field representing the underlying storage has a compiler-generated name that we
cannot use in a constructor to assign to it. The solution is to use another new C# 3.0 feature called
object initializers, as shown in the following example:
using System;
public class Employee
{
public string FullName { get; private set; }
public string Id { get; set; }
}
public class AutoProps
{

70.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 51
static void Main() {
Employee emp = new Employee {
FullName = "John Doe",
Id = "111-11-1111"
};
}
}
Object initializers complement auto-implemented properties. Not only do they allow you a
means to set read-only auto-implemented properties, but they also give the instantiator of the
instance syntax similar to that normally provided by constructors whereby one passes values to the
constructor during instantiation to initialize the type appropriately. You can find out more about
object initializers in the “Object Initializers” section later in this chapter.
Encapsulation
Arguably, one of the most important concepts in object-oriented programming is that of encapsula-
tion. Encapsulation is the discipline of tightly controlling access to internal object data and
procedures. It would be impossible to consider any language that does not support encapsulation
as belonging to the set of object-oriented languages.
You always want to follow this basic concept: Never define the data fields of your objects as
publicly accessible. It’s as simple as that. However, you would be surprised how many programmers
still declare their data fields as public. Typically, this happens when a small utility object is defined
and the creators are either lazy or think they are in too much of a hurry. There are some things,
though, you should just not do; and cutting corners like this is one of them.
You want the clients of your object to speak to it only through controlled means. This normally
means controlling communication to your object via methods on the object (or properties which,
under the covers, are method calls). In this way, you treat the internals of the object as if they are
inside a black box. No internals are visible to the outside world, and all communications that could
modify those internals are done through controlled channels. Through encapsulation, you can
engineer a design whereby the integrity of the object’s state is never compromised.
A simple example of what I’m talking about is in order. In this example, I create a dummy
helper object to represent a rectangle. The example itself is a tad contrived, but it’s a good one for
the sake of argument because of its minimal complexity:
class MyRectangle
{
public uint width;
public uint height;
}
You can see a crude example of a custom rectangle class. Currently, I’m only interested in the
width and the height of the rectangle. Of course, a useful rectangle class for a graphics engine would
contain an origin as well, but for the sake of this example, I’ll only be interested in the width and
height. So, I declare the two fields for width and height as public. Maybe I did that because I was in
a hurry as I was designing this basic little class. But as you’ll soon see, just a little bit more work up
front will provide much greater flexibility.
Now, let’s say that time has passed, and I have merrily used my little rectangle class for many
uses. Never mind the fact that my little rectangle class is not very useful in and of itself, but let’s say I
have come up with a desire to make it a little more useful. Suppose I have some client code that
uses my rectangle class and needs to compute the area of the rectangle. Good object-oriented prin-
ciples guide me to consider that the best way to do this is to let the instances of MyRectangle tell the

71.
52 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
client what their area values are. Back in the days of ANSI C and other purely procedural imperative
programming languages, you would have created a function named something like ComputeArea,
which would take, as a parameter, a pointer to an instance of MyRectangle. Thankfully, those days
are behind us if we’re using an object-oriented approach. So, let’s do it:
class MyRectangle
{
public uint width;
public uint height;
public uint GetArea()
{
return width * height;
}
}
As you can see, I’ve added a new member: the GetArea method. When called on an instance,
the trusty MyRectangle will compute the area of the rectangle and return the result. Now, I’ve still
just got a basic little rectangle class that has one helper function defined on it to make clients’ lives
a little bit easier if they need to know the area of the rectangle. But let’s suppose I have some reason
to precompute the value of the area, so that each time the GetArea method is called, I don’t have to
recompute it every time. Maybe I want to do this because I know, for some reason, that GetArea will
be called many times on the same instance during its lifetime. Ignoring the fact that early optimiza-
tion is foolish, let’s say that I decide to do it. Now, my new MyRectangle class could look something
like this:
class MyRectangle
{
public uint width;
public uint height;
public uint area;
public uint GetArea()
{
return area;
}
}
If you look closely, you can start to see my errors. Notice that all of the fields are public. This
allows the consumer of my MyRectangle instances to access the internals of my rectangle directly.
What would be the point of providing the GetArea method if the consumer can simply access the
area field directly? Well, you say, maybe I should make the area field private. That way, clients are
forced to call GetArea to get the area of the rectangle. This is definitely a step in the right direction.
Let’s do it:
class MyRectangle
{
public uint width;
public uint height;
private uint area;
public uint GetArea()
{

72.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 53
if( area == 0 ) {
area = width * height;
}
return area;
}
}
I’ve made the area field private, forcing the consumer to call GetArea in order to obtain the
area. However, in the process, I realized that I have to compute the area of the rectangle at some
point. So, since I’m lazy to begin with, I decide to check the value of the area field before returning
it, and if it’s 0, I assume that I need to compute the area before I return it. This is a crude attempt at
an optimization. But now, I only compute the area if it is needed. Suppose a consumer of my rectan-
gle instance never needed to know the area of the rectangle. Then, given the previous code, that
consumer wouldn’t have to lose the time it takes to compute the area. Of course, in my contrived
example, this optimization will most likely be extremely negligible. But if you think for just a little
bit, I’m sure you can come up with an example where it may be beneficial to use this lazy evaluation
technique. Think about database access across a slow network where only certain fields in a table
may be needed at run time. Or, for the same database access object, it may be expensive to com-
pute the number of rows in the table. You should only use this technique when necessary.
A glaring problem still exists with my rectangle class. Since the width and height fields are pub-
lic, what happens if consumers change one of the values after they’ve called GetArea on the
instance? Well, then I’ll have a really bad case of inconsistent internals. The integrity of the state of
my object would be compromised. This is definitely not a good situation to be in. So, now you see
the error of my ways yet again. I must make the width and height fields of my rectangle private as
well:
class MyRectangle
{
private uint width;
private uint height;
private uint area;
public uint Width
{
get
{
return width;
}
set
{
width = value;
ComputeArea();
}
}
public uint Height
{
get
{
return height;
}

73.
54 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
set
{
height = value;
ComputeArea();
}
}
public uint Area
{
get
{
return area;
}
}
private void ComputeArea()
{
area = width * height;
}
}
Now, in my latest incarnation of MyRectangle, I have become really wise. After making the width
and height fields private, I realized that the consumer of the objects needs some way to get and set
the values of the width and the height. That’s where I use C# properties. Internally, I now handle the
changes to the internal state through a method body, and the methods called belong to the set of
specially named methods on the class. I have more to say about special—sometimes called
reserved—member names in the section titled “Reserved Member Names.” Now, I have tight control
over access to the internals. And along with that control comes the most essential value of encapsu-
lation. I can effectively manage the state of the internals so that they never become inconsistent. It’s
impossible to guarantee the integrity of the object’s state when foreign entities have access to the
state through back-door means.
In this example, my object knows exactly when the width and height fields change. Therefore, it
can take the necessary action to compute the new area. If the object had used the approach of lazy
evaluation, such that it contained a cached value of the area computed during the first call of the
Area property getter, then I would know to invalidate that cache value as soon as either of the setters
on the Width or Height properties is called.
So, the moral of the story is, a little bit of extra work up front to foster encapsulation goes a long
way as time goes on. One of the greatest properties of encapsulation that you need to burn into
your head and take to the bank is that, when used properly, the object’s internals can change to sup-
port a slightly different algorithm without affecting the consumers. In other words, the interface
visible to the consumer does not change. Interface-based design patterns help in this regard, too.
For example, in the final incarnation of the MyRectangle class, the area is computed up front as soon
as either of the Width or Height properties is set. Maybe once my software is nearing completion, I’ll
run a profiler and determine that computing the area early is really sapping the life out of the
processor as my program runs. No problem. I can change the model to use a cached area value that
is only computed when first needed, and because I followed the tenets of encapsulation, the con-
sumers of my objects don’t even need to know about it. They don’t even know a change internal to
the object occurred. That’s the power of encapsulation. When the internal implementation of an
object can change, and the clients that use it don’t have to change, then you know encapsulation is
working as it should.

74.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 55
■Note Encapsulation helps you achieve the age-old guideline of strong cohesion of objects with weak coupling
between objects.
Accessibility
I’ve mentioned access modifiers several times up to this point. Their use may seem intuitive to you
if you have any experience with any other object-oriented language, such as C++ or Java. However,
certain nuances of C# and CLI member access modifiers bear mentioning. Before I discuss the vari-
ous types of modifiers, let’s talk a little bit about where you can apply them.
Essentially, you can use access modifiers on just about any defined entity in a C# program,
including classes and any member within the class. Access modifiers applied to a class affect its vis-
ibility from outside the containing assembly. Access modifiers applied to class members, including
methods, fields, properties, events, and indexers, affect the visibility of the member from outside of
the class. Table 4-1 describes the various access modifiers available in C#.
Table 4-1. Access Modifiers in C#
Access Modifier Meaning
public Member is completely visible outside both the defining scope and the
internal scope. In other words, access to a public member is not restricted
at all.
protected Member is visible only to the defining class and any class that derives from
the defining class.
internal Member is visible anywhere inside the containing assembly. This includes
the defining class and any scope within the assembly that is outside the
defining class.
protected internal Member is visible within the defining class and anywhere else inside the
assembly. This modifier combines protected and internal using a Boolean
OR operation. The member is also visible to any class that derives from the
defining class, whether it’s in the same assembly or not.
private Member is visible only within the defining class, with no exceptions. This is
the strictest form of access and is the default access for class members.
Note that the CLR supports one more form of accessibility that the C# language designers felt
strongly was unnecessary to implement. Within the CLR, it is known as family-and-assembly acces-
sibility. In C# parlance, that equates to protected AND internal. If, for some reason, you absolutely
must use this accessibility modifier, then you need to use a different language, such as C++/CLI or
raw IL.
Now, let’s examine the allowed usage of these modifiers on various defined entities within C#.
Class members can use all five variants of the C# access modifiers. The default access of the class
members, in the absence of any modifiers at all, is private. Classes defined either within or outside
a namespace can only have one of two access modifiers; they can either be public or internal. By
default, they are internal.
You can apply only public, private, and internal to struct member definitions. I cover struct
definitions in greater detail later in the chapter in the section titled “Value Type Definitions.” Notice
the absence of protected and protected internal. They aren’t needed, because structs are implic-
itly sealed, meaning they cannot be base classes. I cover the sealed modifier in more detail in the
section titled “sealed Classes.”

75.
56 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
■Note One more important note is in order for those used to coding in C++: struct members are private by
default, just like in class definitions, whereas they are public by default in C++.
Lastly, members of interfaces, which I describe fully in Chapter 5, and enums, which I covered in
Chapter 3, are implicitly public by their very nature. Interfaces are meant to define a set of opera-
tions, or a contract, that a class can implement. It makes no sense for an interface to have any
restricted access members, since restricted access members are normally associated with a class
implementation, and interfaces, by their definition, contain no implementation. Enumerations, on
the other hand, are normally used as a named collection of constants. Enumerations have no inter-
nal implementation either, so it makes no sense for enumeration members to have any restricted
access. In fact, you get an error if you specify an access modifier, even public, on an interface mem-
ber or an enumeration member.
As you can see, access for just about anything defaults to the strictest form of access that makes
sense for that entity. In other words, you have to do work to allow others access to classes or class
members. The only exception is the access for a namespace, which is implicitly public and cannot
have any access modifiers applied to it.
Interfaces
Even though I devote much of Chapter 5 to the topic of interfaces, it is worth introducing interfaces
at this point for the purpose of discussion in the rest of this chapter. Generally speaking, an inter-
face is a definition of a contract. Classes can choose to implement various interfaces, and by doing
so, they guarantee to adhere to the rules of the contract. When a class inherits from an interface, it is
required to implement the members of that interface. A class can implement as many interfaces as
it wants by listing them in the base class list of the class definition.
In general terms, an interface’s syntax closely resembles that of a class. However, each member
is implicitly public. In fact, you’ll get a compile-time error if you declare any interface member with
any modifiers. Interfaces can only contain instance methods; therefore, you can’t include any static
methods in the definition. Interfaces don’t include an implementation; therefore, they are semanti-
cally abstract in nature. If you’re familiar with C++, you know that you can create a similar sort of
construct by creating a class that contains all public, pure virtual methods that have no default
implementations.
The members of an interface can only consist of members that ultimately boil down to meth-
ods in the CLR. This includes methods, properties, events, and indexers. I cover indexers in the
“Indexers” section, and I cover events in Chapter 10.
■Note If you’re a stickler for terminology, the C# specification actually calls properties, events, indexers, opera-
tors, constructors, and destructors function members. It’s actually a misnomer to call them methods. Methods
contain executable code, so they’re also considered function members.
The following code shows an example of an interface and a class that implements the interface:
public interface IMusician
//Note:A standard practice is that you preface interface names with a capital "I"
{
void PlayMusic();
}

76.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 57
public class TalentedPerson : IMusician
{
public void PlayMusic() {}
public void DoALittleDance() {}
}
public class EntryPoint
{
static void Main()
{
TalentedPerson dude = new TalentedPerson();
IMusician musician = dude;
musician.PlayMusic();
dude.PlayMusic();
dude.DoALittleDance();
}
}
In this example, I’ve defined an interface named IMusician. A class, TalentedPerson, indicates
that it wants to support the IMusician interface. The class declaration is basically saying, “I would
like to enter into a contract to support the IMusician interface, and I guarantee to support all the
methods of that interface.” The requirement of that interface is merely to support the PlayMusic
method, which the TalentedPerson class does so faithfully. As a final note, it is customary to name
an interface type with a leading uppercase I. When reading code, this stands as a marker to indicate
that the type in question is, in fact, an interface.
Now, clients can access the PlayMusic method in one of two ways. They can either call it
through the object instance directly, or they can obtain an interface reference onto the object
instance and call the method through it. Because the TalentedPerson class supports the IMusician
interface, references to objects of that class are implicitly convertible to references of IMusician. The
code inside the Main method in the previous example shows how to call the method both ways.
The topic of interfaces is broad enough to justify devoting an entire chapter to them, which I
do in Chapter 5. However, the information regarding interfaces that I’ve covered in this section is
enough to facilitate the discussions in the rest of this chapter.
Inheritance
If you ask around, many developers will tell you that inheritance is the backbone of object-oriented
programming. Although inheritance is a really slick concept to those who first encounter it, I beg to
differ that inheritance is the backbone. I’m a firm believer that encapsulation is the strongest fea-
ture of object-oriented programming. Inheritance is an important concept and a useful tool.
However, like many powerful tools, it can be dangerous when misused. My goal in this section is to
introduce you to inheritance in a way that makes you respect its power and that helps you to avoid
abusing it.
Earlier, I covered the syntax for defining a class. You specify the base class after a colon that fol-
lows the class name. In C#, a class can have only one base class. (Some other languages, such as
C++, support multiple inheritance.)
Accessibility of Members
Accessibility of members plays an important aspect in inheritance, specifically with respect to
accessing members of the base class from the derived class. Any public members of the base class
become public members of the derived class.

77.
58 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
Any members marked as protected are only accessible internally to the declaring class and to
the classes that inherit from it. Protected members are never accessible publicly from outside the
defining class or any class deriving from the defining class. Private members are never accessible to
anything except the defining class. So even though a derived class inherits all the members of the
base class, including the private ones, the code in the derived class cannot access the private mem-
bers inherited from the base class. In addition, protected internal members are visible to all types
that are defined within the containing assembly and to classes that derive from the class defining
the member. The reality is that the derived class inherits every member of a base class, except
instance constructors, static constructors, and destructors.
As you’ve seen, you can control the accessibility of the entire class itself when you define it. The
only possibilities for the class type’s accessibility are internal and public. When using inheritance,
the rule is that the base class type must be at least as accessible as the deriving class. Consider the
following code:
class A
{
protected int x;
}
public class B : A
{
}
This code doesn’t compile, because the A class is internal and is not at least as accessible as the
deriving class B. Remember that in the absence of an access modifier, class definitions default to
internal access—hence, the reason class A is internal. In order for the code to compile, you must
either promote class A to public access or demote class B to internal access. Also note that it is legal
for class A to be public and class B to be internal.
Implicit Conversion and a Taste of Polymorphism
You can view inheritance and what it does for you in several ways. First and most obvious, inheri-
tance allows you to borrow an implementation. In other words, you can inherit class D from class A
and reuse the implementation of class A in class D. It potentially saves you from having to do some
work when defining class D. Another use of inheritance is specialization, where class D becomes a
specialized form of class A. For example, consider the class hierarchy, as shown in Figure 4-1.
Figure 4-1. Inheritance specialization

78.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 59
As you can see, classes Rectangle and Circle derive from class GeometricShape. In other words,
they are specializing the GeometricShape class. Specialization is meaningless without polymorphism
and virtual methods. I cover the topic of polymorphism in more detail in the “Inheritance and Vir-
tual Methods” section of this chapter. For the moment, I’ll define basically what it means for the
purpose of this conversation.
Polymorphism describes a situation in which a type referenced with a particular variable can
behave like, and actually be, a different (more specialized) type instance. Chapter 5 examines the
differences and similarities between interfaces and contracts. Figure 4-1 shows a method in
GeometricShape named Draw. This same method appears in both Rectangle and Circle. You can
implement the model with the following code:
public class GeometricShape
{
public virtual void Draw()
{
// Do some default drawing stuff.
}
}
public class Rectangle : GeometricShape
{
public override void Draw()
{
// Draw a rectangle
}
}
public class Circle : GeometricShape
{
public override void Draw()
{
// Draw a circle
}
}
public class EntryPoint
{
private static void DrawShape( GeometricShape shape )
{
shape.Draw();
}
static void Main()
{
Circle circle = new Circle();
GeometricShape shape = circle;
DrawShape( shape );
DrawShape( circle );
}
}
You create a new instance of Circle in the Main method. Right after that, you obtain a
GeometricShape reference on the same object. This is an important step to note. The compiler has
implicitly converted the reference into a GeometricShape type reference by allowing you to use a

79.
60 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
simple assignment expression. Underneath the covers, however, it’s really still referencing the same
Circle object. This is the gist of type specialization and the automatic conversion that goes along
with it.
Now let’s consider the rest of the code in the Main method. After you get a GeometricShape refer-
ence on the Circle instance, you can pass it to the DrawShape method, which does nothing but call
the Draw method on the shape. However, the shape object reference really points to a Circle, the
Draw method is defined as virtual, and the Circle class overrides the virtual method, so calling Draw
on the GeometricShape reference actually calls Circle.Draw. That is polymorphism in action. The
DrawShape method doesn’t need to care at all about what specific type of shape the object is. All it
cares about is whether it is, in fact, a GeometricShape. And Circle is a GeometricShape. This is why
inheritance is often referred to as an is-a relationship. In the given example, Rectangle is-a
GeometricShape, and Circle is-a GeometricShape. The key to determining whether inheritance
makes sense or not is to apply the is-a relationship, along with some good old common sense, to
your design. If a class D inherits from a class B, and class D semantically is-not-a class B, then inheri-
tance is not the correct tool for that relationship.
One last important note about inheritance and convertibility is in order. I’ve said that the com-
piler implicitly converts the Circle instance reference into a GeometricShape instance reference.
Implicit, in this case, means that the code doesn’t have to do anything special to do the conversion,
and by something special, I typically mean a cast operation. Because the compiler has the ability to
do this based upon its knowledge of the inheritance hierarchy, it would seem to make sense that
you don’t have to get a GeometricShape reference before you can call DrawShape with the Circle
object instance. In fact, this is exactly true. The last line of the Main method demonstrates this. You
can simply pass the Circle instance reference directly into the DrawShape method, and because the
compiler can implicitly convert the type to a GeometricShape reference based upon the inheritance,
it does all of the work for you. Again, you can see the power of this mechanism.
Now, you can pass any object instance that derives from GeometricShape. After the software is
shrink-wrapped and labeled version 1, someone can come along later in version 2 and define new
shapes that derive from GeometricShape, and the code for DrawShape does not need to change. It
doesn’t even need to know what the new specializations are. They could be Trapezoid, Square
(a specialization of Rectangle), or Ellipse. It does not matter, as long as they derive from
GeometricShape.
Member Hiding
From the previous section’s discussion, you can see how the concept of inheritance, although a
powerful one, can be overused. When programmers are first introduced to inheritance, they have a
tendency to use it too much, creating designs and hierarchical structures that are hard to maintain.
It’s important to note that there are alternatives to using inheritance that in many cases make more
sense. Among the various types of associations between classes in a software system design, inheri-
tance is the strongest bond of them all. I uncover many more issues with regards to inheritance near
the end of the chapter. However, let’s go ahead and cover some basic effects of inheritance here.
Note that inheritance extends functionality but cannot remove functionality. For example, the
public methods available on a base class are available through instances of the derived class and
classes derived from that class. You cannot remove these capabilities from the derived class. Con-
sider the following code:
public class A
{
public void DoSomething()
{
System.Console.WriteLine( "A.DoSomething" );
}
}

80.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 61
public class B : A
{
public void DoSomethingElse()
{
System.Console.WriteLine( "B.DoSomethingElse" );
}
}
public class EntryPoint
{
static void Main()
{
B b = new B();
b.DoSomething();
b.DoSomethingElse();
}
}
In Main, you create a new instance of class B, which derives from class A. Since class B inherits
from class A, class B gets a union of the members of both class A and class B. That is why you can call
both DoSomething and DoSomethingElse on the instance of class B. This is pretty obvious, since inher-
itance extends functionality.
But what if you want to inherit from class A but hide the DoSomething method? In other words,
what if you just want to extend part of A’s functionality? This is impossible with inheritance. How-
ever, you have the option of member hiding, as shown in the following code, which is a modified
form of the previous example:
public class A
{
public void DoSomething()
{
System.Console.WriteLine( "A.DoSomething" );
}
}
public class B : A
{
public void DoSomethingElse()
{
System.Console.WriteLine( "B.DoSomethingElse" );
}
public new void DoSomething()
{
System.Console.WriteLine( "B.DoSomething" );
}
}
public class EntryPoint
{
static void Main()
{
B b = new B();
b.DoSomething();

81.
62 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
b.DoSomethingElse();
A a = b;
a.DoSomething();
}
}
You can see that in this version I’ve introduced a new method on class B named DoSomething.
Also notice the addition of the new keyword to the declaration of B.DoSomething. If you don’t add this
keyword, the compiler will complain with a warning. This is the compiler’s way of telling you that
you need to be more explicit about the fact that you’re hiding a method in the base class. Arguably,
the compiler does this because hiding members this way is generally considered bad design. Let’s
see why. The output from the previous code is as follows:
B.DoSomething
B.DoSomethingElse
A.DoSomething
First notice that which DoSomething method gets called depends on the type of reference it is
being called through. This is rather nonintuitive, since B is-an A, and you know that inheritance mod-
els an is-a relationship. If that’s the case, shouldn’t the entire public interface for A be available to
consumers of the instance of class B? The short answer is yes. If you really want the method to
behave differently in subclasses, then at the point class A is defined, you would declare the
DoSomething method as virtual. That way, you could utilize polymorphism to do the right thing. Then,
the most derived DoSomething would get called no matter which type of reference it is called through.
I have more to say about virtual methods later on, but think about this for a moment. In order
to declare DoSomething as virtual, you need to think about the future at the point you define it. That
is, you have to anticipate the possibility that someone could inherit from your class and possibly
may want to override this functionality. This is just one reason why inheritance can be more com-
plicated during the design process than it initially seems. As soon as you employ inheritance, you
have to start thinking about a lot more things like this. And we all know that nobody can predict the
future.
Even though class B now hides class A’s implementation of DoSomething, remember, it does not
remove it. It hides it when calling the method through a B reference on the object. However, in the
Main method, you can see that you can easily get around this by using implicit conversion to convert
the B instance reference into an A instance reference and then calling the A.DoSomething implemen-
tation through that. So, it’s not gone—it’s just hidden. You have to do a little more work to get to it.
Suppose you passed the B instance reference to a method that accepted an A instance refer-
ence, similar to the DrawShape example. The B instance reference would be implicitly converted to
an A instance reference, and if that method called DoSomething on that A instance reference passed
to it, it would get to A.DoSomething rather than B.DoSomething. That’s probably not what the caller of
the method would expect.
This is a classic demonstration that just because the language allows you to do something like
this doesn’t mean that doing so fosters good design. Just about any language available out there,
including C++, has features in the backwaters of its spec that, when used (or used improperly),
really just add unnecessary complexity.
The base Keyword
When you derive from a class, often you need to call a method or access a field, a property, or an
indexer on the base class from within a method on the derived class. The base keyword exists for
this purpose. You can use the base keyword just like any other instance variable, but you can use it

82.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 63
only within the block of an instance constructor, instance method, or instance property accessor.
You cannot use it in static methods. This makes complete sense, because base allows access to base
class implementations of an instance, much like this allows access to the instance owning the
method. Let’s look at the following code block:
public class A
{
public A( int var )
{
this.x = var;
}
public virtual void DoSomething()
{
System.Console.WriteLine( "A.DoSomething" );
}
private int x;
}
public class B : A
{
public B()
: base( 123 )
{
}
public override void DoSomething()
{
System.Console.WriteLine( "B.DoSomething" );
base.DoSomething();
}
}
public class EntryPoint
{
static void Main()
{
B b = new B();
b.DoSomething();
}
}
In this example, you can see two uses of the base keyword. The first is in the constructor for
class B. Remember that the base class doesn’t inherit instance constructors. However, when initial-
izing the object, it is sometimes necessary to call one of the base class constructors explicitly during
initialization of the derived class. This explains the notation in the class B instance constructor. The
base class initialization occurs after the declaration of the derived class constructor’s parameter list,
but before the constructor code block. I discuss the ordering of constructor calls and object initial-
ization in greater detail later, in the section titled “Creating Objects.”
The second use of the base keyword is in the B.DoSomething implementation. I have decided
that, in my implementation of class B, I want to borrow the DoSomething implementation in class A
while implementing B.DoSomething. I can call the A.DoSomething implementation directly from
within the B.DoSomething implementation by going through the base keyword.

83.
64 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
If you’re familiar with virtual methods, you may have raised an eyebrow at this point. If the
DoSomething method is virtual, and the base keyword acts like an instance variable on the base class,
wouldn’t the call to base.DoSomething actually end up calling B.DoSomething? After all, that’s how
polymorphism works, and base.DoSomething is equivalent to doing ((B)this).DoSomething, which
is just casting the this reference into a class B reference on this and then calling B.DoSomething, isn’t
it? Well, if that were the case, then the code in B.DoSomething would introduce an infinite loop.
The answer to the question is that no infinite loop has been introduced. The base keyword is
treated specially when used inside an instance member to call a virtual method. Normally, calling a
virtual method on an instance calls the most derived implementation of the virtual method, which
in this case is B.DoSomething. However, when it’s called through the base keyword, the most derived
method with respect to the base class is called. Thus, this is how you can implement an override
method while borrowing the implementation of the base class. If you’re curious about the details,
the fact is that the generated IL code calls through the base reference using the call instruction
rather than callvirt.
sealed Classes
I hinted previously that inheritance is such a powerful tool that it’s easily abused. In fact, this is so
true that I devote an entire discussion to the pitfalls of inheritance in the section titled “Inheritance,
Containment, and Delegation” later in this chapter. When you create a new class, sometimes you
create it with the express intent for it to serve as a base class or to allow for specialization. Often,
though, classes are designed with no knowledge or foresight about whether they will be used as
base classes or not. In fact, it’s likely that a class you design today will be used as a base class tomor-
row, even though you never intended for it to be used as a base class.
C# offers the sealed keyword for the occasions when you never want a client to derive from a
class. When applied to the entire class, the sealed keyword indicates that this class is a leaf class. By
that, I mean that nothing can inherit from this class. If you visualize your inheritance diagrams in
your design as trees, then it makes sense to call sealed classes leaf classes. At first, you might think
that you should rarely use the sealed keyword. However, I believe that the contrary is true. You
should use the sealed keyword as often as possible when designing new classes. In fact, use it by
default.
Inheritance is such a tricky beast that, in order for a class to serve as a good base class, you
must design it with that goal in mind. If not, you should mark it as sealed. It’s as simple as that. Now,
you may be thinking, “Shouldn’t I leave it unsealed so that someone can possibly derive from it in
the future, thus retaining maximum flexibility?” The answer is no, in a good design. Again, a class
that is meant to serve as a base class must be designed with that in mind from the start. If it is not,
then it’s likely that you’ll hit pitfalls while trying to derive from the class effectively.
■Note In many cases, classes that are meant to serve as extendable base classes are contained in consumable
libraries. Creating libraries is a detail-oriented business that you must focus lots of time on for your library to be
maximally useful. Additionally, once you publish a library, you may be stuck with supporting it for a long time;
therefore, you want to get it right the first time. I suggest you reference Krzysztof Cwalina and Brad Abrams’
Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (Boston, MA: Addi-
son-Wesley Professional, 2005) if you’re planning to create libraries; the book originated from the internal design
guidelines that the .NET Base Class Library team used while developing the framework.

84.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 65
abstract Classes
At the opposite end of the spectrum from sealed classes are abstract classes. Sometimes, you need
to design a class whose only purpose is to serve as a base class. You should mark classes such as
these with the abstract keyword.
The abstract keyword tells the compiler that this class is meant to be used only as a base class,
and therefore it does not allow code to create instances of that class. Let’s revisit the GeometricShape
example from earlier in the chapter:
public abstract class GeometricShape
{
public abstract void Draw();
}
public class Circle : GeometricShape
{
public override void Draw()
{
// Do some drawing.
}
}
public class EntryPoint
{
static void Main()
{
Circle shape = new Circle();
// This won't work!
// GeometricShape shape2 = new GeometricShape();
shape.Draw();
}
}
It makes no sense to create a GeometricShape object all by itself, so I’ve marked the
GeometricShape class as abstract. Therefore, if the code in Main attempts to create an instance of
GeometricShape, a compiler error will be emitted. You may have also noted the use of the abstract
keyword on the GeometricShape.Draw method. I cover this usage of the keyword in more detail in
the “Virtual and Abstract Methods” section. In short, using the abstract keyword is a way of saying
to the compiler that the deriving classes must override the method. Since the method must be
overridden by the derived classes, it makes no sense for GeometricShape.Draw to have an implemen-
tation when you can’t ever create an instance of GeometricShape anyway. Therefore, abstract
methods don’t need to have an implementation. If you come from the C++ world, you may be
exclaiming that C++ allows an abstract method to have an implementation. This is true, but the
designers of C# considered the idea unnecessary. In my experience, I’ve rarely found the need to use
a default implementation of an abstract method except in debug builds.
As you can see, there can be times in a design when you use a base class to define a sort of tem-
plate of behavior by providing an implementation to inherit. The leaf classes can inherit from this
base template of an implementation and flesh out the details.
Nested Classes
You define nested classes within the scope of another class definition. Classes that are defined
within the scope of a namespace, or outside the scope of a namespace but not inside the scope of

85.
66 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
another class, are called non-nested classes. Nested classes have some special capabilities and lend
themselves well to situations where you need a helper class that works on behalf of the containing
class.
For example, a container class might maintain a collection of objects. Imagine that you need
some facility to iterate over those contained objects and also allow external users who are doing the
iteration to maintain a marker, or an iterator of sorts, representing their place during the iteration.
This is a common design technique. Preventing the users from holding on to direct references to the
contained objects gives you much greater flexibility to change the internal behavior of the container
class without breaking code that uses the container class. Nested classes provide a great solution to
this problem for several reasons.
First, nested classes have access to all of the members that are visible to the containing class,
even if they’re private. Consider the following code, which represents a container class that contains
instances of GeometricShape:
using System.Collections;
public abstract class GeometricShape
{
public abstract void Draw();
}
public class Rectangle : GeometricShape
{
public override void Draw()
{
System.Console.WriteLine( "Rectangle.Draw" );
}
}
public class Circle : GeometricShape
{
public override void Draw()
{
System.Console.WriteLine( "Circle.Draw" );
}
}
public class Drawing : IEnumerable
{
private ArrayList shapes;
private class Iterator : IEnumerator
{
public Iterator( Drawing drawing )
{
this.drawing = drawing;
this.current = -1;
}
public void Reset()
{
current = -1;
}
public bool MoveNext()
{

87.
68 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
Here’s where it gets interesting. The Iterator class takes a reference to an instance of the con-
taining class, Drawing, as a parameter to its constructor. It then stores away this instance for later
use so that it can get at the shapes collection within the drawing object. However, notice that the
shapes collection in the Drawing class is private. It doesn’t matter, since nested classes have access
to the containing class’s private members.
Also, notice that the Iterator class itself is declared private. Non-nested classes can only be
declared as either public or internal, and they default to internal. You can apply the same access
modifiers to nested classes as you can to any other member of the class. In this case, you declare the
Iterator class as private so that external code, such as in the Main routine, cannot create instances
of the Iterator directly. Only the Drawing class itself can create instances of Iterator. It doesn’t
make sense for anyone other than Drawing.GetEnumerator to be able to create an Iterator instance.
Nested classes that are declared public can be instantiated by code external to the containing
class. The notation for addressing the nested class is similar to that of namespace qualification. In
the following example, you can see how to create an instance of a nested class:
public class A
{
public class B
{
}
}
public class EntryPoint
{
static void Main()
{
A.B b = new A.B();
}
}
Sometimes, when you introduce a nested class, its name may hide a member name within a
base class using the new keyword, similar to the way method hiding works. This is extremely rare,
and can, for the most part, be avoided. Let’s take a look at an example:
public class A
{
public void Foo()
{
}
}
public class B : A
{
public new class Foo
{
}
}
In this case, you define a nested class Foo inside the class B definition. Since the name is the
same as the Foo method in class A, you must use the new keyword, or else the compiler will let you
know about the collision in names. Again, if you get into a situation like this, it’s probably time to
rethink your design or simply rename the nested class unless you really meant to hide the base
member. Hiding base members like this is questionable design and not something you should gen-
erally do just because the language allows it.

88.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 69
Indexers
Indexers allow you to treat an object instance as if it were an array. This allows for a more natural
usage of objects that are meant to behave as a collection, such as instances of the Drawing class from
the previous section.
Generally, indexers look a little bit like a method whose name is this. As with just about every
entity in the C# type system, you can apply metadata attributes to indexers. You can also apply the
same modifiers to them that just about every other class member can have, except one: Indexers
may not be static. Indexers are, therefore, always instance-based and work on a specific instance of
an object of the defining class. Following the modifiers in the declaration is the type of the indexer.
The indexer will return this type of the object to the caller. Then you put the this keyword, followed
by the parameter list in square brackets, which I show in the next example.
Essentially, an indexer behaves a lot like a hybrid between a property and a method. After all,
under the covers, it is one of the special methods defined by the compiler when you define an
indexer. Conceptually, an indexer is similar to a method, in that it can take a set of parameters when
used. However, it also behaves like a property, as you define the accessors with a similar syntax. You
can apply many of the same modifiers to indexers as you can to a method. For example, indexers
can be virtual, they can be an override of a base class indexer, or they can be overloaded based on
the parameter list, just as methods can. Following the parameter list is the code block for the
indexer, which is just like a property code block in its syntax. The main difference is that the acces-
sors for the indexer can access the parameter list variables, whereas the accessors of a property
don’t have user-defined parameters. Let’s add an indexer to the Drawing object and see how you can
use it:
using System.Collections;
public abstract class GeometricShape
{
public abstract void Draw();
}
public class Rectangle : GeometricShape
{
public override void Draw()
{
System.Console.WriteLine( "Rectangle.Draw" );
}
}
public class Circle : GeometricShape
{
public override void Draw()
{
System.Console.WriteLine( "Circle.Draw" );
}
}
public class Drawing
{
private ArrayList shapes;
public Drawing()
{
shapes = new ArrayList();
}

89.
70 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
public int Count
{
get
{
return shapes.Count;
}
}
public GeometricShape this[ int index ]
{
get
{
return (GeometricShape) shapes[index];
}
}
public void Add( GeometricShape shape )
{
shapes.Add( shape );
}
}
public class EntryPoint
{
static void Main()
{
Rectangle rectangle = new Rectangle();
Circle circle = new Circle();
Drawing drawing = new Drawing();
drawing.Add( rectangle );
drawing.Add( circle );
for( int i = 0; i < drawing.Count; ++i ) {
GeometricShape shape = drawing[i];
shape.Draw();
}
}
}
As you can see, you can access the elements of the Drawing object in the Main method as if they
were inside a normal array. Most collection types support some type of indexer such as this. Also,
since this indexer only has a get accessor, it is read-only. However, keep in mind that if the collec-
tion maintains references to objects, the client code can still change the state of the contained
object through that reference. But since the indexer is read-only, the client code cannot swap out
the object reference at a specific index with a reference to a completely different object.
One difference is worth noting between a real array and an object that provides an indexer. You
cannot pass the results of calling an indexer on an object as an out or ref parameter to a method as
you can do with a real array. This is similar to the same restriction placed on properties.
partial Classes
Classes defined as partial were a new addition to C# 2.0. So far, I’ve shown you how to define
classes in one single file. This was a requirement in C# 1.0. It was impossible to split the definition of
a class across multiple files.

90.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 71
At first, such a convenience may not seem worthwhile. After all, if a class has become so large
that the file is hard to manage, that may be an indication of poor design. But arguably, the main rea-
son partial classes were introduced is to support code-generation tools.
Normally, when you work within the confines of the IDE, the IDE tries to help you out by gener-
ating some code for you. For example, a wizard generates helpful DataSet-derived classes when using
ADO.NET facilities. The classic problem has always been editing the resulting code generated by the
tool. It was always a dangerous proposition to edit the output from the tool, because any time the
parameters to the tool change, the tool regenerates the code, thus overwriting any changes made.
This is definitely not desired. Previously, the only way to work around this was to use some form of
reuse, such as inheritance or containment, thus inheriting a class from the class produced by the
code-generation tool. Many times these were not natural solutions to the problem. And many times,
the code generated by these tools was not designed to take inheritance into consideration.
Now, you can slip the partial keyword into the class definition right before the class keyword,
and voilà—you can split the class definition across multiple files. One requirement is that each file
that contains part of the partial class must use the partial keyword, and all of the partial pieces
must be defined within the same namespace, if you declare them in a namespace at all. Now, with
the addition of the partial keyword, the code generated from the code-generation tool can live in a
separate file from the additions to that generated class, and when the tool regenerates the code, you
don’t lose your changes.
You should know some things about the process the compiler goes through to assemble partial
classes into a whole class. You must compile all the partial pieces of a class together at once so the
compiler can find all of the pieces. For the most part, all of the members and aspects of the class are
merged together using a union operation. Therefore, they must coexist together as if you had
declared and defined them all in the same file. Base interface lists are unioned together. However,
since a class can have one base class at most, if the partial pieces list a base class, they must all list
the same base class. Other than those obvious restrictions, I think you’ll agree that partial classes
are a welcome addition to the C# language.
partial Methods
C# 3.0 introduced the partial keyword for methods to complement partial classes. A partial
method is simply a method whose signature is declared without a body in one piece of the partial
class and defined in another piece of the partial class. Just like partial classes, partial methods come
in really handy when you are consuming code created by wizards and code generators. But the
beauty of partial methods is that if a generator creates a declaration for a partial method in one part
of the class declaration and you don’t implement it in your part, then the method is not included as
part of the final assembled class. Moreover, any code in the generated piece that calls the partial
method will not break. It will simply not call the partial method at all. There are several restrictions
on partial methods necessary to provide this behavior.
• Partial methods must have a return type of void.
• Partial methods may not accept out parameters but may accept ref parameters.
• Partial methods may not be extern as well.
• Partial methods cannot be marked virtual and may not be decorated with access modifiers
because they are implicitly private.
• Partial methods can be marked either static or unsafe.
• Partial methods can be generic and may be decorated with constraints, although repeating
the constraints in the declaration of the implementation is optional.
• Delegates may not be wired up to call partial methods since they are not guaranteed to exist
in the final compiled product.

91.
72 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
With all of that in mind, let’s look at a short example of partial methods. Imagine one partial
class that is, for the sake of this example, a result of some code generator and is shown below:
public partial class DataSource
{
// Some useful methods
// ...
partial void ResetSource();
}
Let’s pretend that this DataSource class that the generator created represents some sort of back-
end data store that, in order to satisfy some design requirement, needs to be able to be reset from
time to time. Moreover, let’s assume that the steps required to reset the data source are only known
by the one who completes and consumes this partial class and implements the partial method.
With that in mind, a possible completion of this partial class by the consumer could look like the
following:
using System;
public partial class DataSource
{
partial void ResetSource() {
Console.WriteLine( "Source was reset" );
}
public void Reset() {
ResetSource();
}
}
public class PartialMethods
{
static void Main() {
DataSource ds = new DataSource();
ds.Reset();
}
}
You can see that I had to add a public method named Reset in order for Main to be able to reset
instances of DataSource. That’s because the ResetSource method is implicitly private. If you inspect
the resultant executable with ILDASM, you will see the private method DataSource.ResetSource and
if you inspect the IL generated for DataSource.Reset, you will see it calling through to ResetSource.
If you were to comment out, or remove, the partial implementation of ResetSource and recompile,
ILDASM would show that the DataSource.ResetSource method does not exist and the call to
ResetSource within the Reset method is simply removed.
Static Classes
C# 2.0 introduced a new class modifier that allows you to designate that a class is nothing more
than a collection of static members and cannot have objects instantiated from it. The way you do
this is by decorating the class declaration with the static modifier. Once you do that, several
restrictions are placed upon the class, as follows:
• The class may not derive from anything other than System.Object, and if you don’t specify
any base type, derivation from System.Object is implied.

92.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 73
• The class may not be used as a base class of another class.
• The class can only contain static members, which can be public or private. However, they
cannot be marked protected or protected internal, since the class cannot be used as a base
class.
• The class may not have any operators, since defining them would make no sense if you can-
not create instances of the class.
Even though the entire class is marked static, you still must mark each individual member as
static as well. Although it would be nice for the compiler to just assume that any member within a
static class is static itself, it would add unnecessary complexity to an already complex compiler.
However, constants and nested types declared within a static class are static with respect to the
declaring class by default. But if you put the static modifier on a nested class, it too will be a static
class just as the containing class is, but you’ll be able to instantiate nested classes not decorated
with static.
■Note In essence, declaring a class static is just the same as declaring it sealed and abstract at the same
time, but the compiler won’t let you do such a thing. However, if you look at the IL code generated for a static
class, you’ll see that this is exactly what the compiler is doing—that is, the class is decorated with the abstract
and sealed modifiers in the IL.
The following code shows an example of a static class:
using System;
public static class StaticClass
{
public static void DoWork() {
++callCount;
Console.WriteLine( "StaticClass.DoWork()" );
}
public class NestedClass {
public NestedClass() {
Console.WriteLine( "NestedClass.NestedClass()" );
}
}
private static long callCount = 0;
public static long CallCount {
get {
return callCount;
}
}
}
public static class EntryPoint
{
static void Main() {
StaticClass.DoWork();
// OOPS! Cannot do this!
// StaticClass obj = new StaticClass();

93.
74 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
StaticClass.NestedClass nested =
new StaticClass.NestedClass();
Console.WriteLine( "CallCount = {0}",
StaticClass.CallCount );
}
}
The StaticClass type contains one method, a field, a property, and a nested class. Notice that
since the NestedClass is not declared static, you can instantiate it just like any other class. Also,
since the EntryPoint class merely contains the static Main method, it too is marked as static to pre-
vent anyone from instantiating it inadvertently.
Static classes are useful when you need a logical mechanism to partition a collection of meth-
ods. An example of a static class within the Base Class Library is the venerable System.Console class.
It contains static methods, properties, and events, which are all static since only one console can be
attached to the process at a single time.
THE SINGLETON PATTERN
Probably the most popular design pattern is the Singleton pattern, which typically models a situation in which you
can create only one instance of a class at one time. Historically, you implement the Singleton pattern with private
constructors and with a static method named something like GetInstance to obtain a reference to the one possi-
ble running instance. Although you can use this technique in C#, the static class provides an excellent tool for
implementing the Singleton pattern in certain situations, as you see with System.Console.
If your Singleton is not required to be an instance of a class, then the static class is an excellent tool for imple-
menting it. For example, if you don’t ever need to destroy and re-create your class, and if you won’t use your
Singleton with .NET Remoting, then each application domain has its own instance of the Singleton, since static
fields are application-domain-specific. In fact, such a Singleton will not live on the heap, and all of the bookkeeping
involved with managing the single instance is unnecessary. What’s even better is that since it’s not an actual object
instance, you can use the static class effectively within an object’s finalizer body safely. In Chapter 13, I describe
why using objects in finalizers is so dangerous and how you cannot guarantee in what order finalizers for multiple
objects will be called.
Reserved Member Names
Several of the capabilities provided by the C# language are really just syntactic sugar that boils down
to methods and method calls in the IL code that you never see, unless you open the generated
assembly with a tool such as ILDASM. It’s important to be aware of this, just in case you attempt to
declare a method whose name conflicts with one of these underlying reserved method names.
These syntactic shortcuts include properties, events, and indexers. If you try to declare a method
with one of these special internal names and you also have a property, an event, or an indexer
already defined that declares the same method names internally, the compiler will complain about
duplicate symbols.

94.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 75
■ Note If you follow the conventions in Framework Design Guidelines: Conventions, Idioms, and Patterns for
Reusable .NET Libraries by Krzysztof Cwalina and Brad Abrams (Boston, MA: Addison-Wesley Professional, 2005)
or you use FxCop to regularly analyze your code, you should never encounter a name conflict between one of your
class members and a reserved member name.
Reserved Names for Properties
For a property named Prop of type T, the following signatures are reserved for the implementation
of the property:
T get_Prop();
void set_Prop( T value );
Reserved Names for Indexers
If the class contains an indexer that is of type T and takes a parameter list represented by Params, it
will contain the following reserved method names:
T get_Item( Params );
void set_Item( Params, T value );
Reserved Names for Destructors
If the class is defined with a finalizer (using the destructor syntax), it will contain a definition of the
following method:
void Finalize();
I have a lot more to say about destructors and the Finalize method later in this chapter and in
Chapter 13.
Reserved Names for Events
If the class contains an event definition of type T that is named Event, the following methods are
reserved on the class:
void add_Event( T callback );
void remove_Event( T callback );
I discuss events in Chapter 10, when I cover delegates and anonymous methods.
Value Type Definitions
A value type is a lightweight type that you typically don’t create on the heap. The only exception to
this rule is a value type that is a field in an object that lives on the heap. A value type is a type that
behaves with value semantics. That is, when you assign a value-type variable to another value-type
variable, the contents of the source are copied into the destination and a full copy of the instance is
made. This is in contrast to reference types, or object instances, where the result of copying one ref-
erence-type variable to another is that there is now a new reference to the same object. Also, when

95.
76 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
you pass a value type as a parameter to a method, the method body receives a local copy of the
value, unless the parameter was declared as a ref or an out parameter. All of the C# built-in types
except string, arrays, and delegates are value types. In C#, you declare a value type using the struct
keyword rather than the class keyword.
On the whole, the syntax of defining a struct is the same as for a class—with some notable
exceptions, as you’ll soon see. A struct cannot declare a base class. Also, a struct is implicitly sealed.
That means that nothing else can derive from a struct. Internally, a struct derives from System.
ValueType, which in turn extends System.Object. This is so that ValueType can provide implementa-
tions of Object.Equals and Object.GetHashCode, among others, which are meaningful for value
types. In the section titled “System.Object,” I cover the nuances involved with implementing the
methods inherited from System.Object for a value type. Like classes, structs can be declared in par-
tial pieces, and the same rules for partial pieces apply to structs as they do to classes.
Constructors
Types defined as structs can have static constructors just like classes. Structs can also have instance
constructors, with one notable exception. They cannot have a user-defined default, parameterless
constructor, nor can they have instance field initializers in the struct definition. Static field initializ-
ers are permitted, though. Parameterless constructors are not necessary for value types, since the
system provides one, which simply sets the fields of the value to their default values. In all cases,
that amounts to setting the bits of the field’s storage to 0. So, if a struct contains an int, the default
value will be 0. If a struct contains a reference type field, the default value will be null. Each struct
gets this implicit, parameterless constructor, which takes care of this initialization. It’s all part of the
language’s endeavor to create verifiably type-safe code. However, it’s completely possible for a user
to declare a struct without calling a constructor on it at all. If that happens, the coder is responsible
for setting up the struct appropriately before any methods on it can be called. Consider the follow-
ing code:
using System;
public struct Square
{
// Not a good idea to have public fields, but I use them
// here only for the sake of example. Prefer to expose
// these with properties instead.
public int width;
public int height;
}
public class EntryPoint
{
static void Main()
{
Square sq;
sq.width = 1;
// Can't do this yet.
// Console.WriteLine( "{0} x {1}", sq.width, sq.height );
sq.height = 2;
Console.WriteLine( "{0} x {1}", sq.width, sq.height );
}
}

96.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 77
In Main, I’ve allocated space on the stack for a Square object. However, immediately after, I only
assign to the width field. I’ve commented out a call to Console.WriteLine immediately after that
because it won’t compile. The reason is that you can’t call methods on a struct before it is fully ini-
tialized. Properties are really method calls under the covers. After I initialize the height field, I can
successfully use the Square instance to send the width and height to the console. Can you spot the
problem in the following code?
using System;
public struct Square
{
public int Width
{
get
{
return width;
}
set
{
width = value;
}
}
public int Height
{
get
{
return height;
}
set
{
height = value;
}
}
private int width;
private int height;
}
public class EntryPoint
{
static void Main()
{
Square sq;
sq.Width = 1;
sq.Height = 1;
}
}
The problem is in the Main method. If you try to compile this code, the compiler will fail with
an error. You cannot initialize the fields since they’re now private. Also, you cannot initialize them
with the properties, because properties are really methods, and it’s illegal to call methods on a value
that is not fully initialized. The only way to get out of this pickle is to use the new keyword when you
declare the new Square instance. You can either call one of the constructors on the struct or the

97.
78 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
default constructor. In this case, I’ll call the default constructor so the Main method will change to
the following:
public class EntryPoint
{
static void Main()
{
Square sq = new Square();
sq.Width = 1;
sq.Height = 1;
}
}
Since a struct cannot derive from another struct or class, it is not permitted to call any base
constructor through the base keyword while inside the constructor block. Even though you know
that a struct derives from System.ValueType internally, you may not invoke the constructor of the
base type explicitly.
The Meaning of this
Previously, I said that the this keyword within class methods behaves as a constant, read-only value
that contains a reference to the current object instance. In other words, it’s a read-only object refer-
ence in class methods. However, with value types, this behaves like a regular ref parameter. In
instance constructors that don’t have an initialization list, the this value behaves as an out parame-
ter. That means that you can actually assign a value to this, as in the following example:
public struct ComplexNumber
{
public ComplexNumber( double real, double imaginary )
{
this.real = real;
this.imaginary = imaginary;
}
public ComplexNumber( ComplexNumber other )
{
this = other;
}
private double real;
private double imaginary;
}
public class EntryPoint
{
static void Main()
{
ComplexNumber valA = new ComplexNumber( 1, 2 );
ComplexNumber copyA = new ComplexNumber( valA );
}
}
Notice that the second constructor takes, as a parameter, another ComplexNumber value. This
constructor behaves similarly to a copy constructor in C++. But instead of having to assign each
field individually, you can simply assign to this, thus making a copy of the parameter’s state in one
line of code. Again, the this keyword acts like an out parameter in this case.

98.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 79
Remember that out parameters behave similarly to ref parameters, with one special difference.
When a parameter is marked as an out parameter, the compiler knows that the value is uninitialized
at the point the method body starts executing. Therefore, the compiler must make sure that every
field of the value is initialized before the constructor exits. For example, consider the following
code, which doesn’t compile:
public struct ComplexNumber
{
public ComplexNumber( double real, double imaginary )
{
this.real = real;
this.imaginary = imaginary;
}
public ComplexNumber( double real )
{
this.real = real;
}
private double real;
private double imaginary;
}
The problem with this code lies in the second constructor. Since value types typically are cre-
ated on the stack, the allocation of such values merely requires adjustment of the stack pointer. Of
course, an allocation of this sort says nothing about the state of the memory. The odds are that the
memory reserved on the stack for the value contains random garbage. The CLR could elect to zero-
initialize these blocks of memory, but that would defeat half the purpose of value types. Value types
are meant to be lightweight and fast. If the CLR has to zero-initialize the stack memory for a value
type each time the memory is reserved, that’s hardly a fast operation. Of course, the default parame-
terless constructor generated by the system does exactly this. But you must call it explicitly by
creating the instance with the new keyword. Since the this keyword is treated as an out parameter in
the instance constructors, the instance constructor must initialize each field of the value before it
exits. And it is the duty of the C# compiler, which is supposed to generate verifiably type-safe code,
to make sure you do so. That’s why the previous code example produces a compiler error.
Even though instance constructors in value types cannot use the base keyword to call base
class constructors, they can have an initializer. It is valid for the initializer to use the this keyword
to call other constructors on the same struct during initialization. So you can make one minor mod-
ification to the preceding code example to make it compile:
public struct ComplexNumber
{
public ComplexNumber( double real, double imaginary )
{
this.real = real;
this.imaginary = imaginary;
}
public ComplexNumber( double real )
:this( real, 0 )
{
this.real = real;
}
private double real;
private double imaginary;
}

99.
80 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
public class EntryPoint
{
static void Main()
{
ComplexNumber valA = new ComplexNumber( 1, 2 );
}
}
Notice the difference in the second constructor. I’ve now introduced an initializer that calls the
first constructor from the second one. Even though the single line of code in the second construc-
tor’s body is redundant, I left it there to prove a point. Notice that it only assigns the real value as in
the previous example, but the compiler doesn’t complain. That’s because, when an instance con-
structor contains an initializer, the this keyword behaves as a ref parameter in that constructor’s
body rather than an out parameter. And, since it is a ref parameter, the compiler can assume that
the value has been initialized properly before entry into the method’s code block. In essence, the
initialization burden is deferred to the first constructor, whose duty it is to make sure it initializes all
fields of the value.
One last note to consider is that even though the system generates a default, parameterless ini-
tializer under the covers, you can’t call it using the this keyword. For example, the following code
doesn’t compile:
public struct ComplexNumber
{
public ComplexNumber( double real, double imaginary )
{
this.real = real;
this.imaginary = imaginary;
}
public ComplexNumber( double real )
:this()
{
this.real = real;
}
private double real;
private double imaginary;
}
If you had a struct that had quite a few fields in it and you wanted to initialize all but one of
them to 0 or null, it would save you a little bit of typing to be able to do this. But, alas, the compiler
doesn’t allow it.
Finalizers
Value types are not allowed to have a finalizer. The concept of finalization, or nondeterministic
destruction, is reserved for instances of classes, or objects. If structs had finalizers, the runtime
would have to manage the calling of the finalizer each time the value goes out of scope.
Keep in mind that you want to be careful about initializing resources within constructors of
value types. Just don’t do it. Consider a value type that has a field, which is a handle to some sort of
low-level system resource. Suppose this low-level resource is allocated, or acquired, in a special
constructor that accepts parameters. You now have a couple of problems to deal with. Since you
cannot create a default, parameterless constructor, how can you possibly acquire the resource when
the user creates an instance of the value without using one of the custom constructors? The answer

100.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 81
is, you cannot. The second problem is that you have no automatic trigger to clean up and release
the resource, since you have no destructor. You would have to force the user of the value to call
some special method to clean up before the value goes out of scope. Requiring the user to remem-
ber to do something like that is poor design.
Interfaces
Although it’s illegal for a struct to derive from another class, it can still implement interfaces. Sup-
ported interfaces are listed in the same way as they are for classes, in a base interface list after the
struct identifier. Generally, supporting interfaces for structs is the same as supporting interfaces for
classes. I cover interfaces in much more detail in Chapter 5. There are performance implications of
implementing interfaces on structs, in that doing so incurs a boxing operation to call methods
through an interface reference on the struct value instances.
Anonymous Types
How many times have you needed a lightweight class to hold a handful of related values for use
within a particular method and you lamented having to type a whole type definition complete with
private fields and public property accessors? Enter anonymous types! C# 3.0 allows you to introduce
these types using an extended syntax of the new operator. Let’s see what this looks like:
using System;
public class EntryPoint
{
static void Main() {
var employeeInfo = new { Name = "Joe", Id = 42 };
var customerInfo = new { Name = "Jane", Id = "AB123" };
Console.WriteLine( "Name: {0}, Id: {1}",
employeeInfo.Name,
employeeInfo.Id );
Console.WriteLine( "employeeInfo Type is actually: {0}",
employeeInfo.GetType() );
Console.WriteLine( "customerInfo Type is actually: {0}",
customerInfo.GetType() );
}
}
using System;
public class EntryPoint
{
static void Main() {
var employeeInfo = new { Name = "Joe", Id = 42 };
var customerInfo = new { Name = "Jane", Id = "AB123" };
Console.WriteLine( "Name: {0}, Id: {1}",
employeeInfo.Name,
employeeInfo.Id );

101.
82 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
Console.WriteLine( "employeeInfo Type is actually: {0}",
employeeInfo.GetType() );
Console.WriteLine( "customerInfo Type is actually: {0}",
customerInfo.GetType() );
}
}
Notice the interesting and new syntax within the braces after the new keyword while declaring
employeeInfo. The name/value pairs declare a property name within the anonymous type and ini-
tialize it to the given value. In this case, two anonymous types are created with two properties. In
the first anonymous type, the first property is a System.String called Name, and the second is a
System.Int32 called Id. It’s important to note that the underlying type of the instance created is a
strong type, it’s just compiler generated and you don’t know the name of it. But as you can see from
the following output from the code above, you can figure out the name of the type:
Name: Joe, Id: 42
employeeInfo Type is actually: <>f__AnonymousType0`2[System.String,System.Int32]
customerInfo Type is actually: <>f__AnonymousType0`2[System.String,System.String]
■Note The compiler-generated type names are implementation specific, so you should never rely on them. Addi-
tionally, you’ll notice that they are “unspeakable” to the compiler; if you were to attempt to declare an instance
using that type name, the compiler would complain with a syntax error.
Since you do not know the compiler-generated name of the type, you are forced to declare the
variable instance as an implicitly typed local variable using the var keyword, as I did in the code.
Also, notice that the compiler-generated type is a generic type that takes two type parameters.
It would be inefficient for the compiler to generate a new type for every anonymous type that con-
tains two types with the same field names. The output above indicates that the actual type of
employeeInfo looks similar to the type name below:
<>f__AnonymousType0<System.String, System.Int32>
And since the anonymous type for customerInfo contains the same number of fields with the
same names, the generated generic type is reused and the type of customerInfo looks similar to the
type below:
<>f__AnonymousType0<System.String, System.String>
Had the anonymous type for customerInfo contained different field names than those for
employeeInfo, then another generic anonymous type would have been declared.
Now that you know the basics about anonymous types, I want to show you an abbreviated syn-
tax for declaring them. Pay attention to the bold statements in the following example:
using System;
public class ConventionalEmployeeInfo
{
public ConventionalEmployeeInfo( string Name, int Id ) {
this.name = Name;
this.id = Id;
}

103.
84 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
For illustration purposes, I have declared a type named ConventionalEmployeeInfo that is not an
anonymous type. Notice that at the point where I instantiate the anonymous type for employeeInfo,
I do not provide the names of the fields as before. In this case, the compiler uses the names of the
properties of the ConventionalEmployeeInfo type, which is the source of the data. This same
technique works using local variables, as you can see when I declare the customerInfo instance. In
this case, customerInfo is an anonymous type that implements two read/write properties named
Name and Id. Member declarators for anonymous types that use this abbreviated style are called
projection initializers.1
If you inspect the compiled assembly in ILDASM, you’ll notice that the generated types for
anonymous types are of class type. The class is also marked private and sealed. However, the class
is extremely basic and does not implement anything like a finalizer or IDisposable.
■Note Anonymous types, even though they are classes, do not implement the IDisposable interface. As I men-
tion in Chapter 13, the general guideline for types that contain disposable types is that they, too, should be
disposable. But since anonymous types are not disposable, you should avoid placing instances of disposable types
within them.
Be careful not to strip the type off of anonymous types. For example, if you put instances of
anonymous types in a System.List, how are you supposed to cast those instances back into the
anonymous type when you reference them later? Remember, System.List stores references to
System.Object. And even though the anonymous types derive from System.Object, how are you
going to cast them back into their concrete types to access their properties? You could attempt to
use reflection to overcome this. But then you introduce so much work that you lose any benefit
from using anonymous types in the first place. Similarly, if you want to pass instances of anony-
mous types out of functions via out parameters or via a return statement, you must pass them out
as references to System.Object, thus stripping the variables of their useful type information. If you
need to pass instances out of a method, then you really should be using an explicitly defined type
such as ConventionalEmployeeInfo instead of anonymous types.
After all of these restrictions placed on anonymous types, you may be wondering how they are
useful except in rare circumstances within the local scope. It turns out that they are extremely use-
ful when used with projection operators in LINQ (Language Integrated Query), which I will show
you in Chapter 16.
Object Initializers
C# 3.0 introduces a shorthand you can use while instantiating new instances of objects. How many
times have you written code similar to this?
Employee developer = new Employee();
developer.Name = "Fred Blaze";
developer.OfficeLocation = "B1";
Right after creating an instance of Employee, you immediately start initializing the accessible
properties of the instance. Wouldn’t it be nice if you could do this all in one statement? Of course,
you could always create a specialized overload of the constructor that accepts the parameters to use
while initializing the new instance. However, there may be times where it is more convenient not to
do so.
1. Projection initializers are very handy when used together with LINQ, which I cover in Chapter 16.

104.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 85
■Note If your type contains one or more read-only auto-implemented properties, you must use an object initial-
izer to initialize the properties at instantiation.
The new object initializer syntax is shown below:
using System;
public class Employee
{
public string Name {
get; set;
}
public string OfficeLocation {
get; set;
}
}
public class InitExample
{
static void Main() {
Employee developer = new Employee {
Name = "Fred Blaze",
OfficeLocation = "B1"
};
}
}
Notice how the developer instance is initialized in the Main method. Under the hood, the com-
piler generates the same code it would have if you had initialized the properties manually after
creating the Employee instance. Therefore, this technique only works if the properties, in this case
Name and OfficeLocation, are accessible at the point of initialization.
You can even nest object initializers as shown in the example below:
using System;
public class Employee
{
public string Name { get; set; }
public string OfficeLocation { get; set; }
}
public class FeatureDevPair
{
public Employee Developer { get; set; }
public Employee QaEngineer { get; set; }
}

106.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 87
QaEngineer = {
Name = "Marisa Bozza",
OfficeLocation = "L42"
}
};
}
}
Notice that I was able to leave out the new expressions when initializing the Developer and
QaEngineer properties of spellCheckerTeam. However, this abbreviated syntax requires that the fields
of spellCheckerTeam exist before the properties are set, that is, the fields cannot be null. Therefore,
you see that I had to change the definition of FeatureDevPair to create the contained instances of
the Employee type at the point of initialization.
■Note If you do not initialize fields exposed by properties during object initialization, and then later write code
that initializes instances of those objects using the abbreviated syntax shown above, you will get a nasty surprise
at run time. You might have guessed that your code will generate a NullReferenceException in those cases.
Unfortunately, the compiler cannot detect this potential disaster at compile time. So be very careful when using the
abbreviated syntax shown above. For example, if you are using this syntax to intialize instances of objects that you
did not write, then you should be even more careful because unless you look at the implementation of that third-
party class using ILDASM, you have no way of knowing if the fields are initialized at object initialization time or not.
Boxing and Unboxing
Allow me to introduce boxing and unboxing. All types within the CLR fall into one of two categories:
reference types (objects) or value types (values). You define objects using classes, and you define
values using structs. A clear divide exists between these two. Objects live on the memory heap and
are managed by the garbage collector. Values normally live in temporary storage spaces, such as on
the stack. The one notable exception already mentioned is that a value type can live on the heap as
long as it is contained as a field within an object. However, it is not autonomous, and the GC doesn’t
control its lifetime directly. Consider the following code:
public class EntryPoint
{
static void Print( object obj )
{
System.Console.WriteLine( "{0}", obj.ToString() );
}
static void Main()
{
int x = 42;
Print( x );
}
}
It looks simple enough. In Main, there is an int, which is a C# alias for System.Int32, and it is a
value type. You could have just as well declared x as type System.Int32. The space allocated for x is
on the local stack. You then pass it as a parameter to the Print method. The Print method takes an

107.
88 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
object reference and simply sends the results of calling ToString on that object to the console. Let’s
analyze this. Print accepts an object reference, which is a reference to a heap-based object. Yet,
you’re passing a value type to the method. What’s going on here? How is this possible?
The key is a concept called boxing. At the point where a value type is defined, the CLR creates a
runtime-created wrapper class to contain the value type. Instances of the wrapper live on the heap
and are commonly called boxing objects. This is the CLR’s way of bridging the gap between value
types and reference types. In fact, if you use ILDASM to look at the IL code generated for the Main
method, you’ll see the following:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 15 (0xf)
.maxstack 1
.locals init (int32 V_0)
IL_0000: ldc.i4.s 42
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box [mscorlib]System.Int32
IL_0009: call void EntryPoint::Print(object)
IL_000e: ret
} // end of method EntryPoint::Main
Notice the IL instruction, box, which takes care of the boxing operation before the Print
method is called. This creates an object, which Figure 4-2 depicts.
Figure 4-2 depicts the action of copying the value type into the boxing object that lives on the
heap. The boxing object behaves just like any other reference type in the CLR. Also, note that the
boxing type implements the interfaces of the contained value type. The boxing type is a class type
that is generated internally by the virtual execution system of the CLR at the point where the con-
tained value type is defined. The CLR then uses this internal class type when it performs boxing
operations as needed.
Figure 4-2. Result of boxing operation
The most important thing to keep in mind with boxing is that the boxed value is a copy of the
original. Therefore, any changes made to the value inside the box are not propagated back to the
original value. For example, consider this slight modification to the previous code:
public class EntryPoint
{
static void PrintAndModify( object obj )

108.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 89
{
System.Console.WriteLine( "{0}", obj.ToString() );
int x = (int) obj;
x = 21;
}
static void Main()
{
int x = 42;
PrintAndModify( x );
PrintAndModify( x );
}
}
The output from this code might surprise you:
42
42
The fact is, the original value, x, declared and initialized in Main, is never changed. As you pass
it to the PrintAndModify method, it is boxed, since the PrintAndModify method takes an object as its
parameter. Even though PrintAndModify takes a reference to an object that you can modify, the
object it receives is a boxing object that contains a copy of the original value. The code also intro-
duces another operation called unboxing in the PrintAndModify method. Since the value is boxed
inside an instance of an object on the heap, you can’t change the value because the only methods
supported by that object are methods that System.Object implements. Technically, it also supports
the same interfaces that System.Int32 supports. Therefore, you need a way to get the value out of
the box. In C#, you can accomplish this syntactically with casting. Notice that you cast the object
instance back into an int, and the compiler is smart enough to know that what you’re really doing
is unboxing the value type and using the unbox IL instruction, as the following IL for the
PrintAndModify method shows:
.method private hidebysig static void PrintAndModify(object obj) cil managed
{
// Code size 28 (0x1c)
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldstr "{0}"
IL_0005: ldarg.0
IL_0006: callvirt instance string [mscorlib]System.Object::ToString()
IL_000b: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0010: ldarg.0
IL_0011: unbox [mscorlib]System.Int32
IL_0016: ldind.i4
IL_0017: stloc.0
IL_0018: ldc.i4.s 21
IL_001a: stloc.0
IL_001b: ret
} // end of method EntryPoint::PrintAndModify
Let me be very clear about what happens during unboxing in C#. The operation of unboxing a
value is the exact opposite of boxing. The value in the box is copied into an instance of the value on
the local stack. Again, any changes made to this unboxed copy are not propagated back to the value
contained in the box. Now, you can see how boxing and unboxing can really become confusing. As
shown, the code’s behavior is not obvious to the casual observer who is not familiar with the fact

109.
90 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
that boxing and unboxing are going on internally. What’s worse is that two copies of the int are
created between the time the call to PrintAndModify is initiated and the time that the int is manipu-
lated in the method. The first copy is the one put into the box. The second copy is the one created
when the boxed value is copied out of the box.
Technically, it’s possible to modify the value that is contained within the box. However, you
must do this through an interface. The runtime-generated box that contains the value also imple-
ments the interfaces that the value type implements and forwards the calls to the contained value.
So, you could do the following:
public interface IModifyMyValue
{
int X
{
get;
set;
}
}
public struct MyValue : IModifyMyValue
{
public int x;
public int X
{
get
{
return x;
}
set
{
x = value;
}
}
public override string ToString()
{
System.Text.StringBuilder output =
new System.Text.StringBuilder();
output.AppendFormat( "{0}", x );
return output.ToString();
}
}
public class EntryPoint
{
static void Main()
{
// Create value
MyValue myval = new MyValue();
myval.x = 123;

110.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 91
// box it
object obj = myval;
System.Console.WriteLine( "{0}", obj.ToString() );
// modify the contents in the box.
IModifyMyValue iface = (IModifyMyValue) obj;
iface.X = 456;
System.Console.WriteLine( "{0}", obj.ToString() );
// unbox it and see what it is.
MyValue newval = (MyValue) obj;
System.Console.WriteLine( "{0}", newval.ToString() );
}
}
You can see that the output from the code is as follows:
123
456
456
As expected, you’re able to modify the value inside the box using the interface named
IModifyMyValue. However, it’s not the most straightforward process. And keep in mind that before
you can obtain an interface reference to a value type, it must be boxed. This makes sense if you
think about the fact that references to interfaces are object reference types.
When Boxing Occurs
Since C# handles boxing implicitly for you, it’s important to know the instances when C# boxes a
value. Basically, a value gets boxed when one of the following conversions occurs:
• Conversion from a value type to an object reference
• Conversion from a value type to a System.ValueType reference
• Conversion from a value type to a reference to an interface implemented by the value type
• Conversion from an enum type to a System.Enum reference
In each case, the conversion normally takes the form of an assignment expression. The first
two cases are fairly obvious, since the CLR is bridging the gap by turning a value type instance into a
reference type. The third one can be a little surprising. Any time you implicitly cast your value into
an interface that it supports, you incur the penalty of boxing. Consider the following code:
public interface IPrint
{
void Print();
}
public struct MyValue : IPrint
{
public int x;

111.
92 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
public void Print()
{
System.Console.WriteLine( "{0}", x );
}
}
public class EntryPoint
{
static void Main()
{
MyValue myval = new MyValue();
myval.x = 123;
// no boxing
myval.Print();
// must box the value
IPrint printer = myval;
printer.Print();
}
}
The first call to Print is done through the value reference, which doesn’t incur boxing. How-
ever, the second call to Print is done through an interface. The boxing takes place at the point
where you obtain the interface. At first, it looks like you can easily sidestep the boxing operation by
not acquiring an explicit reference typed on the interface type. This is true in this case, since Print
is also part of the public contract of MyValue. However, had you implemented the Print method as
an explicit interface, which I cover in Chapter 5, then the only way to call the method would be
through the interface reference type. So, it’s important to note that any time you implement an
interface on a value type explicitly, you force the clients of your value type to box it before calling
through that interface. The following example demonstrates this:
public interface IPrint
{
void Print();
}
public struct MyValue : IPrint
{
public int x;
void IPrint.Print()
{
System.Console.WriteLine( "{0}", x );
}
}
public class EntryPoint
{
static void Main()
{
MyValue myval = new MyValue();
myval.x = 123;

112.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 93
// must box the value
IPrint printer = myval;
printer.Print();
}
}
As another example, consider that the System.Int32 type supports the IConvertible interface.
However, most of the IConvertible interface methods are implemented explicitly. Therefore, even if
you want to call an IConvertible method, such as IConvertible.ToBoolean on a simple int, you
must box it first.
■Note Typically, you want to rely upon the external class System.Convert to do a conversion like the one men-
tioned previously. I only mention calling directly through IConvertible as an example.
Efficiency and Confusion
As you might expect, boxing and unboxing are not the most efficient operations in the world. What’s
worse is that the C# compiler silently does the boxing for you. You really must take care to know
when boxing is occurring. Unboxing is usually more explicit, since you typically must do a cast
operation to extract the value from the box, but there is an implicit case I’ll cover soon. Either way,
you must pay attention to the efficiency aspect of things. For example, consider a container type,
such as a System.Collections.ArrayList. It contains all of its values as references to type object. If
you were to insert a bunch of value types into it, they would all be boxed! Thankfully, generics,
which were introduced in C# 2.0 and .NET 2.0 and are covered in Chapter 10, can solve this ineffi-
ciency for you. However, note that boxing is inefficient and should be avoided as much as possible.
Unfortunately, since boxing is an implicit operation in C#, it takes a keen eye to find all of the cases
of boxing. The best tool to use if you’re in doubt whether boxing is occurring or not is ILDASM.
Using ILDASM, you can examine the IL code generated for your methods, and the box operations
are clearly identifiable. You can find ILDASM.exe in the .NET SDK bin folder.
As mentioned previously, unboxing is normally an explicit operation introduced by a cast from
the boxing object reference to a value of the boxed type. However, unboxing is implicit in one
notable case. Remember how I talked about the differences in how the this reference behaves
within methods of classes vs. methods of structs? The main difference is that, for value types, the
this reference acts as either a ref or an out parameter, depending on the situation. So when you call
a method on a value type, the hidden this parameter within the method must be a managed pointer
rather than a reference. The compiler handles this easily when you call directly through a value-type
instance. However, when calling a virtual method or an interface method through a boxed
instance—thus, through an object—the CLR must unbox the value instance so that it can obtain the
managed pointer to the value type contained within the box. After passing the managed pointer to
the contained value type’s method as the this pointer, the method can modify the fields through
the this pointer, and it will apply the changes to the value contained within the box. Be aware of
hidden unboxing operations if you’re calling methods on a value through a box object.
■Note Unboxing operations in the CLR are not inefficient in and of themselves. The inefficiency stems from the
fact that C# typically combines that unboxing operation with a copy of the value.

113.
94 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
System.Object
Every object in the CLR derives from System.Object. Object is the base type of every type. In C#, the
object keyword is an alias for System.Object. It can be convenient that every type in the CLR and in
C# derives from Object. For example, you can treat a collection of instances of multiple types
homogenously simply by casting them to Object references.
Even System.ValueType derives from Object. However, some special rules govern obtaining an
Object reference. On reference types, you can turn a reference of class A into a reference of class
Object with a simple implicit conversion. Going the other direction requires a runtime type check
and an explicit cast using the familiar cast syntax of preceding the instance to convert with the new
type in parentheses. Obtaining an Object reference directly on a value type is, technically, impossi-
ble. Semantically, this makes sense, because value types can live on the stack. It can be dangerous
for you to obtain a reference to a transient value instance and store it away for later use if, poten-
tially, the value instance is gone by the time you finally use the stored reference. For this reason,
obtaining an Object reference on a value type instance involves a boxing operation, as described in
the previous section.
The definition of the System.Object class is as follows:
public class Object
{
public Object();
public virtual void Finalize();
public virtual bool Equals( object obj );
public static bool Equals( object obj1,
object obj2 );
public virtual int GetHashCode();
public Type GetType();
protected object MemberwiseClone();
public static bool ReferenceEquals( object obj1,
object obj2 );
public virtual string ToString();
}
Object provides several methods, which the designers of the CLI/CLR deemed to be important
and germane for each object. The methods dealing with equality deserve an entire discussion
devoted to them; I cover them in detail in the next section. Object provides a GetType method to
obtain the runtime type of any object running in the CLR. Such a capability is extremely handy
when coupled with reflection—the capability to examine types in the system at run time. GetType
returns an object of type Type, which represents the real, or concrete, type of the object. Using this
object, you can determine everything about the type of the object on which GetType is called. Also,
given two references of type Object, you can compare the result of calling GetType on both of them
to find out if they’re actually instances of the same concrete type.
System.Object contains a method named MemberwiseClone, which returns a shallow copy of the
object. I have more to say about this method in Chapter 13. When MemberwiseClone creates the copy,
all value type fields are copied on a bit-by-bit basis, whereas all fields that are references are simply
copied such that the new copy and the original both contain references to the same object. When
you want to make a copy of an object, you may or may not desire this behavior. Therefore, if objects
support copying, you should consider supporting ICloneable and do the correct thing in the imple-
mentation of that interface. Also, note that this method is declared as protected. The main reason
for this is so that only the class for the object being copied can call it, since MemberwiseClone can
create an object without calling its instance constructor. Such behavior could potentially be desta-
bilizing if it were made public.

114.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 95
■Note Be sure to read more about ICloneable in Chapter 13 before deciding whether to implement this
interface.
Four of the methods on Object are virtual, and if the default implementations of the methods
inside Object are not appropriate, you should override them. ToString is useful when generating
textual, or human-readable, output and a string representing the object is required. For example,
during development, you may need the ability to trace an object out to a debug output at run time.
In such cases, it makes sense to override ToString so that it provides detailed information about the
object and its internal state. The default version of ToString simply calls the ToString implementa-
tion on the Type object returned from a call to GetType, thus providing the name of the object’s type.
It’s more useful than nothing, but it’s probably not useful enough for you if you need to call
ToString on an object in the first place.2 Try to avoid adding side effects to the ToString implemen-
tation, since the Visual Studio debugger can call it to display information at debug time. In fact,
ToString is most useful for debugging purposes and rarely useful otherwise.
The Finalize method deserves special mention. C# doesn’t allow you to explicitly override this
method. Also, it doesn’t allow you to call this method on an object. If you need to override this
method for a class, you can use the destructor syntax in C#. I have much more to say about destruc-
tors and finalizers in Chapter 13.
Equality and What It Means
Equality between reference types that derive from System.Object is a tricky issue. By default, the
equality semantics provided by Object.Equals represent identity equivalence. What that means is
that the test returns true if two references point to the same instance of an object. However, you can
change the semantic meaning of Object.Equals to value equivalence. That means that two refer-
ences to two entirely different instances of an object may equate to true as long as the internal
states of the two instances match. Overriding Object.Equals is such a sticky issue that I’ve devoted
several sections within Chapter 13 to the subject.
The IComparable Interface
The System.IComparable interface is a system-defined interface that objects can choose to imple-
ment if they support ordering. If it makes sense for your object to support ordering in collection
classes that provide sorting capabilities, then you should implement this interface. For example, it
may seem obvious, but System.Int32, aliased by int in C#, implements IComparable. In Chapter 13,
I show how you can effectively implement this interface and its generic cousin, IComparable<T>.
Creating Objects
Object creation is a topic that looks simple on the surface, but in reality is relatively complex under
the hood. You need to be intimately familiar with what operations take place during creation of a
new object instance or value instance in order to write constructor code effectively and use field ini-
tializers effectively. Also, in the CLR, not only do object instances have constructors, but so do the
types they’re based on. By that, I mean that even the struct and the class types have a constructor,
2. Be sure to read Chapter 8, where I give reasons why Object.ToString is not what you want when creating
software for localization to various locales and cultures.

115.
96 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
which is represented by a static constructor definition. Constructors allow you to get work done at
the point the type is loaded and initialized into the application domain.
The new Keyword
The new keyword lets you create new instances of objects or values. However, it behaves slightly dif-
ferently when used with value types than with object types. For example, new doesn’t always allocate
space on the heap in C#. Let’s discuss what it does with value types first.
Using new with Value Types
The new keyword is only required for value types when you need to invoke one of the constructors
for the type. Otherwise, value types simply have space reserved on the stack for them, and the client
code must initialize them fully before you can use them. I covered this in the “Value Type Defini-
tions” section on constructors in value types.
Using new with Class Types
You need the new operator to create objects of class type. In this case, the new operator allocates
space on the heap for the object being created. If it fails to find space, it will throw an exception of
type System.OutOfMemoryException, thus aborting the rest of the object-creation process.
After it allocates the space, all of the fields of the object are initialized to their default values.
This is similar to what the compiler-generated default constructor does for value types. For refer-
ence-type fields, they are set to null. For value-type fields, their underlying memory slots are filled
with all zeros. Thus, the net effect is that all fields in the new object are initialized to either null or 0.
Once this is done, the CLR calls the appropriate constructor for the object instance. The constructor
selected is based upon the parameters given and is matched using the overloaded method parame-
ter matching algorithm in C#. The new operator also sets up the hidden this parameter for the
constructor, which is a read-only reference that references the new object created on the heap, and
that reference’s type is the same as the class type. Consider the following example:
public class MyClass
{
public MyClass( int x, int y )
{
this.x = x;
this.y = y;
}
public int x;
public int y;
}
public class EntryPoint
{
static void Main()
{
// We can't do this!
// MyClass objA = new MyClass();
MyClass objA = new MyClass( 1, 2 );
System.Console.WriteLine( "objA.x = {0}, objA.y = {1}",
objA.x, objA.y );
}
}

116.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 97
In the Main method, notice that you cannot create a new instance of MyClass by calling the
default constructor. The C# compiler doesn’t create a default constructor for a class unless no other
constructors are defined. The rest of the code is fairly straightforward. I create a new instance of
MyClass and then output its values to the console. Shortly, in the section titled “Instance Construc-
tor and Creation Ordering,” I cover the minute details of object instance creation and constructors.
Field Initialization
When defining a class, it is sometimes convenient to assign the fields a value at the point where the
field is declared. The fact is, you can assign a field from any immediate value or any callable method
as long as the method is not called on the instance of the object being created. For example, you can
initialize fields based upon the return value from a static method on the same class. Let’s look at an
example:
using System;
public class A
{
private static int InitX()
{
Console.WriteLine( "A.InitX()" );
return 1;
}
private static int InitY()
{
Console.WriteLine( "A.InitY()" );
return 2;
}
private static int InitA()
{
Console.WriteLine( "A.InitA()" );
return 3;
}
private static int InitB()
{
Console.WriteLine( "A.InitB()" );
return 4;
}
private int y = InitY();
private int x = InitX();
private static int a = InitA();
private static int b = InitB();
}
public class EntryPoint
{
static void Main()
{
A a = new A();
}
}
Notice that you’re assigning all of the fields using field initializers and setting the fields to the
return value from the methods called. All of those methods called during field initialization are

117.
98 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
static, which helps reinforce a couple of important points regarding field initialization. The output
from the preceding code is as follows:
A.InitA()
A.InitB()
A.InitY()
A.InitX()
Notice that two of the fields, a and b, are static fields, whereas the fields x and y are instance
fields. The runtime initializes the static fields before the class type is used for the first time in this
application domain. In the next section, “Static (Class) Constructors,” I show how you can relax the
CLR’s timing of initializing the static fields.
During construction of the instance, the instance field initializers are invoked. As expected,
proof of that appears in the console output after the static field initializers have run. Note one
important point: Notice the ordering of the output regarding the instance initializers and compare
that with the ordering of the fields declared in the class itself. You’ll see that field initialization,
whether it’s static or instance initialization, occurs in the order in which the fields are listed in the
class definition. Sometimes this ordering can be important if your static fields are based on expres-
sions or methods that expect other fields in the same class to be initialized first. You should avoid
writing such code at all costs. In fact, any code that requires you to think about the ordering of the
declaration of your fields in your class is bad code. If initialization ordering matters, you should
consider initializing all of your fields in the body of the static constructor. That way, people main-
taining your code at a later date won’t be unpleasantly surprised when they reorder the fields in
your class for some reason.
Static (Class) Constructors
I already touched upon static constructors in the “Fields” section, but let’s look at them in a little
more detail. A class can have at most one static constructor, and that static constructor cannot
accept any parameters. Static constructors can never be invoked directly. Instead, the CLR invokes
them when it needs to initialize the type for a given application domain. The static constructor is
called before an instance of the given class is first created or before some other static fields on the
class are referenced. Let’s modify the previous field initialization example to include a static con-
structor and examine the output:
using System;
public class A
{
static A()
{
Console.WriteLine( "static A::A()" );
}
private static int InitX()
{
Console.WriteLine( "A.InitX()" );
return 1;
}
private static int InitY()
{
Console.WriteLine( "A.InitY()" );
return 2;
}

118.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 99
private static int InitA()
{
Console.WriteLine( "A.InitA()" );
return 3;
}
private static int InitB()
{
Console.WriteLine( "A.InitB()" );
return 4;
}
private int y = InitY();
private int x = InitX();
private static int a = InitA();
private static int b = InitB();
}
public class EntryPoint
{
static void Main()
{
A a = new A();
}
}
I’ve added the static constructor and want to see that it has been called in the output. The out-
put from the previous code is as follows:
A.InitA()
A.InitB()
static A::A()
A.InitY()
A.InitX()
Of course, the static constructor was called before an instance of the class was created. How-
ever, notice the important ordering that occurs. The static field initializers are executed before the
body of the static constructor executes. This ensures that the instance fields are initialized properly
before possibly being referenced within the static constructor body.
It is the default behavior of the CLR to call the type initializer before any member of the type is
accessed. By that, I mean that the type initializer will execute before any code accesses a field or a
method on the class or before an object is created from the class. However, you can apply a meta-
data attribute defined in the CLR, beforefieldinit, to the class to relax the rules a little bit. In the
absence of the beforefieldinit attribute, the CLR is required to call the type initializer before any
member on the class is touched. With the beforefieldinit attribute, the CLR is free to defer the
type initialization to the point right before the first static field access and not any time sooner. This
means that if beforefieldinit is set on the class, you can call instance constructors and methods all
day long without requiring the type initializer to execute first. But as soon as anything tries to access
a static field on the class, the CLR invokes the type initializer first. Keep in mind that the
beforefieldinit attribute gives the CLR this leeway to defer the type initialization to a later time,
but the CLR could still initialize the type long before the first static field is accessed.
The C# compiler sets the beforefieldinit attribute on all classes that don’t specifically define a
static constructor. To see this in action, you can use ILDASM to examine the IL generated for the

119.
100 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
previous two examples. For the example in the previous section, where I didn’t specifically define a
static constructor, the class A metadata looks like the following:
.class public auto ansi beforefieldinit A
extends [mscorlib]System.Object
{
} // end of class A
For the class A metadata in the example in this section, the metadata looks like the following:
.class public auto ansi A
extends [mscorlib]System.Object
{
} // end of class A
This behavior of the C# compiler makes good sense. When you explicitly define a type initial-
izer, you usually want to guarantee that it will execute before anything in the class is utilized or
before any instance of the class is created. However, if you don’t provide an explicit type initializer
and you do have static field initializers, the C# compiler will create a type initializer of sorts that
merely initializes all of the static fields. Since you didn’t provide user code for the type initializer, the
C# compiler can let the class defer the static field initializers until one of the static fields is accessed.
After all of this discussion regarding beforefieldinit, you should make note of one important
point. Suppose you have a class similar to the ones in the examples, where a static field is initialized
based upon the result of a method call. If your class doesn’t provide an explicit type initializer, it
would be erroneous to assume that the code called during the static field initialization will be called
prior to an object creation based on this class. For example, consider the following code:
using System;
public class A
{
public A()
{
Console.WriteLine( "A.A()" );
}
static int InitX()
{
Console.WriteLine( "A.InitX()" );
return 1;
}
public int x = InitX();
}
public class EntryPoint
{
static void Main()
{
// No guarantee A.InitX() is called before this!
A a = new A();
}
}
If your implementation of InitX contains some side effects that are required to run before an
object instance can be created from this class, then you would be better off putting that code in a
static constructor so that the compiler will not apply the beforefieldinit metadata attribute to the

120.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 101
class. Otherwise, there’s no guarantee that your code with the side effect in it will run prior to a class
instance being created.
Instance Constructor and Creation Ordering
Instance constructors follow a lot of the same rules as static constructors, except they’re more flexi-
ble and powerful, so they have some added rules of their own. Let’s examine those rules.
Instance constructors can have what’s called an initializer expression. An initializer expression
allows instance constructors to defer some of their work to other instance constructors within the
class, or more importantly, to base class constructors during object initialization. This is important
if you rely on the base class instance constructors to initialize the inherited members. Remember,
constructors are never inherited, so you must go through explicit means such as this in order to call
the base class constructors during initialization if you need to.
If your class doesn’t implement an instance constructor at all, the compiler will generate a
default parameterless instance constructor for you, which really only does one thing—it merely
calls the base class default constructor through the base keyword. If the base class doesn’t have an
accessible default constructor, a compiler error is generated. For example, the following code
doesn’t compile:
public class A
{
public A(int x) {
this.x = x;
}
private int x;
}
public class B : A
{
}
public class EntryPoint
{
static void Main()
{
B b = new B();
}
}
Can you see why it won’t compile? The problem is that a class with no explicit constructors is
given a default parameterless constructor by the compiler; this constructor merely calls the base
class parameterless constructor, which is exactly what the compiler tries to do for class B. However,
the problem is that, since class A does have an explicit instance constructor defined, the compiler
doesn’t produce a default constructor for class A. So, there is no accessible default constructor avail-
able on class A for class B’s compiler-provided default constructor to call. Therein lies another caveat
to inheritance. In order for the previous example to compile, either you must explicitly provide a
default constructor for class A, or class B needs an explicit constructor. Now, let’s look at an example
that demonstrates the ordering of events during instance initialization:
using System;
class Base
{
public Base( int x )
{

122.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 103
Before I start detailing the ordering of events here, look at the output from this code:
Derived.InitA()
Derived.InitB()
Base.InitX()
Base.Base(int)
Derived.Derived(int)
Derived.Derived(int, int)
Are you able to determine why the ordering is the way it is? It can be quite confusing upon first
glance, so let’s take a moment to examine what’s going on here. The first line of the Main method
creates a new instance of class Derived. As you see in the output, the constructor is called. But, it’s
called in the last line of the output! Clearly, a lot of things are happening before the constructor
body for class Derived executes.
At the bottom, you see the call to the Derived constructor that takes two int parameters. Notice
that this constructor has an initializer using the this keyword. This delegates construction work to
the Derived constructor that takes one int parameter.
The Derived constructor that takes one int parameter also has an initialization list, except it
uses the base keyword, thus calling the constructor for the class Base, which takes one int parame-
ter. However, if a constructor has an initializer that uses the base keyword, the constructor will
invoke the field initializers defined in the class before it passes control to the base class constructor.
And remember, the ordering of the initializers is the same as the ordering of the fields in the class
definition. This behavior explains the first two entries in the output. The output shows that the ini-
tializers for the fields in Derived are invoked first, before the initializers in Base.
After the initializers for Derived execute, control is then passed to the Base constructor that
takes one int parameter. Notice that class Base has an instance field with an initializer, too. The
same behavior happens in Base as it does in Derived, so before the constructor body for the Base
constructor is executed, the constructor implicitly calls the initializers for the class. I have more to
say about why this behavior is defined in this way later in this section, and it involves virtual meth-
ods. This is why the third entry in the output trace is that of Base.InitX.
After the Base initializers are done, you find yourself in the block of the Base constructor. Once
that constructor body runs to completion, control returns to the Derived constructor that takes one
int parameter, and execution finally ends up in that constructor’s code block. Once it’s done there, it
finally gets to execute the body of the constructor that was called when the code created the
instance of Derived in the Main method. Clearly, a lot of initialization work is going on under the
covers when an object instance is created.
As promised, I’ll explain why the field initializers of a derived class are invoked before the con-
structor for the base class is called through an initializer on the derived constructor, and the reason
is subtle. Virtual methods, which I cover in more detail in the section titled “Inheritance and Virtual
Methods,” work inside constructors in the CLR and in C#.
■Note If you’re coming from a C++ programming environment, you should recognize that this behavior of call-
ing virtual methods in constructors is completely different. In C++, you’re never supposed to rely on virtual method
calls in constructors, since the vtable is not set up while the constructor body is running.
Let’s look at an example:
using System;
public class A
{

123.
104 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
public virtual void DoSomething()
{
Console.WriteLine( "A.DoSomething()" );
}
public A()
{
DoSomething();
}
}
public class B : A
{
public override void DoSomething()
{
Console.WriteLine( "B.DoSomething()" );
Console.WriteLine( "x = {0}", x );
}
public B()
:base()
{
}
private int x = 123;
}
public class EntryPoint
{
static void Main()
{
B b = new B();
}
}
The output from this code is as follows:
B.DoSomething()
x = 123
As you can see, the virtual invocation works just fine from the constructor of A. Notice that
B.DoSomething uses the x field. Now, if the field initializers were not run before the base invocation,
imagine the calamity that would ensue when the virtual method is invoked from the class A con-
structor. That, in a nutshell, is why the field initializers are run before the base constructor is called
if the constructor has an initializer. The field initializers are also run before the constructor’s body is
entered, if there is no initializer defined for the constructor.
Destroying Objects
If you thought object creation was complicated, hold onto your hats. As you know, the CLR environ-
ment contains a garbage collector, which manages memory on your behalf. You can create new
objects as much as you want, but you never have to worry about freeing their memory explicitly. A
huge majority of bugs in native applications come from memory allocation/deallocation mis-

124.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 105
matches, otherwise known as memory leaks. Garbage collection is a technique meant to avoid that
type of bug, since the execution environment now handles the tracking of object references and
destroys the object instances when they’re no longer in use.
The CLR tracks every single managed object reference in the system that is just a plain-old
object reference that you’re already used to. Once the CLR realizes that an object is no longer reach-
able via a reference, it flags the object for deletion. The next time the garbage collector compacts the
heap, these flagged objects either have their memory reclaimed or are moved over into a queue for
deletion if they have a finalizer. It is the responsibility of another thread, the finalizer thread, to iter-
ate over this queue of objects and call their finalizers before freeing their memory. Once the
finalizers have completed, the memory for the object is freed on the next collection pass, and the
object is completely dead, never to return.
Finalizers
There are many reasons why you should rarely write a finalizer. When used unnecessarily, finalizers
can degrade the performance of the CLR, because finalizable objects live longer than their nonfinal-
izable counterparts. Even allocating finalizable objects is more costly. Additionally, finalizers are
difficult to write, because you cannot make any assumptions about the state that other objects in
the system are in.
When the finalization thread iterates through the objects in the finalization queue, it calls the
Finalize method on each object. The Finalize method is an override of a virtual method on
System.Object; however, it’s illegal in C# to explicitly override this method. Instead, you write a
destructor that looks like a method that has no return type, cannot have access modifiers applied to
it, accepts no parameters, and whose identifier is the class name immediately prefixed with a tilde.
Destructors cannot be called explicitly in C#, and they are not inherited, just as constructors are not
inherited. A class can have only one destructor.
When an object’s finalizer is called, each finalizer in an inheritance chain is called, from the
most derived class to the least derived class. Consider the following example:
using System;
public class Base
{
~Base()
{
Console.WriteLine( "Base.~Base()" );
}
}
public class Derived : Base
{
~Derived()
{
Console.WriteLine( "Derived.~Derived()" );
}
}
public class EntryPoint
{
static void Main()
{
Derived derived = new Derived();
}
}

125.
106 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
As expected, the result of executing this code is as follows:
Derived.~Derived()
Base.~Base()
Although the garbage collector now handles the task of cleaning up memory so that you don’t
have to worry about it, you have a whole new host of concerns to deal with when it comes to the
destruction of objects. I’ve mentioned that finalizers run on a separate thread in the CLR. Therefore,
whatever objects you use inside your destructor must be thread-safe, but the odds are you should
not even be using other objects in your finalizer, since they may have already been finalized or
destroyed. This includes objects that are fields of the class that contains the finalizer. You have no
guaranteed way of knowing exactly when your finalizer will be called or in what order the finalizer
will be called between two independent or dependent objects. This is one more reason why you
shouldn’t introduce interdependencies on objects in the destructor code block. After all this dust
has settled, it starts to become clear that you shouldn’t do much inside a finalizer except basic
housecleaning, if anything.
Essentially, you only need to write a finalizer when your object manages some sort of unman-
aged resource. However, if the resource is managed through a standard Win32 handle, I highly
recommend that you use the SafeHandle type to manage it. Writing a wrapper such as SafeHandle is
tricky business, mainly because of the finalizer and all of the things you must do to guarantee that it
will get called in all situations, even the diabolical ones such as an out-of-memory condition or in
the face of unexpected exceptions. Finally, any object that has a finalizer must implement the Dis-
posable pattern, which I cover in the forthcoming section titled “Disposable Objects.”
Deterministic Destruction
So far, everything that you’ve seen regarding destruction of objects in the garbage-collected envi-
ronment of the CLR is known as nondeterministic destruction. That means that you cannot predict
the timing of the execution of the destructor code for an object. If you come from a native C++
world, you’ll recognize that this is completely different.
In C++, heap object destructors are called when the user explicitly deletes the object. With the
CLR, the garbage collector handles that for you, so you don’t have to worry about forgetting to do it.
However, for a C++-based stack object, the destructor is called as soon as the execution scope in
which that object is created is exited. This is known as deterministic destruction and is extremely
useful for managing resources.
Let’s examine the case of an object that holds a system file handle. You can use such a stack-
based object in C++ to manage the lifetime of the file handle. When the object is created, the
constructor of the object acquires the file handle, and as soon as the object goes out of scope, the
destructor is called and its code closes the file handle. This frees the client code of the object from
having to manage the resource explicitly. It also prevents resource leaks, because if an exception is
thrown from that code block where the object is used, C++ guarantees that the destructors for all
stack-based objects will be called no matter how the block is exited.
This idiom is called Resource Acquisition Is Initialization (RAII), and it’s extremely useful for
managing resources. C# has almost completely lost this capability of automatic cleanup in a timely
manner. Of course, if you had an object that held a file open and closed it in the destructor, you
wouldn’t have to worry about whether the file gets closed or not, but you will definitely have to con-
sider when it gets closed. The fact is, you don’t know exactly when it will get closed if the code to
close it is in the finalizer, which is fallout from nondeterministic finalization. For this very reason, it
would be bad design to put resource management code, such as closing file handles, in the finalizer.
What if the object is already marked for finalization but has not had its finalizer called yet, and you
try to create a new instance of the object whose constructor tries to open the resource? Well, with an

126.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 107
exclusive-access resource, the code will fail in the constructor for the new instance. I’m sure you’ll
agree that this is not desired, and most definitely would not be expected by the client of your object.
Let’s revisit the finalization ordering problem mentioned a little while ago. If an object contains
another object, and the outer object is put on the finalization queue, the internal objects possibly
are, too. However, the finalizer thread just goes through the queue finalizing the objects individu-
ally. It doesn’t care who was an internal object of whom. So clearly, it’s possible that if destructor
code accesses an object reference in a field, that object could already have been finalized. Accessing
such a field produces the dreaded undefined behavior exception.
This is a perfect example of how the garbage collector removes one bit of complexity but
replaces it with another. In reality, you should avoid finalizers if possible. Not only do they add com-
plexity, but they hamper memory management, since they cause objects to live longer than objects
with no finalizer. This is because they’re put on the finalization list, and it is the responsibility of an
entirely different thread to clean up the finalization list. In the “Disposable Objects” section and in
Chapter 13, I describe an interface, IDisposable, that was included in the Framework Class Library
in order to facilitate a form of deterministic destruction.
Exception Handling
It’s important to note the behavior of exceptions when inside the scope of a finalizer. If you come
from a native C++ world, you know that it is bad behavior to allow exceptions to propagate out from
a destructor, because in certain situations, that may cause your application to abort. In C#, an
exception thrown in a finalizer that leaves the block uncaught will be treated as an unhandled
exception, and by default, the process will be terminated after notifying you of the exception.
■Note This behavior starting with .NET 2.0 is a breaking change from .NET 1.1. Before .NET 2.0, unhandled
exceptions in the finalization thread were swallowed after notifying the user, and the process was allowed to con-
tinue. The danger with this behavior is that the system could be running in a half-baked or inconsistent state.
Therefore, it’s best to kill the process rather than run the risk of it causing more damage. In Chapter 7, I show you
how you can force the CLR to revert to the pre-2.0 behavior if you absolutely must.
Disposable Objects
In the previous section on finalizers, I discussed the differences between deterministic and
nondeterministic finalization, and you also saw that you lose a lot of convenience along with
deterministic finalization. For that reason, the IDisposable interface exists, and in fact, it was only
added during beta testing of the first release of the .NET Framework when developers were shout-
ing about not having any form of deterministic finalization built into the framework. It’s not a
perfect replacement for deterministic finalization, but it does get the job done at the expense of
adding complexity to the client of your objects.
The IDisposable Interface
The IDisposable definition is as follows:
public interface IDisposable
{
void Dispose();
}

127.
108 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
Notice that it has only one method, Dispose, and it is within this method’s implementation that
the dirty work is done. Thus, you should completely clean up your object and release all resources
inside Dispose. Even though the client code rather than the system calls Dispose automatically, it’s
the client code’s way of saying, “I’m done with this object and don’t intend to use it ever again.”
Even though the IDisposable pattern provides a form of deterministic destruction, it is not a
perfect solution. Using IDisposable, the onus is thrown on the client to ensure that the Dispose
method is called. There is no way for the client to rely upon the system, or the compiler, to call it for
them automatically. C# makes this a little easier to manage in the face of exceptions by overloading
the using keyword, which I discuss in the next section.
When you implement Dispose, you normally implement the class in such a way that the final-
izer code reuses Dispose. This way, if the client code never calls Dispose, the finalizer code will take
care of it at finalization time. Another factor makes implementing IDisposable painful for objects,
and that is that you must chain calls of IDisposable if your object contains references to other
objects that support IDisposable. This makes designing classes a little more difficult, since you
must know whether a class that you use for a field type implements IDisposable, and if it does, you
must implement IDisposable and you must make sure to call its Dispose method inside yours.
Given all of this discussion regarding IDisposable, you can definitely start to see how the
garbage collector adds complexity to design, even though it reduces the chance for memory bugs.
I’m not trying to say the garbage collector is worthless; in fact, it’s very valuable when used appro-
priately. However, as with any design, engineering decisions typically have pros and cons in both
directions.
Let’s look at an example implementation of IDisposable:
using System;
public class A : IDisposable
{
private bool disposed = false;
public void Dispose( bool disposing )
{
if( !disposed ) {
if( disposing ) {
// It is safe to access other objects here.
}
Console.WriteLine( "Cleaning up object" );
disposed = true;
}
}
public void Dispose()
{
Dispose( true );
GC.SuppressFinalize( this );
}
public void DoSomething()
{
Console.WriteLine( "A.SoSomething()" );
}
~A()
{
Console.WriteLine( "Finalizing" );

128.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 109
Dispose( false );
}
}
public class EntryPoint
{
static void Main()
{
A a = new A();
try {
a.DoSomething();
}
finally {
a.Dispose();
}
}
}
Let’s go over this code in detail to see what’s really going on. The first thing to notice in the class
is an internal Boolean field that registers whether or not the object has been disposed. It’s there
because it’s perfectly legal for client code to call Dispose multiple times. Therefore, you need some
way to know that you’ve done the work already.
You’ll also see that I’ve implemented the finalizer in terms of the Dispose implementation.
Notice that I have two overloads of Dispose. I’ve done this so that I know inside the Dispose(bool)
method whether I got here through IDisposable.Dispose or through the destructor. It tells me
whether I can safely access contained objects inside the method.
One last point: The Dispose method makes a call to GC.SuppressFinalize. This method on the
garbage collector allows you to keep the garbage collector from finalizing an object. If the client
code calls Dispose, and if the Dispose method completely cleans up all resources, including all the
work a finalizer would have done, then there is no need for this object to ever be finalized. You can
call SuppressFinalize to keep this object from being finalized. This handy optimization helps the
garbage collector get rid of your object in a timely manner when all references to it cease to exist.
Now, let’s take a look at how to use this disposable object. Notice the try/finally block within
the Main method. I cover exceptions in Chapter 7. For now, understand that this try/finally con-
struct is a way of guaranteeing that certain code will be executed no matter how a code block exits.
In this case, no matter how the execution flow leaves the try block—whether normally, through a
return statement, or even by exception—the code in the finally block will execute. View the
finally block as a sort of safety net. It is within this finally block that you call Dispose on the
object. No matter what, Dispose will get called.
This is a perfect example of how nondeterministic finalization throws the onus on the client
code, or the user, to clean up the object, whereas deterministic finalization doesn’t require the user
to bother typing these ugly try/finally blocks or to call Dispose. This definitely makes life harder
on the user, as it makes it much more tedious to create exception-safe and/or exception-neutral
code. The designers of C# have tried to lessen this load by overloading the using keyword. Although
it lessens the load, it doesn’t remove the burden put on the client code altogether.
■Note C++/CLI allows you to use RAII in a way familiar to C++ developers without requiring you to call Dispose
explicitly or use a using block. It would be nice if C# could do the same, but it would cause too much
of a calamity to introduce such a breaking change in the language at this point.

129.
110 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
The using Keyword
The using keyword was overloaded to support the IDisposable pattern, and the general idea is that
the using statement acquires the resources within the parentheses following the using keyword,
while the scope of these local variables is confined to the declaration scope of the following curly
braces.
Let’s look at a modified form of the previous example:
using System;
public class A : IDisposable
{
private bool disposed = false;
public void Dispose( bool disposing )
{
if( !disposed ) {
if( disposing ) {
// It is safe to access other objects here.
}
Console.WriteLine( "Cleaning up object" );
disposed = true;
}
}
public void Dispose()
{
Dispose( true );
GC.SuppressFinalize( this );
}
public void DoSomething()
{
Console.WriteLine( "A.SoSomething()" );
}
~A()
{
Console.WriteLine( "Finalizing" );
Dispose( false );
}
}
public class EntryPoint
{
static void Main()
{
using( A a = new A() ) {
a.DoSomething();
}
using( A a = new A(), b = new A() ) {
a.DoSomething();
b.DoSomething();
}
}
}

130.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 111
The meat of the changes is in the Main method. Notice that I’ve replaced the ugly try/finally
construct with the cleaner using statement. Under the covers, the using statement expands to the
try/finally construct I already had. Now, granted, this code is much easier to read and understand.
However, it still doesn’t remove the burden from the client code of having to remember to use the
using statement in the first place.
The using statement requires that all resources acquired in the acquisition process be implic-
itly convertible to IDisposable. That is, they must implement IDisposable. If they don’t, you’ll see a
compiler warning.
Method Parameter Types
Method parameters follow the same general rules as those of C/C++. That is, by default, parameters
declare a variable identifier that is valid for the duration and scope of the method itself. There are
no const parameters as in C++, and method parameters may be reassigned at will. Unless the
parameter is declared a certain way as a ref or an out parameter, such reassignment will remain
local to the method.
I have found that one of the biggest stumbling blocks for C++ developers in C# is dealing with
the semantics of variables passed to methods. Since the dominant type of type instance within the
CLR is a reference, variables to such objects merely point to their instances on the heap—i.e., argu-
ments are passed to the method using reference semantics. C++ developers are used to copies of
variables being made as they’re passed into methods by default, unless they’re passed by reference
or as pointers. In other words, arguments are passed using value semantics.
In C#, arguments are actually passed by value. However, for references, the value that is copied
is the reference itself and not the object that it references. Changes in state that are made to the ref-
erence object within the method are visible to the caller of the method.
Since there is no notion of a const parameter within C#, you should create immutable objects
to pass where you would have wanted to pass a const parameter. I have more to say about immuta-
ble objects in Chapter 13.
■Note Those C++ developers who are used to using handle/body idioms to implement copy-on-write semantics
must take these facts into consideration. It doesn’t mean that you cannot employ those idioms in C#; rather, it just
means that you must implement them differently.
Value Arguments
In reality, all parameters passed to methods are value arguments, assuming they’re normal, plain,
undecorated parameters that get passed to a method. By undecorated, I mean they don’t have spe-
cial keywords such as out, ref, and params attached to them. They can, however, have attributes
attached to them just as almost everything else in the CLR type system can. As with all parameters,
the identifier is in scope within the method block following the parameter list (i.e., within the curly
braces), and the method receives a copy of the passed variable at invocation time. Be careful about
what this means, though. If the passed variable is a struct, or value type, then the method receives a
copy of the value. Any changes made locally to the value are not seen by the caller. If the passed
variable is a reference to an object on the heap, as any variable for a class instance is, then the
method receives a copy of the reference. Thus, any changes made to the object through the refer-
ence are seen by the caller of the method.

131.
112 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
ref Arguments
Passing parameters by reference is indicated by placing the ref modifier ahead of the parameter
type in the parameter list for the method. When a variable is passed by reference, a new copy of the
variable is not made, and the caller’s variable is directly affected by any actions within the method.
As is usually the case in the CLR, this means two slightly different things, depending on whether the
variable is an instance of a value type (struct) or an object (class).
When a value instance is passed by reference, a copy of the caller’s value is not made. It’s as if
the parameter were passed as a C++ pointer, even though you access the methods and fields of the
variable in the same way as value arguments. When an object (reference) instance is passed by ref-
erence, again, no copy of the variable is made, which means that a new reference to the object on
the heap is not created. In fact, the variable behaves as if it were a C++ pointer to the reference vari-
able, which could be viewed as a C++ pointer to a pointer. Additionally, the verifier ensures that the
variable referenced by the ref parameter has been definitely assigned before the method call. Let’s
take a look at some examples to put the entire notion of ref parameters into perspective:
using System;
public struct MyStruct
{
public int val;
}
public class EntryPoint
{
static void Main() {
MyStruct myValue = new MyStruct();
myValue.val = 10;
PassByValue( myValue );
Console.WriteLine( "Result of PassByValue: myValue.val = {0}",
myValue.val );
PassByRef( ref myValue );
Console.WriteLine( "Result of PassByRef: myValue.val = {0}",
myValue.val );
}
static void PassByValue( MyStruct myValue ) {
myValue.val = 50;
}
static void PassByRef( ref MyStruct myValue ) {
myValue.val = 42;
}
}
This example contains two methods: PassByValue and PassByRef. Both methods modify a field
of the value type instance passed in. However, as the following output shows, the PassByValue
method modifies a local copy, whereas the PassByRef method modifies the caller’s instance as you
would expect:
Result of PassByValue: myValue.val = 10
Result of PassByRef: myValue.val = 42

132.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 113
Also, pay attention to the fact that the ref keyword is required at the point of call into the
PassByRef method. This is necessary because the method could be overloaded based upon the ref
keyword. In other words, another PassByRef method could just as well have taken a MyStruct by
value rather than by ref. Plus, the fact that you have to put the ref keyword on at the point of call
makes the code easier to read in my opinion. When programmers read the code at the point of call,
they can get a pretty clear idea that the method could make some changes to the object being
passed by ref.
Now, let’s consider an example that uses an object rather than a value type:
using System;
public class EntryPoint
{
static void Main() {
object myObject = new Object();
Console.WriteLine( "myObject.GetHashCode() == {0}",
myObject.GetHashCode() );
PassByRef( ref myObject );
Console.WriteLine( "myObject.GetHashCode() == {0}",
myObject.GetHashCode() );
}
static void PassByRef( ref object myObject ) {
// Assign a new instance to the variable.
myObject = new Object();
}
}
In this case, the variable passed by reference is an object. But, as I said, instead of the method
receiving a copy of the reference, thus creating a new reference to the same object, the original ref-
erence is referenced instead. Yes, this can be confusing. In the previous PassByRef method, the
reference passed in is reassigned to a new object instance. The original object is left with no refer-
ences to it, so it is now available for collection. To illustrate that the myObject variable references two
different instances between the point before it is called and the point after it is called, I sent the
results of myObject.GetHashCode to the console to prove it.
out Parameters
Out parameters are almost identical to ref parameters, with two notable differences. First, instead of
using the ref keyword, you use the out keyword, and you still have to provide the out keyword at the
point of call as you do with the ref keyword. However, the variable referenced by the out variable is
not required to have been definitely assigned before the method is called as it is with ref parame-
ters. That’s because the method is not allowed to use the variable for anything useful until it has
assigned the variable. For example, the following is valid code:
public class EntryPoint
{
static void Main() {
object obj;
PassAsOutParam( out obj );
}
static void PassAsOutParam( out object obj ) {
obj = new object();
}
}

133.
114 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
Notice that the obj variable in the Main method is not directly assigned before the call to
PassAsOutParam. That’s perfectly fine, since it is marked an out parameter. The PassAsOutParam
method won’t be referencing the variable unless it has already assigned it. If you were to replace the
two occurrences of out with ref in the previous code, you would see a compiler error similar to the
following:
error CS0165: Use of unassigned local variable 'obj'
param Arrays
C# makes it a snap to pass a variable list of parameters. Simply declare the last parameter in your
parameter list as an array type and precede the array type with the params keyword. Now, if the
method is invoked with a variable number of parameters, those parameters are passed to the
method in the form of an array that you can easily iterate through, and the array type that you use
can be based on any valid type. Here’s a short example:
using System;
public class EntryPoint
{
static void Main() {
VarArgs( 42 );
VarArgs( 42, 43, 44 );
VarArgs( 44, 56, 23, 234, 45, 123 );
}
static void VarArgs( int val1, params int[] vals ) {
Console.WriteLine( "val1: {0}", val1 );
foreach( int i in vals ) {
Console.WriteLine( "vals[]: {0}",
i );
}
Console.WriteLine();
}
}
In each case, VarArgs is called successfully, but in each case, the array referenced by the vals
parameter is different. As you can see, referencing a variable number of parameters is pretty easy in
C#. You can code an efficient Add method to a container type using parameter arrays where only one
call is necessary to add a variable number of items.
Method Overloading
C# overloading is a compile-time technique in which, at a call point, the compiler chooses a
method from a set of methods with the same name. The compiler uses the argument list of the
method to choose the method that fits best. The argument types and the ref, out, and param param-
eter modifiers play a part in method overloading, since they form part of the method signature.
Methods without variable-length parameter arrays get preference over those that have them. Simi-
lar to C++, the method return type is not part of the signature (except in one rare case of conversion
operators, which I cover in Chapter 6). So you cannot have methods within an overloaded class
where the only difference is the return type. Finally, if the compiler gets to a point where multiple
methods are ambiguous with respect to overloading, it stops with an error.

134.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 115
Overall, there’s really nothing different about method overloading in C# compared to C++. It
can’t possibly cause any runtime exceptions, because the entire algorithm is applied at compile
time. When the compiler fails to find an exact match based on the parameters given, it then starts
hunting for a best match based on implicit convertibility of the instances in the parameter list.
Thus, if a single parameter method accepts an object of type A, and you have passed an object of
type B that is derived from type A, in the absence of a method that accepts type B, the compiler will
implicitly convert your instance into a type A reference to satisfy the method call. Depending on the
situation and the size of the overloaded method set, the selection process can still be a tricky one.
I’ve found that it’s best to minimize too many confusing overloads where implicit conversion is nec-
essary to satisfy the resolution. Too many implicit conversions can make code difficult to follow,
requiring you to actually execute it in a debugger to see what happens. That makes it hard on main-
tenance engineers who need to come in behind you and figure out what you were doing. It’s not to
say that implicit conversion is bad during overload resolution, but just use it judiciously and spar-
ingly to minimize future surprises.
Inheritance and Virtual Methods
C# implements the notion of virtual methods just as the C++ and Java languages do. That’s no sur-
prise at all, since C# is an object-oriented language, and virtual methods are the primary
mechanism for implementing dynamic polymorphism. That said, some notable differences from
those languages deserve special mention.
Virtual and Abstract Methods
You declare a virtual method using either the virtual or abstract modifiers on the method at the
point of declaration. They both introduce the method into the declaration space as one that a deriv-
ing class can override. The difference between the two is that abstract methods are required to be
overridden, whereas virtual methods are not. Abstract methods are similar to C++ pure virtual
methods, except that C++ pure virtual methods may have an implementation associated with them,
whereas C# abstract methods may not. Virtual methods, in contrast to abstract methods, are
required to have an implementation associated with them. Virtual methods, along with interfaces,
are the only means of implementing polymorphism within C#.
■Note Under the covers, the CLR implements virtual methods differently from C++. Whereas C++ can create
multiple vtables (dynamic method tables pointing to virtual methods) for an individual object of a class depending
on its static hierarchical structure, CLR objects have only one method table that contains both virtual and nonvir-
tual methods. Additionally, the table in the CLR is built early on in the lifetime of the object. Not only does the
creation order of objects affect the ordering of static initializers and constructor calls in a hierarchy, but it also
gives C# a capability that C++ lacks. In C#, virtual method calls work when called inside constructor bodies,
whereas they don’t in C++. For more information on how the CLR manages method tables for object instances,
read Don Box and Chris Sells’ Essential .NET, Volume 1: The Common Language Runtime (Boston, MA: Addison-
Wesley Professional, 2002).
override and new Methods
To override a method in a derived class, you must tag the method with the override modifier. If you
don’t, you’ll get a compiler warning telling you that you need to provide either the new modifier or

135.
116 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
the override modifier in the derived method declaration. The compiler defaults to using the new
modifier, which probably does the exact opposite of what you intended. This behavior is different
than C++, since in C++, once a method is marked as virtual, any derived method of the same name
and signature is automatically an override of the virtual method, and the virtual modifier on those
derived methods is completely optional. Personally, I prefer the fact that C# requires you to tag the
overriding method simply for the purpose of code readability. I cannot tell you how many poorly
designed C++ code bases I’ve worked on with deep hierarchies where developers were too lazy to
keep tagging the virtual override methods with the virtual keyword. I had no way of knowing if a
method overrides a virtual in a base class without looking at the base class declaration. These terri-
bly designed code bases had such deep hierarchies that they forced me to rifle through a whole
plethora of files just to find the answer. C# drives a stake through the heart of this problem. Check
out the following code:
using System;
public class A
{
public virtual void SomeMethod() {
Console.WriteLine( "A.SomeMethod" );
}
}
public class B : A
{
public void SomeMethod() {
Console.WriteLine( "B.SomeMethod" );
}
}
public class EntryPoint
{
static void Main() {
B b = new B();
A a = b;
a.SomeMethod();
}
}
This code compiles, but not without the following warning:
test.cs(12,17): warning CS0114: 'B.SomeMethod()' hides inherited member 'A.SomeMethod()'.
To make the current member override that implementation, add the override keyword.
Otherwise add the new keyword.
When the code is executed, A.SomeMethod gets called. So what does the new keyword do? It
breaks the virtual chain at that point in the hierarchy. When a virtual method is called through an
object reference, the method called is determined from the method tables at run time. If a method
is virtual, the runtime searches down through the hierarchy looking for the most derived version of
the method, and then it calls that one. However, during the search, if it encounters a method
marked with the new modifier, it backs up to the method of the previous class in the hierarchy and
uses that one instead. That is why A.SomeMethod is the method that gets called. Had B.SomeMethod

136.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 117
been marked as override, then the code would have called B.SomeMethod instead. Since C# defaults
to using the new modifier when none of them are present, it throws off the warning possibly to get
the attention of those of us who are used to the C++ syntax. Finally, the new modifier is orthogonal to
the virtual modifier in meaning, in the sense that the method marked new could either also be vir-
tual or not. In the previous example, I did not also attach the virtual modifier to B.SomeMethod, so
there cannot be a class C derived from B that overrides B.SomeMethod, since it’s not virtual. Thus, the
new keyword not only breaks the virtual chain, but it redefines whether the class and the derived
classes from class B will get a virtual SomeMethod.
Another issue to consider with regard to overriding methods is whether to call the base class
version of the method and when. In C#, you call the base class version using the base identifier as
shown:
using System;
public class A
{
public virtual void SomeMethod() {
Console.WriteLine( "A.SomeMethod" );
}
}
public class B : A
{
public override void SomeMethod() {
Console.WriteLine( "B.SomeMethod" );
base.SomeMethod();
}
}
public class EntryPoint
{
static void Main() {
B b = new B();
A a = b;
a.SomeMethod();
}
}
As expected, the output of the previous code prints A.SomeMethod on the line after it prints
B.SomeMethod. Is this the correct ordering of events? Should it not be the other way around?
Shouldn’t B.SomeMethod call the base class version before it does its work? The point is that you don’t
have enough information to answer this question. Therein lies a problem with inheritance and vir-
tual method overrides. How do you know when and if to call the base class method? The answer is
that the method should be well documented so that you know how to do the right thing. Thus,
inheritance with virtual methods increases your documentation load, because now you must pro-
vide the consumers of your class with information above and beyond just the public interface. For
example, if you follow the Non-Virtual Interface (NVI) pattern that I describe in Chapter 13, the vir-
tual method in question is protected, so now you must document both public methods and some
protected methods, and the virtual methods must clearly state whether the base class should call
them and when. Ouch!

137.
118 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
sealed Methods
For the reasons stated previously, I believe you should seal your classes by default and only make
classes inheritable in well-thought-out circumstances. Many times I see hierarchies where the
developer was thinking, “I’ll just mark all of my methods as virtual to give my deriving classes the
most flexibility.” All this does is create a rat’s nest of bugs later down the line. This thought pattern is
typical of less-experienced designers who are grappling with the complexities of inheritance and
virtual methods. The fact is that inheritance coupled with virtual methods is so surprisingly com-
plex that it’s best to explicitly turn off the capability rather than leave it wide open for abuse.
Therefore, when designing classes, you should prefer to create sealed, noninheritable classes, and
you should document the public interface well. Consumers who need to extend the functionality
can still do so, but through containment rather than inheritance. Extension through containment
coupled with crafty interface definitions is far more powerful than class inheritance.
In rare instances, you’re deriving from a class with virtual methods and you want to force the
virtual chain for a specific method to end at your override. In other words, you don’t want further
derived classes to be able to override the virtual method. To do so, you also mark the method with
the sealed modifier. As is obvious from the name, it means that no further derived classes can over-
ride the method. They can, however, provide a method with the same signature, as long as the
method is marked with the new modifier, as discussed in the previous section. In fact, you could
mark the new method as virtual, thus starting a new virtual chain in the hierarchy. This is not the
same as sealing the entire class, which doesn’t even allow a class to derive from this one in the first
place. Therefore, if the deriving class is marked as sealed, then marking override methods within
that class with sealed is redundant.
A Final Few Words on C# Virtual Methods
Clearly, C# provides a lot of flexible keywords to make some interesting things happen when it
comes to inheritance and virtual methods. However, just because the language provides them does
not mean that it’s wise to use them. Over the past decade, many experts have published countless
books describing how to design C++- and Java-based applications safely and effectively. Many
times, those works indicate things that you should not do rather than things that you should do.
That’s because C++, along with C#, provides you with the power to do things that don’t necessarily
fall within the boundaries of what’s considered good design. In the end, you want to strive for
classes and constructs that are intuitive to use and carry few hidden surprises.
The savvy reader probably noticed that the new modifier is the quickest way to introduce some
serious surprises into a class hierarchy. If you ever find yourself using that modifier on a method,
you’re most likely using a class in a way it was not intended to be used. You could be deriving from
a class that should have been marked sealed in the first place. And you may be cursing the devel-
oper of that class for not marking a particular method virtual so you can easily override it.
Therefore, you resort to using the new modifier. Just because it exists, don’t assume it’s wise to use
it. The designer of the class you’re deriving from probably never intended you to derive from it and
just forgot to mark it sealed. And if the designer intentionally left it unsealed, he probably did not
intend for you to replace the method you’re trying to override. Therefore, always strive to follow
time-tested design techniques and avoid the whiz-bang features of the language that go against
that grain of good design.
Inheritance, Containment, and Delegation
When many people started programming in object-oriented languages some years ago, they
thought inheritance was the greatest thing since sliced bread. In fact, many people consider it an
integral, important part of object-oriented programming. Some argue that a language that doesn’t

138.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 119
support inheritance is not an object-oriented language at all. This arguing point for many people
over the years has almost taken on the form of a religious war at times. As time went on, though,
some astute designers started to notice the pitfalls of inheritance.
Choosing Between Interface and Class Inheritance
When you first discover inheritance, you have a tendency to overuse it and abuse it. This is easy to
do. Misuse can make software designs hard to understand and maintain, especially in languages
such as C++ that support multiple inheritance. It can also make it hard for those designs to adapt to
future needs, thus forcing them to be thrown out and replaced with a completely new design. In
languages that only support single inheritance, such as C# and Java, you’re forced to apply more
diligence to your use of inheritance.
For example, when modeling a human-resources system at company XYZ, one naïve designer
could be inclined to introduce classes such as Payee, BenefitsRecipient, and Developer. Then,
using multiple inheritance, he could build or compose a full-time developer, represented by the
class FulltimeDeveloper, by inheriting from all three, as in Figure 4-3.
Figure 4-3. Example of bad inheritance
As you can see, this forces our designer to create a new class for contract developers, where the
concrete class doesn’t inherit from BenefitsRecipient. After the system grows by leaps and bounds,
you can quickly see the flaw in the design when the inheritance lattice becomes complex and deep.
Now he has two classes for types of developers, thus making the design hard to manage. Now, let’s
look at a bad attempt of the same problem with a language that supports only single inheritance.
Figure 4-4 shows you that this solution is hardly a good one.
Figure 4-4. Example of bad single-inheritance hierarchy
If you look closely, you can see the ambiguity that is present. It’s impossible that the Developer
class can be derived from both Payee and BenefitsRecipient in an environment where only single
inheritance is allowed. Because of that, these two hierarchies cannot live within the same design.
You could create two different variants of the Developer class—one for FulltimeDeveloper to derive

139.
120 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
from, and one for ContractDeveloper to derive from. However, that would be a waste of time. More
importantly, code reuse—the main benefit of inheritance—is gone if you have to create two ver-
sions of essentially the same class.
A better approach is to have a Developer class that contains various properties that represent
these qualities of developers within the company. For example, the support of a specific interface
could represent the support of a certain property. An inheritance hierarchy that is multiple levels
deep is a telltale sign that the design needs some rethinking.
To see what’s really going on here, let’s take a moment to analyze what inheritance does for
you. In reality, it allows you to get a little bit of work for free by inheriting an implementation. There
is an important distinction between inheritance and interface implementation. Although the
object-oriented languages, including C#, typically use a similar syntax for the two, it’s important to
note that classes that implement an interface don’t get any implementation at all. When using
inheritance, not only do you inherit the public contract of the class, but you also inherit the layout,
or the guts.
A good rule of thumb is that when your purpose is primarily to inherit a contract, choose inter-
face implementation over inheritance. This will guarantee that your design has the greatest
flexibility. To understand more why that’s the case, let’s investigate more pitfalls of inheritance.
Delegation and Composition vs. Inheritance
Another very important aspect of inheritance that is unfavorable: Inheritance can break encapsu-
lation and always increases coupling. I’m sure we all agree, or at least we should all agree, that
encapsulation is the most fundamental and important object-oriented concept. If that’s the case,
then why would you want to break it? Yet any time you use encapsulation where the base type con-
tains protected fields, you’re cracking the shell of encapsulation and exposing the internals of the
base class. This cannot be good. Let me explain why it’s not and what sorts of alternatives you have
at your disposal that can create better designs.
Many describe inheritance as white-box reuse. A better form of reuse is black-box reuse,
meaning that the internals of the object are not exposed to you. You can achieve this by using con-
tainment. Yes, that’s correct. Instead of inheriting your new class from another, you can contain an
instance of the other class in your new class, thus reusing the class of the contained type without
cracking the encapsulation. The downside to this technique is that in most languages, including C#,
it requires a little more coding work, but not too much. In the end, it can provide a much more
adaptable design.
For a simple example of what I’m talking about, consider a problem domain where a class han-
dles some sort of custom network communications. Let’s call this class NetworkCommunicator, and
let’s say it looks like this:
public class NetworkCommunicator
{
public void SendData( DataObject obj )
{
// Send the data over the wire.
}
public DataObject ReceiveData()
{
// Receive data over the wire.
}
}

140.
CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS 121
Now, let’s say that you come along later and decide it would be nice to have an
EncryptedNetworkCommunicator object, where the data transmission is encrypted before it is sent. A
common approach would be to derive EncryptedNetworkCommunicator from NetworkCommunicator.
Then, the implementation would look like this:
public class EncryptedNetworkCommunicator : NetworkCommunicator
{
public override void SendData( DataObject obj )
{
// Encrypt the data.
base.SendData( obj );
}
public override DataObject ReceiveData()
{
DataObject obj = base.ReceiveData();
// Decrypt data.
return obj;
}
}
There is a major drawback here. First of all, good design dictates that if you’re going to modify
the functionality of the base class methods, you should override them. To override them properly,
you need to declare them as virtual in the first place. This requires you to be able to tell the future
when you design the NetworkCommunicator class and mark the methods as virtual. Yes, you can hide
them in C# using the new keyword when you define the method on the derived class. But if you do
that, you’re breaking the tenet that the inheritance relationship models an is-a relationship. Now,
let’s look at the containment solution:
public class EncryptedNetworkCommunicator
{
public EncryptedNetworkCommunicator()
{
contained = new NetworkCommunicator();
}
public void SendData( DataObject obj )
{
// Encrypt the data.
contained.SendData( obj );
}
public DataObject ReceiveData()
{
DataObject obj = contained.ReceiveData();
// Decrypt data
return obj;
}
private NetworkCommunicator contained;
}

141.
122 CHAPTER 4 ■ CLASSES, STRUCTS, AND OBJECTS
As you can see, it’s only slightly more work. But the good thing is, you’re able to reuse the
NetworkCommunicator as if it were a black box. The designer of NetworkCommunicator could have cre-
ated the thing sealed, and you would still be able to reuse it. Had it been sealed, you definitely could
not have inherited from it.
Another downfall of using inheritance is that it is not dynamic. It is static by the very fact that it
is determined at compile time. This can be very limiting, to say the least. You can remove this limita-
tion by using containment. However, in order to do that, you have to also employ your good friend,
polymorphism. By doing so, the contained type can be, say, an interface type. Then, the contained
object merely has to support the contract of that interface in order to be reused by the container.
Moreover, you can change this object at run time. Think about this for a moment and let it sink in.
Consider an object that represents a container of sortable objects. Let’s say that this container type
comes with a default sort algorithm. If you implement this default algorithm as a contained type
that you can swap at run time, then if the problem domain required it, you could replace it with a
custom sort algorithm as long as the new sort algorithm object implements the required interface
that the container type expects. This technique is known as the Strategy design pattern. You’ve just
seen an excellent use of a design pattern.
In conclusion, you can see that designs are much more flexible if you favor dynamic rather
than static constructs. This includes favoring containment over inheritance in many reuse cases.
This type of reuse is also known as delegation, since the work is delegated to the contained type.
Containment also preserves encapsulation, whereas inheritance breaks encapsulation. One word of
caution is in order, though. As with just about anything, you can overdo containment. For smaller
utility classes, it may not make sense to go to too much effort to favor containment. And in some
cases, you need to use inheritance to implement specialization. But, in the grand scheme of things,
designs that favor containment over inheritance as a reuse mechanism are magnitudes more flexi-
ble and stand the test of time much better. Always respect the power of inheritance, including the
damage it can cause through its misuse.
Summary
In this very long chapter, I’ve covered the important points regarding the C# type system, which
allows you to create new types that have all of the capabilities of implicit types defined by the run-
time. I started out by covering class definitions used to define new reference types, then I followed
that with struct definitions used to create instances of new value types within the CLR, and I
described the major differences between the two. Related to the topic of value types is that of box-
ing and unboxing, which I showed can introduce unintended inefficiencies when you don’t
understand all of the places boxing can be introduced by the compiler. (In Chapter 11, which covers
generics, you’ll see how you can eliminate boxing and unboxing entirely in some cases.)
I then turned to the complex topics of object creation and initialization, as well as object
destruction. Destruction is a rather tricky topic in the CLR, since your reference types can support
either deterministic or nondeterministic destruction. (I cover destruction in more detail with more
examples in Chapter 13.) Then, I quickly discussed method overloading in C# and the various modi-
fiers you can place on methods to control whether they’re modified as virtual, override, or sealed.
Finally, I spent some time discussing inheritance, polymorphism, and containment, and I provided
some pointers for choosing when to use them.
The last sections in this chapter lead right into the next chapter, where I’ll cover the all-impor-
tant topic of interface-based, or contract-based, programming and how to use it in the CLR.

142.
CHAPTER 5
Interfaces and Contracts
D uring your years as a software developer, you’ve likely come across the notion of interface-based
programming. If you’re familiar with the seminal book, Design Patterns: Elements of Reusable
Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides
(known as the “Gang of Four”),1 then you know that many design patterns employ interface-style
“contracts.” If you’re not familiar with that book and its concepts, I urge you to read it. In this chap-
ter, it is my goal to show you how you can model well-defined, versioned contracts using interfaces.
In this context, a contract is an agreement by a type to support a set of functionality.
If you’ve done any COM or CORBA development over the years, then you’ve most definitely
been doing interface-based development. In fact, the interface is the only form of communication
between components in COM. Therefore, much of the design complexity rests in developing solid
interfaces before you write any line of implementation code. Failure to follow this paradigm has
been the source of many problems. For example, Visual Studio 2003 offered an easy environment
from which you could create web services. By simply annotating methods of a class a certain way,
you could expose those methods as methods of the web service. However, the IDE fostered an
approach whereby the interface was the result of annotating methods on a class rather than the
other way around. Thus, the cart was put before the horse. Instead, you should clearly define the
web service interface before doing any coding, and then code the implementation to implement
the interface. To name just one benefit of this approach, you can code both the client and the server
concurrently rather than one after the other. Another part of the problem is that once an interface is
published to the world, you cannot change it. Doing so would break all implementations based
upon it. Unfortunately, the Visual Studio environment encourages you to break this rule by making
it easy for you to add a new method to a class and annotate it as a web service method.
In a well-designed, interface-based system, such as in service-oriented architecture (SOA) sys-
tems, you should always design the interface first, as it’s the contract between components. The
contract drives the implementation rather than the implementation driving, or defining, the con-
tract. Unfortunately, too many tools in the past and even up to the present have promoted this
backward development. But just because they promote it does not mean you need to follow their
erroneous lead. After all, a contract, when applied to a type, imposes a set of requirements on that
type. It makes no sense for the requirements to be driven by the types themselves. In the .NET envi-
ronment, interfaces are types.
1. Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph John-
son, and John Vlissides (Boston, MA: Addison-Wesley Professional, 1995) is cited in the references at the end
of this book. 123

143.
124 CHAPTER 5 ■ INTERFACES AND CONTRACTS
Interfaces Define Types
An interface declaration defines a reference type. Within variables of this type, you can store a refer-
ence to an object that implements the contract of the interface type. Each variable in the CLR is
stored in a storage location, whether it be on the heap or on the stack. Each storage location has a
type associated with it. Therefore, an interface type can describe the type associated with a specific
storage location. When a variable—say, a reference to an object—is stored in that location, it must
be the same type as the location, or it must be convertible to the type attached to the location. If it
can be converted automatically to the type of the location, then it is implicitly convertible to the
storage location type. If it requires a specific cast syntax to perform the conversion, then it is explic-
itly convertible to the storage location type.
Many examples use a fictitious GUI framework as their basis for demonstration purposes, so
I’ll do the same here. Take a look at the following code snippet:
public interface IUIControl
{
void Paint();
}
public class Button : IUIControl
{
public void Paint() {
// Paint the Button
}
}
public class ListBox : IUIControl
{
public void Paint() {
// Paint the Listbox
}
}
This example declares an interface named IUIControl that simply exposes one method, Paint.
This interface defines a contract, which states that any type that implements this interface must
implement the Paint method. Of course, some documentation describing the semantic meaning of
what Paint is supposed to do would be nice. For example, you can imagine that an interface named
IArtist could have a method named Paint, but the meaning would probably not be reflexive as it is
in the previous example—i.e., IUIControl.Paint likely asks a control to paint itself, while
IArtist.Paint likely means that the artist should paint something.
■Note I’ve found it useful to name methods according to both the action they perform and where the action is
directed. For example, suppose the IUIControl.Paint method takes a Graphics object as a parameter telling it
where to paint itself. In my opinion, it makes the code more readable if the method is named IUIControl.
PaintSelfTo. This way, the method call sort of reads like a spoken language in the sense that a method call that
looks like control.PaintSelfTo( myGraphicsObject ) is saying, “control, please paint yourself to
myGraphicsObject.”
Once the classes ListBox and Button in the previous example implement the interface, they
can both be treated as type IUIControl. It’s handy to consider how the CLR manages the situation.
If you were to attempt to store any instance of either Button or ListBox into a variable declared
as IUIControl, the operation would succeed. The reference to those concrete types is implicitly

144.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 125
convertible to the IUIControl interface type because they both implement the interface. However,
to cast an IUIControl reference back into a ListBox or Button reference requires an explicit cast, and
that explicit cast could fail at run time if, in fact, the IUIControl reference does not point to an
instance of the desired concrete type.
Defining Interfaces
In the previous section, you got a taste of what a C# interface declaration looks like. It looks similar
to a class declaration where the keyword class is simply replaced with the word interface and the
methods have no body. Note some important things, though. If you follow the recommended con-
vention, your interface names will start with the letter I. Thus, you can spot interface types in code
easily. Interfaces can have an access modifier attached to them. This determines whether the inter-
face type declaration is visible outside the assembly. Since most interfaces represent contracts of
communication between consumers and providers, interface declarations are typically declared as
public.
Interface members cannot have any access modifiers attached to them. However, they can be
decorated with the new modifier, which I discuss later on. Interface members are implicitly public.
What would be the point of having a nonpublic interface member when the purpose of the inter-
face is to allow two objects to talk to each other?
INTERFACES DEFINE CONTRACTS
To stress the fact that an interface only specifies a contract, I like to draw an analogy between interface declara-
tions and IDL and Web Services Description Language (WSDL). Both COM and CORBA use IDL to define interfaces.
The syntax is similar to C++. It is typically passed through a translator, such as midl.exe for COM, to generate
wrappers—and possibly proxies and stubs—for whatever language you desire. WSDL is another example, although
it is much more expressive than IDL. An XML schema defines the format of WSDL, and a WSDL document is used to
describe a contract, or interface, into a network service. The usage pattern is similar to IDL. Once you have a WSDL
document, you pass it through a translator for whatever language you’re using to implement or consume the serv-
ice. The translator helps you out by generating a shell of an implementation, or interfaces that are native to the
language you’re using. Declaring and consuming interfaces in the .NET environment should follow the same pat-
tern.
In practice, it usually make sense to house your interface declarations in a separate assembly that contains
only interface definitions and constants, so that the consumer and the provider can base their implementations on
exactly the same version of the interfaces.
What Can Be in an Interface?
Interface declarations may declare zero or more methods, properties, events, and indexers. All are
implicitly public and cannot be static. Interfaces may inherit from one or more other interfaces. The
syntax is the same as that of class inheritance. When it comes to interfaces, I prefer to think of inter-
face B deriving from interface A as meaning that if you implement interface B, you must also
implement interface A. Class inheritance implies an is-a relationship, where the base implementa-
tion is also inherited. Even though interface inheritance borrows the same syntax as class

145.
126 CHAPTER 5 ■ INTERFACES AND CONTRACTS
inheritance, which is an is-a relationship, it’s not completely accurate to consider them one and
the same, since interface inheritance merely declares a generalization and no implementation is
inherited. Therefore, whenever you say interface inheritance, try to think of it more in terms of an
implements relationship. This becomes clearer when I discuss how a derived class can reimplement
interfaces and how the compiler does interface implementation mapping in the concrete types that
implement the interface.
Here’s an example of what you can declare in an interface:
public delegate void DBEvent( IMyDatabase sender );2
public interface IMyDatabase : ISerializable, IDisposable
{
void Insert( object element );
int Count { get; }
object this[ int index ] { get; set; }
event DBEvent dbChanged;
}
In this example, IMyDatabase also implements ISerializable and IDisposable. Therefore, any
concrete type that implements IMyDatabase must also implement ISerializable and IDisposable;
otherwise, the concrete type will not compile. If you were to compile this code snippet into an
assembly and look at it with ILDASM, you would see that the IMyDatabase type contains nothing
more than instance method declarations. Of course, some of those will have special names based
on the fact that they’re accessors for the property, indexer, or event.
Interface Inheritance and Member Hiding
As mentioned previously, interfaces support multiple inheritance from other interfaces in the syn-
tactic sense. As with multiple inheritance in C++, you may also have diamond-lattice hierarchies,
such as in the following code:
public interface IUIControl
{
void Paint();
}
public interface IEditBox : IUIControl
{
}
public interface IDropList : IUIControl
{
}
public class ComboBox : IEditBox, IDropList
{
public void Paint() {
// paint implementation for ComboBox
}
}
2. If you’re unfamiliar with the delegate keyword and how delegates are used to declare events, don’t worry.
You’ll find a thorough discussion of delegates and events in Chapter 10.

146.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 127
In this example, both the IEditBox and IDropList interfaces implement the IUIControl inter-
face. And since ComboBox implements both of those interfaces, it must implement the union of all
the methods declared in the interfaces it directly implements, plus the interfaces those interfaces
implement recursively. In this case, that only includes the IUIControl.Paint method.
Quite simply, all of the methods from all of the interfaces are merged together into one big
union to form the set of methods that the concrete class or structure must implement. Therefore,
the ComboBox class gets only one implementation of the Paint method. If you were to cast a ComboBox
instance into both an IEditBox reference and an IDropList reference, then calling Paint through
both of those would call into exactly the same implementation.
■Note If you come from a native C++ background, you might know all of the intricacies of multiple inheritance
and diamond-lattice inheritance diagrams and how they relate to virtual inheritance in C++ and the multiple com-
piler-generated vtables involved. To understand how C# differs, imagine that C# flattens all of those vtables into
one table at compile time.
Sometimes—although rarely—you need to declare a method in an interface that hides a
method in an inherited interface. You must use the new keyword if you want to keep the compiler
from complaining about it with a warning.
■Note Traditionally, Object-Oriented Analysis and Design (OOA-D) considers it bad design to hide a nonvirtual
inherited member. The implementation that actually gets called depends on the type of reference held, even if the
two references point to the same instance. For example, if A.DoWork isn’t virtual, and B derives from A and intro-
duces a new B.DoWork that hides the base method, then calling DoWork on a reference to B will call B.DoWork,
and calling DoWork on a reference to A obtained by casting a B reference to an A reference will call A.DoWork.
This behavior is nonintuitive in object-oriented systems. Just because the language allows you to do something
does not mean that it’s the correct thing to do. Now you see why the compiler warning exists in the first place.
In the following example, IEditBox, for one reason or another, needs to declare a Paint method
whose signature is exactly that of the one in IUIControl. Therefore, it must use the new keyword:
using System;
public interface IUIControl
{
void Paint();
}
public interface IEditBox : IUIControl
{
new void Paint();
}
public interface IDropList : IUIControl
{
}
public class ComboBox : IEditBox, IDropList
{
public void Paint() {
Console.WriteLine( "ComboBox.IEditBox.Paint()" );
}
}

147.
128 CHAPTER 5 ■ INTERFACES AND CONTRACTS
public class EntryPoint
{
static void Main() {
ComboBox cb = new ComboBox();
cb.Paint();
((IEditBox)cb).Paint();
((IDropList)cb).Paint();
((IUIControl)cb).Paint();
}
}
In all calls to the Paint method in the Main method, it always boils down to a call on
ComboBox.Paint. That’s because the set of required methods that ComboBox must implement are
merged together into one set. Both signatures from Paint—the one from IEditBox and the one from
IUIControl—are merged into one slot in the requirements list. In the end, they both map to
ComboBox.Paint. You can change this behavior by using explicit interface implementation (which I
discuss in the section “Explicit Interface Implementation”), where ComboBox can elect to implement
two different versions of Paint—one for IEditBox and one for IUIControl.
When the IEditBox interface declares the Paint method using the new keyword, it is said to hide
the Paint method declared in IUIControl. When you call ComboBox.Paint, it will invoke the
IEditBox.Paint method as if it chose the IEditBox path in the inheritance hierarchy over the
IDropList path. In essence, any time any path hides a method, it hides the method for all paths.
This will become clearer when I discuss how the compiler matches up a concrete method with an
interface method when you call an interface method. That process is called interface mapping, and
I cover it in the section titled “Interface Member Matching Rules” later in this chapter.
Implementing Interfaces
When implementing interfaces in C#, you have the choice of implementing them one of two ways.
By default, interface implementations are said to be implicit implementations. The method imple-
mentations are part of the public contract of the class but also implement the interface implicitly.
Alternatively, you can implement the interface explicitly, whereby the method implementations are
private to the implementing class and don’t become part of the public interface. Explicit implemen-
tation provides some flexibility, especially when implementing two interfaces that have methods
with the same name in them.
Implicit Interface Implementation
When a concrete type implements the methods in inherited interfaces, and those methods are
marked public, it’s known as implicit interface implementation. What good is it to say that a con-
crete type implements the contract of a specific interface if a consumer of the objects of that type
cannot call the methods in that contract? For example, the following is not valid:
public interface IUIControl
{
void Paint();
}
public class StaticText : IUIControl
{
void Paint(); // !!! WON'T COMPILE !!!
}

148.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 129
If you try to compile this, the compiler will immediately complain that the StaticText class
doesn’t implement all of the methods of the derived interfaces—in this case, IUIControl. In order
for this to work, you could rewrite it as in the following:
public interface IUIControl
{
void Paint();
}
public class StaticText : IUIControl
{
public void Paint(); //Notice that we've added 'public' to the method declaration
}
Now, not only will the code compile, but when you call Paint through a reference to StaticText
or through a reference to IUIControl, the StaticText.Paint method will be called. Thus, consumers
can treat instances of StaticText polymorphically as instances of type IUIControl.
Explicit Interface Implementation
When a concrete type implements an interface implicitly, the interface methods also become part
of the public contract of the concrete type itself. However, you might not always want the interface
method implementations to become part of the public interface of the class that implements the
interface. For example, the System.IO.FileStream class implements IDisposable, but you cannot
call Dispose through an instance of FileStream. Instead, you must first cast the reference to the
FileStream object to an IDisposable interface, and then you may call Dispose. When you need this
behavior in your own types, you must implement the interfaces using explicit interface implemen-
tation.
■Note To achieve the same result as Dispose using a reference to a FileStream object, you must call
FileStream.Close. In the implementation of FileStream.Close calls straight through to the internal implemen-
tation of the Dispose method. Why did the designers of FileStream do this? Most likely because it makes more
linguistic sense to “close” a file rather than “dispose of” it.
You can also use explicit implementation to provide separate implementations for overlapping
methods in inherited interfaces. Let’s look again at the ComboBox example from the previous section.
If you want to provide a separate implementation for IEditBox.Paint and IUIControl.Paint inside
ComboBox, you can do that using explicit interface implementation, as shown here:
using System;
public interface IUIControl
{
void Paint();
}
public interface IEditBox : IUIControl
{
new void Paint();
}

149.
130 CHAPTER 5 ■ INTERFACES AND CONTRACTS
public interface IDropList : IUIControl
{
}
public class ComboBox : IEditBox, IDropList
{
void IEditBox.Paint() {
Console.WriteLine( "ComboBox.IEditBox.Paint()" );
}
void IUIControl.Paint() {
Console.WriteLine( "ComboBox.IUIControl.Paint()" );
}
public void Paint() {
((IUIControl)this).Paint();
}
}
public class EntryPoint
{
static void Main() {
ComboBox cb = new ComboBox();
cb.Paint();
((IEditBox)cb).Paint();
((IDropList)cb).Paint();
((IUIControl)cb).Paint();
}
}
Pay attention to the change in syntax. Now, ComboBox has three implementations for Paint. One
is specific for the IEditBox interface, the other is specific to the IUIControl interface, and the last
one is simply there for convenience to provide a Paint method for the public interface of the
ComboBox class. When you implement interface methods explicitly, not only do you add the interface
name followed by a dot before the method name, but you also remove the access modifier. This
keeps it from being in the public contract for ComboBox. However, the explicit interface implementa-
tions aren’t exactly private in the sense that you can call them after you cast the instance of the
ComboBox to the required interface type. In my implementation of ComboBox.Paint—the one that
contributes to the ComboBox public contract—I get to choose which version of Paint to call. In this
case, I chose to call IUIControl.Paint. I could just as easily have chosen to implement
IEditBox.Paint explicitly and IUIControl.Paint implicitly, and then I wouldn’t have needed the
third implementation of Paint. But in this case, I believe it adds more flexibility and makes more
sense for ComboBox to implement its own Paint method so that it can reuse the other and add value
to it at the same time. If you compile and run the previous example, you’ll see output similar to the
following:
ComboBox.IUIControl.Paint()
ComboBox.IEditBox.Paint()
ComboBox.IUIControl.Paint()
ComboBox.IUIControl.Paint()

150.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 131
Granted, this example is rather contrived, but it’s meant to exhibit the intricacies of explicit
interface implementation and member hiding during multiple interface inheritance.
Overriding Interface Implementations in Derived Classes
Suppose you have a handy implementation of ComboBox, as in the previous section, and the imple-
menter decided not to seal the class so that you can inherit from it.
■Note I suggest that you declare all classes sealed unless the designer explicitly intends them to be inherited
from. In Chapter 4 I explain in detail why this is desired.
Now, suppose you create a new class, FancyComboBox, and you want it to paint itself better,
maybe with some new psychedelic theme. You could try something like this:
using System;
public interface IUIControl
{
void Paint();
void Show();
}
public interface IEditBox : IUIControl
{
void SelectText();
}
public interface IDropList : IUIControl
{
void ShowList();
}
public class ComboBox : IEditBox, IDropList
{
public void Paint() { }
public void Show() { }
public void SelectText() { }
public void ShowList() { }
}
public class FancyComboBox : ComboBox
{
public void Paint() { }
}
public class EntryPoint
{
static void Main() {
FancyComboBox cb = new FancyComboBox();
}
}

151.
132 CHAPTER 5 ■ INTERFACES AND CONTRACTS
However, the compiler will promptly warn you that FancyComboBox.Paint hides ComboBox.Paint
and that you probably meant to use the new keyword. This will surprise you if you were assuming
that methods that implement interface methods are automatically virtual. They are not in C#.
■Note Under the covers, interface method implementations are called as if they are virtual methods. Any inter-
face method implementations not marked virtual in the C# code are marked as virtual and final (sealed) in
the generated IL. If the method is marked virtual in the C# code, then the method is marked with virtual and
newslot (new) in the generated IL. This can be the source of some confusion.
When faced with a problem such as this, you have a couple of options. One option is to have
FancyComboBox reimplement the IUIControl interface:
using System;
public interface IUIControl
{
void Paint();
void Show();
}
public interface IEditBox : IUIControl
{
void SelectText();
}
public interface IDropList : IUIControl
{
void ShowList();
}
public class ComboBox : IEditBox, IDropList
{
public void Paint() {
Console.WriteLine( "ComboBox.Paint()" );
}
public void Show() { }
public void SelectText() { }
public void ShowList() { }
}
public class FancyComboBox : ComboBox, IUIControl
{
public new void Paint() {
Console.WriteLine( "FancyComboBox.Paint()" );
}
}
public class EntryPoint
{
static void Main() {
FancyComboBox cb = new FancyComboBox();
cb.Paint();

152.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 133
((IUIControl)cb).Paint();
((IEditBox)cb).Paint();
}
}
In this example, note a couple of things. First, FancyComboBox lists IUIControl in its inheritance
list. That’s how you indicate that FancyComboBox is planning to reimplement the IUIControl inter-
face. Had IUIControl inherited from another interface, FancyComboBox would have had to
reimplement the methods from those inherited interfaces as well. I also had to use the new keyword
for FancyComboBox.Paint, since it hides CombBox.Paint. This wouldn’t have been a problem had
ComboBox implemented the IUIControl.Paint method explicitly, since it wouldn’t have been part of
the ComboBox public contract. When the compiler matches class methods to interface methods, it
also considers public methods of base classes. In reality, FancyComboBox could have indicated that it
reimplements IUIControl but without redeclaring any methods, as the compiler would have just
wired up the interface to the base class methods. Of course, doing so would be pointless, since the
reason you reimplement an interface in a derived class is to modify behavior.
■Note The ability to reimplement an interface is a powerful one. It highlights the vast differences between the
way C# and the CLR handle interfaces and the C++ treatment of interfaces as abstract class definitions. Gone are
the intricacies of C++ vtables, as well as the question of when you should use C++ virtual inheritance. As I’ve said
before, and don’t mind saying again, C#/CLR interfaces are nothing more than contracts that say, “You, Mr. Con-
crete Class, agree to implement all of these methods in said contract, a.k.a. interface.”
When you implement methods in an interface contract implicitly, they must be publicly acces-
sible. As long as they meet those requirements, they can also have other attributes, including the
virtual keyword. In fact, implementing the IUIControl interface in ComboBox using virtual methods
as opposed to nonvirtual methods would make the previous problem a lot easier to solve, as
demonstrated here:
using System;
public interface IUIControl
{
void Paint();
void Show();
}
public interface IEditBox : IUIControl
{
void SelectText();
}
public interface IDropList : IUIControl
{
void ShowList();
}
public class ComboBox : IEditBox, IDropList
{
public virtual void Paint() {
Console.WriteLine( "ComboBox.Paint()" );
}
public void Show() { }

153.
134 CHAPTER 5 ■ INTERFACES AND CONTRACTS
public void SelectText() { }
public void ShowList() { }
}
public class FancyComboBox : ComboBox
{
public override void Paint() {
Console.WriteLine( "FancyComboBox.Paint()" );
}
}
public class EntryPoint
{
static void Main() {
FancyComboBox cb = new FancyComboBox();
cb.Paint();
((IUIControl)cb).Paint();
((IEditBox)cb).Paint();
}
}
In this case, FancyComboBox doesn’t have to reimplement IUIControl. It merely has to override
the virtual ComboBox.Paint method. It’s much cleaner for ComboBox to declare Paint virtual in the
first place. Any time you have to use the new keyword to keep the compiler from warning you about
hiding a method, consider whether the method of the base class should be virtual.
■Caution Hiding methods causes confusion and makes code hard to follow and debug. Again, just because the
language allows you to do something does not mean that you should.
Of course, the implementer of ComboBox would have had to think ahead and realize that some-
one might derive from ComboBox, and anticipated these issues. In my opinion, it’s best to seal the
class and avoid any surprises by people who attempt to derive from your class when you never
meant for it to be derived from. Imagine who they will scream at when they encounter a problem.
Have you ever used Microsoft Foundation Classes (MFC) in the past and come to a point where
you’re pulling your hair out because you’re trying to derive from an MFC class and wishing a partic-
ular method were virtual? In that case, it’s easy to blame the designers of MFC for being so flagrantly
thoughtless and not making the method virtual when, in reality, it’s more accurate to consider the
fact that they probably never meant for you to derive from the class in the first place. Chapter 13
describes how containment rather than inheritance is the key in situations like these.
Beware of Side Effects of Value Types Implementing Interfaces
All the examples so far have shown how classes may implement interface methods. In fact, value
types can implement interfaces as well. However, there’s one major side effect to doing so. If you
cast a value type to an interface type, you’ll incur a boxing penalty. Even worse, if you modify the
value via the interface reference, you’re modifying the boxed copy and not the original. Given the
intricacies of boxing that I cover in Chapters 4 and 13, you may consider that to be a bad thing.

154.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 135
As an example, consider System.Int32. I’m sure you’ll agree that it is one of the most basic
types in the CLR. However, you may or may not have noticed that it also implements several inter-
faces: IComparable, IFormattable, and IConvertible. Consider System.Int32’s implementation of
IConvertible, for example. All of the methods are implemented explicitly. IConvertible has quite a
few methods declared within it. However, none of those are in the public contract of System.Int32. If
you want to call one of those methods, you must first cast your Int32 value type into an IConvertible
interface reference. Only then may you call one of the IConvertible methods. And of course, since
interface-typed variables are references, the Int32 value must be boxed.
PREFER THE CONVERT CLASS OVER ICONVERTIBLE
Even though I use the IConvertible interface implemented by a value type as an example to prove a point, the
documentation urges you not to call the methods of IConvertible on Int32; rather, it recommends using the
Convert class instead. The Convert class provides a collection of methods with many overloads of common
types for converting a value to just about anything else, including custom types (by using Convert.ChangeType),
and it makes your code easier to change later. For example, if you have the following
int i = 0;
double d = Int32.ToDouble(i);
and you want to change the type of i to long, you have to also change the Int32 type to Int64. On the other
hand, if you write
int i = 0;
double d = Convert.ToDouble(i);
then all you have to do is change the type of i.
Interface Member Matching Rules
Each language that supports interface definitions has rules about how it matches up method imple-
mentations with interface methods. The interface member matching rules for C# are pretty
straightforward and boil down to some simple rules. However, to find out which method actually
gets called at run time, you need to consider the rules of the CLR as well. These rules are only
relevant at compile time. Suppose you have a hierarchy of classes and interfaces. To find the imple-
mentation for SomeMethod on ISomeInterface, start at the bottom of the hierarchy and search for the
first type that implements the interface in question. In this case, that interface is ISomeInterface.
This is the level at which the search for a matching method begins. Once you find the type, recur-
sively move up through the type hierarchy and search for a method with the matching signature,
while first giving preference to explicit interface member implementations. If you don’t find any,
look for public instance methods that match the same signature.
The C# compiler uses this algorithm when matching up method implementations with inter-
face implementations. The method that it picks must be a public instance method or an explicitly
implemented instance method, and it may or may not be tagged in C# as virtual. However, when
the IL code is generated, all interface method calls are made through the IL callvirt instruction.

155.
136 CHAPTER 5 ■ INTERFACES AND CONTRACTS
So, even though the method is not necessarily marked as virtual in the C# sense, the CLR treats
interface calls as virtual. Be sure that you don’t confuse these two concepts. If the method is marked
as virtual in C# and has methods that override it in the types below it, the C# compiler will gener-
ate vastly different code at the point of call. Be careful, as this can be quite confusing, as shown by
the following contrived example:
using System;
public interface I
{
void Go();
}
public class A : I
{
public void Go() {
Console.WriteLine( "A.Go()" );
}
}
public class B : A
{
}
public class C : B, I
{
public new void Go() {
Console.WriteLine( "C.Go()" );
}
}
public class EntryPoint
{
static void Main() {
B b1 = new B();
C c1 = new C();
B b2 = c1;
b1.Go();
c1.Go();
b2.Go();
((I)b2).Go();
}
}
The output from this example is as follows:
A.Go()
C.Go()
A.Go()
C.Go()

156.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 137
The first call, on b1, is obvious, as is the second call on c1. However, the third call, on b2, is not
obvious at all. Since the A.Go method is not marked as virtual, the compiler generates code that
calls A.Go. The fourth and final call is almost equally confusing, but not if you consider the fact that
the CLR handles virtual calls on class type references and calls on interface references significantly
differently. The generated IL for the fourth call makes a call to I.Go, which, in this case, boils down
to a call to C.Go, since b2 is actually a C, and C reimplements I.
You have to be careful when searching for the actual method that gets called, since you must
consider whether the type of your reference is a class type or an interface type. The C# compiler
generates IL virtual method calls in order to call through to interfaces methods, and the CLR uses
interface tables internally to achieve this.
■Note C++ programmers must realize that interface tables are different from C++ vtables. Each CLR type only
has one method table, whereas a C++ instance of a type may have multiple vtables.
The contents of these interface tables are defined by the compiler using its method-matching
rules. For more detailed information regarding these interface tables, see Don Box and Chris Sells’
Essential .NET, Volume I: The Common Language Runtime (Boston, MA: Addison-Wesley Profes-
sional, 2002), as well as the CLI standard document itself.
The C# method-matching rules explain the situation I discussed previously in the section
“Interface Inheritance and Member Hiding.” Hiding a method in one hierarchical path of a dia-
mond-shaped hierarchy hides the method in all inheritance paths. The rules state that when you
walk up the hierarchy, you short-circuit the search once you find a method at a particular level.
These simple rules also explain how interface reimplementation can greatly affect the method-
matching process, thus short-circuiting the compiler’s search during its progression up the
hierarchy. Let’s consider an example of this in action:
using System;
public interface ISomeInterface
{
void SomeMethod();
}
public interface IAnotherInterface : ISomeInterface
{
void AnotherMethod();
}
public class SomeClass : IAnotherInterface
{
public void SomeMethod() {
Console.WriteLine( "SomeClass.SomeMethod()" );
}
public virtual void AnotherMethod() {
Console.WriteLine( "SomeClass.AnotherMethod()" );
}
}

157.
138 CHAPTER 5 ■ INTERFACES AND CONTRACTS
public class SomeDerivedClass : SomeClass
{
public new void SomeMethod() {
Console.WriteLine( "SomeDerivedClass.SomeMethod()" );
}
public override void AnotherMethod() {
Console.WriteLine( "SomeDerivedClass.AnotherMethod()" );
}
}
public class EntryPoint
{
static void Main() {
SomeDerivedClass obj = new SomeDerivedClass();
ISomeInterface isi = obj;
IAnotherInterface iai = obj;
isi.SomeMethod();
iai.SomeMethod();
iai.AnotherMethod();
}
}
Let’s apply the search rules to each method call in Main in the previous example. In all cases,
I’ve implicitly converted an instance of SomeDerivedClass to references of the two interfaces,
ISomeInterface and IAnotherInterface. I place the first call to SomeMethod through ISomeInterface.
First, walk up the class hierarchy, starting at the concrete type of the reference, looking for the first
class that implements this interface or an interface derived from it. Doing so leaves us at the
SomeClass implementation, because, even though it does not implement ISomeInterface directly, it
implements IAnotherInterface, which derives from ISomeInterface. Thus, we end up calling
SomeClass.SomeMethod. You may be surprised that SomeDerivedClass.SomeMethod was not called. But
if you follow the rules, you’ll notice that you skipped right over SomeDerivedClass, looking for the
bottom-most class in the hierarchy that implements the interface. In order for SomeDerivedClass.
SomeMethod to be called instead, SomeDerivedClass would need to reimplement ISomeInterface. The
second call to SomeMethod through the IAnotherInterface reference follows exactly the same path
when finding the matching method.
Things get interesting in the third call in Main, where you call AnotherMethod through a refer-
ence to IAnotherInterface. As before, the search begins at the bottom-most class in the hierarchy
that implements this interface, inside SomeClass. Since SomeClass has a matching method signature,
your search is complete. However, the twist is that the matching method signature is declared
virtual. So when the call is made, the virtual method mechanism places execution within
SomeDerivedClass.AnotherMethod. It’s important to note that AnotherMethod doesn’t change the rules
for interface method matching, even though it is implemented virtually. It’s not until after the inter-
face method has been matched that the virtual nature of the method has an impact on exactly
which implementation gets called at run time.
■Note Interface method matching is applied statically at compile time. Virtual method dispatching happens
dynamically at run time. You should note the difference between the two when trying to determine which method
implementation gets invoked.

158.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 139
The output from the previous example code is as follows:
SomeClass.SomeMethod()
SomeClass.SomeMethod()
SomeDerivedClass.AnotherMethod()
Explicit Interface Implementation with
Value Types
Many times, you’ll encounter general-use interfaces that take parameters in the form of a reference
to System.Object. These interfaces are typically general usage, nongeneric interfaces. For example,
consider the IComparable interface, which looks like the following:
public interface IComparable
{
int CompareTo( object obj );
}
■Note NET 2.0 added support for IComparable<T>, which you should always consider using along with
IComparable in order to offer greater type safety.
It makes sense that the CompareTo method accepts such a general type, because it would be
nice to be able to pass it just about anything to see how the object in question compares to the one
that implements it. When dealing strictly with reference types, there’s really no loss of efficiency
here, since conversion to and from System.Object on reference types is free for all practical pur-
poses. But things get a little sticky when you consider value types. Let’s look at some code to see the
gory details:
using System;
public struct SomeValue : IComparable
{
public SomeValue( int n ) {
this.n = n;
}
public int CompareTo( object obj ) {
if( obj is SomeValue ) {
SomeValue other = (SomeValue) obj;
return n - other.n;
} else {
throw new ArgumentException( "Wrong Type!" );
}
}
private int n;
}

159.
140 CHAPTER 5 ■ INTERFACES AND CONTRACTS
public class EntryPoint
{
static void Main() {
SomeValue val1 = new SomeValue( 1 );
SomeValue val2 = new SomeValue( 2 );
Console.WriteLine( val1.CompareTo(val2) );
}
}
In the innocuous call to WriteLine in Main, you see val1 being compared to val2. But look
closely at how many boxing operations are required. First, since CompareTo takes an object refer-
ence, val2 must be boxed at the point of the method call. Had you implemented the CompareTo
method explicitly, you would have needed to cast the val1 value into an IComparable interface,
which would incur a boxing penalty. But once you’re inside the CompareTo method, the boxing night-
mare is still not over. Ouch. Thankfully, you can employ an optimization when SomeValue is
compared to certain types. Take, for example, the case where an instance of SomeValue is compared
to another SomeValue instance. You can provide a type-safe version of the CompareTo method to get
the job done, as shown here:
using System;
public struct SomeValue : IComparable
{
public SomeValue( int n ) {
this.n = n;
}
int IComparable.CompareTo( object obj ) {
if( obj is SomeValue ) {
SomeValue other = (SomeValue) obj;
return n - other.n;
} else {
throw new ArgumentException( "Wrong Type!" );
}
}
public int CompareTo( SomeValue other ) {
return n - other.n;
}
private int n;
}
public class EntryPoint
{
static void Main() {
SomeValue val1 = new SomeValue( 1 );
SomeValue val2 = new SomeValue( 2 );
Console.WriteLine( val1.CompareTo(val2) );
}
}

160.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 141
In this example, there is absolutely no boxing in the call to CompareTo. That’s because the com-
piler picks the one with the best match for the type. In this case, since you implement IComparable.
CompareTo explicitly, there is only one overload of CompareTo in the public contract of SomeValue. But
even if IComparable.CompareTo had not been implemented explicitly, the compiler would have still
chosen the type-safe version. The typical pattern involves hiding the typeless versions from casual
use so that the user must do a boxing operation explicitly. This operation converts the value to an
interface reference in order to get to the typeless version.
The bottom line is that you’ll definitely want to follow this idiom any time you implement an
interface on a value type where you determine that you can define overloads with better type safety
than the ones listed in the interface declaration. Avoiding unnecessary boxing is always a good
thing, and your users will appreciate your detail and commitment to efficiency.
Versioning Considerations
The concept of versioning is essentially married to the concept of interfaces. When you create,
define, and publish an interface, you’re defining a contract—or viewed in more rigid terms—a stan-
dard. Any time you have a standard form of communication, you must adhere to it so as not to
break any clients of that contract. For example, consider the 802.11 standard upon which many
WiFi devices are based. It’s important that access points from one vendor work with devices from as
many vendors as possible. This works as long as all of the vendors agree and follow the standard.
Can you imagine the chaos that would erupt if a single vendor’s WiFi card were the only one that
worked at your favorite Pacific Northwest-based coffee shops? It would be pandemonium. There-
fore, we have standards.
Now, nothing states that the standard cannot be augmented. Certain manufacturers do just
that. In some cases, if you use Manufacturer A’s access point with the same manufacturer’s wireless
card, you can achieve speeds greater than those supported by the standard. However, note that
those augmentations only augment, and don’t alter, the standard. Similarly, nothing states that a
standard cannot be revised. Standards normally have version numbers attached to them, and when
they are revised, the version number is incremented. Most of the time, devices that implement the
new version also support the previous version. Although not required, it’s a good move for those
manufacturers who want to achieve maximum market saturation. In the 802.11 example, 802.11a,
802.11b, and 802.11g represent the various revisions of the standard.
The point of this example is that you should apply these same rules to your interfaces once you
publish them. You don’t normally create interfaces unless you’re doing so to allow entities to inter-
act with each other using a common contract. So, once you’re done with creating that contract, do
the right thing and slap a version number on it. You can create your version number in many ways.
For new revisions of your interface, you could simply give it a new name—the key point being that
you never change the original interface. You’ve probably already seen exactly the same idiom in use
in the COM world. Typically, if someone, probably Microsoft, decides they have a good reason to
augment the behavior of an interface, you’ll find a new interface definition ending with either an
Ex suffix or a numeric suffix. At any rate, it’s a completely different interface than the previous one,
even though the contract of the new interface could inherit the original interface, and the imple-
mentations may be shared.
■Note Current design guidelines in wide use suggest that if you need to create an augmented interface based
upon another, you shouldn’t use the suffix Ex as COM does. Instead, you should follow the interface name with
an ordinal. So, if the original interface is ISomeContract, then you should name the augmented interface
ISomeContract2.

161.
142 CHAPTER 5 ■ INTERFACES AND CONTRACTS
In reality, if your interface definitions live within a versioned assembly, you may define a newer
version of the same interface, even with the same name, in an assembly with the same name but
with a new version number. The assembly loader will resolve and load the proper assembly at run
time. However, this practice can become confusing to the developers using your interface, since
they now have to be more explicit about which assembly to reference at build time.
Contracts
Many times, you need to represent the notion of a contract when designing an application or a
system. A programming contract is no different than any other contract. You usually define a con-
tract to facilitate communication between two types in your design. For example, suppose you
have a virtual zoo, and in your zoo, you have animals. Now, an instance of your ZooKeeper needs a
way to communicate to the collection of these ZooDweller objects that they should fly to a specific
location. Ignoring the fact that they had all better be fairly obedient, they had also better be able to
fly. However, not all animals can fly, so clearly not all of the types in the zoo can support this flying
contract.
Contracts Implemented with Classes
Let’s consider one way to manage the complexity of getting these creatures to fly from one location
to the next. First, consider the assumptions that you can make here. Let’s say that this Zoo can have
only one ZooKeeper. Second, let’s assume that you can model the locations within this Zoo by using a
simple two-dimensional Point structure. It starts to look as though you can model this system by
the following code:
using System;
using System.Collections.ObjectModel;
namespace CityOfShanoo.MyZoo
{
public struct Point
{
public double X;
public double Y;
}
public abstract class ZooDweller
{
public void EatSomeFood() {
DoEatTheFood();
}
protected abstract void DoEatTheFood();
}
public sealed class ZooKeeper
{
public void SendFlyCommand( Point to ) {
// Implementation removed for clarity.
}
}

162.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 143
public sealed class Zoo
{
private static Zoo theInstance = new Zoo();
public static Zoo GetInstance() {
return theInstance;
}
private Zoo() {
creatures = new Collection<ZooDweller>();3
zooKeeper = new ZooKeeper();
}
public ZooKeeper ZooKeeper {
get {
return zooKeeper;
}
}
private ZooKeeper zooKeeper;
private Collection<ZooDweller> creatures;
}
}
Since there can only be one zoo in the CityOfShanoo, the Zoo is modeled as a singleton object,
and the only way to obtain the instance of the one and only Zoo is to call Zoo.GetInstance. Also, you
can get a reference to the ZooKeeper via the Zoo.ZooKeeper property. It is common practice in the
.NET Framework to name the property after the custom type that it represents.
■Note The Singleton design pattern is one of the most widely used and well-known design patterns. Essentially,
the pattern allows only one instance of its type to exist at one time. Many people still argue about the best way to
implement it. Implementation difficulty varies depending on the language you’re using. But in general, some
static private instance within the type declaration is lazily initialized at the point of first access. The previous
implementation of the Zoo class does that, since the static initializer is not called until the type is first accessed
through the GetInstance method.
This initial design defines the ZooDweller as an abstract class that implements a method
EatSomeFood. The ZooDweller uses the Non-Virtual Interface (NVI) pattern described in Chapter 13,
where the virtual method that the concrete type overrides is declared protected rather than public.
It’s important to note that the ZooDweller type does, in fact, define a contract even though it is
not an interface. The contract, as written, states that any type that derives from ZooDweller must
implement EatSomeFood. Any code that uses a ZooDweller instance can be guaranteed that this
method is supported.
■Note Notice that an interface is not required in order to define a contract.
3. If the syntax of Collection<ZooDweller> looks foreign to you, don’t worry. It is a declaration of a collection
based on a generic collection type. I will cover generics in detail in Chapter 11.

163.
144 CHAPTER 5 ■ INTERFACES AND CONTRACTS
So far, this design is missing a key operation, and that is the one commanding the creatures to
fly to a destination within the zoo. Clearly, you cannot put a Fly method on the ZooDweller type,
because not all animals in the zoo can fly. You must express this contract in a different way.
Interface Contracts
Since not all creatures in the zoo can fly, an interface provides an excellent mechanism for defining
the flying contract. Consider the following modifications to the example from the previous section:
public interface IFly
{
void FlyTo( Point destination );
}
public class Bird : ZooDweller, IFly
{
public void FlyTo( Point destination ) {
Console.WriteLine( "Flying to ({0}. {1}).",
destination );
}
protected override void DoEatTheFood() {
Console.WriteLine( "Eating some food." );
}
}
Now, using the interface IFly, Bird is defined such that it derives from ZooDweller and imple-
ments IFly.
■Note If you intend to have various bird types derive from Bird, and those various birds have different imple-
mentations of ToFly, consider using the NVI pattern. You could introduce a protected virtual method named
DoFlyTo that the base types override, while having Bird.FlyTo call through to DoFlyTo. Read the section titled
“Use the Non-Virtual Interface (NVI) Pattern” in Chapter 13 for more information on why this is a good idea.
Choosing Between Interfaces and Classes
The previous section on contracts shows that you can implement a contract in multiple ways. In the
C# and .NET environments, the two main methods are interfaces and classes, where the classes
may even be abstract. In the zoo example, it’s pretty clear as to when you should use an interface
rather than an abstract class to define an interface. However, the choice is not always so clear, so
let’s consider the ramifications of both methods.
Since C# supports abstract classes, you can easily model a contract using abstract classes. But
which method is more powerful? And which is more appropriate? These are not easy questions to
answer, although the guideline tends to be that you should prefer a class if possible. Let’s explore this.

164.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 145
■Note Since COM became so popular, some developers have a false notion that the only way to define a con-
tract is by defining an interface. It’s easy to jump to that conclusion when moving from the COM environment to
the C# environment, simply because the basic building block of COM is the interface, and C# and .NET support
interfaces natively. However, jumping to that conclusion would be perilous to your designs.
If you’re familiar with COM and you’ve created any serious COM projects in the past, you most certainly
implemented the COM objects using C++. You probably even used the Active Template Library (ATL) to shield your-
self from the intricacies of the mundane COM development tasks. But at the core of it all, how does C++ model
COM interfaces? The answer is with abstract classes.
When you implement a contract by defining an interface, you’re defining a versioned contract.
That means that the interface, once released, must never change, as if it were cast into stone. Sure,
you could change it later, but you would not be very popular when all of your clients’ code fails to
compile with the modified interface. Consider the following example:
public interface IMyOperations
{
void Operation1();
void Operation2();
}
// Client class
public class ClientClass : IMyOperations
{
public void Operation1() { }
public void Operation2() { }
}
Now, you’ve released this wonderful IMyOperations interface to the world, and thousands of
clients have implemented it. Then, you start getting requests from your clients asking for
Operation3 support in your library. It seems like it would be easy enough to simply add Operation3
to the IMyOperations interface, but that would be a terrible mistake. If you add another operation to
IMyOperations, then all of a sudden your clients’ code won’t compile until they implement the new
operation. Also, code in another assembly that knows about the newer IMyOperations could attempt
to cast a ClientClass instance into an IMyOperations reference and then call Operation3, thus creat-
ing a runtime failure. Clearly, you shouldn’t modify an already published interface.
■Caution Never modify an already publicly published interface declaration.
You could also address this problem by defining a completely new interface, say
IMyOperations2. However, ClientClass would need to implement both interfaces in order to get
the new behavior, as shown here:
public interface IMyOperations
{
void Operation1();
void Operation2();
}

165.
146 CHAPTER 5 ■ INTERFACES AND CONTRACTS
public interface IMyOperations2
{
void Operation1();
void Operation2();
void Operation3();
}
// Client class
public class ClientClass : IMyOperations,
IMyOperations2
{
public void Operation1() { }
public void Operation2() { }
public void Operation3() { }
}
public class AnotherClass
{
public void DoWork( IMyOperations ops ) {
}
}
Modifying ClientClass to support the new operation from IMyOperations2 isn’t terribly diffi-
cult, but what about the code that already exists, such as what is shown in AnotherClass? The
problem is that the DoWork method accepts a type of IMyOperations. In order to make it to where the
new Operation3 method can be called, the prototype of DoWork must change, or the code within it
must do a cast to IOperations2, which could fail at run time. Since you want the compiler to be able
to catch as many type bugs as possible, it would be better if you change the prototype of DoWork to
accept a type of IMyOperations2.
■Note If you define your original IMyOperations interface within a fully versioned, strongly named assembly,
then you can get away with creating a new interface with the same name in a new assembly, as long as the ver-
sion of the new assembly is different. Although the .NET Framework supports this explicitly, it doesn’t mean you
should do it without careful consideration, since introducing two IMyOperations interfaces that differ only by ver-
sion number of the containing assembly could be confusing to your clients.
That was a lot of work just to make a new operation available to clients. Let’s examine the same
situation, except using an abstract class:
public abstract class MyOperations
{
public virtual void Operation1() {
}
public virtual void Operation2() {
}
}
// Client class
public class ClientClass : MyOperations
{

166.
CHAPTER 5 ■ INTERFACES AND CONTRACTS 147
public override void Operation1() { }
public override void Operation2() { }
}
public class AnotherClass
{
public void DoWork( MyOperations ops ) {
}
}
MyOperations is a base class of ClientClass. One advantage is that MyOperations can contain
default implementations if it wants to. Otherwise, the virtual methods in MyOperations could have
been declared abstract. The example also declares MyOperations abstract, since it makes no sense
for clients to be able to create instances of MyOperations. Now, let’s suppose you want to add a new
Operation3 method to MyOperations, and you don’t want to break existing clients. You can do this as
long as the added operation is not abstract, such that it forces changes on derived types, as shown
here:
public abstract class MyOperations
{
public virtual void Operation1() {
}
public virtual void Operation2() {
}
public virtual void Operation3() {
// New default implementation
}
}
// Client class
public class ClientClass : MyOperations
{
public override void Operation1() { }
public override void Operation2() { }
}
public class AnotherClass
{
public void DoWork( MyOperations ops ) {
ops.Operation3();
}
}
Notice that the addition of MyOperations.Operation3 doesn’t force any changes upon
ClientClass, and AnotherClass.DoWork can make use of Operation3 without making any changes
to the method declaration. This technique doesn’t come without its drawbacks, though. You’re
restricted by the fact that the managed runtime only allows a class to have one base class. Since
ClientClass has to derive from MyOperations to get the functionality, it uses up its only inheritance
ticket. This may put complicated restrictions upon your client code. For example, what if one of
your clients needs to create an object for use with .NET Remoting? In order to do so, the class must
derive from MarshalByRefObject.

167.
148 CHAPTER 5 ■ INTERFACES AND CONTRACTS
Sometimes, it’s tricky to find a happy medium when deciding between interfaces and classes. I
use the following rules of thumb:
• If modeling an is-a relationship, use a class: If it makes sense to name your contract with a
noun, then you should probably model it with a class.
• If modeling an IMPLEMENTS relationship, use an interface: If it makes sense to name your
contract with an adjective, as if it is a quality, then you should probably model it as an inter-
face.
• Consider wrapping up your interface and abstract class declarations in a separate assembly:
Implementations in other assemblies can then reference this separate assembly.
• If possible, prefer classes over interfaces: This can be helpful for the sake of extensibility.
You can see examples of these techniques throughout the .NET Framework Base Class Library
(BCL). Consider using them in your own code as well.
Summary
This chapter introduced you to interfaces and how you can model a well-defined, versioned con-
tract using an interface. Along with showing you the various ways that classes can implement
interfaces, I also described the process that the C# compiler follows when matching up interface
methods to implementations in the implementing class. I described interfaces from the perspective
of reference types and value types—specifically, how expensive boxing operations can cause you
pain when using interfaces on value types. Finally, I spent some time comparing and contrasting
the use of interfaces and classes when modeling contracts between types in your design.
In the next chapter, I’ll explain the intricacies of operator overloading in the C# language and
why you may want to avoid it when creating code used by other .NET languages.

168.
CHAPTER 6
Overloading Operators
C# adopted the capability of operator overloading from C++. Just as you can overload methods,
you can overload operators such as +, -, *, and so on. In addition to overloading arithmetic opera-
tors, you can also create custom conversion operators to convert from one type to another. You can
overload other operators to allow objects to be used in Boolean test expressions.
Just Because You Can Doesn’t Mean You Should
Overloading operators can make certain classes and structs more natural to use. However, over-
loading operators in a slipshod way can make code much more difficult to read and understand.
You must be careful to consider the semantics of a type’s operators. Be careful not to introduce
something that is hard to decipher. Always aim for the most readable code, not only for the next for-
tunate soul who claps eyes on your code, but also for yourself. Have you ever looked at code and
wondered, “Who in their right mind wrote this stuff?!?” only to find out it was you? I know I have.
Another reason not to overload operators is that not all .NET languages support overloaded
operators, because overloading operators is not part of the CLS. Languages that target the CLI aren’t
required to support operator overloading. For example, Visual Basic 2005 was the first .NET version
of the language to support operator overloading. Therefore, it’s important that your overloaded
operators be syntactic shortcuts to functionality provided by other methods that perform the same
operation and can be called by CLS-compliant languages. In fact, I recommend that you design
types as if overloaded operators don’t exist. Then, later on, you can add overloaded operators in
such a way that they simply call the methods you defined that carry the same semantic meaning.
Types and Formats of Overloaded Operators
You define all overloaded operators as public static methods on the classes they’re meant to aug-
ment. Depending on the type of operator being overloaded, the method may accept either one or
two parameters, and it always returns a value. For all operators except conversion operators, one of
the parameter types must be of the same type as the enclosing type for the method. For example, it
makes no sense to overload the + operator on class Complex if it adds two double values together,
and, as you’ll see shortly, it’s impossible.
A typical + operator for a class Complex could look like the following:
public static Complex operator+( Complex lhs, Complex rhs )
Even though this method adds two instances of Complex together to produce a third instance of
Complex, nothing says that one of the parameters cannot be that of type double, thus adding a
double to a Complex instance. Now, how you add a double value to a Complex instance and produce
another Complex instance is for you to decipher. In general, operator overloading syntax follows the
149

169.
150 CHAPTER 6 ■ OVERLOADING OPERATORS
previous pattern, with the + replaced with the operator du jour, and of course, some operators
accept only one parameter.
■Note When comparing C# operators with C++ operators, note that C# operator declarations are more similar to
the friend function technique of declaring C++ operators since C# operators are not instance methods.
There are essentially three different groups of overloadable operators. Unary operators accept
only one parameter. Familiar unary operators include the ++ and -- operators. Binary operators, as
the name implies, accept two parameters and include familiar mathematical operators such as +, -,
/, and *, as well as the familiar comparison operators. Finally, conversion operators define a user-
defined conversion. They must have either the operand or the return value type declared the same
as the containing class or struct type.
Even though operators are static and public, and thus are inherited by derived classes, operator
methods must have at least one parameter in their declaration that matches the enclosing type,
making it impossible for the derived type’s operator method to match the signature of the base class
operator method exactly. For example, the following is not valid:
public class Apple
{
public static Apple operator+( Apple rhs, Apple lhs ) {
// Method does nothing and exists only for example.
return rhs;
}
}
public class GreenApple : Apple
{
// INVALID!! — Won't compile.
public static Apple operator+( Apple rhs, Apple lhs ) {
// Method does nothing and exists only for example.
return rhs;
}
}
If you attempt to compile the previous code, you’ll get the following compiler error:
error CS0563: One of the parameters of a binary operator must be the containing type
Operators Shouldn’t Mutate Their Operands
You already know that operator methods are static. Therefore, it is highly recommended (read:
required) that you do not mutate the operands passed into the operator methods. Instead, you
should create a new instance of the return value type and return the result of the operation. Structs
and classes that are immutable, such as System.String, are perfect candidates for implementing
custom operators. This behavior is natural for operators such as boolean operators, which usually
return a type different from the types passed into the operator.

170.
CHAPTER 6 ■ OVERLOADING OPERATORS 151
■Note “Now wait just a minute!” some of you from the C++ community may be saying. “How in the world can
you implement the postfix and prefix operators ++ and -- without mutating the operand?” The answer lies in the
fact that the postfix and prefix operators as implemented in C# are somewhat different than those of C++. All C#
operators are static, and that includes the postfix and prefix operators, whereas in C++ they are instance methods
that modify the object instance through the this pointer. The beauty of the C# approach is that you don’t have to
worry about implementing two different versions of the ++ operator in order to support both postfix and prefix
incrementing, as you do in C++. The compiler handles the task of making temporary copies of the object to handle
the difference in behavior between postfix and prefix. This is yet another reason why your operators must return
new instances while never modifying the state of the operands themselves. If you don’t follow this practice, you’re
setting yourself up for some major debugging heartbreak.
Does Parameter Order Matter?
Suppose you create a struct to represent simple complex numbers—say, struct Complex—and you
need to add instances of Complex together. It would also be convenient to be able to add a plain old
double to the Complex instance. Adding this functionality is no problem, since you can overload the
operator+ method such that one parameter is a Complex and the other is a double. That declaration
could look like the following:
static public Complex operator+( Complex lhs, double rhs )
With this operator declared and defined on the Complex struct, you can now write code such as
the following:
Complex cpx1 = new Complex( 1.0, 2.0 );
Complex cpx2 = cpx1 + 20.0;
This saves you the time of having to create an extra Complex instance with just the real part set
to 20.0 in order to add it to cpx1. However, suppose you want to be able to reverse the operands on
the operator and do something like the following instead:
Complex cpx2 = 20.0 + cpx1;
If you want to support different orderings of operands of different types, you must provide dif-
ferent overloads of the operator. If you overload a binary operator that uses different parameter
types, you can create a mirror overload—that is, another operator method that reverses the
parameters.
Overloading the Addition Operator
Let’s take a look at a cursory example of a Complex struct, which is by no means a complete imple-
mentation, but merely a demonstration of how to overload operators. Throughout this chapter, I’ll
build upon this example and add more operators to it:
using System;
public struct Complex
{
public Complex( double real, double imaginary ) {
this.real = real;
this.imaginary = imaginary;
}

172.
CHAPTER 6 ■ OVERLOADING OPERATORS 153
Notice that, as recommended, the overloaded operator methods call methods that perform the
same operation. In fact, doing so makes supporting both orderings of operator+ that add a double
to a Complex a snap.
■ If you’re absolutely sure that your type will only be used in a C# environment or in a language that supports
Tip
overloaded operators, then you can forgo this exercise and simply stick with the overloaded operators.
Operators That Can Be Overloaded
Let’s take a quick look at which operators you can overload. Unary operators, binary operators,
and conversion operators are the three general types of operators. It’s impossible to list all of the
conversion operators here, since the set is limitless. Additionally, you can use the one ternary opera-
tor—the familiar ?: operator—for conditional statements, but you cannot overload it directly. Later,
in the “Boolean Operators” section, I describe what you can do to play nicely with the ternary oper-
ator. Table 6-1 lists all of the operators except the conversion operators.
Table 6-1. Unary and Binary Operators
Unary Operators Binary Operators
+ +
- -
! *
~ /
++ %
-- &
true and false |
^
<<
>>
== and !=
> and <
>= and <=
Comparison Operators
The binary comparison operators == and !=, < and >, and >= and <= are all required to be imple-
mented as pairs. Of course, this makes perfect sense, because I doubt there would ever be a case
where you would like to allow users to use operator== and not operator!=. Moreover, if your type
allows ordering via implementation of the IComparable interface or its generic counterpart
IComparable<T>, then it makes the most sense to implement all comparison operators. Implement-
ing these operators is trivial if you follow the canonical guidelines given in Chapters 4 and 13 by
overriding Equals and GetHashCode and implementing IComparable (and optionally IComparable<T>
and IEquatable<T>) appropriately. Given that, overloading the operators merely requires you to call

175.
156 CHAPTER 6 ■ OVERLOADING OPERATORS
Console.WriteLine( "cpx1 < cpx2 ? {0}", cpx1 < cpx2 );
Console.WriteLine( "cpx1 > cpx2 ? {0}", cpx1 > cpx2 );
Console.WriteLine( "cpx1 <= cpx2 ? {0}", cpx1 <= cpx2 );
Console.WriteLine( "cpx1 >= cpx2 ? {0}", cpx1 >= cpx2 );
}
}
Notice that the operator methods merely call the methods that implement Equals and Com-
pareTo. Also, I’ve followed the guideline of providing type-safe versions of the two methods by
implementing IComparable<Complex> and IEquatable<Complex>, since the Complex type is a value
type and I want to avoid boxing if possible.1 Additionally, I implemented the IComparable.CompareTo
method explicitly to give the compiler a bigger type-safety hammer to wield by making it harder for
users to call the wrong one inadvertently. Anytime you can utilize the compiler’s type system to
sniff out errors at compile time rather than run time, you should do so. Had I not implemented
IComparable.CompareTo explicitly, then the compiler would have happily compiled a statement
where I attempt to compare an Apple instance to a Complex instance. Of course, you would expect
an InvalidCastException at run time if you were to attempt something so silly, but again, always
prefer compile-time errors over run time errors.
Conversion Operators
Conversion operators are, as the name implies, operators that convert objects of one type into
objects of another. Conversion operators can allow implicit conversion as well as explicit conver-
sion. Implicit conversion is done with a simple assignment, whereas explicit conversion requires
the familiar casting syntax with the target type of the conversion provided in parentheses immedi-
ately preceding the instance being assigned from.
There is an important restriction on implicit operators. The C# standard requires that implicit
operators do not throw exceptions and that they’re always guaranteed to succeed with no loss of
information. If you cannot meet that requirement, then your conversion must be an explicit one.
For example, when converting from one type to another, there’s always the possibility for loss of
information if the target type is not as expressive as the original type. Consider the conversion from
long to short. Clearly, it’s possible that information could be lost if the value in the long is greater
than the highest value a short can represent. Even though an exception is not thrown by default in
this case if truncation occurs, in some cases it may make sense to throw an exception at run time.
Such a conversion must be an explicit one and require the user to use the casting syntax. Now, sup-
pose you were going the other way and converting a short into a long. Such a conversion will always
succeed, so therefore it can be implicit.
■Note Performing explicit conversions from a type with larger storage to a type with smaller storage may result
in a truncation error if the original value is too large to be represented by the smaller type. For example, if you
explicitly cast a long into a short, you may trigger an overflow situation. By default, your compiled code will
silently perform the truncation. If you compile your code with the /checked+ compiler option, it actually would
throw a System.OverflowException if your explicit conversion from a long to a short caused an overflow. I
recommend that you lean toward building with /checked+ turned on.
Let’s see what kind of conversion operators you should provide for Complex. I can think of at
least one definite case, and that’s the conversion from double to Complex. Definitely, such a
1. I describe this guideline in more detail in Chapter 5 in the section titled “Explicit Interface Implementation
with Value Types.”

177.
158 CHAPTER 6 ■ OVERLOADING OPERATORS
The syntax in the Main method uses conversion operators. However, be careful when imple-
menting conversion operators to make sure that you don’t open up users to any surprises or
confusion with your implicit conversions. It’s difficult to introduce confusion with explicit operators
when the users of your type must use the casting syntax to get it to work. After all, how can users be
surprised when they must provide the type to convert to within parentheses? On the other hand,
inadvertent use or misguided use of implicit conversion can be the source of much confusion. If
you write a bunch of implicit conversion operators that make no semantic sense, I guarantee your
users will find themselves in a confusing spot one day when the compiler decides to do a conver-
sion for them when they least expect it. For example, the compiler could do an implicit conversion
when trying to coerce an argument on a method call. Even if the conversion operators do make
semantic sense, they can still provide plenty of surprises, because the compiler will have the liberty
of silently converting instances of one type to another when it feels it's necessary.
C# requires that you explicitly write an implicit operator on the types that you define.2 Thus,
you can’t accidentally create an implicit conversion operator without realizing you’re doing so (as
you can in C++). However, in order to provide these conversions, you must bend the rules of
method overloading ever so slightly for this one case. Consider the case where Complex provides
another explicit conversion operator to convert to an instance of Fraction as well as to an instance
of double. This would give Complex two methods with the following signatures:
public static explicit operator double( Complex d )
public static explicit operator Fraction( Complex f )
These two methods take the same type, Complex, and return another type. However, the over-
load rules clearly state that the return type doesn’t participate in the method signature. Going by
those rules, these two methods should be ambiguous and result in a compiler error. In fact, they are
not ambiguous, because a special rule exists to allow the return type of conversion operators to be
considered in the signature. Incidentally, the implicit and explicit keywords don’t participate in
the signature of conversion operator methods. Therefore, it’s impossible to have both implicit and
explicit conversion operators with the same signature. Naturally, at least one of the types in the sig-
nature of a conversion operator must be the enclosing type. It is invalid for a type Complex to
implement a conversion operator from type Apples to type Oranges.
Boolean Operators
It makes sense for some types to participate in Boolean tests, such as within the parentheses of an
if block or with the ternary operator ?:. In order for this to work, you have two alternatives. The
first is that you can implement two conversion operators, known as operator true and operator
false. You must implement these two operators in pairs to allow the Complex number to participate
in Boolean test expressions. Consider the following modification to the Complex type, where you
now want to use it in expressions where a value of (0, 0) means false and anything else means
true:
using System;
public struct Complex
{
2. Yes, I realize the implications of my explicit, and possible confusing, use of the words implicit and explicit. I
explicitly hope that I have not implicitly confused you.

180.
CHAPTER 6 ■ OVERLOADING OPERATORS 161
The end result is the same with this example. Now, you may be wondering why you would ever
want to implement operator true and operator false rather than just an implicit bool conversion
operator. The answer lies in whether it is valid for your type to be converted to a bool type or not.
With the latter form, where you implement the implicit conversion operator, the following state-
ment would be valid:
bool f = cpx1;
This assignment would work because the compiler would find the implicit conversion operator
at compile time and apply it. However, if you were extremely tired the night you coded this line and
really meant to assign f from a completely different variable, it might be a long time before you find
the bug. This is one example of how gratuitous use of implicit conversion operators can get you in
trouble.
The rule of thumb is this: Provide only enough of what is necessary to get the job done and no
more. If all you want is for your type—in this case, Complex—to participate in Boolean test expres-
sions, only implement operator true and operator false. Do not implement the implicit bool
conversion operator unless you have a real need for it. If you do happen to have a need for it, and
thus implement the implicit bool conversion operator, you don’t have to implement operator true
and operator false, because they would be redundant. If you do provide all three, the compiler will
go with the implicit conversion operator rather than operator true and operator false, because
invoking one is not more efficient than the other, assuming you code them the same.
Summary
In this chapter, I covered some useful guidelines for overloading operators, including unary, binary,
and conversion operators. Operator overloading is one of the features that makes C# such a power-
ful and expressive .NET language. However, just because you can do something doesn’t mean that
you should. Misuse of implicit conversion operators and improperly defined semantics in other
operator overloads has proven time and time again to be the source of great user confusion (and
that user could be the author of the type) as well as unintended behavior. When it comes to over-
loading operators, provide only enough of what is necessary, and don’t go counter to the general
semantics of the various operators. Since the CLS doesn’t require overloaded operator support, not
all .NET languages support overloaded operators. Therefore, it’s important to always provide explic-
itly named methods that provide the same functionality. Sometimes, those methods are already
defined in system interfaces, such as IComparable or IComparable<T>. Never isolate functionality
strictly within overloaded operators unless you’re 100% sure that your code will be consumed by
.NET languages that do support operator overloading.
In the next chapter, I’ll cover the intricacies and tricks involved in creating exception-safe and
exception-neutral code in the .NET Framework.

181.
CHAPTER 7
Exception Handling and
Exception Safety
T he CLR contains strong support for exceptions. Exceptions can be created and thrown at a point
where code execution cannot continue because of some exceptional condition (usually a method
failure or an invalid state). Writing exception-safe code is a difficult art to master. It would be a mis-
take to assume that the only tasks required when writing exception-safe code are simply throwing
exceptions when an error occurs and catching them at some point. Such a view of exception-safe
code is shortsighted and will lead you down a path of despair. Instead, exception-safe coding means
guaranteeing the integrity of the system in the face of exceptions. When an exception is thrown, the
runtime will iteratively unwind the stack while cleaning up. Your job as an exception-safe program-
mer is to structure your code in such a way that the integrity of the state of your objects is not
compromised as the stack unwinds. That is the true essence of exception-safe coding techniques.
In this chapter, I will show you how the CLR handles exceptions and the mechanics involved
with handling exceptions. However, there is more to exception handling than just that. For example,
I’ll describe which areas of code should handle exceptions as well as pitfalls to avoid when imple-
menting exception handling. Most importantly, I will show you how writing exception-safe code
may not even involve handling exceptions at all. Such code is typically called exception-neutral
code. It may sound surprising, but read on for all of the details.
How the CLR Treats Exceptions
Once an exception is thrown, the CLR begins the process of unwinding the execution stack itera-
tively, frame by frame.1 As it does so, it cleans up any objects that are local to each stack frame. At
some point, a frame on the stack could have an exception handler registered for the type of excep-
tion thrown. Once the CLR reaches that frame, it invokes the exception handler to remedy the
situation. If the stack unwinds completely and a handler is not found for the exception thrown, then
the unhandled-exception event for the current application domain may be fired and the applica-
tion could be aborted.
1. If you’re not familiar with the term stack frame, you may want to reference http://en.wikipedia.org/wiki/
Stack_frame. In short, as each method is called throughout the execution of a program, a frame is built on the
stack that contains the passed parameters and any local parameters to the method. The frame is deleted
upon return from the method. However, as the method calls other methods, and so on, new frames are
stacked on top of the current frame, thus implementing a nested call-frame structure. 163

182.
164 CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY
Mechanics of Handling Exceptions in C#
If you’ve ever used exceptions in other C-style languages such as C++, Java, or even C/C++ using the
Microsoft structured exception-handling extensions (__try/__catch/__finally), then you’re already
familiar with the basic syntax of exceptions in C#. In that case, you may find yourself skimming the
next few sections or treating the material as a refresher. I’ve tried to point out any areas that are sig-
nificantly different from the other C-style languages in the process.
Throwing Exceptions
The act of throwing an exception is actually quite easy. You simply execute a throw statement whose
parameter is the exception you would like to throw. For example, suppose you have written a cus-
tom collection class that allows users to access items by index, and you would like to notify users
when an invalid index is passed as a parameter. You could throw an ArgumentOutOfRange exception,
as in the following code:
public class MyCollection
{
public object GetItem( int index ) {
if( index < 0 || index >= count ) {
throw new ArgumentOutOfRangeException();
}
// Do other useful stuff here
}
private int count;
}
The runtime can also throw exceptions as a side effect to code execution. An example of a sys-
tem-generated exception is NullReferenceException, which occurs if you attempt to access a field
or call a method on an object when, in fact, the reference to the object doesn’t exist.
Changes with Unhandled Exceptions Starting with .NET 2.0
When an exception is thrown, the runtime begins to search up the stack for a matching catch block
for the exception. As it walks up the execution stack, it unwinds the stack at the same time, cleaning
up each frame along the way.
If the search ends in the last frame for the thread, and it still finds no handler for the exception,
the exception is considered unhandled at that point. What happens next depends on what version
of the .NET Framework your code uses.
■ Note You can install an unhandled-exception filter by registering a delegate with AppDomain.
UnhandledException. When an unhandled exception comes up through the stack, this
delegate will be called and will receive an instance of UnhandledExceptionEventArgs.
■Note The CLR translates unhandled exceptions passing through static constructors. I’ll cover that in more detail
in the section titled “Exceptions Thrown in Static Constructors.”

183.
CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY 165
In .NET 1.1, the CLR designers decided to swallow certain unhandled exceptions in the pursuit
of greater stability. For example, if a finalizer throws an exception in .NET 1.1 instead of aborting the
finalizer thread and the process, the exception is swallowed and not allowed to kill the finalizer
thread or terminate the process. Similarly, if an unhandled exception percolates up in a thread
other than the main thread, that thread is terminated without affecting the rest of the process. In a
thread-pool thread, the exception is swallowed and the thread is returned to the pool, which is
behavior that is similar to exception handling in the finalizer thread. If an unhandled exception
propagates up from the main thread, then it behaves as expected, and either the process is termi-
nated or the JIT debugging dialog is displayed, asking the user what to do.
This behavior sounds good in concept, but in reality, it gives the opposite of the desired result.
Instead of providing greater stability, systems become unstable because code runs in a nondeter-
ministic state. For example, consider a finalizer that does some crucial work. Suppose that halfway
through that work, an exception is thrown. The second half of the work in the finalizer never runs.
Now, the system is in a potentially unstable, half-baked state. Everything continues to run normally,
although the state of the system could be far from normal. In practice, this causes great instability
because the sources of the errors are hard to find since the exceptions are swallowed.
.NET 2.0 solves this problem by requiring that any unhandled exception, except
AppDomainUnloadException and ThreadAbortException, causes the thread to terminate. It sounds
rude, but in reality, this is the behavior you should want from an unhandled exception. After all, it’s
an unhandled exception. Now that the thread terminates as expected, a big red flag is raised at the
point of the exception that allows you to find the problem immediately and fix it. This is always a
good thing. You always want errors to present themselves as soon as possible; never swallow excep-
tions and just let the system keep running as if everything were normal.
■Note If you really want the unhandled-exception behavior to emulate the .NET 1.1 behavior, you can request
that by adding the following option to the application’s configuration file:
<system>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1"/>
</runtime>
</system>
Syntax Overview of the try Statement
The code within a try block is guarded against exceptions such that, if an exception is thrown, the
runtime searches for a suitable catch block to handle the exception. Whether a suitable catch block
exists or not, if a finally block is provided, the finally block is always executed no matter how exe-
cution flow leaves the try block. Let’s look at an example of a C# try statement:
using System;
using System.Collections;
using System.Runtime.CompilerServices;
// Disable compiler warning: CS1058
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = false)]
public class Entrypoint
{

184.
166 CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY
static void Main() {
try {
ArrayList list = new ArrayList();
list.Add( 1 );
Console.WriteLine( "Item 10 = {0}", list[10] );
}
catch( ArgumentOutOfRangeException x ) {
Console.WriteLine( "=== ArgumentOutOfRangeException"+
" Handler ===" );
Console.WriteLine( x );
Console.WriteLine( "=== ArgumentOutOfRangeException"+
" Handler ===nn" );
}
catch( Exception x ) {
Console.WriteLine( "=== Exception Handler ===" );
Console.WriteLine( x );
Console.WriteLine( "=== Exception Handler ===nn" );
}
catch {
Console.WriteLine( "=== Unexpected Exception" +
" Handler ===" );
Console.WriteLine( "An exception I was not" +
" expecting..." );
Console.WriteLine( "=== Unexpected Exception" +
" Handler ===" );
}
finally {
Console.WriteLine( "Cleaning up..." );
}
}
}
Once you see the code in the try block, you know it is destined to throw an ArgumentOutOfRange
exception. Once the exception is thrown, the runtime begins searching for a suitable catch clause
that is part of this try statement and matches the type of the exception as best as possible. Clearly,
the first catch clause is the one that fits best. Therefore, the runtime will immediately begin execut-
ing the statements in the first catch block. Had I not been interested in the actual exception
contents, I could have left off the declaration of the exception variable x in the catch clause and
only declared the type. But in this case, I wanted to demonstrate that exception objects in C# pro-
duce a nice stack trace that can be useful during debugging. While generating the output for this
chapter, I compiled the samples without debugging symbols turned on. However, if you turn on
debugging symbols, you’ll notice that the stack trace also includes file and line numbers of the vari-
ous levels in the stack.
The second catch clause will catch exceptions of the general Exception type. Should the
code in the try block throw an exception derived from System.Exception other than
ArgumentOutOfRangeException, then this catch block would handle it. In C#, multiple catch clauses
associated with a single try block must be ordered such that more specific exception types are
listed first. The C# compiler will simply not compile code in which more general catch clauses are
listed before more specific catch clauses. You can verify this by swapping the order of the first two
catch clauses in the previous example.
In C#, every exception that you can possibly throw must derive from System.Exception. Since I
declared a catch clause that traps exceptions of type System.Exception specifically, what’s the story
with the third and last catch clause? Even though it is impossible to throw an exception of any type
not derived from System.Exception in the C# language, it is not impossible in the CLR. (For

185.
CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY 167
example, you can throw an exception of any type in C++.) Therefore, if you wrote ArrayList in a lan-
guage that allows this, it’s possible that the code could throw a not-very-useful type, such as
System.Int32. It sounds strange, but it is possible. In this case, you can catch such an exception in
C# by using a catch clause with neither an explicit exception type nor a variable. Unfortunately,
there’s no easy way to know what type the thrown exception is. Also, a try statement can have, at
most, one such general catch clause.
■Note Starting with .NET 2.0, the situation regarding general catch clauses is a little different than in .NET 1.1. It
features a new attribute, RuntimeCompatibilityAttribute, that you can attach to your assembly. The C# and
Visual Basic compilers that target .NET 2.0 apply this property by default. It tells the runtime to wrap exceptions
that are not derived from System.Exception inside an exception of type RuntimeWrappedException, which is
derived from System.Exception. This is handy, because it allows your C# code to access the thrown exception.
Previously, you could not access the thrown exception, since it was caught by a general, parameterless catch
clause. You can access the actual thrown exception type via the RuntimeWrappedException.
WrappedException property. If your code contains a parameterless catch clause, the compiler emits a warning
of type CS1058 by default, unless you disable the attribute as I did in the previous example.
Last of all, there is the finally block. No matter how the try block is exited, whether by reach-
ing the end point of the block or via an exception or a return statement, the finally block will
always execute. If there is a suitable catch block in the same frame as the finally block, it will exe-
cute before the finally block. You can see this by looking at the output of the previous code
example, which looks like the following:
=== ArgumentOutOfRangeException Handler ===
System.ArgumentOutOfRangeException: Index was out of range. Must be ?
non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.ArrayList.get_Item(Int32 index)
at Entrypoint.Main()
=== ArgumentOutOfRangeException Handler ===
Cleaning up...
Rethrowing Exceptions and Translating Exceptions
Within a particular stack frame, you may find it necessary to catch all exceptions, or a specific sub-
set of exceptions, long enough to do some cleanup and then rethrow the exception in order to let it
continue to propagate up the stack. To do this, you use the throw statement with no parameter:
using System;
using System.Collections;
public class Entrypoint
{
static void Main() {
try {
try {
ArrayList list = new ArrayList();

186.
168 CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY
list.Add( 1 );
Console.WriteLine( "Item 10 = {0}", list[10] );
}
catch( ArgumentOutOfRangeException ) {
Console.WriteLine( "Do some useful work and" +
" then rethrow" );
// Rethrow caught exception.
throw;
}
finally {
Console.WriteLine( "Cleaning up..." );
}
}
catch {
Console.WriteLine( "Done" );
}
}
}
Note that any finally blocks associated with the exception frame that the catch block is asso-
ciated with will execute before any higher-level exception handlers are executed. You can see this in
the output from the code:
Do some useful work and then rethrow
Cleaning up...
Done
In the “Achieving Exception Neutrality” section, I introduce some techniques that can help you
avoid having to catch an exception, do cleanup, and then rethrow the exception. That sort of work
flow is cumbersome, since you must be careful to rethrow the exception appropriately. If you acci-
dentally forget to rethrow, things could get ugly, since you would not likely be remedying the
exceptional situation. The techniques that I show you help you achieve a goal where the only place
to introduce a catch block is at the point where correctional action can occur.
Sometimes, you may find it necessary to “translate” an exception within an exception handler.
In this case, you catch an exception of one type, but you throw an exception of a different, possibly
more precise, type in the catch block for the next level of exception handlers to deal with. Consider
the following example:
using System;
using System.Collections;
public class MyException : Exception
{
public MyException( String reason, Exception inner )
:base( reason, inner ) {
}
}
public class Entrypoint
{
static void Main() {
try {
try {
ArrayList list = new ArrayList();

187.
CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY 169
list.Add( 1 );
Console.WriteLine( "Item 10 = {0}", list[10] );
}
catch( ArgumentOutOfRangeException x ) {
Console.WriteLine( "Do some useful work" +
" and then rethrow" );
throw new MyException( "I'd rather throw this",
x ) ;
}
finally {
Console.WriteLine( "Cleaning up..." );
}
}
catch( Exception x ) {
Console.WriteLine( x );
Console.WriteLine( "Done" );
}
}
}
One special quality of the System.Exception type is its ability to contain an inner exception ref-
erence via the Exception.InnerException property. This way, when the new exception is thrown,
you can preserve the chain of exceptions for the handlers that process them. I recommend you use
this useful feature of the standard exception type of C# when you translate exceptions. The output
from the previous code is as follows:
Do some useful work and then rethrow
Cleaning up...
MyException: I'd rather throw this —-> System.ArgumentOutOfRangeException: ➥
Index was out of range. ➥
Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.ArrayList.get_Item(Int32 index)
at Entrypoint.Main()
—- End of inner exception stack trace —-
at Entrypoint.Main()
Done
Keep in mind that you should avoid translating exceptions if possible. The more you catch and
then rethrow within a stack, the more you insulate the code that handles the exception from the
code that throws the exception. That is, it’s harder to correlate the point of catch to the original
point of throw. Yes, the Exception.InnerException property helps mitigate some of this disconnect,
but it still can be tricky to find the root cause of a problem if there are exception translations along
the way.
Exceptions Thrown in finally Blocks
It is possible, but highly inadvisable, to throw exceptions within a finally block. The following code
shows an example:
using System;
using System.Collections;
public class Entrypoint

188.
170 CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY
{
static void Main() {
try {
try {
ArrayList list = new ArrayList();
list.Add( 1 );
Console.WriteLine( "Item 10 = {0}", list[10] );
}
finally {
Console.WriteLine( "Cleaning up..." );
throw new Exception( "I like to throw" );
}
}
catch( ArgumentOutOfRangeException ) {
Console.WriteLine( "Oops! Argument out of range!" );
}
catch {
Console.WriteLine( "Done" );
}
}
}
The first exception is simply lost, and the new exception is propagated up the stack. Clearly,
this is not desirable. You never want to lose track of exceptions, because it becomes virtually impos-
sible to determine what caused an exception in the first place.
Exceptions Thrown in Finalizers
C# destructors are not really deterministic destructors, but rather CLR finalizers. Finalizers are run
in the context of the finalizer thread, which is effectively an arbitrary thread context. If the finalizer
were to throw an exception, the CLR might not know how to handle the situation and might simply
shut down the thread (and the process). Consider the following code:
using System;
public class Person
{
~Person() {
Console.WriteLine( "Cleaning up Person..." );
Console.WriteLine( "Done Cleaning up Person..." );
}
}
public class Employee : Person
{
~Employee() {
Console.WriteLine( "Cleaning up Employee..." );
object obj = null;
// The following will throw an exception.
Console.WriteLine( obj.ToString() );
Console.WriteLine( "Done cleaning up Employee..." );
}
}

189.
CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY 171
public class Entrypoint
{
static void Main() {
Employee emp = new Employee();
emp = null;
}
}
The output from executing this code is as follows:
Cleaning up Employee...
Unhandled Exception: System.NullReferenceException: Object reference not set ➥
to an instance of an object.
at Employee.Finalize()
Cleaning up Person...
Done Cleaning up Person...
You will notice slightly different behavior with this example between the .NET 1.1 and .NET 2.0
runtimes. In .NET 1.1, the exception is swallowed while it is logged in the console, and execution
then continues. In .NET 2.0, your development environment presents you with the familiar JIT
debugger dialog, asking if you would like to debug the application. The problem is, you have a lim-
ited amount of time within which to respond before the .NET 2.0 runtime aborts your application. If
you haven’t already, be sure to read about how .NET 1.1 and .NET 2.0 treat unhandled exceptions
differently in this chapter’s previous section, “Changes with Unhandled Exceptions in .NET 2.0.”
You should avoid knowingly throwing exceptions in finalizers at all costs, because you could
abort the process. As a final note, be sure to read about all of the pros and cons of creating a final-
izer in the first place in Chapter 13.
Exceptions Thrown in Static Constructors
If an exception is thrown and there is no handler in the stack, so that the search for the handler ends
up in the static constructor, the runtime handles this case specially. It translates the exception into a
System.TypeInitializationException and throws that instead. Before throwing the new exception,
it sets the InnerException property of the new exception to the original exception. That way, any
handler for type initialization exceptions can easily find out exactly why things failed.
Translating such an exception makes sense because constructors cannot, by their very nature,
have a return value to indicate success or failure. Exceptions are the only mechanism you have to
indicate that a constructor has failed. More importantly, since the system calls static constructors at
system-defined times,2 it makes sense for them to use the TypeInitializationException type in
order to be more specific about when something went wrong. For example, suppose you have a
static constructor that can potentially throw an ArgumentOutOfRangeException. Now, imagine the
frustration users would have if your exception propagated out to the enclosing thread at some
seemingly random time, because the exact moment of a static constructor call is system-defined. It
could appear that the ArgumentOutOfRange exception materialized out of thin air. Wrapping your
exception inside a TypeInitializationException takes a little of the mystery out of it and tips off
users, or hopefully the developer, that the problem happened during type initialization.
2. The system could call static constructors at type load time or just prior to a static member access, depending
on how the CLR is configured for the current process.

190.
172 CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY
The following code shows an example of what a TypeInitializationException with an inner
exception looks like:
using System;
using System.IO;
class EventLogger
{
static EventLogger() {
eventLog = File.CreateText( "logfile.txt" );
// Statement below will throw an exception.
strLogName = (string) strLogName.Clone();
}
static public void WriteLog( string someText ) {
eventLog.Write( someText );
}
static private StreamWriter eventLog;
static private string strLogName;
}
public class EntryPoint
{
static void Main() {
EventLogger.WriteLog( "Log this!" );
}
}
When you run this example, the output looks like the following:
Unhandled Exception: System.TypeInitializationException:
The type initializer for 'EventLogger' threw
an exception. —-> System.NullReferenceException: Object reference not set ➥
to an instance of an object.
at EventLogger..cctor()
—- End of inner exception stack trace —-
at EntryPoint.Main()
Notice that along with describing that the outermost exception is of type
TypeInitializationException, the output also shows that the inner exception, which started it all, is
a NullReferenceException.
Who Should Handle Exceptions?
Where should you handle exceptions? You can find the answer by applying a variant of the Expert
pattern, which states that work should be done by the entity that is the expert with respect to that
work. That is a circuitous way of saying that you should catch the exception at the point where you
can actually handle it with some degree of knowledge available to remedy the exceptional situation.
Sometimes, the catching entity could be close to the point of the exception generation within the
stack frame. The code could catch the exception, then take some corrective action, and then allow
the program to continue to execute normally. In other cases, the only reasonable place to catch an
exception is at the entry-point Main method, at which point you could either abort the process after

191.
CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY 173
providing some useful data, or reset the process as if the application were just restarted. The bottom
line is that you should figure out the best way to recover from exceptions, if that is possible, and the
best place to do so based upon where it makes the most sense to do it.
Avoid Using Exceptions to Control Flow
It can be tempting to use exceptions to manage the flow of execution in complex methods. This is
never a good idea, for a couple of reasons. First, exceptions are generally expensive to generate and
handle. Therefore, if you were to use them to control execution flow within a method that is at the
heart of your application, your performance would likely degrade. Second, it trivializes the excep-
tional nature of exceptions in the first place. The whole point of exceptions is to indicate an
exceptional condition in a way that can be handled or reported cleanly.
Historically, programmers have been rather lazy when it comes to handling error conditions.
How many times have you seen code where the programmer never even bothered to check the
return value of an API function or a method call? Such lackadaisical approaches to error handling
can lead to headaches in a hurry. Exceptions provide a syntactically succinct way to indicate and
handle error conditions without littering your code with a plethora of if blocks and other tradi-
tional (nonexception-based) error-handling constructs. At the same time, the runtime supports
exceptions, and it does a lot of work on your behalf when exceptions are thrown. Unwinding the
stack is no trivial task in itself. Lastly, the point where an exception is thrown and the point where
it’s handled can be disjointed and have no connection to each other. Thus, it can be difficult when
reading code to determine where an exception will be caught and handled. These reasons alone are
enough for you to stick to traditional techniques when managing normal execution flow.
■Note You can find an article, “The Cost of Exceptions,” on Rico Mariani’s blog at http://blogs.msdn.com/
ricom/archive/2003/12/19/44697.aspx. Rico is an expert on performance-related issues in the CLR.
Achieving Exception Neutrality
When exceptions were first added to C++, many developers were excited to be able to throw them,
catch them, and handle them. In fact, a common misconception at the time was that exception
handling simply consisted of strategically placing try statements throughout the code and tossing
in an occasional throw when necessary. Over time, the developer community realized that dropping
try statements all over the place made their code difficult to read when, most of the time, the only
thing they wanted to do was clean up gracefully when an exception was thrown and allow the
exception to keep propagating up the stack. Even worse, it made the code hard to write and difficult
to maintain. Code that doesn’t handle exceptions but is expected to behave properly in the face of
exceptions is generally called exception-neutral code.
Clearly, there had to be a better way to write exception-neutral code without having to rely on
writing try statements all over the place. In fact, the only place you need a try statement is the
point at which you perform any sort of system recovery or logging in response to an exception. Over
time, everyone started to realize that writing try statements was, in fact, the least significant part of
writing exception-safe and exception-neutral code. Generally, the only code that should catch an
exception is code that knows specifically how to remedy the situation. That code could even be in
the main entry point and could merely reset the system to a known start state, effectively restarting
the application.

192.
174 CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY
By exception-neutral code, I mean code that doesn’t really have the capability to specifically
handle the exception but that must be able to handle exceptions gracefully. Usually, this code sits
somewhere on the stack in between the code that throws the exception and the code that catches
the exception, and it must not be adversely affected by the exception passing through on its way up
the stack. At this point, some of you are probably starting to think about the throw statement with
no parameters that allows you to catch an exception, do some work, and then rethrow the excep-
tion. However, I want to introduce you to an arguably cleaner technique that allows you to write
exception-neutral code without using a single try statement and that also produces code that is
easier to read and more robust.
Basic Structure of Exception-Neutral Code
The general idea behind writing exception-neutral code is similar to the idea behind creating com-
mit/rollback code. You write such code with the guarantee that if it doesn’t finish to completion, the
entire operation is reverted with no change in state to the system. The changes in state are commit-
ted only if the code reaches the end of its execution path. You should code your methods like this in
order for them to be exception-neutral. If an exception is thrown before the end of the method, the
state of the system should remain unchanged. The following shows how you should structure your
methods in order to achieve these goals:
void ExceptionNeutralMethod()
{
//——————————
// All code that could possibly throw exceptions is in this
// first section. In this section, no changes in state are
// applied to any objects in the system including this.
//——————————
//——————————
// All changes are committed at this point using operations
// strictly guaranteed not to throw exceptions.
//——————————
}
As you can see, this technique doesn’t work unless you have a set of operations that are guaran-
teed never to throw exceptions. Otherwise, it would be impossible to implement the commit/
rollback behavior as illustrated. Thankfully, the .NET runtime does provide quite a few operations
that the specification guarantees will never throw exceptions.
Let’s start by building an example to describe what I mean. Suppose you have a system or an
application where you’re managing employees. For the sake of argument, say that once an
employee is created and represented by an Employee object, it must exist within one and only one
collection in the system. Currently, the only two collections in the system are one to represent active
employees and one to represent terminated employees. Additionally, the collections exist within an
EmployeeDatabase object, as shown in the following example:
using System.Collections;
class EmployeeDatabase
{
private ArrayList activeEmployees;
private ArrayList terminatedEmployees;
}

193.
CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY 175
The example uses collections of the ArrayList type, which is contained in the System.
Collections namespace. A real-world system would probably use something more useful, such as a
database.
Now, let’s see what happens when an employee quits. Naturally, you need to move that
employee from the activeEmployees to the terminatedEmployees collection. A naïve attempt at such
a task could look like the following:
using System.Collections;
class Employee
{
}
class EmployeeDatabase
{
public void TerminateEmployee( int index ) {
object employee = activeEmployees[index];
activeEmployees.RemoveAt( index );
terminatedEmployees.Add( employee );
}
private ArrayList activeEmployees;
private ArrayList terminatedEmployees;
}
This code looks reasonable enough. The method that does the move assumes that the calling
code somehow figured out the index for the current employee in the activeEmployees list prior to
calling TerminateEmployee. It copies a reference to the designated employee, removes that reference
from activeEmployees, and adds it to the terminatedEmployees collection. So what’s so bad about
this method?
Look at the method closely, and see where exceptions could be generated. The fact is, an excep-
tion could be thrown upon execution of any of the method calls in this method. If the index is out of
range, you would expect to see ArgumentOutOfRange exceptions thrown from the first two lines. Of
course, if the range exception is thrown from the first line, execution would never see the second
line, but you get the idea. And, if memory is scarce, it’s possible that the call to Add could fail with an
exception. The danger comes from the possibility of the exception being thrown after the state of
the system is modified. Suppose the index passed in is valid. The first two lines will likely succeed.
However, if an exception is thrown while trying to add the employee to terminatedEmployees, then
the employee will get lost in the system. So, what can you do to fix the glitch?
An initial attempt could use try statements to avoid damage to the system state. Consider the
following example.
using System.Collections;
class Employee
{
}
class EmployeeDatabase
{
public void TerminateEmployee( int index ) {
object employee = null;
try {
employee = activeEmployees[index];
}

194.
176 CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY
catch {
// oops! We must be out of range here.
}
if( employee != null ) {
activeEmployees.RemoveAt( index );
try {
terminatedEmployees.Add( employee );
}
catch {
// oops! Allocation may have failed.
activeEmployees.Add( employee );
}
}
}
private ArrayList activeEmployees;
private ArrayList terminatedEmployees;
}
Look how quickly the code becomes hard to read and understand, thanks to the try state-
ments. You have to pull the employee reference out of the try statement and initialize it to null.
Once you attempt to get the reference to the employee, you have to check the reference for null to
make sure you actually got a reference to it. Once that succeeds, you can proceed to add the
employee to the terminatedEmployees list. However, if that fails for some reason, you need to put
the employee back into the activeEmployees list.
You may have already spotted a multitude of problems with this approach. First of all, what
happens if you have a failure to add the employee back into the activeEmployees collection? Do you
just fail at that point? That’s unacceptable, since the state of the system has changed already. Sec-
ond, you probably need to return an error code from this method to indicate why it may have
failed. That’s something I didn’t do in the previous code. The method can’t just return happily as if
everything went smoothly when, in fact, the action failed to complete. Third, the code is just plain
ugly and hard to read. Lastly, a variety of problems still exist with this code that I won’t waste time
going into.
So what’s the solution? Well, think of what you attempted to do with the try statements. You
want to do the actions that possibly throw exceptions, and if they fail, revert to the previous state.
You can actually perform a variation on this theme without try statements that goes like this:
Attempt all of the actions in the method that could throw exceptions up front, and once you get past
that point, commit those actions using operations that can’t throw exceptions.
■Note The C++ community has accepted these techniques, thanks, in part, to the excellent works published by
Herb Sutter in his Exceptional C++ series (Boston, MA: Addison-Wesley Professional). There is no good reason you
cannot apply the same techniques wholesale in the C# world.
Let’s see what this method would look like:
using System.Collections;
class Employee
{
}

195.
CHAPTER 7 ■ EXCEPTION HANDLING AND EXCEPTION SAFETY 177
class EmployeeDatabase
{
public void TerminateEmployee( int index ) {
// Clone sensitive objects.
ArrayList tempActiveEmployees =
(ArrayList) activeEmployees.Clone();
ArrayList tempTerminatedEmployees =
(ArrayList) terminatedEmployees.Clone();
// Perform actions on temp objects.
object employee = tempActiveEmployees[index];
tempActiveEmployees.RemoveAt( index );
tempTerminatedEmployees.Add( employee );
// Now commit the changes.
ArrayList tempSpace = null;
ListSwap( ref activeEmployees,
ref tempActiveEmployees,
ref tempSpace );
ListSwap( ref terminatedEmployees,
ref tempTerminatedEmployees,
ref tempSpace );
}
void ListSwap( ref ArrayList first,
ref ArrayList second,
ref ArrayList temp ) {
temp = first;
first = second;
second = temp;
temp = null;
}
private ArrayList activeEmployees;
private ArrayList terminatedEmployees;
}
First, notice the absence of any try statements. The nice thing about their absence is that the
method doesn’t need to return a result code. The caller can expect the method to either work as
advertised or throw an exception otherwise. The only two lines in the method that affect the state of
the system are the last two calls to ListSwap. ListSwap was introduced to allow you to swap the ref-
erences of the ArrayList objects in the EmployeeDatabase with the references to the temporary
modified copies that you made.
How is this technique so much better when it appears to be so much less efficient? There are
two tricks here. The obvious one is that, no matter where in this method an exception is thrown, the
state of the EmployeeDatabase will remain unaffected. But what if an exception is thrown inside
ListSwap? Ah! Here you have the second trick: ListSwap will never throw an exception. One of the
most important features required in order to create exception-neutral code is that you have a small
set of operations that are guaranteed not to fail under normal circumstances. No, I’m not including
the case of some bozo pulling the plug on the computer in the middle of a ListSwap call, nor am I
considering the case of a catastrophic earthquake or tornado at that point either. Let’s see why
ListSwap won’t throw any exceptions.
In order to create exception-neutral code, it’s imperative that you have a handful of operations,
such as an assignment operation, that are guaranteed not to throw. Thankfully, the CLR provides
such operations. The assignment of references, when no conversion is required, is one example of a