Head First C#: A Learner's Guide To Real World Programming With Visual C# And .NET (Head Guides) C Learners Net

head-first-c-a-learners-guide-to-real-world-programming-with-visual-c-and-net

head-first-c-a-learners-guide-to-real-world-programming-with-visual-c-and-net

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 840

DownloadHead First C#: A Learner's Guide To Real-World Programming With Visual C# And .NET (Head Guides) Head-first-c-a-learners-guide-to-real-world-programming-with-visual-c-and-net
Open PDF In BrowserView PDF
Advance Praise for Head First C#
“I’ve never read a computer book cover to cover, but this one held my interest from the first page to the
last. If you want to learn C# in depth and have fun doing it, this is THE book for you.”
— Andy Parker, fledgling C# programmer
“It’s hard to really learn a programming language without good engaging examples, and this book is full
of them! Head First C# will guide beginners of all sorts to a long and productive relationship with C#
and the .NET Framework.”
—Chris Burrows, developer for Microsoft’s C# Compiler team
“With Head First C#, Andrew and Jenny have presented an excellent tutorial on learning C#. It is very
approachable while covering a great amount of detail in a unique style. If you’ve been turned off by
more conventional books on C#, you’ll love this one.”
—Jay Hilyard, software developer, co-author of C# 3.0 Cookbook
“I’d reccomend this book to anyone looking for a great introduction into the world of programming and
C#. From the first page onwards, the authors walks the reader through some of the more challenging
concepts of C# in a simple, easy-to-follow way. At the end of some of the larger projects/labs, the
reader can look back at their programs and stand in awe of what they’ve accomplished.”
—David Sterling, developer for Microsoft’s Visual C# Compiler team
“Head First C# is a highly enjoyable tutorial, full of memorable examples and entertaining exercises. Its
lively style is sure to captivate readers—from the humorously annotated examples, to the Fireside Chats,
where the abstract class and interface butt heads in a heated argument! For anyone new to programming,
there’s no better way to dive in.”
—Joseph Albahari, C# Design Architect at Egton Medical Information Systems,
the UK’s largest primary healthcare software supplier,
co-author of C# 3.0 in a Nutshell
“[Head First C#] was an easy book to read and understand. I will recommend this book to any developer
wanting to jump into the C# waters. I will recommend it to the advanced developer that wants to
understand better what is happening with their code. [I will recommend it to developers who] want to
find a better way to explain how C# works to their less-seasoned developer friends.”
—Giuseppe Turitto, C# and ASP.NET developer for Cornwall Consulting Group
“Andrew and Jenny have crafted another stimulating Head First learning experience. Grab a pencil, a
computer, and enjoy the ride as you engage your left brain, right brain, and funny bone.”
—Bill Mietelski, software engineer
“Going through this Head First C# book was a great experience. I have not come across a book series
which actually teaches you so well.…This is a book I would definitely recommend to people wanting to
learn C#”
—Krishna Pala, MCP

Praise for other Head First books
“Kathy and Bert’s Head First Java transforms the printed page into the closest thing to a GUI you’ve ever
seen. In a wry, hip manner, the authors make learning Java an engaging ‘what’re they gonna do next?’
experience.”
—Warren Keuffel, Software Development Magazine

“Beyond the engaging style that drags you forward from know-nothing into exalted Java warrior status,
Head First Java covers a huge amount of practical matters that other texts leave as the dreaded “exercise
for the reader….” It’s clever, wry, hip and practical—there aren’t a lot of textbooks that can make that
claim and live up to it while also teaching you about object serialization and network launch protocols. ”
—Dr. Dan Russell, Director of User Sciences and Experience Research
IBM Almaden Research Center (and teaches Artificial Intelligence at
Stanford University)
“It’s fast, irreverent, fun, and engaging. Be careful—you might actually learn something!”
—Ken Arnold, former Senior Engineer at Sun Microsystems
Co-author (with James Gosling, creator of Java),
The Java Programming Language
“I feel like a thousand pounds of books have just been lifted off of my head.”
—Ward Cunningham, inventor of the Wiki and founder of the Hillside Group
“Just the right tone for the geeked-out, casual-cool guru coder in all of us. The right reference for
practical development strategies—gets my brain going without having to slog through a bunch of tired
stale professor­-speak.”
—Travis Kalanick, Founder of Scour and Red Swoosh
Member of the MIT TR100
“There are books you buy, books you keep, books you keep on your desk, and thanks to O’Reilly and the
Head First crew, there is the penultimate category, Head First books. They’re the ones that are dogeared, mangled, and carried everywhere. Head First SQL is at the top of my stack. Heck, even the PDF I
have for review is tattered and torn.”
— Bill Sawyer, ATG Curriculum Manager, Oracle
“This book’s admirable clarity, humor and substantial doses of clever make it the sort of book that helps
even non-programmers think well about problem-solving.”
— Cory Doctorow, co-editor of Boing Boing
Author, Down and Out in the Magic Kingdom
and Someone Comes to Town, Someone Leaves Town

Praise for other Head First books
“I received the book yesterday and started to read it…and I couldn’t stop. This is definitely très ‘cool.’ It
is fun, but they cover a lot of ground and they are right to the point. I’m really impressed.”
— Erich Gamma, IBM Distinguished Engineer, and co-author of
Design Patterns
“One of the funniest and smartest books on software design I’ve ever read.”
— Aaron LaBerge, VP Technology, ESPN.com
“What used to be a long trial and error learning process has now been reduced neatly into an engaging
paperback.”
— Mike Davidson, CEO, Newsvine, Inc.
“Elegant design is at the core of every chapter here, each concept conveyed with equal doses of
pragmatism and wit.”
— Ken Goldstein, Executive Vice President, Disney Online
“I ♥ Head First HTML with CSS & XHTML—it teaches you everything you need to learn in a ‘fun
coated’ format.”
— Sally Applin, UI Designer and Artist
“Usually when reading through a book or article on design patterns, I’d have to occasionally stick myself
in the eye with something just to make sure I was paying attention. Not with this book. Odd as it may
sound, this book makes learning about design patterns fun.
“While other books on design patterns are saying ‘Bueller… Bueller… Bueller…’ this book is on the float
belting out ‘Shake it up, baby!’”
— Eric Wuehler
“I literally love this book. In fact, I kissed this book in front of my wife.”
— Satish Kumar

Other related books from O’Reilly
Programming C# 4.0
C# 4.0 in a Nutshell
C# Essentials
C# Language Pocket Reference

Other books in O’Reilly’s Head First series
Head First Java
Head First Object-Oriented Analysis and Design (OOA&D)
Head Rush Ajax
Head First HTML with CSS and XHTML
Head First Design Patterns
Head First Servlets and JSP
Head First EJB
Head First PMP
Head First SQL
Head First Software Development
Head First JavaScript
Head First Ajax
Head First Statistics
Head First Physics
Head First Programming
Head First Ruby on Rails
Head First PHP & MySQL
Head First Algebra
Head First Data Analysis
Head First Excel

Head First C#
Second Edition

Wouldn’t it be dreamy
if there was a C# book that
was more fun than endlessly
debugging code? It’s probably
nothing but a fantasy....

Andrew Stellman
Jennifer Greene

Beijing • Cambridge • Kln • Sebastopol • Taipei • Tokyo

Head First C#
Second Edition

by Andrew Stellman and Jennifer Greene
Copyright © 2010 Andrew Stellman and Jennifer Greene. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly Media books may be purchased for educational, business, or sales promotional use. Online editions are also
available for most titles (http://my.safaribooksonline.com). For more information, contact our corporate/institutional sales
department: (800) 998-9938 or corporate@oreilly.com.

Series Creators:		

Kathy Sierra, Bert Bates

Cover Designers:		

Louise Barr, Karen Montgomery

Production Editor:		

Rachel Monaghan

Proofreader: 		

Emily Quill

Indexer:			

Lucie Haskins

Page Viewers:

Quentin the whippet and Tequila the pomeranian

Printing History:
November 2007: First Edition.
May 2010: Second Edition.

The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. The Head First series designations, Head First C#,
and related trade dress are trademarks of O’Reilly Media, Inc.
Microsoft, Windows, Visual Studio, MSDN, the .NET logo, Visual Basic and Visual C# are registered trademarks of
Microsoft Corporation.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks.
Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trademark claim, the
designations have been printed in caps or initial caps.
While every precaution has been taken in the preparation of this book, the publisher and the authors assume no
responsibility for errors or omissions, or for damages resulting from the use of the information contained herein.
No bees, space aliens, or comic book heroes were harmed in the making of this book.
ISBN: 978-1-449-38034-2
[SB]										

This book is dedicated to the loving memory of Sludgie the Whale,
who swam to Brooklyn on April 17, 2007.

You were only in our canal for a day,
but you’ll be in our hearts forever.

the authors

Thanks for buying our book! We really
love writing about this stuff, and we
hope you get a kick out of reading it…

Andrew

This photo (and the photo of the
Gowanus Canal) by Nisha Sondhe

…because we know
you’re going to have a
great time learning C#.

Jenny

Andrew Stellman, despite being raised a

New Yorker, has lived in Pittsburgh twice. The
first time was when he graduated from Carnegie
Mellon’s School of Computer Science, and then
again when he and Jenny were starting their
consulting business and writing their first book for
O’Reilly.

When he moved back to his hometown, his first
job after college was as a programmer at EMICapitol Records—which actually made sense,
since he went to LaGuardia High School of
Music and Art and the Performing Arts to study
cello and jazz bass guitar. He and Jenny first
worked together at that same financial software
company, where he was managing a team of
programmers. He’s had the privilege of working
with some pretty amazing programmers over the
years, and likes to think that he’s learned a few
things from them.
When he’s not writing books, Andrew keeps
himself busy writing useless (but fun) software,
playing music (but video games even more),
experimenting with circuits that make odd noises,
studying taiji and aikido, having a girlfriend
named Lisa, and owning a pomeranian.

viii

Jennifer Greene studied philosophy in

college but, like everyone else in the field, couldn’t
find a job doing it. Luckily, she’s a great software
engineer, so she started out working at an online
service, and that’s the first time she really got a
good sense of what good software development
looked like.

She moved to New York in 1998 to work on
software quallity at a financial software company.
She managed a team of testers at a really cool
startup that did artificial intelligence and natural
language processing.
Since then, she’s traveled all over the world to work
with different software teams and build all kinds of
cool projects.
She loves traveling, watching Bollywood movies,
reading the occasional comic book, playing PS3
games (especially LittleBigPlanet!), and owning a
whippet.

software engineering together since they
Jenny and Andrew have been building software and writing about
ct Management, was published by O’Reilly in
first met in 1998. Their first book, Applied Software Proje
First PMP, in 2007.
2005. They published their first book in the Head First series, Head
a really neat software project for
They founded Stellman & Greene Consulting in 2003 to buildthey’r
e not building software or writing
scientists studying herbicide exposure in Vietnam vets. When
are engineers, architects and
books, they do a lot of speaking at conferences and meetings of softw
project managers.
ellman-greene.com
Check out their blog, Building Better Software: http://www.st

table of contents

Table of Contents (Summary)
Intro

xxix

1

Get productive with C#: Visual Applications, in 10 minutes or less

1

2

It’s All Just Code: Under the hood

41

3

Objects: Get Oriented: Making code make sense

85

4

Types and References: It’s 10:00. Do you know where your data is?

125

C# Lab 1: A Day at the races

169

5

Encapsulation: Keep your privates… private

179

6

Inheritance: Your object’s family tree

215

7

Interfaces and abstract classes: Making classes keep their promises

269

8

Enums and collections: Storing lots of data

327

C# Lab 2: The Quest

385

9

Reading and Writing Files: Save the byte array, save the world

407

10

Exception Handling: Putting out fires gets old

463

11

Events and Delegates: What your code does when you’re not looking

507

12

Review and Preview: Knowledge, power, and building cool stuff

541

13

Controls and Graphics: Make it pretty

589

14

Captain Amazing: The Death of the Object

647

15

LINQ: Get control of your data

685

C# Lab 3: Invaders

713

Leftovers: The top 11 things we wanted to include in this book

735

i

Table of Contents (the real thing)
Intro
Your brain on C#.  You’re sitting around trying to learn something, but
your brain keeps telling you all that learning isn’t important. Your brain’s saying,
“Better leave room for more important things, like which wild animals to avoid and
whether nude archery is a bad idea.” So how do you trick your brain into thinking
that your life really depends on learning C#?
Who is this book for?

xxx

We know what you’re thinking

xxxi

Metacognition

xxxiii

Bend your brain into submission

xxxv

What you need for this book

xxxvi

Read me

xxxvii

The technical review team

xxxviii

Acknowledgments

xxxix

ix

table of contents

1

get productive with C#
Visual Applications, in 10 minutes or less
Want to build great programs really fast?
With C#, you’ve got a powerful programming language and a valuable tool
at your fingertips. With the Visual Studio IDE, you’ll never have to spend hours
writing obscure code to get a button working again. Even better, you’ll be able
to focus on getting your work done, rather than remembering which method
parameter was for the name of a button, and which one was for its label. Sound
appealing? Turn the page, and let’s get programming.

x

Why you should learn C#					

2

C# and the Visual Studio IDE make lots of things easy		

3

Help the CEO go paperless					

4

Get to know your users’ needs before you start
building your program					

5

What you do in Visual Studio…				

8

What Visual Studio does for you…				

8

Develop the user interface					

12

Visual Studio, behind the scenes				

14

Add to the auto-generated code				

15

We need a database to store our information			

18

The IDE created a database					

19

SQL is its own language					

19

Creating the table for the Contact List				

20

Finish building the table					

25

Insert your card data into the database				

26

Connect your form to your database objects with a data source

28

Add database-driven controls to your form			

30

How to turn YOUR application into EVERYONE’S application

35

Give your users the application				

36

You’re NOT done: test your installation				

37

You’ve built a complete data-driven application			

38

table of contents

2

it’s all just code
Under the hood
You’re a programmer, not just an IDE user.
You can get a lot of work done using the IDE. But there’s only so far it
can take you. Sure, there are a lot of repetitive tasks that you do when
you build an application. And the IDE is great at doing those things for
you. But working with the IDE is only the beginning. You can get your
programs to do so much more—and writing C# code is how you do it.
Once you get the hang of coding, there’s nothing your programs can’t do.
When you’re doing this…					

42

…the IDE does this						

43

Where programs come from					

44

The IDE helps you code					

46

When you change things in the IDE, you’re also changing
your code							

4849

Anatomy of a program					

50

Your program knows where to start				

5253

Two classes can be in the same namespace			

59

Your programs use variables to work with data			

60

C# uses familiar math symbols				

62

Use the debugger to see your variables change			

63

Loops perform an action over and over				

65

Time to start coding					

66

if/else statements make decisions				

67

Set up conditions and see if they’re true				

68

xi

table of contents

3

objects: get oriented!
Making Code Make Sense
Every program you write solves a problem.
When you’re building a program, it’s always a good idea to start by thinking about what
problem your program’s supposed to solve. That’s why objects are really useful. They
let you structure your code based on the problem it’s solving, so that you can spend your
time thinking about the problem you need to work on rather than getting bogged down in
the mechanics of writing code. When you use objects right, you end up with code that’s
intuitive to write, and easy to read and change.

w
ne

)
r(
to
ga
vi
Na

new N
aviga
tor()
ne
w

xii

Na
vi
ga
to
r(
)

How Mike thinks about his problems				

86

How Mike’s car navigation system thinks about his problems

87

Mike’s Navigator class has methods to set and modify routes		

88

Use what you’ve learned to build a program that uses a class

8990

Mike can use objects to solve his problem			

92

You use a class to build an object				

93

When you create a new object from a class, it’s called an instance
of that class						

94

A better solution…brought to you by objects!			

95

An instance uses fields to keep track of things			

100

Let’s create some instances!					

101

What’s on your program’s mind				

103

You can use class and method names to make your code intuitive

104

Give your classes a natural structure				

106

Class diagrams help you organize your classes so they make sense

108

Build a class to work with some guys				

112

Create a project for your guys					

113

Build a form to interact with the guys				

114

There’s an easier way to initialize objects			

117

table of contents

4

types and references
It’s 10:00. Do you know where your data is?
Data type, database, Lieutenant Commander Data…
it’s all important stuff. Without data, your programs are useless. You
need information from your users, and you use that to look up or produce new
information to give back to them. In fact, almost everything you do in programming
involves working with data in one way or another. In this chapter, you’ll learn the
ins and outs of C#’s data types, see how to work with data in your program, and
even figure out a few dirty secrets about objects (pssst…objects are data, too).
The variable’s type determines what kind of data it can store

126

A variable is like a data to-go cup				

128

10 pounds of data in a 5 pound bag				

129

Even when a number is the right size, you can’t just assign it to
any variable						

130

When you cast a value that’s too big, C# will adjust it automatically 131

y
Luck

y
Luck

fido

C# does some casting automatically				

132

When you call a method, the arguments must be compatible
with the types of the parameters				

133

Combining = with an operator 				

138

Objects use variables, too					

139

Refer to your objects with reference variables			

140

References are like labels for your object			

141

If there aren’t any more references, your object gets
garbage-collected						

142

Multiple references and their side effects			

144

Two references means TWO ways to change an object’s data

149

A special case: arrays					

150

Welcome to Sloppy Joe’s Budget House o’ Discount Sandwiches!

152

Objects use references to talk to each other			

154

Where no object has gone before				

155

Build a typing game					

160

fido

xiii

table of contents

C# Lab 1
A Day at the Races
Joe, Bob, and Al love going to the track, but they’re
tired of losing all their money. They need you to build a
simulator for them so they can figure out winners before
they lay their money down. And, if you do a good job,
they’ll cut you in on their profits.

xiv

The spec: build a racetrack simulator				

170

The Finished Product					

178

table of contents

5

encapsulation
Keep your privates… private
Ever wished for a little more privacy?
Sometimes your objects feel the same way. Just like you don’t want anybody you
don’t trust reading your journal or paging through your bank statements, good objects
don’t let other objects go poking around their fields. In this chapter, you’re going to
learn about the power of encapsulation. You’ll make your object’s data private, and
add methods to protect how that data is accessed.
Kathleen is an event planner					

180

What does the estimator do?					

181

Kathleen’s Test Drive					

186

Each option should be calculated individually			

188

It’s easy to accidentally misuse your objects			

190

Encapsulation means keeping some of the data in a class private

191

Use encapsulation to control access to your class’s methods
and fields							

192

But is the realName field REALLY protected?			

193

Private fields and methods can only be accessed from
inside the class 						

194

Encapsulation keeps your data pristine				

202

Properties make encapsulation easier				

203

Build an application to test the Farmer class			

204

Use automatic properties to finish the class			

205

What if we want to change the feed multiplier?			

206

Use a constructor to initialize private fields			

207

xv

table of contents

6

inheritance
Your object’s family tree
Sometimes you DO want to be just like your parents.
Ever run across an object that almost does exactly what you want your object to do?
Found yourself wishing that if you could just change a few things, that object would
be perfect? Well, that’s just one reason that inheritance is one of the most powerful
concepts and techniques in the C# language. Before you’re through with this chapter,
you’ll learn how to subclass an object to get its behavior, but keep the flexibility to
make changes to that behavior. You’ll avoid duplicate code, model the real world
more closely, and end up with code that’s easier to maintain.
Kathleen does birthday parties, too				

216

We need a BirthdayParty class				

217

Build the Party Planner version 2.0				

218

When your classes use inheritance, you only need to write
your code once						

226

Kathleen needs to figure out the cost of her parties, no matter what
kind of parties they are.					
226

xvi

Build up your class model by starting general and getting
more specific						

227

How would you design a zoo simulator?				

228

Use inheritance to avoid duplicate code in subclasses		

2290

Think about how to group the animals				

231

Create the class hierarchy					

232

Every subclass extends its base class				

233

A subclass can override methods to change or replace methods
it inherited						

238

Any place where you can use a base class, you can use one of
its subclasses instead					

239

A subclass can hide methods in the superclass			

246

Use the override and virtual keywords to inherit behavior		

248251

Now you’re ready to finish the job for Kathleen!		

252

Build a beehive management system				

257

First you’ll build the basic system				

258

Use inheritance to extend the bee management system		

263

table of contents

7

interfaces and abstract classes
Making classes keep their promises
Actions speak louder than words.
Sometimes you need to group your objects together based on the things they can
do rather than the classes they inherit from. That’s where interfaces come in—they
let you work with any class that can do the job. But with great power comes great
responsibility, and any class that implements an interface must promise to fulfill all of
its obligations…or the compiler will break their kneecaps, see?
Let’s get back to bee-sics					

270

We can use inheritance to create classes for different types of bees

271

An interface tells a class that it must implement certain methods
and properties						

272

Use the interface keyword to define an interface			

273

Classes that implement interfaces have to include ALL of the
interface’s methods 						

275

You can’t instantiate an interface, but you can reference an interface 278278
Interface references work just like object references		

279

You can find out if a class implements a certain interface with “is”

280

Interfaces can inherit from other interfaces			

281

Upcasting works with both objects and interfaces			

285

Downcasting lets you turn your appliance back into a coffee maker

286

Upcasting and downcasting work with interfaces, too		

287

There’s more than just public and private			

291

Access modifiers change visibility				

292

Some classes should never be instantiated			

295

An abstract class is like a cross between a class and an interface

296

An abstract method doesn’t have a body			

299

Polymorphism means that one object can take many different forms 307

xvii

table of contents

8

enums and collections
Storing lots of data
When it rains, it pours.
In the real world, you don’t get to handle your data in tiny little bits and pieces.
No, your data’s going to come at you in loads, piles, and bunches. You’ll need
some pretty powerful tools to organize all of it, and that’s where collections
come in. They let you store, sort, and manage all the data that your programs
need to pore through. That way, you can think about writing programs to work
with your data, and let the collections worry about keeping track of it for you.

poof!

xviii

Strings don’t always work for storing categories of data		

328

Enums let you work with a set of valid values			

329

Enums let you represent numbers with names			

330

We could use an array to create a deck of cards…			

333

Lists are more flexible than arrays				

336

Generics can store any type					

340

Collection initializers work just like object initializers		

344

Let’s create a List of Ducks					

345

Lists are easy, but SORTING can be tricky			

346

IComparable  helps your list sort its ducks		

347

Use IComparer to tell your List how to sort			

348

Create an instance of your comparer object			

349

IComparer can do complex comparisons			

350

Overriding a ToString() method lets an object describe itself

353

Update your foreach loops to let your Ducks and Cards
print themselves						

354

You can upcast an entire list using IEnumerable			

356

You can build your own overloaded methods			

357

The Dictionary Functionality Rundown				

364

Build a program that uses a Dictionary				

365

And yet MORE collection types…				

377

A queue is FIFO—First In, First Out				

378

A stack is LIFO—Last In, First Out				

379

table of contents

C# Lab 2
The Quest
Your job is to build an adventure game where a mighty
adventurer is on a quest to defeat level after level of
deadly enemies. You’ll build a turn-based system, which
means the player makes one move and then the enemies
make one move. The player can move or attack, and then
each enemy gets a chance to move and attack. The game
keeps going until the player either defeats all the enemies
on all seven levels or dies.
The spec: build an adventure game				

386

The fun’s just beginning!					

406

xix

table of contents

9

reading and writing files
Save the byte array, save the world
Sometimes it pays to be a little persistent.
So far, all of your programs have been pretty short-lived. They fire up, run for
a while, and shut down. But that’s not always enough, especially when you’re
dealing with important information. You need to be able to save your work. In
this chapter, we’ll look at how to write data to a file, and then how to read that
information back in from a file. You’ll learn about the .NET stream classes,
and also take a look at the mysteries of hexadecimal and binary.

69 1

xx

1 7 114

101 1
07 97 33

.NET uses streams to read and write data			

408

Different streams read and write different things			

409

A FileStream reads and writes bytes to a file			

410

How to write text to a file in 3 simple steps			

411

Reading and writing using two objects				

415

Data can go through more than one stream			

416

Use built-in objects to pop up standard dialog boxes		

419

Dialog boxes are just another .NET control			

420

Dialog boxes are objects, too					

421

IDisposable makes sure your objects are disposed of properly

427

Avoid file system errors with using statements			

428

Writing files usually involves making a lot of decisions		

434

Use a switch statement to choose the right option			

435

Serialization lets you read or write a whole object all at once

442

.NET uses Unicode to store characters and text			

447

C# can use byte arrays to move data around			

448

You can read and write serialized files manually, too		

451

Working with binary files can be tricky				

453

Use file streams to build a hex dumper				

454

StreamReader and StreamWriter will do just fine (for now)		

455

Use Stream.Read() to read bytes from a stream			

456

table of contents

10

exception handling
Putting out fires gets old
Programmers aren’t meant to be firefighters.
You’ve worked your tail off, waded through technical manuals and a few engaging
Head First books, and you’ve reached the pinnacle of your profession: master
programmer. But you’re still getting panicked phone calls in the middle of the night
from work because your program crashes, or doesn’t behave like it’s supposed
to. Nothing pulls you out of the programming groove like having to fix a strange bug…
but with exception handling, you can write code to deal with problems that come up.
Better yet, you can even react to those problems, and keep things running.
Brian needs his excuses to be mobile				

464

When your program throws an exception, .NET generates an
Exception object.						

468

All exception objects inherit from Exception			

472

The debugger helps you track down and prevent exceptions
in your code						

473

Use the IDE’s debugger to ferret out exactly what went wrong in the
474
Excuse Manager						
Handle exceptions with try and catch				

479

What happens when a method you want to call is risky?		

480

Use the debugger to follow the try/catch flow			

482

If you have code that ALWAYS should run, use a finally block

484

One class throws an exception, another class catches the exception

491

Bees need an OutOfHoney exception				

492

An easy way to avoid a lot of problems:
using gives you try and finally for free				

495

Exception avoidance: implement IDisposable to
do your own cleanup					

496

The worst catch block EVER: catch-all plus comments		

498

Temporary solutions are OK (temporarily)			

499

A few simple ideas for exception handling			

500

Brian finally gets his vacation…				

505

xxi

table of contents

11

events and delegates
What your code does when you’re not looking
Your objects are starting to think for themselves.
You can’t always control what your objects are doing. Sometimes things…happen. And
when they do, you want your objects to be smart enough to respond to anything that
pops up. And that’s what events are all about. One object publishes an event, other
objects subscribe, and everyone works together to keep things moving. Which is great,
until you want your object to take control over who can listen. That’s when callbacks will
come in handy.

xxii

Ever wish your objects could think for themselves?		

508

But how does an object KNOW to respond?			

508

When an EVENT occurs…objects listen			

509

Then, the other objects handle the event			

511

Connecting the dots					

512

The IDE creates event handlers for you automatically		

516

Generic EventHandlers let you define your own event types		

522

The forms you’ve been building all use events			

523

One event, multiple handlers					

524

Connecting event senders with event receivers			

526

A delegate STANDS IN for an actual method			

527

Delegates in action						

528

An object can subscribe to an event…				

531

Use a callback to control who’s listening				

532

A callback is just a way to use delegates				

534

table of contents

12

review and preview
Knowledge, power, and building cool stuff
Learning’s no good until you BUILD something.
Until you’ve actually written working code, it’s hard to be sure if you really get some
of the tougher concepts in C#. In this chapter, we’re going to use what we’ve learned
to do just that. We’ll also get a preview of some of the new ideas coming up soon.
And we’ll do all that by building phase I of a really complex application to make
sure you’ve got a good handle on what you’ve already learned from earlier chapters.
So buckle up…it’s time to build some software!
You’ve come a long way, baby					

542

We’ve also become beekeepers				

543

The beehive simulator architecture				

544

Building the beehive simulator				

545

Life and death of a flower					

549

Now we need a Bee class					

550

P. A. H. B. (Programmers Against Homeless Bees)			

554

The hive runs on honey					

554

Filling out the Hive class					

558

The hive’s Go() method					

559

We’re ready for the World					

560

We’re building a turn-based system				

561

Here’s the code for World					

562

Giving the bees behavior					

568

The main form tells the world to Go()				

570

We can use World to get statistics				

571

Timers fire events over and over again				

572

Let’s work with groups of bees				

580

A collection collects…DATA					

581

LINQ makes working with data in collections and databases easy

583

One final challenge: Open and Save				

585

xxiii

table of contents

13

controls and graphics
Make it pretty
Sometimes you have to take graphics into your own hands.
We’ve spent a lot of time relying on controls to handle everything visual in our applications.
But sometimes that’s not enough—like when you want to animate a picture. And once
you get into animation, you’ll end up creating your own controls for your .NET programs,
maybe adding a little double buffering, and even drawing directly onto your forms.
It all begins with the Graphics object, bitmaps, and a determination to not accept the
graphics status quo.

xxiv

You’ve been using controls all along to interact with your programs

590

Form controls are just objects					

591

Use controls to animate the beehive simulator			

592

Add a renderer to your architecture				

594

Controls are well suited for visual display elements		

596

Build your first animated control				

599

Create a button to add the BeeControl to your form		

602

Your controls need to dispose their controls, too!			

603

A UserControl is an easy way to build a control			

604

Your simulator’s renderer will use your BeeControl to draw
animated bees on your forms					

606

Add the hive and field forms to the project			

608

Build the renderer						

609

You resized your Bitmaps using a Graphics object			

618

Your image resources are stored in Bitmap objects		

619

Use System.Drawing to TAKE CONTROL of graphics yourself

620

A 30-second tour of GDI+ graphics				

621

Use graphics to draw a picture on a form			

622

Graphics can fix our transparency problem…			

627

Use the Paint event to make your graphics stick			

628

A closer look at how forms and controls repaint themselves		

631

Double buffering makes animation look a lot smoother		

634

Use a Graphics object and an event handler for printing		

640

table of contents

14

CAPTAIN AMAZING
THE DEATH
OF THE OBJECT

Your last chance to DO something…your object’s finalizer		

654

When EXACTLY does a finalizer run?				

655

Dispose() works with using, finalizers work with garbage collection

656

Finalizers can’t depend on stability				

658

Make an object serialize itself in its Dispose()			

659

A struct looks like an object…				

663

…but isn’t an object					

663

Values get copied; references get assigned			

664

The stack vs. the heap: more on memory			

667

Use out parameters to make a method return more than one value

670

Pass by reference using the ref modifier				

671

Use optional parameters to set default values			

672

Use nullable types when you need nonexistent values		

673

Nullable types help you make your programs more robust		

674

Captain Amazing…not so much				

677

Extension methods add new behavior to EXISTING classes

678

Extending a fundamental type: string				

6800

xxv

table of contents

15

LINQ
Get control of your data
It’s a data-driven world…you better know how to live in it.
Gone are the days when you could program for days, even weeks, without dealing with
loads of data. But today, everything is about data. In fact, you’ll often have to work
with data from more than one place…and in more than one format. Databases, XML,
collections from other programs…it’s all part of the job of a good C# programmer. And
that’s where LINQ comes in. LINQ not only lets you query data in a simple, intuitive way,
but it lets you group data, and merge data from different data sources.

xxvi

An easy project…						

686

…but the data’s all over the place				

687

LINQ can pull data from multiple sources			

688

.NET collections are already set up for LINQ			

689

LINQ makes queries easy					

690

LINQ is simple, but your queries don’t have to be			

691

LINQ is versatile						

694

LINQ can combine your results into groups			

699

Combine Jimmy’s values into groups				

700

Use join to combine two collections into one query		

703

Jimmy saved a bunch of dough				

704

Connect LINQ to a SQL database				

706

Use a join query to connect Starbuzz and Objectville		

710

table of contents

C# Lab 3
Invaders
In this lab you’ll pay homage to one of the most popular,
revered and replicated icons in video game history, a
game that needs no further introduction. It’s time to
build Invaders.
The grandfather of video games				

714

And yet there’s more to do…					

733

xxvii

table of contents

i

leftovers
The top 11 things we wanted to include
in this book
The fun’s just beginning!
We’ve shown you a lot of great tools to build some really powerful software with C#. But
there’s no way that we could include every single tool, technology, or technique in this
book—there just aren’t enough pages. We had to make some really tough choices about
what to include and what to leave out. Here are some of the topics that didn’t make the
cut. But even though we couldn’t get to them, we still think that they’re important and
useful, and we wanted to give you a small head start with them.

xxviii

#1. The Basics						

736

#2. Namespaces and assemblies				

742

#3. Use BackgroundWorker to make your UI responsive		

746

#4. The Type class and GetType()				

749

#5. Equality, IEquatable, and Equals()				

750

#6. Using yield return to create enumerable objects		

753

#7. Refactoring						

756

#8. Anonymous types, anonymous methods, and
lambda expressions						

758

#9. Serializing data using DataContractSerializer			

760

#10. LINQ to XML					

762

#11. Windows Presentation Foundation				

764

Did you know that C# and the .NET Framework can…		

766

how to use this book

Intro
I can’t believe they
put that in a C#
programming book!

:
er the burning question
In this section, we antswthat in a C# programming book?”
“So why DID they pu

xxix

how to use this book

Who is this book for?
If you can answer “yes” to all of these:
1

Do you want to learn C#?

2

Do you like to tinker—do you learn by doing, rather than
just reading?

3

Do you prefer stimulating dinner party conversation
to dry, dull, academic lectures?

this book is for you.

Who should probably back away from this book?
If you can answer “yes” to any of these:
1

Does the idea of writing a lot of code make you bored
and a little twitchy?

2 Are you a kick-butt C++ or Java programmer looking for
a reference book?

3

Are you afraid to try something different? Would
you rather have a root canal than mix stripes with
plaid? Do you believe that a technical book can’t be
serious if C# concepts are anthropomorphized?

this book is not for you.

[Note from marketing: this boo
for anyone with a credit card.] k is

xxx   intro

the intro

We know what you’re thinking.
“How can this be a serious C# programming book?”
“What’s with all the graphics?”
“Can I actually learn it this way?”

And we know what your brain is thinking.

Your bra
THIS is imin thinks
portant.

Your brain craves novelty. It’s always searching, scanning, waiting for
something unusual. It was built that way, and it helps you stay alive.
So what does your brain do with all the routine, ordinary, normal things
you encounter? Everything it can to stop them from interfering with
the brain’s real job—recording things that matter. It doesn’t bother
saving the boring things; they never make it past the “this is obviously
not important” filter.
How does your brain know what’s important? Suppose you’re out for
a day hike and a tiger jumps in front of you, what happens inside your
head and body?
Neurons fire. Emotions crank up. Chemicals surge.
And that’s how your brain knows…
This must be important! Don’t forget it!
But imagine you’re at home, or in a library. It’s a safe, warm, tiger‑free zone.
You’re studying. Getting ready for an exam. Or trying to learn some
tough technical topic your boss thinks will take a week, ten days at
the most.

in thinks
Your bran’t worth
THIinS gis.
sav

Great. Only
700 more dull,
dry, boring pages.

Just one problem. Your brain’s trying to do you a big favor. It’s trying
to make sure that this obviously non-important content doesn’t clutter
up scarce resources. Resources that are better spent storing the really
big things. Like tigers. Like the danger of fire. Like how you should
never have posted those “party” photos on your Facebook page.
And there’s no simple way to tell your brain, “Hey brain, thank you
very much, but no matter how dull this book is, and how little I’m
registering on the emotional Richter scale right now, I really do want
you to keep this stuff around.”

you are here 4   xxxi

how to use this book

t”
We think of a “Head Firs

reader as a learner.

ke sure
ve to get it, then ma
thing? First, you ha
me
so
rn
lea
the
to
e
on
d
tak
. Base
So what does it
facts into your head
It’s not about pushing
onal psychology,
ati
uc
ed
d
you don’t forget it.
urobiology, an
ne
,
ce
ien
sc
e
itiv
gn
ns your brain on.
latest research in co
. We know what tur
ge
pa
a
on
t
tex
n
more tha
learning takes a lot
ciples:
First lear ning prin
Some of the Head

le than words alone, and
s are far more memorab
age
Im
l.
ua
and
vis
it
Make
improvement in recall
re effective (up to 89%
mo
ch
mu
ng
rni
e
lea
th
t
make
understandable. Pu
o makes things more
than on
transfer studies). It als
s they relate to, rather
near the gr aphic
or
in
th
wi
s
likely to
rd
as
wo
rs will be up to twice
ther page, and learne
ano
on
or
m
tto
bo
the
d to the content.
solve problems relate
dies,
d style. In recent stu
l and personalize
na
tio
sa
er
nv
ke
co
spo
tent
Use a
earning tests if the con
to 40% better on post-l
students performed up
n
tha
versational style rather
using a first-person, con
guage.
directly to the reader,
turing. Use casual lan
l stories instead of lec
Tel
e.
ton
l
a
ma
for
a
tak ing
pay more attention to:
iously. Which would you
ser
too
lf
rse
you
e
tak
Don’t
ture?
ty companion, or a lec
stimulating dinner par
s you
In other words, unles
ink more deeply.
th
to
er
rn
lea
der
e
rea
th
Get
ns in your head. A
s, nothing much happe
ron
neu
r
you
, draw
flex
ms
ly
active
pired to solve proble
aged, curious, and ins
eng
d,
ate
tiv
mo
llenges,
be
cha
has to
for that, you need
new knowledge. And
ate
ner
ge
and
both
ns,
e
sio
olv
conclu
activities that inv
vok ing questions, and
pro
htug
tho
and
es,
exercis
multiple senses.
sides of the brain and
this but
“I really want to learn
ion. We’ve all had the
nt
te
at
’s
er
t of
ad
ou
re
he
ion to things that are
Get—and keep—t
Your brain pays attent
e.
enc
eri
gh,
exp
e”
tou
,
on
e
new
t pag
ected. Learning a
I can’t stay awake pas
e, eye -catching, unexp
ang
str
g,
ly if
stin
ick
ere
qu
re
int
the ordinary,
will learn much mo
be boring. Your brain
to
e
hav
’t
esn
do
ic
top
technical
it’s not.

r ability to remember
We now know that you
s.
ion
ot
em
what
eir
th
Touch
tent. You remember
ent on its emotional con
nd
pe
de
ely
g
larg
is
kin
something
ing. No, we’re not tal
r when you feel someth
be
em
rem
You
ut.
like
s
otion
you care abo
dog. We’re talking em
s about a boy and his
t comes when
tha
heart‑wrenching storie
le!”
Ru
“I
of
…?” , and the feeling
the
hat
“w
,
fun
ity,
you
ios
surprise, cur
nks is hard, or realize
ing everybody else thi
eth
som
rn
lea
sn’t.
e,
zzl
doe
pu
you solve a
b from engineering
technical than thou” Bo
re
mo
“I’m
t
tha
ing
know someth

xxxii   intro

the intro

Metacognition: thinking about thinking
If you really want to learn, and you want to learn more quickly and more deeply,
pay attention to how you pay attention. Think about how you think. Learn how you
learn.
Most of us did not take courses on metacognition or learning theory when we were
growing up. We were expected to learn, but rarely taught to learn.

I wonder how I
can trick my brain
into remembering
this stuff…

But we assume that if you’re holding this book, you really want to learn how to
build programs in C#. And you probably don’t want to spend a lot of time. If you
want to use what you read in this book, you need to remember what you read. And
for that, you’ve got to understand it. To get the most from this book, or any book or
learning experience, take responsibility for your brain. Your brain on this content.
The trick is to get your brain to see the new material you’re learning
as Really Important. Crucial to your well-being. As important as
a tiger. Otherwise, you’re in for a constant battle, with your brain
doing its best to keep the new content from sticking.

So just how DO you get your brain to treat C# like
it was a hungry tiger?
There’s the slow, tedious way, or the faster, more effective way.
The slow way is about sheer repetition. You obviously know that
you are able to learn and remember even the dullest of topics
if you keep pounding the same thing into your brain. With enough
repetition, your brain says, “This doesn’t feel important to him, but he keeps looking
at the same thing over and over and over, so I suppose it must be.”
The faster way is to do anything that increases brain activity, especially different
types of brain activity. The things on the previous page are a big part of the solution,
and they’re all things that have been proven to help your brain work in your favor. For
example, studies show that putting words within the pictures they describe (as opposed to
somewhere else in the page, like a caption or in the body text) causes your brain to try to
makes sense of how the words and picture relate, and this causes more neurons to fire.
More neurons firing = more chances for your brain to get that this is something worth
paying attention to, and possibly recording.
A conversational style helps because people tend to pay more attention when they
perceive that they’re in a conversation, since they’re expected to follow along and hold up
their end. The amazing thing is, your brain doesn’t necessarily care that the “conversation”
is between you and a book! On the other hand, if the writing style is formal and dry, your
brain perceives it the same way you experience being lectured to while sitting in a roomful
of passive attendees. No need to stay awake.
But pictures and conversational style are just the beginning.

you are here 4   xxxiii

how to use this book

Here’s what WE did:
We used pictures, because your brain is tuned for visuals, not text. As far as your
brain’s concerned, a picture really is worth a thousand words. And when text and
pictures work together, we embedded the text in the pictures because your brain
works more effectively when the text is within the thing the text refers to, as opposed
to in a caption or buried in the text somewhere.
We used redundancy, saying the same thing in different ways and with different media types,
and multiple senses, to increase the chance that the content gets coded into more than one area
of your brain.
We used concepts and pictures in unexpected ways because your brain is tuned for novelty,
and we used pictures and ideas with at least some emotional content, because your brain
is tuned to pay attention to the biochemistry of emotions. That which causes you to feel
something is more likely to be remembered, even if that feeling is nothing more than a little
humor, surprise, or interest.
We used a personalized, conversational style, because your brain is tuned to pay more
attention when it believes you’re in a conversation than if it thinks you’re passively listening
to a presentation. Your brain does this even when you’re reading.
We included more than 80 activities, because your brain is tuned to learn and remember
more when you do things than when you read about things. And we made the exercises
challenging-yet-do-able, because that’s what most people prefer.
We used multiple learning styles, because you might prefer step-by-step procedures,
while someone else wants to understand the big picture first, and someone else just
wants to see an example. But regardless of your own learning preference, everyone
benefits from seeing the same content represented in multiple ways.
We include content for both sides of your brain, because the more of your brain you
engage, the more likely you are to learn and remember, and the longer you can stay focused.
Since working one side of the brain often means giving the other side a chance to rest, you
can be more productive at learning for a longer period of time.
And we included stories and exercises that present more than one point of view,
because your brain is tuned to learn more deeply when it’s forced to make evaluations and
judgments.
We included challenges, with exercises, and by asking questions that don’t always have
a straight answer, because your brain is tuned to learn and remember when it has to work at
something. Think about it—you can’t get your body in shape just by watching people at the
gym. But we did our best to make sure that when you’re working hard, it’s on the right things.
That you’re not spending one extra dendrite processing a hard-to-understand example,
or parsing difficult, jargon-laden, or overly terse text.
We used people. In stories, examples, pictures, etc., because, well, because you’re a person.
And your brain pays more attention to people than it does to things.

xxxiv   intro

When you define a class, you define
its methods, just like a blueprint
defines the layout of the house.

You can use one blueprint to
make any number of houses,
and you can use one class to
make any number of objects.

the intro

Here’s what YOU can do to bend
					
your brain into submission
So, we did our part. The rest is up to you. These tips are a
starting point; listen to your brain and figure out what works
for you and what doesn’t. Try new things.

Cut this out an
ick it
on your refrigerdatst
or.
1

Slow down. The more you understand,
the less you have to memorize.

6

Speaking activates a different part of the brain.
If you’re trying to understand something, or
increase your chance of remembering it later, say
it out loud. Better still, try to explain it out loud
to someone else. You’ll learn more quickly, and
you might uncover ideas you hadn’t known were
there when you were reading about it.

Don’t just read. Stop and think. When the
book asks you a question, don’t just skip to the
answer. Imagine that someone really is asking
the question. The more deeply you force your
brain to think, the better chance you have of
learning and remembering.
2

Do the exercises. Write your own notes.

7

Read the “There are No Dumb Questions”

8

Make this the last thing you read before
bed. Or at least the last challenging thing.

Part of the learning (especially the transfer to
long-term memory) happens after you put the
book down. Your brain needs time on its own, to
do more processing. If you put in something new
during that processing time, some of what you
just learned will be lost.
5

Drink water. Lots of it.

Your brain works best in a nice bath of fluid.
Dehydration (which can happen before you ever
feel thirsty) decreases cognitive function.

Feel something.

Your brain needs to know that this matters. Get
involved with the stories. Make up your own
captions for the photos. Groaning over a bad joke
is still better than feeling nothing at all.

That means all of them. They’re not optional
sidebars—they’re part of the core content!
Don’t skip them.
4

Listen to your brain.

Pay attention to whether your brain is getting
overloaded. If you find yourself starting to skim
the surface or forget what you just read, it’s time
for a break. Once you go past a certain point, you
won’t learn faster by trying to shove more in, and
you might even hurt the process.

We put them in, but if we did them for you,
that would be like having someone else do
your workouts for you. And don’t just look at
the exercises. Use a pencil. There’s plenty of
evidence that physical activity while learning
can increase the learning.
3

Talk about it. Out loud.

9

Write a lot of software!

There’s only one way to learn to program: writing
a lot of code. And that’s what you’re going to do
throughout this book. Coding is a skill, and the only
way to get good at it is to practice. We’re going to
give you a lot of practice: every chapter has exercises
that pose a problem for you to solve. Don’t just skip
over them—a lot of the learning happens when
you solve the exercises. We included a solution to
each exercise—don’t be afraid to peek at the
solution if you get stuck! (It’s easy to get snagged on
something small.) But try to solve the problem before
you look at the solution. And definitely get it working
before you move on to the next part of the book.
you are here 4   xxxv

how to use this book

What you need for this book:
We wrote this book using Visual C# 2010 Express Edition, which uses C# 4.0 and .NET Framework 4.0. All of
the screenshots that you see throughout the book were taken from that edition, so we recommend that you use it.
If you’re using Visual Studio 2010 Professional, Premium, Ultimate or Test Professional editions, you’ll see some
small differences, which we’ve pointed out wherever possible. You can download the Express Edition for free
from Microsoft’s website—it installs cleanly alongside other editions, as well as previous versions of Visual Studio.

SETTING UP VISUAL STUDIO 2010 EXPRESS EDITION

� It’s easy enough to download and install Visual C# 2010 Express Edition. Here’s the link to the Visual Studio
2010 Express Edition download page:

http://www.microsoft.com/express/downloads/
You don’t need to check any of the options in the installer to get the code in this book to run, but feel free to if
you want.

If you absolutely must use an
older version of Visual Studio,
C# or the .NET Framework,
then please keep in mind that
you’ll come across topics in this
book that won’t be compatible
with your version. The C# team
at Microsoft has added some
pretty cool features to the
language. Keep in mind that
if you’re not using the latest
version, there will be some code
in this book that won’t work.

� Download the installation package for Visual C# 2010 Express Edition. Make sure you do a complete

installation. That should install everything that you need: the IDE (which you’ll learn about),.NET Framework
4.0, and other tools.

� Once you’ve got it installed, you’ll have a new Start menu option: Microsoft Visual C# 2010 Express Edition.
Click on it to bring up the IDE, and you’re all set.

xxxvi   intro

the intro

Read me
This is a learning experience, not a reference book. We deliberately stripped out
everything that might get in the way of learning whatever it is we’re working on at
that point in the book. And the first time through, you need to begin at the beginning,
because the book makes assumptions about what you’ve already seen and learned.
The activities are NOT optional.
The exercises and activities are not add-ons; they’re part of the core content of the
book. Some of them are to help with memory, some for understanding, and some to
help you apply what you’ve learned. Don’t skip the written problems. The pool
puzzles are the only things you don’t have to do, but they’re good for giving your brain a
chance to think about twisty little logic puzzles.
The redundancy is intentional and important.
One distinct difference in a Head First book is that we want you to really get it. And we
want you to finish the book remembering what you’ve learned. Most reference books
don’t have retention and recall as a goal, but this book is about learning, so you’ll see
some of the same concepts come up more than once.
Do all the exercises!
The one big assumption that we made when we wrote this book is that you want to
learn how to program in C#. So we know you want to get your hands dirty right away,
and dig right into the code. We gave you a lot of opportunities to sharpen your skills
by putting exercises in every chapter. We’ve labeled some of them “Do this!”—when
you see that, it means that we’ll walk you through all of the steps to solve a particular
problem. But when you see the Exercise logo with the running shoes, then we’ve left
a big portion of the problem up to you to solve, and we gave you the solution that we
came up with. Don’t be afraid to peek at the solution—it’s not cheating! But you’ll
learn the most if you try to solve the problem first.
We’ve also placed all the exercise solutions’ source code on the web so you can download
it. You’ll find it at http://www.headfirstlabs.com/books/hfcsharp/
The “Brain Power” exercises don’t have answers.

rams to
We use a lot of diag
easier
ts
ep
make tough conc
to understand.



cia
Age
nt

mi
5A
gent

the
You should do ALL of tiv
ities
ac
“Sharpen your pencil”

Activities marked with
the
Exercise (running shoe
)
are really important! D logo
skip them if you’re serioon’t
us
about learning C#.

o,
If you see the Pool Puzzle logif
the activity is optional, andyou
you don’t like twisty logic,
won’t like these either.

For some of them, there is no right answer, and for others, part of the learning
experience of the Brain Power activities is for you to decide if and when your answers
are right. In some of the Brain Power exercises you will find hints to point you in the
right direction.

you are here 4   xxxvii

the review team

The technical review team
Lisa Kellner

Chris Burrow
s

ateful for
r
g
y
ll
ia
c
e
We’re esp sight and almost ck.
Chris’s insly helpful feedba
ridiculou

David Sterling

Nick Paladino

David really helped us out,
especially with some very
neat IDE tricks.

Not pictured (but just
as awesome are the
reviewers from the first
edition): Joe Albahari,
Jay Hilyard, Aayam
Singh, Theodore, Peter
Ritchie,Bill Meitelski
Andy Parker, Wayne
Bradney, Dave Murdoch,
Bridgette Julie Landers.
And special thanks
to Jon Skeet for his
thorough review and
suggestions for the first
edition!

Technical Reviewers:
When we wrote this book, it had a bunch of mistakes, issues, problems, typos, and terrible arithmetic errors. OK, it
wasn’t quite that bad. But we’re still really grateful for the work that our technical reviewers did for the book. We
would have gone to press with errors (including one or two big ones) had it not been for the most kick-ass review team
EVER.…
First of all, we really want to thank Chris Burrows and David Sterling for their enormous amount of technical
guidance. We also want to thank Lisa Kellner—this is our sixth book that she’s reviewed for us, and she made a huge
difference in the readability of the final product. Thanks, Lisa! And special thanks to Nick Paladino. Thanks!
Chris Burrows is a developer at Microsoft on the C# Compiler team who focused on design and implementation of
language features in C# 4.0, most notably dynamic.
David Sterling has worked on the Visual C# Compiler team for nearly 3 years.
Nicholas Paldino has been a Microsoft MVP for .NET/C# since the discipline’s inception in the MVP program and has
over 13 years of experience in the programming industry, specifically targeting Microsoft technologies.
xxxviii   intro

the intro

Acknowledgments
Our editor:
We want to thank our editors, Brett McLaughlin and
Courtney Nash, for editing this book. Brett helped with a lot of
the narrative, and the comic idea in Chapter 14 was completely his,
and we think it turned out really well. Thanks!

Brett McLaughlin

Courtney Nash

The O’Reilly team:
Lou Barr is an amazing graphic designer who went above and beyond
on this one, putting in unbelievable hours and coming up with some pretty
amazing visuals. If you see anything in this book that looks fantastic, you can
thank her (and her mad InDesign skillz) for it. She did all of the monster and
alien graphics for the labs, and the entire comic book. Thanks so much, Lou!
You are our hero, and you’re awesome to work with.

Lou Barr

Sanders Kleinfeld

There are so many people at O’Reilly we want to thank that we hope we
don’t forget anyone. Special thanks to production editor Rachel Monaghan,
indexer Lucie Haskins, Emily Quill for her sharp proofread, Ron
Bilodeau for volunteering his time and preflighting expertise, and Sanders
Kleinfeld for offering one last sanity check—all of whom helped get this
book from production to press in record time. And as always, we love Mary
Treseler, and can’t wait to work with her again! And a big shout out to our
other friends and editors, Andy Oram and Mike Hendrickson. And if
you’re reading this book right now, then you can thank the greatest publicity
team in the industry: Marsee Henon, Sara Peyton, Mary Rotman,
Jessica Boyd, Kathryn Barrett, and the rest of the folks at Sebastopol.

you are here 4   xxxix

safari books online

Safari® Books Online
Safari Books Online is an on-demand digital library that lets you easily search over 7,500
technology and creative reference books and videos to find the answers you need quickly.
With a subscription, you can read any page and watch any video from our library online. Read books on your cell
phone and mobile devices. Access new titles before they are available for print, and get exclusive access to manuscripts
in development and post feedback for the authors. Copy and paste code samples, organize your favorites, download
chapters, bookmark key sections, create notes, print out pages, and benefit from tons of other time-saving features.
O’Reilly Media has uploaded this book to the Safari Books Online service. To have full digital access
to this book and others on similar topics from O’Reilly and other publishers, sign up for free at
http://my.safaribooksonline.com/?portal=oreilly.

xl   intro

1 get productive with c#

Visual Applications, in 10
minutes or less
Don’t worry, Mother. With Visual
Studio and C#, you’ll be able to
program so fast that you’ll never
burn the pot roast again.

Want to build great programs really fast?
With C#, you’ve got a powerful programming language and a valuable tool
at your fingertips. With the Visual Studio IDE, you’ll never have to spend hours
writing obscure code to get a button working again. Even better, you’ll be able
to focus on getting your work done, rather than remembering which method
parameter was for the name of a button, and which one was for its label. Sound
appealing? Turn the page, and let’s get programming.

this is a new chapter   1

c# makes it easy

Why you should le arn C#
C# and the Visual Studio IDE make it easy for you to get to the business
of writing code, and writing it fast. When you’re working with C#, the
IDE is your best friend and constant companion.

Here’s what the IDE automate s for you…
Every time you want to get started writing a program, or
just putting a button on a form, your program needs a
whole bunch of repetitive code.

ic;
using System;
llections.Gener
using System.Co
ndows.Forms;
using System.Wi
gram
Pro
ew_
A_N
namespace
{
Program
static class
{
lication.
///  entry point for the app
/// The main >
ary
/// > Other Windows menu.
Then in each of the blanks, try and fill in an annotation saying what that part of the IDE does. We’ve
done one to get you started.

This toolbar has button
that apply to what yo s
currently doing in the u’re
IDE.

If your IDE doesn’t look exactly like this
picture, you can select “Reset Window
Layout” from the Window menu.

We’ve blown up this
window below so you
have more room.

If you don’t see the
Error List or Toolbox,
choose them from View
>> Other Windows.

you are here 4   9

know your ide

This toolbar has button
that apply to what yo s
currently doing in the u’re
IDE.

This is the
toolbox. It
has a bunch of
visual controls
that you can
drag onto your
form.

shows
This Error List window in
rs
you when there are erro ow
ll sh
your code. This pane wi t
abou
lots of diagnostic info
your program.
The Form1.cs an
d
files that the Program.cs
ID
for you when yo E created
u
new project ap added the
pear
Solution Explor in the
er.

10   Chapter 1

We’ve filled in the annotations about the different sections of the Visual
Studio C# IDE. You may have some different things written down, but you
should have been able to figure out the basics of what each window and
section of the IDE is used for.

This window shows
properties of the
control currently
selected on your
form.
See this little
pushpin icon?
If you click it,
you can turn
auto-hide on or
off. The Toolbox
window has
auto-hide turned
on by default.

You can switch
between
files using the
Solution
Explorer in the
IDE.

get productive with c#

Q:

So if the IDE writes all this code
for me, is learning C# just a matter of
learning how to use the IDE?

A:

No. The IDE is great at automatically
generating some code for you, but it can
only do so much. There are some things it’s
really good at, like setting up good starting
points for you, and automatically changing
properties of controls on your forms. But
the hard part of programming—figuring out
what your program needs to do and making
it do it—is something that no IDE can do
for you. Even though the Visual Studio IDE
is one of the most advanced development
environments out there, it can only go so far.
It’s you—not the IDE—who writes the code
that actually does the work.

Q:

I created a new project in Visual
Studio, but when I went into the “Projects”
folder under My Documents, I didn’t see it
there. What gives?

A:

When you first create a new project in
Visual Studio 2010 Express, the IDE creates
the project in your Local Settings\

Application Data\Temporary
Projects folder. When you save the
project for the first time, it will prompt you
for a new filename, and save it in the My

Documents\Visual Studio
2010\Projects folder. If you try to

open a new project or close the temporary
one, you’ll be prompted to either save or
discard the temporary project. (NOTE: The
other, non-Express versions of Visual Studio
do not use a temporary projects folder. They
create the project directly in Projects!)

Q:

What if the IDE creates code I don’t
want in my project?

A:

You can change it. The IDE is set up to
create code based on the way the element
you dragged or added is most commonly

used. But sometimes that’s not exactly what
you wanted. Everything the IDE does for
you—every line of code it creates, every file
it adds—can be changed, either manually by
editing the files directly or through an easyto-use interface in the IDE.

Q:

Is it OK that I downloaded and
installed Visual Studio Express? Or do
I need to use one of the versions of
Visual Studio that isn’t free in order to do
everything in this book?

A:

There’s nothing in this book that you
can’t do with the free version of Visual Studio
(which you can download from Microsoft’s
website). The main differences between
Express and the other editions (Professional
and Team Foundation) aren’t going to get
in the way of writing C# and creating fully
functional, complete applications.

Q:

Can I change the names of the files
the IDE generates for me?

A:

Absolutely. When you create a new
project, the IDE gives you a default form called
Form1 (which has files called Form1.cs,
Form1.Designer.cs, and Form1.
resx). But you can use the Solution
Explorer to change the names of the files to
whatever you want. By default, the names of
the files are the same as the name of the form.
If you change the names of the files, you’ll
be able to see in the Properties window that
the form will still be called Form1. You can
change the name of the form by changing the
“(Name)” line in the Properties window. If you
do, the filenames won’t change.
C# doesn’t care what names you choose for
your files or your forms (or any other part of
the program), although there are a few rules
for this. But if you choose good names, it
makes your programs easier to work with.
For now, don’t worry about names—we’ll talk
a lot more about how to choose good names
for parts of your program later on.

Q:

I’m looking at the IDE right now,
but my screen doesn’t look like yours! It’s
missing some of the windows, and others
are in the wrong place. What gives?

A:

If you click on the “Reset Window
Layout” command under the “Window” menu,
the IDE will restore the default window layout
for you. Then you can use the “View >>
Other Windows” menu to make your screen
look just like the ones in this chapter.

Visual Studio will
generate code
you can use as a
starting point for
your applications.
Making sure
the application
does what it’s
supposed to do
is entirely up to
you.
you are here 4   11

a picturebox is worth a thousand words

Develop the user interface
Adding controls and polishing the user interface is as easy as
dragging and dropping with the Visual Studio IDE. Let’s add a
logo to the form:
1

Use the PictureBox control to add a picture.
Click on the PictureBox control in the Toolbox, and drag it
onto your form. In the background, the IDE added code to
Form1.Designer.cs for a new picture control.

If you don’t see
the toolbox, try
hovering over the
word “Toolbox”
that shows up
in the upper
left-hand corner
of the IDE. If it’s
not there, select
“Toolbox” from
the View menu to
make it appear.

Every time you make a cha
properties on the form, thengecodto a control’s
Designer.cs is getting changed e in Form1.
by the IDE.
C#
Form1.Designer.cs

12   Chapter 1

		It’s OK if you’re not a pro at user
interface design.
We’ll talk a lot more about designing
good user interfaces later on. For now,
just get the logo and other controls on your form, and
worry about behavior. We’ll add some style later.

get productive with c#
.NET Visual
Objects

.NET
Database
Objects

Data Storage
Stored
Procedures

You are Here

2

Set the PictureBox to Zoom mode.
Every control on your form has properties that you can
set. Click the little black arrow for a control to access
these properties. Change the PictureBox’s Size property
to “Zoom” to see how this works:

You can also use the
“Properties” window in
the IDE to set the
Size property. The
little black arrow is
just there to make
it easy to access
the most common
properties of any
control.

Then click “Choose Image”
the Select Resource dialog to bring up
can import a local resourc box so you
e.
3

Deployment
Pack age

little
Click on this to
access
black arrow operties.
a control’s pr

Choose “
the PictuZr oom” so that
will change eBox frame
size of th to match the
put in it. e picture you

Download the Objectville Paper Company logo.
Download the Objectville Paper Co. logo from Head First Labs (http://
www.headfirstlabs.com/books/hfcsharp) and save it to your hard drive.
Then click the PictureBox properties arrow, and select Choose Image. You’ll see a
Select Resources window pop up. Click the “Local Resource” radio button to enable the
“Import…” button at the top of the form. Click that button, find your logo, and you’re all set.

logo,
Here’s the OPurCeBox
and the Pict the size
zooms to get
just right.

you are here 4   13

conserving c#’s natural resources

Visual Studio, behind the scene s
Every time you do something in the Visual Studio IDE, the IDE is
writing code for you. When you created the logo and told Visual
Studio to use the image you downloaded, Visual Studio created a resource
and associated it with your application. A resource is any graphics file,
audio file, icon, or other kind of data file that gets bundled with your
application. The graphics file gets integrated into the program, so that
when it’s installed on another computer, the graphic is installed along with
it and the PictureBox can use it.
When you dragged the PictureBox control onto your form, the IDE
automatically created a resource file called Form1.resx to store that
resource and keep it in the project. Double-click on this file, and you’ll be
able to see the newly imported image.

This image is now a resource of the
Contact List application.

Go to the Solution Explorer and click on the “expand” icon next
to Form1.cs to expand it (if it’s not already expanded). This
will display two files: Form1.Designer.cs and Form1.
resx. Double-click on Form1.resx, click on the arrow next
to “Strings”, and select “Images” from the drop-down list (or hit
Ctrl-2) to see the logo that you imported. That file is what links it
to the PictureBox, and the IDE added code to do the linking.

If you chose the other
“Import.” button from
the Select Resource
dialog on the last page,
then your image will
show up in the Resources
folder in the Solution
Explorer instead. Don’t
worry—just go back to
Select Resources, choose
“Local Resource,” and
reimport the image into
the resources, and it’ll
show up here.

C#
C#

e files
Here are tdhio
Visual Stu arlier.
created e

Form1.cs

14   Chapter 1

Form1.Designer.cs

C#
Program.cs

C#
Form1.resx

When you imported the image, the
IDE created this file for you.
It contains all of the resources
(graphics, video, audio and other
stored data) associated with Form1.

get productive with c#

Add to the auto-generated code
The IDE creates lots of code for you, but you’ll still want to get
into this code and add to it. Let’s set the logo up to show an About
message when the users run the program and click on the logo.
When you’re editing a form in the IDE, double-clicking on any of
the toolbox controls causes the IDE to automatically add code to
your project. Make sure you’ve got the form showing in the IDE,
and then double-click on the PictureBox control. The IDE will
add code to your project that gets run any time a user clicks on the
PictureBox. You should see some code pop up that looks like this:
public partial class Form1 : Form
{

When you double-clicked on the PictureBox control,
the IDE created this method. It will run every time
a user clicks on the logo in the running application.
InitializeComponent();
od name gives you nsa :
th
me
s
hi
T
}
en it ru
good idea about wh
on this
ks
ic
cl
private void pictureBox1_Click(object sender, EventArgs e)
when someone
PictureBox control.
public Form1()
{

{

MessageBox.Show(“Contact List 1.0.\nWritten by: Your Name”, “About”);
}

}

When you double-click on the
PictureBox, it will open this
code up with a cursor blinking
right here. Ignore any windows
the IDE pops up as you type;
it’s trying to help you, but we
don’t need that right now.

Q:
A:

Type in this line
box to pop up witof code. It causes a message
box will be titled h the text you provide. The
“About”.

What’s a method?

A method is just a named block of code.
We’ll talk a lot more about methods in Chapter 2.

Q:
A:

Once you’ve typed in the line
of code, save it using the Save
icon on the IDE toolbar or
by selecting “Save” from the
File menu. Get in the habit of
doing “Save All” regularly!

What does that \n thing do?

That’s a line break. It tells C# to put
“Contact List 1.0.” on one line, and then start a
new line for “Written by:”.

you are here 4   15

run the app (already!)

You can alre ady run your application
Press the F5 key on your keyboard, or click the green
arrow button ( ) on the toolbar to check out what you’ve
done so far. (This is called “debugging,” which just means
running your program using the IDE.) You can stop
debugging by selecting “Stop Debugging” from the Debug
.
menu or clicking this toolbar button:

All three of thes
buttons work—ande yo
didn’t have to write u
code to make them any
work.

Clicking on the
OPC logo brings up
the About box you
just coded.

Where are my file s?
When you run your program, Visual Studio copies
your files to My Documents\Visual Studio
2010\Projects\Contacts\Contacts\
bin\debug. You can even hop over to that
directory and run your program by double-clicking
on the .exe file the IDE creates.

C#

Program.cs

C#
C#

Form1.cs

Form1.
Designer.cs

C# turns your
program into a
file that you can
run, called an
executable. You’ll
find it in here, in
the debug folder.

Form1.resx

Contacts.csproj

bin
Properties

This isn’t a mistake; there are two levels of folders. The inner
folder has the actual C# code files.
16   Chapter 1

In my IDE, the green arrow is marked as
“Debug.” Is that a problem?
No. Debugging, at least for our purposes
right now, just means running your application
inside the IDE. We’ll talk a lot more about
debugging later, but for now, you can simply think
about it as a way to run your program.

Q:

C#
C#

Q:
A:

I don’t see the Stop Debugging button
on my toolbar. What gives?

A:

The Stop Debugging button shows up in a
special toolbar that only shows up when your
program is running. Try starting the application
again, and see if it appears.

get productive with c#

Here’s what we’ve done so far
We’ve built a form and created a PictureBox object that pops up a
message box when it’s clicked on. Next, we need to add all the other
fields from the card, like the contact’s name and phone number.
Let’s store that information in a database. Visual Studio can connect
fields directly to that database for us, which means we don’t have to
mess with lots of database access code (which is good). But for that
to work, we need to create our database so that the controls on the
form can hook up to it. So we’re going to jump from the .NET Visual
Objects straight to the Data Storage section.

SQL
a
D tabase

.NET Visual
Objects
.NET
Database
Objects

Here’s what we’ve
already done…

ed some
…but we still ne
act
objects to intaerwe’ll put
with the dat e.
in our databas

This step is about
connecting our form
to the database, so
we’re not ready for
it yet, since we don’t
have a database.

Data Storage

Deployment
Pack age

Stored
Procedures

So we need to focus
on this step next:
creating our database,
and putting some
initial data into it.

Visual Studio can generate code to connect your
form to a database, but you need to have the
database in place BEFORE generating that code.
you are here 4   17

save it for later

We need a database to store our information
Before we add the rest of the fields to the form, we need
to create a database to hook the form up to. The IDE
can create lots of the code for connecting our form to
our data, but we need to define the database itself first.
1

Make sure you’
stopped debuggiveng
before you contin
ue

Add a new SQL database to your project.
In the Solution Explorer, right-click the Contacts project,
select Add, and then choose New Item. Choose the SQL
Database icon, and name it ContactDB.sdf.

.

This file is our
new database.

SQL
ContactDB.sdf

Choose Local
Database
to create a
SQL Server
Compact
Edition file,
which will hold
your entire
database.
Name your file
ContactDB.sdf.

2

3

4

Click on the Add button in the Add New Item
window.
Cancel the Data Source Configuration Wizard.
For now, we want to skip configuring a data source, so
click the Cancel button. We’ll come back to this once
we’ve set up our database structure.
View your database in the Solution Explorer.
Go to the Solution Explorer, and you’ll see that
ContactDB has been added to the file list. Double-click
ContactDB.sdf in the Solution Explorer and look at the
left side of your screen. The Toolbox has changed to a
Database Explorer.

18   Chapter 1

is
A Local Database rv
er
Se
L
actually a SQ
n
io
it
Compact Ed
database file, which
typically has the gives
extension SDF. It
you an easy way to into
embed a database
your program.

If you’re not using
the Express edition,
you’ll see “Server
Explorer” instead of
“Database Explorer.”
The Visual Studio 2010 Professional
and Team Foundation editions don’t
have a Database Explorer window.
Instead, they have a Server Explorer
window, which does everything the
Database Explorer does, but also lets
you explore data on your network.

get productive with c#

The IDE cre ated a database

.NET Visual
Objects

.NET
Database
Objects

Data Storage

Deployment
Pack age

Stored
Procedures

When you told the IDE to add a new SQL database to
your project, the IDE created a new database for you. A
SQL database is a system that stores data for you in an
organized, interrelated way. The IDE gives you all the
tools you need to maintain your data and databases.
Data in a SQL database lives in tables. For now, you
can think of a table like a spreadsheet. It organizes your
information into columns and rows. The columns are the
data categories, like a contact’s name and phone number,
and each row is the data for one contact card.

in a
Your data’s storedns and
table with colum readsheet.
rows, like in a sp

You are Here

A SQL database stores your
data, and has information abo
how it’s structured and SQL ut
code to help you access it.
Tables

Store
Procedudre
s

SQL
Database

SQL is its own language
SQL stands for Structured Query Language.
It’s a programming language for accessing data in
databases. It’s got its own syntax, keywords, and
structure. SQL code takes the form of statements
and queries, which access and retrieve the data.
A SQL database can hold stored procedures,
which are a bunch of SQL statements and queries
that are stored in the database and can be run at
any time. The IDE generates SQL statements and
stored procedures for you automatically to let your
program access the data in the database.

SQL

The SQL database is in this file.
We’re just about to define tables
and data for it, and all of that
will be stored in here too.

ContactDB.sdf

[note from marketing: Can we get a plug
for Head First SQL in here?]
you are here 4   19

data storage made easy

Cre ating the table for the Contact List
We have a database, and now we need to store information
in it. But our information actually has to go into a table,
the data structure that databases use to hold individual bits
of data. For our application, let’s create a table called
“People” to store all the contact information:
1

Add a table to the ContactDB database.
Right-click on Tables in the Database Explorer, and select
Create Table. This will open up a window where you can
define the columns in the table you just created.

Q:
A:

What’s a column again?

A column is one field of a table. So in a
People table, you might have a FirstName and
LastName column. It will always have a data
type, too, like String or Date or Bool.

Q:

Why do we need this ContactID
column?

A:

It helps to have a unique ID for each
record in most database tables. Since we’re
storing contact information for individual
people, we decided to create a column for that,
and call it ContactID.

Now we need to add columns to our table. First, let’s add a
column called ContactID to our new People table, so that
each Contact record has its own unique ID.
2

Add a ContactID column to the People table.
Type “ContactID” in the Column Name field, and
select Int from the Data Type drop-down box. Be sure
to select “No” for Allow Nulls.
Finally, let’s make this the primary key of our table.
Highlight the ContactID column you just created, and
click the Primary Key button. This tells the database
that each entry will have a unique primary key entry.

type “int”. Make sure to
Add a new column called “ContactID” with data
ary Key to “Yes.”
set “Allow Nulls” to No, “Unique” to Yes, and Prim
20   Chapter 1

Q:
A:

What’s that Int from Data Type mean?

The data type tells the database what
type of information to expect for a column.
Int stands for integer, which is just a whole
number. So the ContactID column will have
whole numbers in it.

Q:

This is a lot of stuff. Should I be
getting all of this?

A:

No, it’s OK if you don’t understand
everything right now. Your goal right now
should be to start to get familiar with the basics
of using the Visual Studio IDE to lay out your
form and run your program. (If you’re dying to
know more about databases, you can always
pick up Head First SQL.)

get productive with c#
.NET Visual
Objects

3

Tell the database to autogenerate IDs.
Since ContactID is a number for the database, and not
our users, we can tell our database to handle creating and
assigning IDs for us automatically. That way, we don’t have
to worry about writing any code to do this.

.NET
Database
Objects

Data Storage

Deployment
Pack age

Stored
Procedures

You are Here

In the properties below your table, set Identity to “True” to
make ContactID an identity column for your table.
And make sure you specify the table name “People” in the
Name box at the top of the window.

u use
This window is what yoand
to define your tablee.
the data it will stor

A primary key helps
your database look
up records quickly.
Since the primary
key is the main way
your program will
locate records, it
always needs to
have a value.

You’ll need to click on the right column and
select “True” from the drop-down next to
Identity to designate ContactID as your
table’s record Identifier.

This will make
it so that the
ContactID
field updates
automatically
whenever a new
record is added.
you are here 4   21

let’s table this discussion

The blanks on the contact card
are columns in our People table
Now that you’ve created a primary key for the table, you need
to define all of the fields you’re going to track in the database.
Each field on our written contact card should become a
column in the People table.

People
Name:

Laverne Smith

Company:

XYZ Industries

(212)555-8129
Email: Laverne.Smith@XyZindustries.com

Telephone:
Client:		
Yes

Last call:

05/26/07

For each person, we want to
store data:
her name, company, phone num
address, if she’s an OPC clientber, email
date of the last time she wa , and the
s called.

Each blank on
should map to the card
the people tab a column in
le.

What kinds of problems could result from having
multiple rows stored for the same person?

22   Chapter 1

get productive with c#

Now that you’ve created a People table and a primary key column, you need to add columns for all of the data
fields. See if you can work out which data type goes with each of the columns in your table, and also match the
data type to the right description.

Column Name

Data Type

Last Call

int

Description
This type stores a date
and time

A Boolean true/false type

Name

bit
ContactID

nvarchar(100)

A string of letters,
numbers, and other
characters with a
maximum length of 100

Client?

datetime

A whole number

you are here 4   23

it’s just my type

Now that you’ve created a People table and a primary key column, you need to add columns for all of the data
fields. See if you can work out which data type goes with each of the columns in your table, and also match the
data type to the right description.

Column Name

Data Type

Last Call

int

Description
This type stores a date
and time

A Boolean true/false type

Name

bit
ContactID

nvarchar(100)

A string of letters,
numbers, and other
characters with a
maximum length of 100

Client?

datetime

24   Chapter 1

A whole number

get productive with c#

Finish building the table

.NET Visual
Objects

.NET
Database
Objects

Data Storage

Deployment
Pack age

Stored
Procedures

Go back to where you entered the ContactID column
and add the other five columns from the contact card.
Here’s what your database table should look like
when you’re done:
You are Here

ow
If you set A, llthe
Nulls to No
column must .
have a value

Bit fields
hold True or
False values
and can be
represented
as a checkbox.

Some cards might
have some missing
information, so we
let certain columns’ll
be blank.
Click on the OK button to save your new table. This will add an empty table
to your database.

Once you click OKds, a
Visual Studio ade to
new People tabl
the database.

People

ContactDB

This new t
ready for yaoble is empty, but it’s
u to add dat
a!
you are here 4   25

adding your data

Insert your card data into the database
Now you’re ready to start entering cards into the database.
Here are some of the boss’s contacts—we’ll use those to
set up the database with a few records.

1

Expand Tables and then right-click
on the People table in the Database
Explorer (or Server Explorer) and
select Show Table Data.

2

Once you see the Table grid in the
main window, go ahead and add all
of the data below. (You’ll see all null
values at first—just type over them
when you add your first row. And
ignore the exclamation points that
appear next to the data.) You don’t
need to fill in the ContactID column;
that happens automatically.

se”
or “Faln.
”
e
u
r
T
Type “ Client columated
in the l get transl tores
That’l e way SQL s
to th no info.
yes or

Name:

Lloyd Jones
Company: Black Box inc.
Name:

(718)555-5638
Email: LJones@Xblackboxinc.com
Last call: 05/26/10
Client:		
Yes

Telephone:

26   Chapter 1

Your job is to enter
the data from all six
of these cards into
the People table.

Liz Nelson
JTP
Company:
78
: 19)555-25
Telephone (4
P.ORg
izNelson@JT
Email: L
03/04/09
Last call:
s
e
Y
ent:		

Name:

Cli

Lucinda Ericson

Company:

Ericson Events

(212)555-9523
Email: Lucy@EricsonEvents.info

Telephone:
Client:		
No

Last call:

05/17/10

get productive with c#

Name:

Name:

Matt Franks

Company:
Telephone:

XYZ Industries

(614)555-5641
Email: Sarah@KRS.org

Telephone:

(212)555-8125
Email: Matt.Franks@XyZindustries.com
Client:		
Yes
Last call: 05/26/10
Name:

Objectville Paper Company is in the
United States, so the CEO writes
dates so that 05/26/10 means May
26, 2010. If your machine is set to
a different location, you may need to
enter dates differently; you might
need to use 26/05/10 instead.
3

Client:		
no

Last call:

12/10/08

Laverne Smith

Company:

XYZ Industries

(212)555-8129
Email: Laverne.Smith@XyZindustries.com

Telephone:
Client:		
Yes

Once you’ve entered all six records,
select Save All from the File menu
again. That should save the records
to the database.

Q:

So what happened to the data after I entered it? Where
did it go?

A:

Sarah Kalter
Kalter, Riddle and Stoft

Company:

The IDE automatically stored the data you entered into the
People table in your database. The table, its columns, the data
types, and all of the data inside it is all stored in the SQL Server
Compact database file, ContactDB.sdf. That file is stored as part
of your project, and the IDE updates it just like it updates your
code files when you change them.

Last call:

04/11/10

e
“Save All” tells the IDE to sav
n.
tio
lica
everything in your app
, which
That’s different from “Save”kin
g on.
wor
’re
just saves the file you

Q:

OK, I entered these six records. Will they be part of
my program forever?

A:

Yes, they’re as much a part of the program as the code
that you write and the form that you’re building. The difference is
that instead of being compiled into an executable program, the
ContactDB.sdf file is copied and stored along with the executable.
When your application needs to access data, it reads and writes
to ContactDB.sdf, in the program’s output directory.

This file is actually a SQ
database, and your prograL
can use it with the code m
IDE generated for you. the

SQL

ContactDB.sdf

you are here 4   27

the data’s all in there

Connect your form to your database
objects with a data source
We’re finally ready to build the .NET database objects that our
form will use to talk to your database. We need a data source,
which is really just a collection of SQL statements your program
will use to talk to the ContactDB database.
1

Go back to your application’s form.
Close out the People table and the ContactDB database
diagram. You should now have the Form1.cs [Design] tab visible.

2

Add a new data source to your application.
This should be easy by now. Click the Data menu, and then
select Add New Data Source…from the drop-down.

Once you’re done entering
data,
close the data entr
y
wi
nd
ow
to
get back to your form.

The data source you’re
creating will handle all the
interactions between your
form and your database.

28   Chapter 1

get productive with c#
.NET Visual
Objects

3

Configure your new data source.
Now you need to set up your data source to use the ContactDB
database. Here’s what to do:

.NET
Database
Objects

Data Storage

Deployment
Pack age

Stored
Procedures

You are Here

≥≥ Step 1: Choose a Data Source Type. Select Database
and click the Next button.
≥≥ Step 2: Choose a Database Model. Select Dataset and
click the Next button.
≥≥ Step 3: Choose Your Data Connection. You should see
your Contact database in the drop-down. Click Next.
≥≥ Step 4: Choose Your Database Objects. Click the
Tables checkbox.
≥≥ In the Dataset Name field, make sure it says
“ContactDBDataSet” and click Finish.

These steps connect your
new data source
the People table inwith
the
ContactDB database.

In the non-Expr
itions, you may be
asked to save theesscoed
nn
config. Answer “Yes.” ection in the app

data
Now your form can use the
the
h
source to interact wit
ContactDB database.
XML
ContactDBDataSet.xsd

C#

Here’s your existing form.

ContactDBDataSet.
Designer.cs

SQL
ContactDB.sdf

This file is your database.

These files are what’s
generated by the data
source you just set up.
you are here 4   29

bind it all together

Add database-dri ven controls to your form
Now we can go back to our form and add some more controls. But these
aren’t just any controls—they are controls that are bound to our database
and the columns in the People table. That just means that a change to
the data in one of the controls on the form automatically changes the
data in the matching column in the database.

It took a little work, but now we’re
back to creating form objects that
interact with our data storage.

Here’s how to create several database-driven controls:

1

Select the data source you want to use.
Select Show Data Sources from the Data pull-down menu. This
will bring up the Data Sources window, showing the sources you
have set up for your application.

This window shows yo
sources. We’ve only gotu all your data
you could have more fo one setup, but
tables or databases. r different
2

If you don’t see this tab,
select Show Data Sources
from the Data menu.

You can also
look for, and
click on, the
Data Sources
tab along the
bottom of your
Database
Explorer window.

Select the People table.
Under the ContactDBDataSet, you should see the People table and all of the columns in it.
Click the “expand” icon next to the People table to expand it—you’ll see the columns that you
added to your table. When you click on the People table in the Data Sources window and drag
it onto your form, the IDE automatically adds data controls to your form that the user can use
to browse and enter data. By default it adds a DataGridView, which lets the user work with the
data using one big spreadsheet-like control. Click the arrow next to the People table and select
Details—that tells the IDE to add individual controls to your form for each column in the table.

choose Details to
Click this arrow andd individual controls
tell the IDE to ader than one large
to your form rath ta control.
spreadsheet-like da
All of the columns
you created should
show up here.
30   Chapter 1

op-down if you’ve
You’ll only see this dr
ndow open in the
got a form designeragwidata controls
IDE. It lets you drur data source and
directly out of yo
onto your form.

get productive with c#
.NET Visual
Objects

.NET
Database
Objects

Data Storage

Deployment
Pack age

Stored
Procedures

You are Here
3

Create controls that bind to the People table.
Drag and drop the People table onto your form in the form
designer window. You should see controls appear for each
column in your database. Don’t worry too much about how they
look right now; just make sure that they all appear on the form.
If you accidentally click out of the form you’re working on, you
can always get back to it by clicking the “Form1.cs [Design]”
tab, or opening Form1.cs from the Solution Explorer.

The IDE
creates this
toolbar for
navigating
through the
People table.

These won’t
show up on
your form, but
represent the
code that the
IDE created to
interact with
the People table
and ContactDB
database.

When you
dragged the
People table
onto the form,
a control was
created for
each column in
the table.

This object connects th
form to your People ta e
ble.

This adapter allows your
controls to interact
with SQL commands
that the IDE and data
source generated for you.

The bindin
connects thgenavigator
controls to toolbar
your
table.
you are here 4   31

make it pretty

Good programs are intuiti ve to use
Right now, the form works. But it doesn’t look that great. Your
application has to do more than be functional. It should be
easy to use. With just a few simple steps, you can make the
form look a lot more like the paper cards we were using at the
beginning of the chapter.

1

Name:

Our form would
be more intuitive
if it looked
a lot like the
contact card.

Laverne Smith

Company:

XYZ Industries

(212)555-8129
Laverne.Smith@XyZindustriescom

Telephone:
Email:

Client:		
Yes

Last call: 05/26/07

Line up your fields and labels.
Line up your fields and labels along the left edge of
the form. Your form will look like other applications,
and make your users feel more comfortable using it.

Blue lines will show
up on the form as
you drag controls
around. They’re
there to help you
line the fields up.

2

Change the Text Property on the Client checkbox.
When you first drag the fields onto the form, your Client
checkbox will have a label to the right that needs to be deleted.
Right below the Solution Explorer, you’ll see the Properties
window. Scroll down to the Text property and delete the
“checkbox1” label.

Delete this word to make
the label go away.

32   Chapter 1

get productive with c#
.NET Visual
Objects

.NET
Database
Objects

Data Storage
Stored
Procedures

You are Here

3

Make the application look professional.
You can change the name of the form by clicking on any empty
space within the form, and finding the Text property in the
Properties window of your IDE. Change the name of the form
to Objectville Paper Company Contact List.
You can also turn off the Maximize and Minimize buttons
in this same window, by looking for the MaximizeBox and
MinimizeBox properties. Set these both to False.

s window
The Propertgieht below
should be ri plorer, in
Solution Ex ght pane of
the lower ri
your IDE.

Deployment
Pack age

The reason you want to turn
off the Maximize button is
that maximizing your form
won’t change the positions of
the controls, so it’ll look weird.

The Text property
controls the heading on
your form’s title bar.

If you don’t have a Properties window, you can turn
it on by selecting it from the View drop-down menu.

A good application not only works, but is easy
to use. It’s always a good idea to make sure it
behaves as a typical user would expect it to.
you are here 4   33

ok, one last thing…

Test dri ve
OK, just one more thing to do… run your program and make sure
it works the way you think it should! Do it the same way you did
before—press the F5 key on your keyboard, or click the green arrow
button
on the toolbar (or choose “Run” from the Debug menu).

Click the X box
to stop the prograinmthe corner
can move on to the so you
next step.

You can always run your programs at any time, even when they’re not
done—although if there’s an error in the code, the IDE will tell you
and stop you from executing it.

Building your
program
overwrites
the data in
your database.

These controls
let you page
through the
different records
in the database.

We’ll spend more time
on this in the next
chapter.

The IDE builds first, then runs
When you run your program in the IDE it actually does two things. First it
builds your program, then it executes it. This involves a few distinct parts.
It compiles the code, or turns it into an executable file. Then it places the
compiled code, along with any resources and other files, into a subdirectory
underneath the bin folder.
In this case, you’ll find the executable and SQL database file in bin/
debug. Since it copies the database out each time, any changes you
make will be lost the next time you run inside the IDE. But if you run the
executable from Windows, it’ll save your data—until you build again, at
which point the IDE will overwrite the SQL database with a new copy that
contains the data you set up from inside the Database Explorer.
34   Chapter 1

Every time you
build your
program, the
IDE puts a
fresh copy of
the database
in the bin
folder. This will overwrite
any data you added when
you ran the program.
When you debug your program,
the IDE rebuilds it if the
code has changed—which
means that your database will
sometimes get overwritten
when you run your program in
the IDE. If you run the program
directly from the bin/debug or
bin/release folder, or if you
use the installer to install it on
your machine, then you won’t
see this problem.

get productive with c#

How to turn YOUR application
into EVERYONE’S application
At this point, you’ve got a great program. But it only runs
on your machine. That means that nobody else can use the
app, pay you for it, see how great you are and hire you…
and your boss and customers can’t see the reports you’re
generating from the database.
C# makes it easy to take an application you’ve created, and
deploy it. Deployment is taking an application and installing
it onto other machines. And with the Visual C# IDE, you
can set up a deployment with just two steps.

1

Select Publish Contacts from
the Project menu.

2

Just accept all of the defaults in
the Publish Wizard by clicking
Finish. You’ll see it package up
your application and then show
you a folder that has your Setup.
exe in it.

.NET Visual
Objects

.NET
Database
Objects

Data Storage

Deployment
Pack age

Stored
Procedures

You are Here

Building the solution just
copies the files to your
local machine. Publish
creates a Setup executable
and a configuration file
so that any machine could
install your program.

If you’re using Visual Studio
Express, you’ll find “Publish”
in the Project menu, but in
other editions it may be in
the Build menu.

you are here 4   35

share the love

Gi ve your users the application
Once you’ve created a deployment, you’ll have a new folder
called publish/. That folder has several things in it, all
used for installation. The most important for your users is
setup, a program that will let them install your program on
their own computers.

of the
This is where all for the
supporting files ed.
installer are stor
You may
need to
run the
installer as
administrator.
If SQL Server
Compact isn’t already
installed on the
machine, the installer
will automatically
download and install
it. On some machines,
this won’t work unless
you run the setup
as administrator, so
right-click on “setup”
and choose “Run
as administrator” to
install it. If you don’t
have access to do
that, don’t worry! You
don’t need to in order
to move forward in the
book.

installer
This file tells theneeds
everything that hen the
to be included w led.
program is instal

This is how your
users will install
the program on
their computers!

My secretary just told me that you’ve
got the new contact database working
already. Pack your bags—we’ve got room on
the jet to Aspen for a go-getter like you!

pleased. Good job!
Sounds like the boss is th
ing to do before
There’s just one more e slopes, though…
you can jet off to th
36   Chapter 1

get productive with c#

You’re NOT done: te st
your installation

.NET Visual
Objects

.NET
Database
Objects

Data Storage

Deployment
Pack age

Stored
Procedures

Before you pop the cork on any champagne bottles, you need
to test your deployment and installation. You wouldn’t give
anyone your program without running it first, would you?
Close the Visual Studio IDE. Click the setup program,
and select a location on your own computer to install the
program. Now run it from there, and make sure it works like
you expect. You can add and change records, too, and they’ll
be saved to the database.

You are Here

Now you can m
e changes
to the data, anak
d
saved to the dat they’ll get
abase.

You can use the
arrows and the
text field to switch
between records.

Go ahead…make
some changes.
You’ve deployed
it so this time,
they’ll stick.

TEST EVERYTHING!
Test your program, test
your deployment, test the
data in your application.

The contacts you
entered are all
there. They’re part
of the ContactDB.
sdf database file,
which gets installed
along with your
program.

you are here 4   37

super fast!

You’ve built a comple te
data-dri ven application

.NET Visual
Objects

.NET
Database
Objects

Data Storage

Deployment
Pack age

Stored
Procedures

The Visual Studio IDE made it pretty easy to create
a Windows application, create and design a database,
and hook the two together. You even were able to
build an installer with a few extra clicks.

From this
Lloyd Jones
Company: Black Box inc.
Name:

(718)555-5638
Email: LJones@Xblackboxinc.com
Last call: 05/26/07
Client:		
Yes

Telephone:

to this

in no time flat.

The power of Visual C# is that you can quickly
get up and running, and then focus on what
your program’s supposed to do…not lots of
windows, buttons, and SQL access code.
38   Chapter 1

get productive with c#

CSharpcross
Take some time to sit back and exercise your C# vocabulary with
this crossword; all of the solution words are from this chapter.
1

2
4

3

5
6

7

8
9

10

11

12

13

14
15
16

Across

3. The __________ explorer is where you edit the
contents of your SQL tables and bind them to
your program
5. An image, sound, icon, or file that's attached to
your project in a way that your code can access
easily
9. You build one of these so you can deploy your
program to another computer
12. What the "I" in IDE stands for
14. When you double-clicked on a control, the
IDE created this for you and you added code to it
15. Every row contains several of these, and all of
them can have different data types
16. The _________ Explorer shows you all of the
files in your project

Down

1. What's happening when code is turned into an
executable
2. What you change to alter the appearance or
behavior of controls on your form
3. What you're doing when you run your program
from inside the IDE
4. The "About" box in the Objectville Paper
Company Contact List program was one of these
6. You displayed the Objectville Paper Company
logo with one of these
7. Before you start building a program, you
should always think about users and their ______
8. A database can use many of these to store
data
10. The data type in a SQL database that you use
to store true/false values
11. Before you can run your program, the IDE
does this to create the executable and move files
to the output directory
13. You drag controls out of this and onto your
form
you are here 4   39

crossword solution

CSharpcross Solution
1

2

C

4

O

E

P

S

9

I

5

M

M
N

S

R

8

T

T

A

L

L

E

B

R

E

G

L

T

E

E

B
O

L

E

S

O U

R

U M N

R

10

B

12

I

N

T

13

T

E

6

E

E

L

G

3. The __________ explorer is where you edit the
contents of your SQL tables and bind them to
your program [database]
5. An image, sound, icon, or file that's attached to
your project in a way that your code can access
easily [resource]
9. You build one of these so you can deploy your
program to another computer [installer]
12. What the "I" in IDE stands for [integrated]
14. When you double-cli
IDE created this for you
[method]
15. Every row contains several of these, and all of
them can have different data types [columns]
16. The _________ Explorer shows you all of the
files in your project [solution]

A

Down

E

U
14

11

B

D

U

S

I

R

M E

B
O

T

E

N

C

G R

S

7

P

G

N

S

A

E

O

16

B

I

I
S

A

U

I

X

40   Chapter 1

T

E

O

X

Across

C

A

B

P

A

C

D

O

L

15

3

P

L
T

H

O D

B
L

U

T

I

O N
X

1. What's happening when code is turned into an
executable [compile]
2. What you change to alter the appearance or
behavior of controls on your form [properties]
3. What you're doing when you run your program
from inside the IDE [debugging]
4. The "About" box in the Objectville Paper
Company Contact List program was one of these
[messagebox]
aper Company
]
7. Before you start building a program, you
should always think about users and their ______
[needs]
8. A database can use many of these to store
data [table]
10. The data type in a SQL database that you use
to store true/false values [bit]
11. Before you can run your program, the IDE
does this to create the executable and move files
to the output directory [build]
13. You drag controls out of this and onto your
form [toolbox]

2 it’s all just code

Under the hood
One of these days
I’ll figure out what’s
going on under there…

You’re a programmer, not just an IDE user.
You can get a lot of work done using the IDE. But there’s only so far it
can take you. Sure, there are a lot of repetitive tasks that you do when
you build an application. And the IDE is great at doing those things for
you. But working with the IDE is only the beginning. You can get your
programs to do so much more—and writing C# code is how you do it.
Once you get the hang of coding, there’s nothing your programs can’t do.

this is a new chapter   41

at your service

When you’re doing this…
The IDE is a powerful tool—but that’s all it is, a tool for you to use. Every time
you change your project or drag and drop something in the IDE, it creates code
automatically. It’s really good at writing boilerplate code, or code that can be
reused easily without requiring much customization.
Let’s look at what the IDE does in typical application development, when you’re…
1

Creating a Windows Forms Application project
There are several kinds of applications the IDE lets you
build, but we’ll be concentrating on Windows Forms
applications for now. Those are programs that have
visual elements, like forms and buttons.

Make sure you always create a Windows Forms Application
project—that tells the IDE to create an empty form
and add it to your new project.
2

Dragging a button out of the toolbox and
onto your form, and then double-clicking it
Buttons are how you make things happen in your form.
We’ll use a lot of buttons to explore various parts of the
C# language. They’re also a part of almost every C#
application you’ll write.

3

Setting a property on your form
The Properties window in the IDE is a really
powerful tool that you can use to change attributes of
just about everything in your program: all visual and
functional properties for the controls on your form,
attributes of your databases, and even options on your
project itself.

42   Chapter 2

The Properties wind
really easy way to edow in the IDE is a
of code in Form1.Des it a specific chunk
It would take a lot igner.cs automatically.
hand. Use the F4 shlonger to do it by
Properties window if ortcut to open the
it’s closed.

All of these tasks have to
do with standard actions
and boilerplate code. Those
are the things the IDE is
great for helping with.

it’s all just code

…the IDE doe s this
Every time you make a change in the IDE, it makes a
change to the code, which means it changes the files that
contain that code. Sometimes it just modifies a few lines,
but other times it adds entire files to your project.

1

...the IDE creates the files and folders
for the project.

WindowsApplication1
.csproj

2

These files are created
a predefined template from
contains the basic codethat
create and display a fo to
rm.

Form1.cs

Form1.Designer.cs

...the IDE adds code to the Form1.Designer.cs file that adds
the button to the form, and then adds code to the Form1.cs
file to handle the button click.
private void button1_Click(object sender, EventArgs e)
{
}

3

Properties

Program.cs

The IDE knows how to add an empty method
to handle a button click. But it doesn’t know
what to put inside it—that’s your job.

...the IDE opens the Form1.Designer.cs file and
updates a line of code.

Form1.Designer.cs

This code
gets added
Form1.cs. to
Form1.cs

e…
The IDE went into this fil

partial class Form1
{ .
.
.
this.Text = “Objectville Paper Company Contact List”;
.
.
.
}

Form1.Designer.cs

…and updated this line of

code.
you are here 4   43

great, the “talk”

Where programs come f rom
A C# program may start out as statements in a bunch of
files, but it ends up as a program running in your computer.
Here’s how it gets there.

Ever y program starts out as source code files
You’ve already seen how to edit a program, and how the IDE saves your program
to files in a folder. Those files are your program—you can copy them to a new
folder and open them up, and everything will be there: forms, resources, code, and
anything else you added to your project.
You can think of the IDE as a kind of fancy file editor. It automatically does the
indenting for you, changes the colors of the keywords, matches up brackets for you,
and even suggests what words might come next. But in the end, all the IDE does is
edit the files that contain your program.
The IDE bundles all of the files for your program into a solution by creating a
solution (.sln) file and a folder that contains all of the other files for the program.
The solution file has a list of the project files (which end in .csproj) in the
solution, and the project files contain lists of all the other files associated with
the program. In this book, you’ll be building solutions that only have one project
in them, but you can easily add other projects to your solution using the IDE’s
Solution Explorer.

The .NET Framework gives you the right tools for the job
C# is just a language—by itself, it can’t actually do anything. And that’s where
the .NET Framework comes in. Remember that Maximize button you turned
off for the Contacts form? When you click the Maximize button on a window,
there’s code that tells the window how to maximize itself and take up the whole
screen. That code is part of the .NET Framework. Buttons, checkboxes, lists…
those are all pieces of the .NET Framework. So are the internal bits that hooked
your form up to the database. It’s got tools to draw graphics, read and write files,
manage collections of things…all sorts of tools for a lot of jobs that programmers
have to do every day.
The tools in the .NET Framework are divided up into namespaces. You’ve seen
these namespaces before, at the top of your code in the “using” lines. One namespace
is called System.Windows.Forms—it’s where your buttons, checkboxes, and
forms come from. Whenever you create a new Windows Forms Application project,
the IDE will add the necessary files so that your project contains a form, and those
files have the line “using System.Windows.Forms;” at the top.
44   Chapter 2

There’s no reason you
couldn’t build your
programs in Notepad,
but it’d be a lot
more time-consuming.

it’s all just code

Build the program to cre ate an e xecutable
When you select “Build Solution” from the Build menu, the IDE
compiles your program. It does this by running the compiler, which
is a tool that reads your program’s source code and turns it into an
executable. The executable is a file on your disk that ends in .exe—
that’s what you double-click on to run your program. When you build
the program, it creates the executable inside the bin folder, which is
inside the project folder. When you publish your solution, it copies
the executable (and any other files necessary) into the folder you’re
publishing to.
When you select “Start Debugging” from the Debug menu, the IDE
compiles your program and runs the executable. It’s got some more
advanced tools for debugging your program, which just means running
it and being able to pause (or “break”) it so you can figure out what’s
going on.

Your program runs inside the CLR
When you double-click on the executable, Windows runs your program.
But there’s an extra “layer” between Windows and your program called
the Common Language Runtime, or CLR. Once upon a time, not
so long ago (but before C# was around), writing programs was harder,
because you had to deal with hardware and low-level machine stuff. You
never knew exactly how someone was going to configure his computer.
The CLR—often referred to as a virtual machine—takes care of all
that for you by doing a sort of “translation” between your program and
the computer running it.
You’ll learn about all sorts of things the CLR does for you. For example,
it tightly manages your computer’s memory by figuring out when your
program is finished with certain pieces of data and getting rid of them
for you. That’s something programmers used to have to do themselves,
and it’s something that you don’t have to be bothered with. You won’t
know it at the time, but the CLR will make your job of learning C# a
whole lot easier.

You don’t really have to worry
about the CLR much right
now. It’s enough to know
it’s there, and takes care
of running your program for
you automatically. You’ll learn
more about it as you go.
you are here 4   45

mother’s little helper

The IDE helps you code
You’ve already seen a few of the things that the IDE can do.
Let’s take a closer look at some of the tools it gives you.
≥

The Solution Explorer shows you everything in your project
You’ll spend a lot of time going back and forth between classes, and the easiest
way to do that is to use the Solution Explorer. Here’s what the Solution Explorer
looks like after creating the Objectville Paper Company Contact List program:

The Solution
Explorer shows
you how the
different files
in the solution
folder.

≥

Use the tabs to switch between open files
Since your program is split up into more than one file, you’ll usually have several
code files open at once. When you do, each one will be in its own tab in the code
editor. The IDE displays an asterisk (*) next to a filename if it hasn’t been saved yet.

en have two tabs
When you’re working on a form, you’ll oft
form designer, and
for it at the same time—one for the rolto switch
one to view the form’s code. Use cont tab
between open windows quickly.
46   Chapter 2

Here’s the form’s
resource file that
you added the
Objectville Paper
Company logo to.

it’s all just code

≥

The IDE helps you write code
Did you notice little windows popping up as you typed code into the IDE? That’s
a feature called IntelliSense, and it’s really useful. One thing it does is show you
possible ways to complete your current line of code. If you type MessageBox and
then a period, it knows that there are three valid ways to complete that line:

The IDE knows that MessageBox has three
methods called Equals, ReferenceEquals, and Show.
If you type S, it selects Show. Type “(“ or space,
Tab, or Enter to tell the IDE to fill it in for you.
That can be a real timesaver if you’re typing a lot
of really long method names.

If you select Show and type (, the IDE’s IntelliSense will show you information
about how you can complete the line:

This means that there
are 21 different ways
that you can call the
MessageBox’s Show
method (like ways to
display different buttons
The IDE also has shortcuts called snippets that let you type an abbreviation to tell
or icons).

it to fill in the rest of the code. Here’s a useful one: type mbox and press the Tab key
twice, and the IDE will fill in the MessageBox.Show method for you:

≥

gging
When you use Start Debu
to run your program insideit
the IDE, the first thing
If
does is build your program.
m
ra
og
The Error List helps you troubleshoot compiler errors
it compiles, then your prn, and
If you haven’t already discovered how easy it is to make typos in a C#
runs. If not, it won’t ruthe
program, you’ll find out very soon! Luckily, the IDE gives you a great tool for
will show you errors in
troubleshooting them. When you build your solution, any problems that keep it Error List.
from compiling will show up in the Error List window at the bottom of the IDE:

A missing semicolon
at the end of a
statement is one of
the most common
errors that keeps your
program from building!
Double-click on an error, and the IDE will jump to the problem in the code:

The IDE will show a red
underscore to show you
that there’s an error.

you are here 4   47

let’s dig in

When you change things in the IDE,
you’re also changing your code

When you see a “Do this!”, pop open the IDE
and follow along. We’ll tell you exactly what
to do, and point out what to look for to get
the most out of the example we show you.

The IDE is great at writing visual code for you. But don’t
take our word for it. Open up Visual Studio, create a new
Windows Forms Application project, and see for yourself.
1

Do this!

Open up the designer code
Open the Form1.Designer.cs file in the IDE. But this time, instead of opening it in
the Form Designer, open up its code by right-clicking on it in the Solution Explorer and
selecting “View Code.” Look for the Form1 class declaration:
partial class Form1

Notice how it’s a partial

class? We’ll talk about

that in a minute.

2

Open up the Form designer and add a PictureBox to your form
Get used to working with more than one tab. Go to the Solution Explorer and open up the
Form designer by double-clicking on Form1.cs. Drag a new PictureBox onto a new form.

2

Find and expand the designer-generated code for the PictureBox control
Then go back to the Form1.Designer.cs tab in the IDE. Scroll down and look for this line in the code:

Click on the plus sign
+
Windows Form Designer generated code
Click on the + on the left-hand side of the line to expand the code. Scroll down and find these lines:

//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(276, 28);
this.pictureBox1.Name = “pictureBox1”;
this.pictureBox1.Size = new System.Drawing.Size(100, 50);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;

48   Chapter 2

Don’t worry if the
numbers in your code
for the Location and
Size lines are a little
different than these…

it’s all just code

Wait, wait! What did that say?
Scroll back up for a minute. There it is, at the top of the Windows
Form Designer–generated code section:
///
///
///
///


Required method for Designer support - do not modify
the contents of this method with the code editor.


There’s nothing more attractive to a kid than a big sign that says, “Don’t
touch this!” Come on, you know you’re tempted… let’s go modify the
contents of that method with the code editor! Add a button to your
form, and then go ahead and do this:

1

Change the code that sets the button1.Text property. What
do you think it will do to the Properties window in the IDE?
Give it a shot—see what happens! Now go back to the form designer and
check the Text property. Did it change?

2

Stay in the designer, and use the Properties window to
change the Name property to something else.
See if you can find a way to get the IDE to change the Name property. It’s
in the Properties window at the very top, under “(Name)”. What happened
to the code? What about the comment in the code?

3

Change the code that sets the Location property to (0,0) and
the Size property to make the button really big.
Did it work?

4

Go back to the designer, and change the button’s BackColor
property to something else.
Look closely at the Form1.Designer.cs code. Were any lines added?

Most comments only start
with two slashes (//).
But the IDE sometimes
adds these three-slash
comments.
These are XML comments,
and you can use them to
document your code. Flip to
“Leftovers” section #1 in the
Appendix of this book to learn
more about them.

e
You don’t have to saverath
m
og
pr
e
form or run th
to see the changes. Juste code
make the change in th on
editor, and then click .cs
the tab labeled “Form1to the
[Design]” to flip over anges
form designer—the ch tely.
should show up immedia

It’s always easier to use the IDE to change your form’s
Designer‑generated code. But when you do, any change you
make in the IDE ends up as a change to your project’s code.
you are here 4   49

your program makes a statement

Anatomy of a program
Every C# program’s code is structured in exactly the
same way. All programs use namespaces, classes,
and methods to make your code easier to manage.

Every time you make
define a namespace foar new program, you
separate from the .NETit so that its code is
Framework classes.

A class contains a piece of your ll
program (although some very sma
programs can have just one class).

A class has one or more methods.
Your methods always have to
live inside a class. And methods
are made up of statements—like
the ones you’ve already seen.

Namespace
Class
Method 1
statement
statement

Method 2
statement
statement

Le t’s take a closer look at your code
Open up the code from your Contacts project’s Form1.cs so
we can go through it piece by piece.
1

The code file starts by using the .NET Framework tools

You’ll find a set of using lines at the top of every program file. They tell C# which parts of
the .NET Framework to use. If you use other classes that are in other namespaces, then you’ll
add using lines for them, too. Since forms often use a lot of different tools from the .NET
Framework, the IDE automatically adds a bunch of using lines when it creates a form and
adds it to your project.

using
using
using
using
using
using
using
using

System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Linq;
System.Text;
System.Windows.Forms;

These using lines are at the top
of every code file. They tell
C# to use all of those .NET
Framework classes. Each one tells
your program that the classes in
this particular .cs file will use all
of the classes in one specific .NET
Framework namespace.

One thing to keep in mind: you don’t actually have to use a using statement. You can always
use the fully qualified name. So if you leave out using System.Windows.Forms, you can
still show a message box by calling System.Windows.Forms.MessageBox.Show(),
and the compiler will know what namespace you’re talking about.
50   Chapter 2

it’s all just code

C# programs are organized into classes

2

Every C# program is organized into classes. A class can do anything, but most classes do one
specific thing. When you created the new program, the IDE added a class called Form1 that
displays a form.
When you called your program Contacts,

the IDE created a
namespace for it called Contacts by adding the namespace
keyword at the top of your code file. Everything inside its
pair of curly brackets is part of the Contacts namespace.

namespace Contacts
{
public partial class Form1 : Form
This is a class called Form1. It contains all of the code to draw the
{
controls on it. The IDE created it when you

form and the Toolbox
told it to create a new Windows Forms Application project.

Classes contain methods that perform actions

3

Look for the
matching pairs
of brackets.
Every { is
eventually
paired up with
a }. Some
pairs can be
inside others.
4

When a class needs to do something, it uses a method. A method takes an input, performs
some action, and sometimes produces an output. The way you pass input into a method is by
using parameters. Methods can behave differently depending on what input they’re given.
Some methods produce output. When they do, it’s called a return value. If you see the
keyword void in front of a method, that means it doesn’t return anything.

public Form1()
{
}

InitializeComponent();

This line calls a method named
InitializeComponent(), which the
IDE also created for you.

A statement performs one single action

When you added the MessageBox.Show() line to your program, you were adding a
statement. Every method is made up of statements. When your program calls a method, it
executes the first statement in the method, then the next, then the next, etc. When the method
runs out of statements or hits a return statement, it ends, and the program resumes after the
statement that originally called the method.

eBox1_Click() that
This is a method called pictur
on the picture box.
gets called when the user clicks

}

}

This method has two parameters called
sender and e.

private void pictureBox1_Click(object sender, EventArgs e)
{
MessageBox.Show(“Contact List 1.0”, “About”);
}
Your statement called the Show() method,

This is a statement. You already
which is part of the MessageBox class, which
a
up
pops
does—it
it
what
know
is inside the System.Windows.Forms namespace.
.
window
box
message
little
Your statement passed two parameters to the Show()
method. The first one was a string of text to display
in the message box, and the second one was a string to
display in its title bar.
you are here 4  

51

a closer look

Your program knows where to start
When you created the new Windows Application solution, one of the files the
IDE added was called Program.cs. Go to the Solution Explorer and doubleclick on it. It’s got a class called Program, and inside that class is a method called
Main(). That method is the entry point, which means that it’s the very first
thing that’s run in your program.

Here’s some code the IDE built for you
automatically in the last chapter. You’ll
find it in Program.cs.

1

using
using
using
using

Every C# program can only
have one entry point method
and it’s always called Main(). ,
That’s how it knows where to
start when you run it.

Your Code Up Close

System;
System.Linq;
System.Collections.Generic;
System.Windows.Forms;

is code is
The namespace for allabth
t namespaces
ou
namespace Contacts
Contacts. We’ll talk
{
more in a few pages.
3
Lines that begin with two or more slashes are
static class Program
comme
nts, which you can add anywhere you want.
{
The slashes tell C# to ignore them.
2

/// 
/// The main entry point for the application.
/// 

Every time you run your pro m,
it starts here, at the entry gra
point.

[STAThread]

static void Main()
5
{

Application.EnableVisualStyles();
4 Application.SetCompatibleTextRenderingDefault(false);

}

}

}

Application.Run(new Form1());

This statement creates and
displays the Contacts form, and
ends the program when the
form’s closed.

I do declare!

The first part of every class or
method is called a declaration.

52   Chapter 2

Remember, this is just a starting point for you to
dig into the code. But before you do, you’ll need to
know what you’re looking at.

it’s all just code

1

C# and .NET have lots of built-in features.

You’ll find lines like this at the top of almost every C# class
file. System.Windows.Forms is a namespace. The
using System.Windows.Forms line makes everything
in that namespace available to your program. In this case, that
namespace has lots of visual elements in it like buttons and
forms.
2

The IDE chose a namespace for your code.

Here’s the namespace the IDE created for you—it chose
Contacts based on your project’s name. All of the code in
your program lives in this namespace.

3

Your code is stored in a class.

This code has one method, and it
contains several statements.

A namespace has classes in it, and classes have methods.
Inside each method is a set of statements. In this
program, the statements handle starting up the Contacts
form. Methods are where the action happens—every
method does something.

5

Each program has a special kind of
method called the entry point.

Every C# program must have exactly one
method called Main. Even though your
program has a lot of methods, only one can be
the first one that gets executed, and that’s your
Main method. C# checks every class in your
code for a method that reads static void
Main(). Then, when the program is run, the
first statement in this method gets executed, and
everything else follows from that first statement.

If you didn’t specify the “using” line,
you’d have to explicitly type out System.
Windows.Forms every time you use
anything in that namespace.

Namespaces let you use the same e
in different programs, as long as nam
those
programs aren’t also in the same nam
espace.

This particular class is called Program. The IDE created it
and added the code that starts the program and brings up the
Contacts form.

4

Your programs will use more and more
namespaces like this one as you learn
about C# and .NET’s other built-in
features throughout the book.

You can have multipnalemespace.
classes in a single

can have more
Technically, a program od
and you can
than one Main() meththe, entry point…
tell C# which one is do that now.
but you won’t need to

Every C# program must
have exactly one method
called Main. That method
is the entry point for
your code.
When you run your code,
the code in your Main()
method is executed FIRST.
you are here 4   53

classy things

You can change your
program’s entr y point
As long as your program has an entry point, it doesn’t
matter which class your entry point method is in, or
what that method does. Open up the program you
wrote in Chapter 1, remove the Main method in
Program.cs, and create a new entry point.
1

2

Do this!

Go back to Program.cs and change the name of the Main method to
NotMain. Now try to build and run the program. What happens?

Write down what happened
when you changed they you
method name, and wh
think that happened.

Now let’s create a new entry point. Add a new class called AnotherClass.
cs. You add a class to your program by right-clicking on the project name
in the Solution Explorer and selecting “Add>>Class…”. Name your class
file AnotherClass.cs. The IDE will add a class to your program called
AnotherClass. Here’s the file the IDE added:
using
using
using
using

System;
System.Linq;
System.Collections.Generic;
System.Text;

namespace Contacts
{
class AnotherClass
{
}
}

Right-click on the
project in Properties
and select “Add” and
“Class…”

These four standard using
lines were added to the file.
This class is in the same Contacts namespace
that the IDE added when you first created
the Windows Application project.

The IDE automatica
class based on the filly named the
lename.

3

Add a new using line to the top of the file: using System.Windows.Forms;
Don’t forget to end the line with a semicolon!

4

Add this method to the AnotherClass class by typing it in between the curly brackets:

MessageBox is a class that lives
in the System.Windows.Forms
namespace, which is why you had
to add the using line in step #3.
Show() is a method that’s part of
the MessageBox class.
54   Chapter 2

class AnotherClass
{
public static void Main()
{
MessageBox.Show(“Pow!”);
}
}

it’s all just code

Now run it!
So what happened?
Instead of popping up the Contacts application, your
program now shows this message box. When you made
the new Main() method, you gave your program a new
entry point. Now the first thing the program does is run
the statements in that method—which means running
that MessageBox.Show() statement. There’s nothing
else in that method, so once you click the OK button, the
program runs out of statements to execute and then it ends.
5

Figure out how to fix your program so it pops up Contacts again.

Hint: You only have
to change two lines in
two files to do it.

Fill in the annotations so they describe the lines in this C# file
that they’re pointing to. We’ve filled in the first one for you.

using
using
using
using

System;
System.Linq;
System.Text;
System.Windows.Forms;

ese “using”
C# classes have thds
from
lines to add metho
other namespaces

namespace SomeNamespace
{
class MyClass {
		

public static void DoSomething() {

			
		

MessageBox.Show(“This is a message”);

}

}
}

you are here 4   55

get some answers

Q:
A:

What’s with all the curly brackets?

  C# uses curly brackets (or “braces”) to
group statements together into blocks. Curly
brackets always come in pairs. You’ll only
see a closing curly bracket after you see an
opening one. The IDE helps you match up
curly brackets—just click on one, and you’ll
see it and its match get shaded darker.

Q:

I don’t quite get what the entry
point is. Can you explain it one more
time?

Q:

A:

Your program has a whole lot of
statements in it, but they’re not all run at
once. The program starts with the first
statement in the program, executes it, and
then goes on to the next one, and the next
one, etc. Those statements are usually
organized into a bunch of classes. So when
you run your program, how does it know
which statement to start with?

How come I get errors in the
Error List window when I try to run my
program? I thought that only happened
when I did “Build Solution.”

A:

That’s where the entry point comes in. The
compiler will not build your code unless there is
exactly one method called Main(), which
we call the entry point. The program starts
running with the first statement in Main().

Because the first thing that happens
when you choose “Start Debugging” from
the menu or press the toolbar button to
start your program running is that it saves
all the files in your solution and then tries to
compile them. And when you compile your
code—whether it’s when you run it, or when
you build the solution—if there are errors,
the IDE will display them in the Error List
instead of running your program.

A lot of the errors that show up when you comp
your code also show up in the Error List window ileand
as red squiggles under your code.

Fill in the annotations so they describe the lines in this C# file
that they’re pointing to. We’ve filled in the first one for you.

using
using
using
using

System;
System.Linq;
System.Text;
System.Windows.Forms;

namespace SomeNamespace
{

ese “using”
C# classes have thds
from
lines to add metho
other namespaces.
All of the code lives in
classes, so the program
needs a class here.

class MyClass {
		

public static void DoSomething() {

			
		
}
}

56   Chapter 2

This class has one method.
Its name is “DoSomething,”
and when it’s called it pops
up a MessageBox..

}

MessageBox.Show(“This is a message”);

This is a statemenedt.,
When it’s execut e
it pops up a littl
window with a it.
message inside of

it’s all just code

Match each of these fragments of code generated by the IDE to what it does.
(Some of these are new—take a guess and see if you got it right!)
partial class Form1
{ .
.
.
this.BackColor = Color.DarkViolet;
.
.
.
}

// This loop gets executed three times

Set properties for a label

Nothing—it’s a comment that the
programmer added to explain the code
to anyone who’s reading it

partial class Form1
{
private void InitializeComponent()
{
.
.
.
}
}

Disable the maximize icon (
) in the
title bar of the Form1 window

number_of_pit_stopsLabel.Name
= “number_of_pit_stopsLabel”;
number_of_pit_stopsLabel.Size
= new System.Drawing.Size(135, 17);
number_of_pit_stopsLabel.Text
= “Number of pit stops:”;

A special kind of comment that the IDE
uses to explain what an entire block of
code does

///
///
///
///


Bring up the picture of Rover when
the button is clicked


partial class Form1
{ .
.
.
this.MaximizeBox = false;
.
.
.
}

Change the background color of the
Form1 window

A block of code that executes whenever
a program opens up a Form1 window

you are here 4   57

exercise solution

Match each of these fragments of code generated by the IDE to what it does.
(Some of these are new—take a guess and see if you got it right!)

partial class Form1
{ .
.
.
this.BackColor = Color.DarkViolet;
.
.
.
}

// This loop gets executed three times

Set properties for a label

Nothing—it’s a comment that the
programmer added to explain the code
to anyone who’s reading it

partial class Form1
{
private void InitializeComponent()
{
.
.
.
}
}

Disable the maximize icon (
) in the
title bar of the Form1 window

number_of_pit_stopsLabel.Name
= “number_of_pit_stopsLabel”;
number_of_pit_stopsLabel.Size
= new System.Drawing.Size(135, 17);
number_of_pit_stopsLabel.Text
= “Number of pit stops:”;

A special kind of comment that the IDE
uses to explain what an entire block of
code does

///
///
///
///


Bring up the picture of Rover when
the button is clicked


partial class Form1
{ .
.
.
this.MaximizeBox
= false;
.
.
.
}

58   Chapter 2

Change the background color of the
Form1 window

A block of code that executes whenever
a program opens up a Form1 window

it’s all just code

Two classes can be in the
same name space
Take a look at these two class files from a
program called PetFiler2. They’ve got
three classes: a Dog class, a Cat class, and
a Fish class. Since they’re all in the same
PetFiler2 namespace, statements in the
Dog.Bark() method can call Cat.Meow()
and Fish.Swim(). It doesn’t matter how
the various namespaces and classes are divided
up between files. They still act the same when
they’re run.
class

SomeClasses.cs

namespace PetFiler2 {
class Dog {
public void Bark() {
// statements go here
}

is “public”
When a
her
it means every otram can
class in the progds.
access its metho

}
partial class Cat {
public void Meow() {
// more statements
}

MoreClasses.cs

namespace PetFiler2 {
class Fish {
public void Swim() {
// statements
}
}
partial class Cat {
public void Purr() {
// statements
}
}

}

}

}

Since these classes are in the same namespace,
they can all “see” each other—even though
they’re in different files. A class can span
multiple files too, but you need to use the
partial keyword when you declare it.
You can only split a class up into different
files if you use the partial keyword. You
probably won’t do that in any of the code
you write in this book, but the IDE used it
to split your form up into two files, Form1.
cs and Form1.Designer.cs.

There’s more to namespaces and class declarations, but you
won’t need them for the work you’re doing right now. Flip to #2
in the “Leftovers” appendix to read more.

you are here 4   59

your mileage may vary

Your programs use variable s to work with data
When you get right down to it, every program is basically a data cruncher.
Sometimes the data is in the form of a document, or an image in a
video game, or an instant message. But it’s all just data. And that’s where
variables come in. A variable is what your program uses to store data.

Declare your variable s
Whenever you declare a variable, you tell your program its type and its name.
Once C# knows your variable’s type, it’ll keep your program from compiling
if you make a mistake and try to do something that doesn’t make sense, like
subtract “Fido” from 48353.

ble types.
			
are the varia
These

These are th
of these variaebnames
les.

		

int maxWeight;

		

bool boxChecked;

		

If so, you might find a few
things in this chapter seem
really familiar. Still, it’s worth
taking the time to run through
the exercises anyway,
because there may be a few
ways that C# is different from
what you’re used to.

string message;

C# uses the va
to define what ridable type
variables can hold ata these
.

r YOU.
These names are focla
sses, use
d
an
s
Like method
e and
names that make seblnse’s usage.
describe the varia

Variable s var y
A variable is equal to different values at different times while your
program runs. In other words, a variable’s value varies. (Which is
why “variable” is such a good name.) This is really important, because
that idea is at the core of every program that you’ve written or will ever
write. So if your program sets the variable myHeight equal to 63:
int myHeight = 63;

any time myHeight appears in the code, C# will replace it with its
value, 63. Then, later on, if you change its value to 12:
myHeight = 12;

C# will replace myHeight with 12—but the variable is still called
myHeight.
60   Chapter 2

Are you
already
familiar with
another
language?

Whenever your
program needs to
work with numbers,
text, true/false
values, or any other
kind of data, you’ll
use variables to keep
track of them.

it’s all just code

You have to assign value s to variables
before you use them
Try putting these statements into a C# program:
int z;
MessageBox.Show(“The answer is ” + z);

Go ahead, give it a shot. You’ll get an error, and the IDE will
refuse to compile your code. That’s because the compiler
checks each variable to make sure that you’ve assigned it a
value before you use it. The easiest way to make sure you
don’t forget to assign your variables values is to combine
the statement that declares a variable with a statement that
assigns its value:

These values
are assigned to
the variables.

int maxWeight = 25000;

string message = “Hi!”;
bool boxChecked = true;
Each declaration has a type,
exactly like before.

A fe w useful t ype s
Every variable has a type that tells C# what kind of data it can
hold. We’ll go into a lot of detail about the many different types
in C# in Chapter 4. In the meantime, we’ll concentrate on the
three most popular types. int holds integers (or whole numbers),
string holds text, and bool holds Boolean true/false values.

var-i-a-ble, adjective.

If you write code
that uses a variable
that hasn’t been
assigned a value,
your code won’t
compile. It’s easy
to avoid that error
by combining your
variable declaration
and assignment into a
single statement.
Once you’ve assigned
to your variable, thata vavalue
can change. So there’s nolue
disadvantage to assig
ga
variable an initial valueninwh
en
you declare it.

able to be changed or adapted.
The drill’s variable speed bit let
Bob change the drill speed from slow
to fast based on the job he had to do.

you are here 4   61

operators are standing by

C# uses familiar math symbols
Once you’ve got some data stored in a variable, what can you
do with it? Well, if it’s a number, you’ll probably want to add,
subtract, multiply, or divide it. And that’s where operators come
in. You already know the basic ones. Let’s talk about a few more.
Here’s a block of code that uses operators to do some simple math:

We declared a new
int variable called
number and set it to
15. Then we added 10
to it. After the second
statement, number is
equal to 25.

The *= operator
is similar to +=,
except it multiplies
the current value of
number by 3, so it
ends up set to 48.

This MessageBox
will pop up a box
that says “hello
again hello”

int number = 15;

number = number + 10;
number = 36 * 15;

number = 12 - (42 / 7);
number += 10;
number *= 3;

number = 71 / 3;
int count = 0;
count ++;
count --;

To programmers, the
word “string” almost
always means a string of
text, and “int” is almost
always short for integer.

The third statement changes the
value of number, setting it equal to
36 times 15, which is 540. Then it
resets it again, setting it equal to
12 - (42 / 7), which is 6.

This operator is a little different.
+= means take the value of number
and add 10 to it. Since number is
currently equal to 6, adding 10 to it
sets its value to 16.

Normally, 71 divided by 3 is 23.666666.... But when you’re
dividing two ints, you’ll always get an int result, so 23.666…
gets truncated to 23.

You’ll use int a lot for counting, and when you do, the ++
and -- operators come in handy. ++ increments count
by adding one to the value, and -- decrements count by
subtracting one from it, so it ends up equal to zero.

string result = “hello”;

When you use the + operator
with a string, it just puts
MessageBox.Show(result);
two strings together. It’ll
The “” is an empty string.
automatically convert
result = “the value is: ” + count; numbers to strings for you.
It has no characters.
(It’s kind of like a zero result = “”;
for adding strings.)
result += “ again ” + result;

A bool stores true
or false. The !
bool yesNo = false;
operator means NOT.
It flips true to
bool anotherBool = true;
false, and vice versa.
yesNo = !anotherBool;
62   Chapter 2

		Don’t worry about
memorizing these
operators now.
You’ll get to know them
because you’ll see ’em over and over again.

it’s all just code

Use the debugger to see your variable s change

Debug this!

The debugger is a great tool for understanding how your programs
work. You can use it to see the code on the previous page in action.
1

Create a new Windows Forms Application project
Drag a button onto your form and double-click it. Enter all of the code on the previous
page. Then take a look at the comments in the screenshot below:

When you set a breakpoin
of code, the line turns redt on a line
red dot appears in the margand a
in of
the code editor.
When you debug your co
running it inside the IDE,deasby
soon as your program hit a
breakpoint it’ll pause ands let
inspect and change the values you
of
all the variables.

2

Creating a new
Windows Forms
Application project
will tell the IDE to
create a new project
with a blank form
and an entry point.
You might want to
name it something like
“Chapter 2 program
1”—you’ll be building a
whole lot of programs
throughout the book.
Comments (which either
start with two or more
slashes or are surrounded
by /* and */ marks)
show up in the IDE as
green text. You don’t
have to worry about
what you type in between
those marks, because
comments are always
ignored by the compiler.

Insert a breakpoint on the first line of code
Right-click on the first line of code (int number = 15;) and choose “Insert Breakpoint” from the
Breakpoint menu. (You can also click on it and choose Debug >> Toggle Breakpoint or press F9.)

Flip the page and keep going!
you are here 4   63

stop bugging me!

3

Start debugging your program
Run your program in the debugger by clicking the Start Debugging button
(or by pressing F5, or by choosing Debug >> Start Debugging from the
menu). Your program should start up as usual and pop up the form.

4

Click on the button to trigger the breakpoint
As soon as your program gets to the line of code that has the breakpoint,
the IDE automatically brings up the code editor and highlights the current
line of code in yellow.

5

6

Add a watch for the number variable
Right-click on the number variable (any occurrence of it will do!) and
choose Expression: ‘number’ >> Add Watch from the menu. The
Watch window should appear in the panel at the bottom of the IDE:

Step through the code
Press F10 to step through the code. (You can also choose Debug >> Step Over
from the menu, or click the Step Over button in the Debug toolbar.) The current
line of code will be executed, setting the value of number to 15. The next line of
code will then be highlighted in yellow, and the Watch window will be updated:

As soon as the number
variable gets a new
value (15), its watch is
updated.
7

Continue running the program
When you want to resume, just press F5 (or Debug >> Continue), and the
program will resume running as usual.

64   Chapter 2

You can also hover over
a variable while you’re
debugging to see its value
displayed in a tooltip…and
you can pin it so it says open!

Adding a watch
can help you
keep track of
the values of
the variables in
your program.
This will really
come in handy
when your
programs get
more complex.

it’s all just code

Loops perform an action over and over
Here’s a peculiar thing about most large programs: they almost always
involve doing certain things over and over again. And that’s what
loops are for—they tell your program to keep executing a certain set
of statements as long as some condition is true (or false!).

}

x = x - 3;

In a while loop, all of
the statements inside
the curly brackets get
executed as long as
the condition in the
parentheses is true.

If your brackets (or braces—either name
will do) don’t match up, your program
won’t build, which leads to frustrating
bugs. Luckily, the IDE can help with this!
Put your cursor on a bracket, and the
IDE highlights its match:

That’s a big part of why . A
booleans are so important
loop uses a test to figure g.
out if it should keep loopin

while (x > 5)

{

IDE Tip: Brackets

Every for loop has three statements. The first sets
up the loop. The statement will keep looping as long as
the second one is true. And the third statement gets
executed after each time through the loop.
for (int i = 0; i < 8; i = i + 2)

{

}

MessageBox.Show(“I’ll pop up 4 times”);

Use a code snippe t to write simple for loops
You’ll be typing for loops in just a minute, and the IDE can help
speed up your coding a little. Type for followed by two tabs,
and the IDE will automatically insert code for you. If you type
a new variable, it’ll automatically update the rest of the snippet.
Press tab again, and the cursor will jump to the length.

Press tab to get the cursor
to jump to the length. The
number of times this loop runs
is determined by whatever
you set length to. You can
change length to a number or a
variable.

If you change the variable to
something else, the snippet
automatically changes the
other two occurrences of it.

you are here 4   65

ready, set, code!

A few helpful tips

Time to start coding
The real work of any program is in its statements. But
statements don’t exist in a vacuum. So let’s set the stage
for digging in and getting some code written. Create a
new Windows Forms Application project.

forget that all your statements need
± Dto on’t
end in a semicolon:

name = “Joe”;

add comments to your code by
± Ystarting
ou can them
with two slashes:

// this text is ignored

are declared with a name and a
± Vtype
ariables
(there are plenty of types that you’ll

Build this form

learn about in Chapter 4):

int weight;
// weight is an integer

for a class or a method goes
± Tbetween
he code curly
braces:

public void Go() {
// your code here
}

± M ost of the time, extra whitespace is fine:
int j

private void button1_Click(object sender, EventArgs e)

{

// this is a comment

string name = “Quentin”;
int x = 3;

x = x * 17;

double d = Math.PI / 2;

There’s a built-in cla
Math, and it’s got a ssmecalled
called PI. Math lives in mber
System namespace, so ththe
file this code came frome
needs to have a using Sy
stem;
line at the top.

MessageBox.Show(“name is “ + name
+ “\nx is “ + x

}

;

int j = 1234;

Get started by double-clicking on the first button. Then add
these statements to the button1_Click() method. Look
closely at the code and the output it produces.

66   Chapter 2

1234

is the same as:

Add statements to show a me ssage

t”
x is a variable. The “in
’s
it
at
part tells C# th rest
an integer, and thesets
of the statement
its value to 3.

=

+ “\nd is “ + d);

The \n is an escape sequence
to add a line break to the
message box.

it’s all just code

if/else statements make decisions
Use if/else statements to tell your program to do certain
things only when the conditions you set up are (or aren’t)
true. A lot of if/else statements check if two things are equal.
That’s when you use the == operator. That’s different from the
single equals sign (=) operator, which you use to set a value.

if (someValue == 24)

{

}

Every if statement
starts with a
conditional test.

MessageBox.Show(“The value was 24.”);
ns to check if
Always use two equalstosigeach other.
two things are equal

The statement insidise
the curly brackets e
executed only if th
test is true.

if (someValue == 24)

{
if/else statements are
.
rd
wa
for
ht
aig
pretty str
// You can have as many statements
If the conditional
// as you want inside the brackets
test is true, the
program executes the
MessageBox.Show(“The value was 24.”);
statements between the
} else {
first set of brackets.
Otherwise, it executes
MessageBox.Show(“The value wasn’t 24.”);
the statements between
.
set
the second
}

Don’t confuse the two equals sign operators!
You use one equals sign (=) to set a variable’s value, but two equals
signs (==) to compare two variables. You won’t believe how many bugs in
programs—even ones made by experienced programmers!—are caused
by using = instead of ==. If you see the IDE complain that you “cannot implicitly
convert type ‘int’ to ‘bool’”, that’s probably what happened.

you are here 4   67

the things you can do

Se t up conditions and see if they’re true
Use if/else statements to tell your program to do certain
things only when the conditions you set up are (or aren’t) true.

Use logical operators to check conditions
You’ve just looked at the == operator, which you use to test whether two
variables are equal. There are a few other operators, too. Don’t worry about
memorizing them right now—you’ll get to know them over the next few
chapters.
≥≥ The != operator works a lot like ==, except it’s true if the two things
you’re comparing are not equal.
≥≥ You can use > and < to compare numbers and see if one is bigger or
smaller than the other.

When you use
a conditional
operator to
compare two
numbers, it’s
called a
conditional test.

≥≥ The ==, !=, >, and < operators are called conditional operators.
When you use them to test two variables or values, it’s called
performing a conditional test.
≥≥ You can combine individual conditional tests into one long test using
the && operator for AND and the || operator for OR. So to check if
i equals 3 or j is less than 5, do (i == 3) || (j < 5).

Se t a variable and then check its value
Here’s the code for the second button. It’s an if/else statement that
checks an integer variable called x to see if it’s equal to 10.

Make sure you stop your program before
you do this—the IDE won’t let you edit
the code while the program’s running.
You can stop it by closing the window,
using the stop button on the toolbar, or
selecting “Stop Debugging” from the
Debug menu.

private void button2_Click(object sender, EventArgs e)
{
int x = 5;
if (x == 10)
First we set
{
up a variable
MessageBox.Show(“x must be 10”);
called x and
}
make it equal
else
to 5. Then we
{
check if it’s
MessageBox.Show(“x isn’t 10”);
equal to 10.
}
}

Here’s the output. See if you can tweak one line
of code and get it to say “x must be 10” instead.
68   Chapter 2

it’s all just code

Add another conditional te st
This line checks someValue to
see if it’s equal to 3, and then
it checks to make sure name
is “Joe”.

The third button makes this output. Now make a change to
two lines of code so that it pops up both message boxes.

private void button3_Click(object sender, EventArgs e)

{

int someValue = 4;

string name = “Bobbo Jr.”;

if ((someValue == 3) && (name == “Joe”))
{
}
}

MessageBox.Show(“x is 3 and the name is Joe”);

MessageBox.Show(“this line runs no matter what”);

Add loops to your program
Here’s the code for the last button. It’s got two loops. The first is a while loop,
which repeats the statements inside the brackets as long as the condition is true—do
something while this is true. The second one is a for loop. Take a look and see how it
works.

This loop keeps
repeating as long as
the count variable
is less than 10.

private void button4_Click(object sender, EventArgs e)
{
int count = 0;
ond part of the
while (count < 10)
{
count = count + 1;
}

for statement is
The sec
g as i is less than
the test. It says “for as lon
ng”. The test
five the loop should keep onck,goiand the block
is run before the code blo st is true.
is executed only if the te

for (int i = 0; i < 5; i++)
{
count = count - 1;
}

This sets up the loop.
It just assigns a
value to the integer
that’ll be used in it.
}

MessageBox.Show(“The answer is ” + count);

at
This statement gets executhteisdcase,
In
p.
the end of each loo
e the
it adds one to i every timled
the
cal
is
loop executes. This
ely
iat
ed
imm
iterator, and it’s run in the
s
nt
me
after all the state
code block.

Before you click on the button, read through the code and try to figure out what the
message box will show. Then click the button and see if you were right!
you are here 4   69

over and over and over and…

Let’s get a little more practice with conditional tests and loops. Take a
look at the code below. Circle the conditional tests, and fill in the blanks
so that the comments correctly describe the code that’s being run.

int result = 0; // this variable will hold the final result
int x = 6; // declare a variable x and

set it to 6

We filled in the
first one for you.

while (x > 3) {
// execute these statements as long as
result = result + x; // add x
x = x - 1; // subtract
}
for (int z = 1; z < 3; z = z + 1) {
// start the loop by
// keep looping as long as
// after each loop,
result = result + z; //
}
// The next statement will pop up a message box that says
//
MessageBox.Show(“The result is ” + result);

More about conditional tests

You can do simple conditional tests by checking the value of a variable
using a comparison operator. Here’s how you compare two ints, x and y:
x < y (less than)
x > y (greater than)
x == y (equals—and yes, with two equals signs)

These are the ones you’ll use most often.
70   Chapter 2

it’s all just code
Wait up! There’s a flaw in your
logic. What happens to my loop if I
write a conditional test that never
becomes false?

Then your loop runs forever!
Every time your program runs a conditional test, the result
is either true or false. If it’s true, then your program
goes through the loop one more time. Every loop should
have code that, if it’s run enough times, should cause
the conditional test to eventually return false. But if it
doesn’t, then the loop will keep running until you kill the
program or turn the computer off !
called

,
n infinite loou’pll
a
es
im
This is sometre actually times when yo
and there a one in your program.
want to use

Here are a few loops. Write down if each loop will repeat forever or
eventually end. If it’s going to end, how many times will it loop?

Loop #1
int count = 5;
while (count > 0) {
count = count * 3;
count = count * -1;
}
For Loop #3, how

many times will this
statement be executed?

Loop #2
int i = 0;
int count = 2;
while (i == 0) {
count = count * 3;
count = count * -1;
}

Remember, a for loop always
runs the conditional test at the
beginning of the block, and the
iterator at the end of the block.

Loop #3
int j = 2;
for (int i = 1; i < 100;
i = i * 2)
{
j = j - i;
while (j < 25)
{
j = j + 5;
}
}
For Loop #5, how
Loop #4

many times will this
statement be executed?

while (true) { int i = 1;}

Loop #5
int p = 2;
for (int q = 2; q < 32;
q = q * 2)
{
while (p < q)
{
p = p * 2;
}
q = p - q;
}

Hint: q starts out equal to
2. Think about when the
iterator “q = q * 2” is
executed.

Can you think of a reason that you’d want to write a
loop that never stops running? (Hint: You’ll use one
in Chapter 13….)

you are here 4   71

if only, but only if

Let’s get a little more practice with conditional tests and loops. Take a
look at the code below. Circle the conditional tests, and fill in the blanks
so that the comments correctly describe the code that’s being run.

int result = 0; // this variable will hold the final result
int x = 6; // declare a variable x and

set it to 6

while (x > 3) {
// execute these statements as long as
result = result + x; // add x
x = x - 1; // subtract

x is greater than 3

to the result variable

1 from the value of x

}
for (int z = 1; z < 3; z = z + 1) {

This loop runs twice—first with z set to 1, and
then a second time with z set to 2. Once it hits
3, it’s no longer less than 3, so the loop stops.

declaring a variable z and setting it to 1
// keep looping as long as z is less than 3
// after each loop, add 1 to z
result = result + z; // add the value of z to result
// start the loop by

}
// The next statement will pop up a message box that says
//

The result is 18

MessageBox.Show(“The result is ” + result);
Here are a few loops. Write down if each loop will repeat forever or
eventually end. If it’s going to end, how many times will it loop?

Loop #1
This loop executes once

Loop #3
This loop executes 7 times

Loop #2
This loop runs forever

Loop #4
Another infinite loop

Loop #5
This loop
executes 8 times

Take the time to really figure this one out. Here’s a perfect opportunity to try out the debugger on your own! Set a
breakpoint on the statement q = p - q;. Add watches for the variables p and q and step through the loop.
72   Chapter 2

it’s all just code

Q:
A:

Is every statement always in a class?

Yes. Any time a C# program does something, it’s because
statements were executed. Those statements are a part of classes,
and those classes are a part of namespaces. Even when it looks
like something is not a statement in a class—like when you use
the designer to set a property on an object on your form—if you
search through your code you’ll find that the IDE added or changed
statements inside a class somewhere.

Q:

Are there any namespaces I’m not allowed to use? Are
there any I have to use?

A:

Yes, there are a few namespaces that are not recommended to
use. Notice how all of the using lines at the top of your C# class
files always said System? That’s because there’s a System
namespace that’s used by the .NET Framework. It’s where you
find all of your important tools to add power to your programs, like
System.Data, which lets you work with tables and databases,
and System.IO, which lets you work with files and data streams.
But for the most part, you can choose any name you want for a
namespace (as long as it only has letters, numbers, and underscores).
When you create a new program, the IDE will automatically choose a
namespace for you based on the program’s name.

Q:
A:

Q:

So exactly how careful do I have to be with the code that’s
automatically generated by the IDE?

A:

You should generally be pretty careful. It’s really useful to
know what the IDE is doing to your code, and once in a while you’ll
need to know what’s in there in order to solve a serious problem. But
in almost all cases, you’ll be able to do everything you need to do
through the IDE.

¢¢

¢¢
¢¢

I still don’t get why I need this partial class stuff.

Partial classes are how you can spread the code for one
class between more than one file. The IDE does that when it
creates a form—it keeps the code you edit in one file (like Form1.
cs), and the code it modifies automatically for you in another file
(Form1.Designer.cs). You don’t need to do that with a
namespace, though. One namespace can span two, three, or a
dozen or more files. Just put the namespace declaration at the top of
the file, and everything within the curly brackets after the declaration
is inside the same namespace. One more thing: you can have more
than one class in a file. And you can have more than one namespace
in a file. You’ll learn a lot more about classes in the next few chapters.

Q:

Let’s say I drag something onto my form, so the IDE
generates a bunch of code automatically. What happens to that
code if I click “Undo”?

A:

Drag a button on a form, change properties. Then try to undo it. What
happens? Well, for simple things you’ll see that the IDE is smart
enough to undo it itself. But for more complex things, like adding
a new SQL database to your project, you’ll be given a warning
message. It still knows how to undo the action, but it may not be able
to redo it.

The best way to answer this question is to try it! Give it a shot—
do something where the IDE generates some code for you.

¢¢

¢¢

¢¢

¢¢

¢¢

You tell your program to perform actions using
statements. Statements are always part of classes, and
every class is in a namespace.
Every statement ends with a semicolon (;).
When you use the visual tools in the Visual Studio IDE,
it automatically adds or changes code in your program.
Code blocks are surrounded by curly braces { }.
Classes, while loops, if/else statements, and lots of
other kinds of statements use those blocks.
A conditional test is either true or false. You use
conditional tests to determine when a loop ends, and
which block of code to execute in an if/else statement.
Any time your program needs to store some data, you
use a variable. Use = to assign a variable, and == to
test if two variables are equal.
A while loop runs everything within its block (defined
by curly braces) as long as the conditional test is
true.
If the conditional test is false, the while loop code
block won’t run, and execution will move down to the
code immediately after the loop block.

you are here 4   73

your code… now in magnet form

Code Magnets

Part of a C# program is all scrambled up on the fridge. Can you rearrange
the code snippets to make a working C# program that produces the
message box? Some of the curly braces fell on the floor and they were
too small to pick up, so feel free to add as many of those as you need!
(Hint: you’ll definitely need to add a couple. Just write them in!)

The “” is an empty string—it means Result
has no characters in it yet.

“”;
string Result =

if (x
== 1)
{
Resul
t = R
esult
+ “d”
x = x
;
- 1;
}

This magnet didn’t fall
off the fridge…

if (x == 2) {

Result = Result + “b c”;

}

if (x > 2) {

+ “a”;
Result = Result

}
int x = 3;

x = x - 1;

Result = Re
sult + “-”;
{
while (x > 0)

Output:

MessageBox.Show(Result);

74   Chapter 2

Answers on page 82.

it’s all just code

We’ll give you a lot of exercises like this throughout the book.
We’ll give you the answer in a couple of pages. If you get stuck,
don’t be afraid to peek at the answer—it’s not cheating!

You’ll be creating a lot of applications
throughout this book, and you’ll need to give
each one a different name. We recommend
naming this one “2 Fun with if-else
statements” based on the chapter number
and the text in the title bar of the form.

Time to get some practice using if/else statements. Can you build this program?

Here’s the form.

Add this checkbox.
Drag it out of the toolbox and onto your
form. Use the Text property to change the
text that’s next to it. (You also use the Text
property to change the button and label text.)

This is a label.
You can use the properties to change the
font size and make it boldface. Use the
BackColor property to set to red—choose
“Red” from the selection of web colors.

Pop up this message if the user clicks the button but the
box IS NOT checked.
If your checkbox is named checkBox1 (you can change the Name property
if you want), then here’s the conditional test to see if it’s checked:
checkBox1.Checked == true

If the user clicks the button and the box IS checked, change the
background color of the label.
If the label background color is red, change it to blue when the button is clicked. If it’s blue,
change it back to red. Here’s a statement that sets the background color of a label called label1:
label1.BackColor = Color.Red;

(Hint: The conditional test to check whether a label’s background color is red looks a lot like that
statement—but with one important difference!)

you are here 4   75

ooh, pretty!

Let’s build something flashy! Start by creating a new Windows Forms Application in the IDE.

1

Here’s the form to build

c = 0; …)—then
le inside a for loop—for (int So
e
Hint: If you declare a variabide
loop’s curly brackets. if you hav
that variable’s only valid ins thethevariable, you’ll either declare it in each
two for loops that both use outside the loop. And if the variable c is
loop or have one declaration the loops, you can’t use it in either one.
already declared outside of
2

Make the form background go all psychedelic!
When the button’s clicked, make the form’s background
color cycle through a whole lot of colors! Create a loop that
has a variable c go from 0 to 253. Here’s the block of code
that goes inside the curly brackets:
this.BackColor = Color.FromArgb(c, 255 - c, c);
Application.DoEvents();

This line tells the program to
the other things it needs to dostop your loop momentarily and do
mouse clicks, etc. Try taking out, like refresh the form, check for
The form doesn’t redraw itself this line and seeing what happens.
done before it deals with those , because it’s waiting until the loop is
events.
For now, you’ll use Application.DoEvents() to make sure
your form stays responsive while it’s in a loop, but it’s
kind of a hack. You shouldn’t use this code outside of a
toy program like this. Later on in the book, you’ll learn
about a much better way to let your programs do more
than one thing at a time!
3

Make it slower
Slow down the flashing by adding this line after the
Application.DoEvents() line:
System.Threading.Thread.Sleep(3);

d!
e
s
s
e
r
p
m
i
e
Color m
efined

nch of pred but it also
u
b
a
s
a
h
,
.NET
lue and Red colors using
B
e
k
li
s
r
lo
n
co
y
ke your ow
lets you ma romArgb() method, bvalue,
the Color.Fthree numbers: a red
specifying e, and a blue value.
a green valu

ts a 3 millisecond
This statement inser
a part of
delay in the loop. Itan’sd it’s in the
the .NET library, ng namespace.
em.Threadi
Syst

76   Chapter 2

it’s all just code

4

Make it smoother
Let’s make the colors cycle back to where they started. Add another loop that has
c go from 254 down to 0. Use the same block of code inside the curly brackets.

5

Keep it going
Surround your two loops with another loop that continuously executes and doesn’t
stop, so that when the button is pressed, the background starts changing colors and
then keeps doing it. (Hint: The while (true) loop will run forever!)

When one loop is
inside another
one, we call it a
“nested” loop.

Uh-oh! The program doe sn’t stop!
Run your program in the IDE. Start it looping. Now close the window. Wait a
minute—the IDE didn’t go back into edit mode! It’s acting like the program
is still running. You need to actually stop the program using the square stop
button in the IDE (or select “Stop Debugging” from the Debug menu).

6

Make it stop
Make the loop you added in step #5 stop when the program is
closed. Change your outer loop to this:
while (Visible)
Now run the program and click the X box in the corner. The
window closes, and then the program stops! Except…there’s a
delay of a few seconds before the IDE goes back to edit mode.

When you’re checking a Boolean value like Visible
in an if statement or a loop, sometimes it’s
tempting to test for (Visible == true). You can
leave off the “== true”—it’s enough to include
the Boolean.

When you’re working with a
form or control, Visible is
true as long as the form or
control is being displayed. If
you set it to false, it makes
the form or control disappear.

Hint: The && operat
“AND”. It’s how you storrinmeans
of conditional tests togegtha bunch
one big test that’s true on er into
first test is true AND th ly if the
is true AND the third, ete second
it’ll come in handy to solve c. And
this
problem.

Can you figure out what’s causing that
delay? Can you fix it so the program ends
immediately when you close the window?

you are here 4   77

exercise solution

Time to get some practice using if/else statements. Can you build this program?

using
using
using
using
using
using
using
using

System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Linq;
Here’s the code for the form.
System.Text;
“Fun with If Else”, so the IDE
System.Windows.Forms;
Fun_with_If_Else. If you

We named our solution
made the namespace
gave your solution a
different name, it’ll have a different namespace.

namespace Fun_with_If_Else
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

The outer if
statement checks
the checkbox to
see if it’s been
checked. Check!

}

}

The IDE added the method called
button1_Click() to your form
when you double-clicked on the
button. The method gets run
every time the button’s clicked.

private void button1_Click(object sender, EventArgs e)
{
if (checkBox1.Checked == true)
{
if (label1.BackColor == Color.Red)
{
label1.BackColor = Color.Blue;
}
else
{
label1.BackColor = Color.Red;
}
}
else
{
MessageBox.Show(“The box is not checked”);
}
}

This statement’s
run if the label’s
background color is
not red to make it
set back to red.

This MessageBox pops up if
the checkbox isn’t checked.

You can download the code for all of the exercise solutions
in this book from www.headfirstlabs.com/books/hfcsharp/
78   Chapter 2

The inner if statement
checks the label’s
color. If the label
is currently red, it
executes a statement
to turn it blue.

it’s all just code

Let’s build something flashy!

Sometimes we won’t show you the entire code
in the solution, just the bits that changed. All
of the logic in the FlashyThing project is in this
button1_Click() method that the IDE added when
you double-clicked the button in the form designer.

When the IDE added this method, it added an extra
return before the curly bracket. Sometimes we’ll put the
bracket on the same line like this to save space—but C#
doesn’t care about extra space, so this is perfectly valid.
Consistency is generally really important to make it easy
for people to read code. But we’re purposefully showing you
different ways, because you’ll need to get used to reading
code from different people using different styles.

private void button1_Click(object sender, EventArgs e) {
while (Visible) {

The outer loop
keeps running as
long as the form
is visible. As soon
as it’s closed,
Visible is false,
and the while
will stop looping.
We used &&
Visible instead
of && Visible
== true. It’s
just like saying
“if it’s visible”
instead of “if
it’s true that
it’s visible”—they
mean the same
thing.
}
}

for (int c = 0; c < 254 && Visible; c++) {
this.BackColor = Color.FromArgb(c, 255 - c, c);

The first for loop makes
colors cycle one way, and the
second for loop reverses the
so they look smooth. them

Application.DoEvents();
System.Threading.Thread.Sleep(3);
}

for (int c = 254; c >= 0 && Visible; c--) {
this.BackColor = Color.FromArgb(c, 255 - c, c);
Application.DoEvents();
System.Threading.Thread.Sleep(3);
}

We fixed the extra delay byke
using the && operator to macheck
each of the for loops also ends
Visible. That way the loop se.
as soon as Visible turns fal

Can you figure out what’s causing that
delay? Can you fix it so the program ends
immediately when you close the window?

The delay happens because the for loops need to finish before the
while loop can check if Visible is still true. You can fix it by adding
&& Visible to the conditional test in each for loop.

Was your code a little different than ours? There’s more than one way
to solve any programming problem—like you could have used while loops
instead of for loops. If your program works, then you got the exercise right!
you are here 4   79

this puzzle’s tougher than it looks

Pool Puzzle

Your job is to take code snippets from
the pool and place them into
the blank lines in the code. You
may not use the same snippet
more than once, and you won’t
need to use all the snippets.
Your goal is to make a class
that will compile and run. Don’t
be fooled—this one’s harder than it
looks.

Output

int x = 0;
String Poem = “”;
while ( __________ ) {
_____________________________
if ( x < 1 ) {
___________________________
}
_____________________________
if ( __________ ) {
____________________________
___________
}
if ( x == 1 ) {

We included these “Pool Puzzle” exercises throughout the book
to give your brain an extra-tough workout. If you’re the kind
of person who loves twisty little logic puzzles, then you’ll love
this one. If you’re not, give it a shot anyway—but don’t be
afraid to look at the answer to figure out what’s going on.
And if you’re stumped by a pool puzzle, definitely move on.

____________________________
}
if ( ___________ ) {
}

____________________________

____________
}
__________________

Note: each snippet
from the pool can only
be used once!

Poem = Poem + “ ”;
Poem = Poem + “a “;
Poem = Poem + “n“;
Poem = Poem + “an“;

80   Chapter 2

x>0
x<1
x>1
x>3
x<4

x = x + 1;
x = x + 2;
x = x - 2;
x = x - 1;

MessageBox.Show(Poem);

Poem = Poem + “noys “;
Poem = Poem + “oise “;
Poem = Poem + “ oyster “;
Poem = Poem + “annoys”;
Poem = Poem + “noise”;

Answers on page 83.

it’s all just code

Csharpcross
How does a crossword help you learn C#? Well, all the words are C#related and from this chapter. The clues also provide mental twists and
turns that will help you burn alternative routes to C# right into your brain.
1
2

3

4

5

6

7
8

9

10

11

12

13

14

15

16

Across
Across
3. You give
information to a method using these
_________
3. You give information to a method using these
4. button1.Text
checkBox3.Name are
andand
checkBox3.Name
are examples
examplesofof
4. button1.Text
8. Every statement ends with one of these
8. Every 10.
statement
with C#
oneprogram'
of these
The nameends
of every
s entry point
11. Contains
methods
10. The name
of every
C# program’s entry point
12. Your statements live here
11. Contains
14. Amethods
kind of variable that's either true or false
12. Your 15.
code
statements
livethat
in one
these
A special
method
tellsof
your
program where to
start
14. A kind of variable that’s either true or false
16. This kind of class spans multiple files
15. A special method that tells your program where to start
16. This kind of class spans multiple files

Down
1.Down
The output of a method is its _________ value
1. The output of a method is its _________ value
an example
of one of
2.2.System.Windows.Forms
System.Windows.Forms is an is
example
of one of
these
these
tinypiece
piece of
5.5. AA tiny
of aaprogram
programthat
thatdoes
doessomething
something
6. A block of code is surrounded by
6.7. A
block
is surrounded
by _________
The
kind of
of code
test that
tells a loop when
to end
You can
_________.Show()
to when
pop upto
a simple
7.9.The
kindcall
of test
that tells a loop
end
Windows dialog box
pop up
a simple
9.13.You
_________.
Thecan
kindcall
of variable
thatShow()
contains to
a whole
number
Windows dialog box
13. The kind of variable that contains a whole number

you are here 4   81

exercise solutions

Code Magnets Solution

Part of a C# program is all scrambled up on the fridge. Can you
rearrange the code snippets to make a working C# program that
produces the message box? Some of the curly braces fell on the
floor and they were too small to pick up, so feel free to add as
many of those as you need!

“”;
string Result =

This magnet didn’t fall
off the fridge…
The first time through thes
loop, x is equal to 3 so thi e.
conditional test will be tru

int x = 3;

{
while (x > 0)

if (x > 2) {

+ “a”;
Result = Result

}

This statement mak
equal to 2 the firs es x
through the loop, ant time
second time throug d 1 the
h.

x = x - 1;

Result = Re
sult + “-”;
if (x == 2) {

Result = Result + “b c”;

}
if (x
== 1)
{
Resul
t = R
esult
+ “d”
x = x
;
- 1;
}

MessageBox.Show(Result);

82   Chapter 2

Output:

it’s all just code

Pool Puzzle Solution
Your job was to take code snippets from the
pool and place them into the blank lines
in the code. Your goal was to make a
class that will compile and run.

int x = 0;
String Poem = “”;
while ( x < 4 ) {
Poem = Poem + “a”;
if ( x < 1 ) {
Poem = Poem + “ ”;
}
Poem = Poem + “n”;

Output:

if ( x > 1 ) {
Poem = Poem + “ oyster”;
x = x + 2;
}
if ( x == 1 ) {
Poem = Poem + “noys ”;
}
if ( x < 1 ) {
}

Poem = Poem + “oise ”;

x = x + 1;
}
MessageBox.Show(Poem);

Did you get a different
solution? Type it into the IDE
and see if it works! There’s
more than one correct solution
to the pool puzzle.

If you want a real challenge, see if you
can figure out what it is! Here’s a hint:
There’s another solution that keeps the
word fragments in order.

you are here 4   83

crossword solution

Csharpcross Solution
1
2

3

N

P

A

R

A M

E

T

A
B
R
A
11

C

K
E

P

R

O

P

E

R

T

I

E

E
8

S

E

P
L

A
C
E

E

R

S

T
4

M
6

R

9

M

I

C

O

L

O

10

N

M

E
S

M

S

S

15

E

14

I

B

O

O

L

N
N

T

B

E

O

G

X

U

T

R

A

I

7

N

E

R

Y

P

O

I

N

E

C
O
N

T

H

O

M
13

A
G

S

T
12

S

T

5

D
I

A

N

T

N

I

T

O
N
A

16

E

P

A

R

T

I

A

L

R
Across
3. You give information to a method using these
[parameters]
4. button1.Text and checkBox3.Name are examples of
[properties]
8. Every statement ends with one of these [semicolon]
10. The name of every C# program's entry point
[main]
11. Contains methods [class]
12. Your statements live here [method]
14. A kind of variable that's either true or false
[boolean]
A special 2method that tells your program where to
84  15.Chapter
start [entry point]
16. This kind of class spans multiple files [partial]

Down
1. The output of a method is its _________ value
[return]
2. System.Windows.Forms is an example of one of
these [namespace]
5. A tiny piece of a program that does something
[statement]
6. A block of code is surrounded by [brackets]
7. The kind of test that tells a loop when to end
[conditional]
9. You can call _________.Show() to pop up a simple
Windows dialog box [MessageBox]
13. The kind of variable that contains a whole number
[integer]

3 objects: get oriented!

Making code make sense
...and that’s why my
Husband class doesn’t have a
HelpOutAroundTheHouse()
method or a PullHisOwnWeight()
method.

Every program you write solves a problem.
When you’re building a program, it’s always a good idea to start by thinking about what
problem your program’s supposed to solve. That’s why objects are really useful. They
let you structure your code based on the problem it’s solving, so that you can spend your
time thinking about the problem you need to work on rather than getting bogged down in
the mechanics of writing code. When you use objects right, you end up with code that’s
intuitive to write, and easy to read and change.

this is a new chapter   85

mike’s going places

How Mike thinks about his problems
Mike’s a programmer about to head out to a job
interview. He can’t wait to show off his C# skills, but
first he has to get there—and he’s running late!
1

Mike figures out the route he’ll take to get to the interview.
I’ll take the 31st Street
bridge, head up Liberty Avenue,
and go through Bloomfield.

Mike sets his destination,
then comes up with a route.
2

Good thing he had his radio on. There’s
a huge traffic jam that’ll make him late!

Mike gets newabout a
information eeds to avoid.
street he n

This is Frank Loudly with
your eye-in-the-sky shadow traffic
report. It looks like a three-car
pileup on Liberty has traffic backed
up all the way to 32nd Street.

3

Now he can come up
with a new route to
the interview.

86   Chapter 3

Mike comes up with a new route to get
to his interview on time.

No problem. If I take
Route 28 instead, I’ll
still be on time!

objects: get oriented!

How Mike’s car navigation system thinks about his problems
Mike built his own GPS navigation system, which he
uses to help him get around town.

Here’s a diagram of a class
in Mike’s program. It shows
the name on top, and the
methods on the bottom.

SetDestination(“Fifth Ave & Penn Ave”);
string route;
Here’s the output from the
route = GetRoute();
GetRoute() method—it’s

a string that contains the .
directions Mike should follow

The navigation system sets
a destination and comes up
with a route.

Navigator
SetCurrentLocation()
SetDestination()
ModifyRouteToAvoid()
ModifyRouteToInclude()
GetRoute()
GetTimeToDestination()
TotalDistance()

“Take 31st Street Bridge to Liberty Avenue to Bloomfield”

The navigation system gets
new information about a
street it needs to avoid.
ModifyRouteToAvoid(“Liberty Ave”);

p with a new
u
e
m
o
c
n
a
c
Now it
destination.
route to the
string route;
route = GetRoute();

“Take Route 28 to the Highland Park Bridge to Washington Blvd”

GetRoute() gives a new route
that doesn’t include the
street Mike wants to avoid.

Mike’s navigation system solves the street
navigation problem the same way he does.
you are here 4   87

set methods and modify routes

Mike’s Navigator class has me thods to se t and modif y route s
Mike’s Navigator class has methods, which are where the action happens. But unlike the
button_Click() methods in the forms you’ve built, they’re all focused around a single
problem: navigating a route through a city. That’s why Mike stuck them together into one
class, and called that class Navigator.
Mike designed his Navigator class so that it’s easy to create and modify routes. To get a
route, Mike’s program calls the SetDestination() method to set the destination, and
then uses the GetRoute() method to put the route into a string. If he needs to change the
route, his program calls the ModifyRouteToAvoid() method to change the route so that
it avoids a certain street, and then calls the GetRoute() method to get the new directions.

class Navigator {

Mike chose method
names that would make
sense to someone who
was thinking about how
to navigate a route
through a city.

public void SetCurrentLocation(string locationName) { ... }
public void SetDestination(string destinationName) { ... };
public void ModifyRouteToAvoid(string streetName) { ... };

}

public string GetRoute() { ... };

This is the return type
statement calling the of the method. It means that the
string variable that wiGetRoute() method can use it to set a
that means the methodll contain the directions. When it’s void
,
doesn’t return anything
.

string route =
GetRoute();

Some me thods have a re turn value

Every method is made up of statements that do things. Some methods just execute
their statements and then exit. But other methods have a return value, or a value
that’s calculated or generated inside the method, and sent back to the statement that
called that method. The type of the return value (like string or int) is called the
return type.
The return statement tells the method to immediately exit. If your method doesn’t
have a return value—which means it’s declared with a return type of void—then
the return statement just ends with a semicolon, and you don’t always have to
have one in your method. But if the method has a return type, then it must use the
return statement.

Here’s an example of a method
that has a return type—it s
returns an int. The method usee
the two parameters to calculat
the result and uses the return
statement to pass the value
back to the statement that
called it.

public int MultiplyTwoNumbers(int firstNumber, int secondNumber) {
int result = firstNumber * secondNumber;

}

return result;

Here’s a statement that calls a method to multiply two numbers. It returns an int:
int myResult = MultiplyTwoNumbers(3, 5);

88   Chapter 3

values like 3 and
Methods can taalkeso use variables to
5. But you cana method.
pass values to

objects: get oriented!

¢¢

¢¢

¢¢

¢¢
¢¢

Classes have methods that contain statements that perform actions. You can design a class that is easy to use by
choosing methods that make sense.
Some methods have a return type. You set a method’s return type in its declaration. A method with a declaration that starts
“public int” returns an int value. Here’s an example of a statement that returns an int value: return 37;
When a method has a return type, it must have a return statement that returns a value that matches a return type. So if
you’ve got a method that’s declared “public string” then you need a return statement that returns a string.
As soon as a return statement in a method executes, your program jumps back to the statement that called the method.
Not all methods have a return type. A method with a declaration that starts  “public void” doesn’t return anything at
all. You can still use a return statement to exit a void method: if (finishedEarly) { return; }

Use what you’ve learned to build a program that uses a class
Let’s hook up a form to a class, and make its button call a method inside that class.

Do this!

1

Create a new Windows Forms Application project in the IDE. Then add a class file to it called
Talker.cs by right-clicking on the project in the Solution Explorer and selecting “Class…” from
the Add menu. When you name your new class file “Talker.cs”, the IDE will automatically name
the class in the new file Talker. Then it’ll pop up the new class in a new tab inside the IDE.

2

Add using System.Windows.Forms; to the top of the class file. Then add code to the class:

class Talker {
public static int BlahBlahBlah(string thingToSay, int numberOfTimes)
{
string finalString = “”;
This statement ing for (int count = 1; count <= numberOfTimes; count++)
declares a finalStrit
{
variable and sets
finalString = finalString + thingToSay + “\n”;
equal to an empty
}
This line of code adds the
string.
MessageBox.Show(finalString);
contents of thingToSay and a line
return finalString.Length;
break (“\n”) onto the end of it to
}
the finalString variable.
The BlahBlahBlah() method’s return value is an
}

integer that has the total length of the message it
displayed. You can add “.Length” to any string to
figure out how long it is.

This is called a property. Every string
has a property called Length. When it
calculates the length of a string, a line
break (“\n”) counts as one character.

Flip the page to keep going!
you are here 4   89

introducing objects

So what did you just build?
The new class has one method called BlahBlahBlah() that takes two parameters. The first
parameter is a string that tells it something to say, and the second is the number of times to say it.
When it’s called, it pops up a message box with the message repeated a number of times. Its return
value is the length of the string. The method needs a string for its thingToSay parameter and a
number for its numberOfTimes parameter. It’ll get those parameters from a form that lets the user
enter text using a TextBox control and a number using NumericUpDown control.
Now add a form that uses your new class!

3

Set the default text of
the TextBox to “Hello!”
using its Text property.

Make your project’s form look like this.
Then double-click on the button and have it run this code that calls BlahBlahBlah() and assigns its return
This is a NumericUpDown control.
value to an integer called len:

Set its Minimum property to 1, its
Maximum property to 10, and its
Value property to 3.

private void button1_Click(object sender, EventArgs e)
{
int len = Talker.BlahBlahBlah(textBox1.Text, (int)numericUpDown1.Value);
MessageBox.Show(“The message length is ” + len);
}

4

Now run your program! Click the button and watch it pop up two
message boxes. The class pops up the first message box, and the
form pops up the second one.

The BlahBlahBlah() method
pops up this message box
based on what’s in its
parameters.

When the
method returns
a value, the form
pops it up in this
message box.

You can add a class to your project and share
its methods with the other classes in the project.
90   Chapter 3

objects: get oriented!
It’d be great if I
could compare a few
routes and figure out
which is fastest....

Mike ge ts an ide a
The interview went great! But the traffic
jam this morning got Mike thinking about
how he could improve his navigator.

He could cre ate three dif ferent Navigator classes…
Mike could copy the Navigator class code and paste it into two more
classes. Then his program could store three routes at once.

This box is a class diagram. It lists
all of the methods in a class, and
it’s an easy way to see everything
that it does at a glance.

Navigator
SetDestination()
ModifyRouteToAvoid()
ModifyRouteToInclude()
GetRoute()
GetTimeToDestination()
TotalDistance()

Navigator2
SetDestination()
ModifyRouteToAvoid()
ModifyRouteToInclude()
GetRoute()
GetTimeToDestination()
TotalDistance()

Navigator3
SetDestination()
ModifyRouteToAvoid()
ModifyRouteToInclude()
GetRoute()
GetTimeToDestination()
TotalDistance()

Whoa, that can’t be right!
What if I want to change a
method? Then I need to go
back and fix it in three places.

Right! Maintaining three copies of the same code
is really messy. A lot of problems you need to solve need a
way to represent one thing a bunch of different times. In this case,
it’s a bunch of routes. But it could be a bunch of turbines, or dogs,
or music files, or anything. All of those programs have one thing in
common: they always need to treat the same kind of thing in the
same way, no matter how many of the thing they’re dealing with.
you are here 4   91

for instance…

Mike can use objects to solve his problem
Objects are C#’s tool that you use to work with
a bunch of similar things. Mike can use objects
to program his Navigator class just once, but
use it as many times as he wants in a program.

SetCurrentLocation()
SetDestination()
ModifyRouteToAvoid()
ModifyRouteToInclude()
GetRoute()
GetTimeToDestination()
TotalDistance()

w
ne

Na
vigator o

new
Navi
gato
r()

ne
w

navigator2

bje
ct

Navigator

()
or
at
g
vi
Na

bje
ct

lass
Navigator clists
e
h
t
is
is
h
T
ogram. It
in Mike’s prmethods that a
all of the object can use.
Navigator

navigator1

Na
vi
ga
to
r(
)

Na
vigator o

All you need to create an
object is the new keyword
and the name of a class.

bje
ct

navigator3

Na
vigator o

Mike needed to compare
three different routes
at once, so he used
three Navigator objects
at the same time.

Navigator navigator1 = new Navigator();

navigator1.SetDestination(“Fifth Ave & Penn Ave”);

string route;

route = navigator1.GetRoute();
Now you can use the object! When you
create an object from a class, that object
has all of the methods from that class.

92   Chapter 3

objects: get oriented!

You use a class to build an object
A class is like a blueprint for an object. If you wanted to build
five identical houses in a suburban housing development, you
wouldn’t ask an architect to draw up five identical sets of
blueprints. You’d just use one blueprint to build five houses.

When you define a class, you define
its methods, just like a blueprint
defines the layout of the house.

You can use one blueprint to
make any number of houses,
and you can use one class to
make any number of objects.

An object ge ts its me thods f rom its class
Once you build a class, you can create as many objects as you want from
it using the new statement. When you do, every method in your class
becomes part of the object.

38 Pine
Street

ct

Ho
use obje

Ho
use obje

ct

GiveShelter()
GrowLawn()
MailDelivered()
ClogDrainPipes()
AccruePropertyTaxes()
NeedRepairs()

115 Maple
Drive

Ho
use obje

ct

House

26A Elm
Lane

you are here 4   93

objects improve your code

When you cre ate a ne w object f rom a class,
it’s called an instance of that class
Guess what…you already know this stuff ! Everything in the toolbox
is a class: there’s a Button class, a TextBox class, a Label
class, etc. When you drag a button out of the toolbox, the IDE
automatically creates an instance of the Button class and calls
it button1. When you drag another button out of the toolbox,
it creates another instance called button2. Each instance of
Button has its own properties and methods. But every button acts
exactly the same way, because they’re all instances of the same class.

Before: Here’s a picture of your
computer’s memory when your
program starts.
Your program
executes a new
statement.

House mapleDrive115 = new House();
After: Now it’s
got an instance
of the House y.
class in memor

115 Maple
Drive

ct

Ho
use obje
Check it out for yourself!
Open any project that uses a button called button1,
and use the IDE to search the entire project for the
text “button1 = new”. You’ll find the code that
the IDE added to the form designer to create the
instance of the Button class.

94   Chapter 3

Do this!

in-stance, noun.

an example or one occurrence of
something. The IDE search-andreplace feature finds ever y instance
of a word and changes it to another.

objects: get oriented!

GUI stands for Graphical
User Interface, which is
what you’re building when
you make a form in the
form designer.

A be t ter solution…brought to you by objects!
Mike came up with a new route comparison program that uses objects to find
the shortest of three different routes to the same destination. Here’s how he
built his program.

2

Mike set up a GUI with a text box—textBox1 contains the destination for the three
routes. Then he added textBox2, which has a street that one of the routes should avoid; and
textBox3, which contains a different street that the third route has to include.
He created a Navigator object and set its destination.

navigator1
3.5 miles

Navigator

bje
ct

1

The navigator1
object is an
instance of the
Navigator class.

Na
vigator o

SetCurrentLocation()
SetDestination()
ModifyRouteToAvoid()
ModifyRouteToInclude()
GetRoute()
GetTimeToDestination()
TotalDistance()

string destination = textBox1.Text;
Navigator navigator1 = new Navigator();
navigator1.SetDestination(destination);
route = navigator1.GetRoute();

3

Then he added a second Navigator object called navigator2. He
called its SetDestination() method to set the destination, and
then he called its ModifyRouteToAvoid() method.

4

The third Navigator object is called navigator3. Mike set its
destination, and then called its ModifyRouteToInclude() method.

Na
vigator o
5

Na
vigator o

navigator3
4.2 miles

bje
ct

3.8 miles

bje
ct

navigator2

3.5 miles

bje
ct

navigator1

Na
vigator o

Now Mike can call each object’s TotalDistance() method to figure
out which route is the shortest. And he only had to write the code once,
not three times!

ination(), d
The SetDesteT
oAvoid(), an
ModifyRout eToInclude()
ModifyRout take a string as a
methods all
parameter.

Any time you
create a new
object from a
class, it’s called
creating an
instance of
that class.
you are here 4   95

a little head first secret sauce

Wait a minute! You didn’t give
me nearly enough information
to build the navigator program.

That’s right, we didn’t. A geographic navigation program is
a really complicated thing to build. But complicated programs follow
the same patterns as simple ones. Mike’s navigation program is an
example of how someone would use objects in real life.

Theor y and practice
Speaking of patterns, here’s a pattern that you’ll see over and over again
throughout the book. We’ll introduce a concept or idea (like objects) over the
course of a few pages, using pictures and small code excerpts to demonstrate the
idea. This is your opportunity to take a step back and try to understand what’s
going on without having to worry about getting a program to work.

When we’re introducing a new concept
(like objects), keep your eyes open for
pictures and code excerpts like this.

After we’ve introduced a concept, we’ll give you a chance to get it into your
brain. Sometimes we’ll follow up the theory with a writing exercise—like the
Sharpen your pencil exercise on the next page. Other times we’ll jump straight
into code. This combination of theory and practice is an effective way to get
these concepts off of the page and stuck in your brain.

A lit tle advice for the code e xercises
If you keep a few simple things in mind, it’ll make the code exercises go
smoothly:
≥≥ It’s easy to get caught up in syntax problems, like missing parentheses
or quotes. One missing bracket can cause many build errors.
≥≥ It’s much better to look at the solution than get frustrated with a
problem. When you’re frustrated, your brain doesn’t like to learn.
≥≥ All of the code in this book is tested and definitely works in Visual
Studio 2010! But it’s easy to accidentally type things wrong (like
typing a one instead of a lowercase L).
≥≥ If your solution just won’t build, try downloading it from the Head
First Labs website: http://www.headfirstlabs.com/hfcsharp
96   Chapter 3

115 Maple
Drive

Ho
use obje

ct

House mapleDrive115 = new House();

When you run into
a problem with
a coding exercise,
don’t be afraid
to peek at the
solution. You can
also download the
solution from the
Head First Labs
website.

objects: get oriented!

Follow the same steps that Mike followed on the facing page to write
the code to create Navigator objects and call their methods.

string destination = textBox1.Text;
string route2StreetToAvoid = textBox2.Text;
string route3StreetToInclude = textBox3.Text;
Navigator navigator1 = new Navigator();
navigator1.SetDestination(destination);
int distance1 = navigator1.TotalDistance();

We gave you a head start. Here’s
the code Mike wrote to get the
destination and street names from
the textboxes.

the
And here’s the code to create
ation,
tin
des
its
set
,
navigator object
ce.
tan
and get the dis

1. Create the navigator2 object, set its destination, call its ModifyRouteToAvoid() method, and use its
TotalDistance() method to set an integer variable called distance2.

Navigator navigator2 =
navigator2.
navigator2.
int distance2 =

2. Create the navigator3 object, set its destination, call its ModifyRouteToInclude() method, and use its
TotalDistance() method to set an integer variable called distance3.

compares two numbers and
The Math.Min() method built into the .NET Framework est
ce to the destination.
returns the smallest one. Mike used it to find the short distan
int shortestDistance = Math.Min(distance1, Math.Min(distance2, distance3));

you are here 4   97

static cling

Follow the same steps that Mike followed on the facing page to write
the code to create Navigator objects and call their methods.

string destination = textBox1.Text;
string route2StreetToAvoid = textBox2.Text;
string route3StreetToInclude = textBox3.Text;
Navigator navigator1 = new Navigator();
navigator1.SetDestination(destination);
int distance1 = navigator1.TotalDistance();

We gave you a head start. Here’s
the code Mike wrote to get the
destination and street names from
the textboxes.
the
And here’s the code to create
ation,
tin
des
its
set
,
navigator object
and get the distance.

1. Create the navigator2 object, set its destination, call its ModifyRouteToAvoid() method, and use its
TotalDistance() method to set an integer varable called distance2.

Navigator navigator2 =
navigator2.
navigator2.

new Navigator()

SetDestination(destination);
ModifyRouteToAvoid(route2StreetToAvoid);

int distance2 =

navigator2.TotalDistance();

2. Create the navigator3 object, set its destination, call its ModifyRouteToInclude() method, and use its
TotalDistance() method to set an integer varable called distance3.

Navigator navigator3 = new Navigator()
navigator3.SetDestination(destination);
navigator3.ModifyRouteToInclude(route3StreetToInclude);
int distance3 = navigator3.TotalDistance();

compares two numbers and
The Math.Min() method built into the .NET Framework est
ce to the destination.
returns the smallest one. Mike used it to find the short distan
int shortestDistance = Math.Min(distance1, Math.Min(distance2, distance3));

98   Chapter 3

objects: get oriented!
I’ve written a few classes now, but I haven’t used “new”
to create an instance yet! So does that mean I can call
methods without creating objects?

Yes! That’s why you used the static keyword in your methods.
Take another look at the declaration for the Talker class you built a few pages ago:
class Talker
{
public static int BlahBlahBlah(string thingToSay, int numberOfTimes)
{
string finalString = “”;

When you called the method you didn’t create a new instance of Talker. You just did this:
Talker.BlahBlahBlah(“Hello hello hello”, 5);

That’s how you call static methods, and you’ve been doing that all along. If you take away
the static keyword from the BlahBlahBlah() method declaration, then you’ll have to
create an instance of Talker in order to call the method. Other than that distinction, static
methods are just like object methods. You can pass parameters, they can return values, and
they live in classes.
There’s one more thing you can do with the static keyword. You can mark your whole
class as static, and then all of its methods must be static too. If you try to add a non-static
method to a static class, it won’t compile.

Q:

When I think of something that’s “static,” I think of
something that doesn’t change. Does that mean non-static
methods can change, but static methods don’t? Do they
behave differently?

A:

No, both static and non-static methods act exactly the
same. The only difference is that static methods don’t require
an instance, while non-static methods do. A lot of people have
trouble remembering that, because the word “static” isn’t really
all that intuitive.

Q:

So I can’t use my class until I create an instance of
an object?

A:

You can use its static methods. But if you have methods
that aren’t static, then you need an instance before you can
use them.

Q:

Then why would I want a method that needs an
instance? Why wouldn’t I make all my methods static?

A:

Because if you have an object that’s keeping track of
certain data—like Mike’s instances of his Navigator
class that each kept track of a different route—then you can
use each instance’s methods to work with that data. So when
Mike called his ModifyRouteToAvoid() method
in the navigator2 instance, it only affected the route
that was stored in that particular instance. It didn’t affect the
navigator1 or navigator3 objects. That’s how he
was able to work with three different routes at the same time—
and his program could keep track of all of it.

Q:
A:

So how does an instance keep track of data?

Turn the page and find out!
you are here 4   99

an object’s state of affairs

An instance use s fields to keep track of things
You change the text on a button by setting its Text property in the
IDE. When you do, the IDE adds code like this to the designer:
button1.Text = “Text for the button”;
Now you know that button1 is an instance of the Button class.
What that code does is modify a field for the button1 instance.
You can add fields to a class diagram—just draw a horizontal line in
the middle of it. Fields go above the line, methods go underneath it.

This is where a class
diagram shows the
fields. Every instance
of the class uses
them to keep track
of its state.

Technically, it’s setting a
property. A property is very
similar to a field—but we’ll
get into all that a little
later on.

Class
Field1
Field2
Field3
Method1()
Method2()
Method3()

Add this line to
separate the fields
from the methods.

Methods are what an object does. Fields are what the object knows.
When Mike created three instances of Navigator classes, his program created three objects.
Each of those objects was used to keep track of a different route. When the program created the
navigator2 instance and called its SetDestination() method, it set the destination for that
one instance. But it didn’t affect the navigator1 instance or the navigator3 instance.

Navigator
Destination
Route
SetCurrentLocation()
SetDestination()
ModifyRouteToAvoid()
ModifyRouteToInclude()
GetRoute()
GetTimeToDestination()
TotalDistance()

100   Chapter 3

Every instance of Navigator knows
its destination and its route.
What a Navigator object does is
let you set a destination, modify
its route, and get information
about that route.

An object’s behavior is defined by its methods,
and it uses fields to keep track of its state.

objects: get oriented!

Remember, when you see
“void” in front of a method
it means that it doesn’t ,
return any value.

Le t’s cre ate some instance s!
It’s easy to add fields to your class. Just declare
variables outside of any methods. Now every
instance gets its own copy of those variables.

class Clown {
public string Name;
public int Height;

Clown
Name
Height
TalkAboutYourself()

When you want to create instances
of your class, don’t use the static
keyword in either the class declaration
or the method declaration.

}

public void TalkAboutYourself() {
MessageBox.Show(“My name is ”
+ Name + “ and I’m ”
+ Height + “ inches tall.”);
}

Remember, the *= operator tells C#
to take whatever’s on the left of the
operator and multiply it by whatever’s
on the right.

Write down the contents of each message box that will be displayed
after the statement next to it is executed.

Clown oneClown = new Clown();
oneClown.Name = “Boffo”;
oneClown.Height = 14;
oneClown.TalkAboutYourself();

“My name is _______ and I’m ______ inches tall.”

Clown anotherClown = new Clown();
anotherClown.Name = “Biff”;
anotherClown.Height = 16;
anotherClown.TalkAboutYourself();

“My name is _______ and I’m ______ inches tall.”

Clown clown3 = new Clown();
clown3.Name = anotherClown.Name;
clown3.Height = oneClown.Height - 3;
clown3.TalkAboutYourself();

“My name is _______ and I’m ______ inches tall.”

anotherClown.Height *= 2;
anotherClown.TalkAboutYourself();

“My name is _______ and I’m ______ inches tall.”

you are here 4   101

a heaping helping of objects

Thanks for the memor y
When your program creates an object, it lives in a part of the
computer’s memory called the heap. When your code creates an
object with a new statement, C# immediately reserves space in the
heap so it can store the data for that object.

Here’s a picture of the heap before the
project starts. Notice that it’s empty.

Le t’s take a closer look at what happened here

Write down the contents of each message box that will be displayed
after the statement next to it is executed.

Clown oneClown = new Clown();
oneClown.Name = “Boffo”;
oneClown.Height = 14;

Each of these new statements
creates an instance of the Clo
class by reserving a chunk of
wn
me
object and filling it up with th mory on the heap for that
e object’s data.

oneClown.TalkAboutYourself();

Boffo and I’m ______
14 inches tall.”
“My name is _______

Clown anotherClown = new Clown();
anotherClown.Name = “Biff”;
anotherClown.Height = 16;
anotherClown.TalkAboutYourself();

Biff and I’m ______
16 inches tall.”
“My name is _______

Clown clown3 = new Clown();
clown3.Name = anotherClown.Name;
clown3.Height = oneClown.Height - 3;
clown3.TalkAboutYourself();
anotherClown.Height *= 2;
anotherClown.TalkAboutYourself();

Biff and I’m ______
11 inches tall.”
“My name is _______
Biff and I’m ______
32 inches tall.”
“My name is _______

When your program creates a new object, it gets added to the heap.
102   Chapter 3

objects: get oriented!

Here’s how your program creates a new instance of the
Clown class:

Clo
wn objec

That’s actually two statements combined into one. The
first statement declares a variable of type Clown (Clown
myInstance;). The second statement creates a new
object and assigns it to the variable that was just created
(myInstance = new Clown();). Here’s what the heap
looks like after each of these statements:

Clo
wn objec

2

“Biff”

t#

16

Clo
wn objec

it

16

Clo
wn objec

“Biff”
32

t#

11

14

3

“Biff”

1

“Boffo”

Clo
wn objec

2

There’s no new command, which means
these statements don’t create a new
object. They’re just modifying one
that’s already in memory.

t#

Clo
wn objec

t#

anotherClown.Height *= 2;
anotherClown.TalkAboutYourself();

“Biff”

2

Clo
wn objec

wn object is
Then the third Claloted.
created and popu

4

Clo
wn objec

t#

11

14

1

“Boffo”

3

Clown anotherClown = new Clown();
anotherClown.Name = “Biff”; These statements create
the second object and fill
anotherClown.Height = 16;
with data.
anotherClown.TalkAboutYourself();

Clown clown3 = new Clown();
clown3.Name = anotherClown.Name;
clown3.Height = oneClown.Height - 3;
clown3.TalkAboutYourself();

t#

14

Clown oneClown = new Clown();
object
The firsted, and its
oneClown.Name = “Boffo”;
is creat e set.
oneClown.Height = 14;
fields ar
oneClown.TalkAboutYourself();

“Biff”

3

1

“Boffo”

t#

2

t#

14

Clown myInstance = new Clown();

1

1

“Boffo”

t#

What’s on your program’s mind

This object is an instance of the
Clown class.

Clo
wn objec

you are here 4   103

making methods make sense

You can use class and me thod
names to make your code intuiti ve
When you put code in a method, you’re making a choice about how to structure
your program. Do you use one method? Do you split it into more than one? Or do
you even need a method at all? The choices you make about methods can make your
code much more intuitive—or, if you’re not careful, much more convoluted.
1

Here’s a nice, compact chunk of code. It’s from a control program that
runs a machine that makes candy bars.
T

“tb”, “ics”, and “m”
are terrible names!
We have no idea
what they do. And
what’s that T class
for?

int t = m.chkTemp();
if (t > 160) {
T tb = new T();
tb.clsTrpV(2);
ics.Fill();
ics.Vent();
m.airsyschk();
}

he chkTemp() met
hod returns an
integer… but wha
t does it do?
The clsTrpV()
method has one
parameter, but we
don’t know what
it’s supposed to be.

Take a second and look at that code. Can you figure out what it does?

2

Those statements don’t give you any hints about why the code’s doing what it’s doing. In this case, the
programmer was happy with the results because she was able to get it all into one method. But making
your code as compact as possible isn’t really useful! Let’s break it up into methods to make it easier to
read, and make sure the classes are given names that make sense. But we’ll start by figuring out what the
code is supposed to do.

out what
How do you figureosed to do?
your code is suppwritten for
Well, all code is up to you to
a reason. So it’s reason! In this
figure out that up the page
case, we can lookion manual
in the specificatmmer followed.
that the progra

er
General Electronics Type 5 Candy Bar Mak
ual
Man
tion
Specifica
minutes by an
The nougat temperature must be checked every 3
C, the candy
160°
automated system. If the temperature exceeds
isolation
y
is too hot, and the system must perform the cand
cooling system (CICS) vent procedure.
• Close the trip throttle valve on turbine #2
of water
• Fill the isolation cooling system with a solid stream
• Vent the water
• Verify that there is no evidence of air in the system

104   Chapter 3

objects: get oriented!

3

That page from the manual made it a lot easier to understand the code. It also gave us some great
hints about how to make our code easier to understand. Now we know why the conditional test checks
the variable t against 160—the manual says that any temperature above 160°C means the nougat
is too hot. And it turns out that m was a class that controlled the candy maker, with static methods
to check the nougat temperature and check the air system. So let’s put the temperature check into a
method, and choose names for the class and the methods that make the purpose obvious.

The IsNougatTooHot()
method’s return type

public boolean IsNougatTooHot() {
int temp = Maker.CheckNougatTemperature();
if (temp > 160) {
By naming the class “Maker” and the
,
return true;
method “CheckNougatTemperature”and
} else {
the code is a lot easier to underst .
return false;
}
This method’s return type is
}
a

Boolean, which means it returns
true or false value.

4

What does the specification say to do if the nougat is too hot? It tells us to perform the candy isolation
cooling system (or CICS) vent procedure. So let’s make another method, and choose an obvious name
for the T class (which turns out to control the turbine) and the ics class (which controls the isolation
cooling system, and has two static methods to fill and vent the system):

A void return type means
the method doesn’t
return any value at all.

5

public void DoCICSVentProcedure() {
Turbine turbineController = new Turbine();
turbineController.CloseTripValve(2);
IsolationCoolingSystem.Fill();
IsolationCoolingSystem.Vent();
Maker.CheckAirSystem();
}

Now the code’s a lot more intuitive! Even if you don’t know that the CICS vent procedure needs to
be run if the nougat is too hot, it’s a lot more obvious what this code is doing:
if (IsNougatTooHot() == true) {
DoCICSVentProcedure();
}

You can make your code easier to read and write by thinking about
the problem your code was built to solve. If you choose names for your
methods that make sense to someone who understands that problem,
then your code will be a lot easier to decipher…and develop!
you are here 4   105

classes au naturale

Gi ve your classe s a natural structure
Take a second and remind yourself why you want to make your methods intuitive:
because every program solves a problem or has a purpose. It might not
be a business problem—sometimes a program’s purpose (like FlashyThing) is just to
be cool or fun! But no matter what your program does, the more you can make your
code resemble the problem you’re trying to solve, the easier your program will be to
write (and read, and repair, and maintain…).

sses
Use class diagrams to plan out your claam
e

r
A class diagram is a simple way to draw youtool
classes out on paper. It’s a really valuable rt
for designing your code BEFORE you sta
writing it.
of
Write the name of the class at the top the
in
hod
met
the diagram. Then write each
the
box at the bottom. Now you can see all of
parts of the class at a glance!

ClassN

Method()
Method()
Method()
..
.

Le t’s build a class diagram
Take another look at the if statement in #5 on the previous page. You already know that statements
always live inside methods, which always live inside classes, right? In this case, that if statement was
in a method called DoMaintenanceTests(), which is part of the CandyController class.
Now take a look at the code and the class diagram. See how they relate to each other?
class CandyController {
public void DoMaintenanceTests() {
...
if (IsNougatTooHot() == true) {
DoCICSVentProcedure();
}
...
}
public void DoCICSVentProcedure() ...
public boolean IsNougatTooHot() ...
}
106   Chapter 3

CandyController
DoMaintenanceTests()
DoCICSVentProcedure()
IsNougatTooHot()

objects: get oriented!

t

The code for the candy control system we built on the previous
page called three other classes. Flip back and look through the
code, and fill in their class diagrams.

Turbine

We filled in the
for this one. Whacltass name
method
goes here?

Fill()

had
One of the classeFs ill().
d
a method calle name
Fill in its class ethod.
and its other m

There was one other
class in the code on e
previous page. Fill in th
name and method. its

you are here 4   107

a few helpful tips

Class diagrams help you organize your
classes so they make sense
Writing out class diagrams makes it a lot easier to spot potential problems in your
classes before you write code. Thinking about your classes from a high level before
you get into the details can help you come up with a class structure that will make
sure your code addresses the problems it solves. It lets you step back and make sure
that you’re not planning on writing unnecessary or poorly structured classes or
methods, and that the ones you do write will be intuitive and easy to use.

Dishwasher
CleanDishes()
AddDetergent()
SetWaterTemperature()
ParkTheCar()

Dishwasher
CleanDishes()
AddDetergent()
SetWaterTemperature()

The class is called
“Dishwasher”, so all the
methods should be about
washing dishes. But one
method—ParkTheCar()—has
nothing to do with dishes, so it
should be taken out and put in
another class.

The code for the candy control system we built on the
previous page called three other classes. Flip back and
look through the code, and fill in their class diagrams.

t

Turbine

CloseTripValve()

108   Chapter 3

IsolationCoolingSystem
Fill()

Vent()

You could figure out that
Maker is a class because it
appears in front of a dot in
Maker.CheckAirSystem().

Maker
CheckNougatTemperature()
CheckAirSystem()

objects: get oriented!

Each of these classes has a serious design flaw. Write down what
you think is wrong with each class, and how you’d fix it.

v

Class23

This class is part of the candy manufacturing system from earlier.

CandyBarWeight()
PrintWrapper()
GenerateReport()
Go()

DeliveryGuy
These two classes are part of a system that a pizza parlor uses to
track the pizzas that are out for delivery.

AddAPizza()
PizzaDelivered()
TotalCash()
ReturnTime()

DeliveryGirl
AddAPizza()
PizzaDelivered()
TotalCash()
ReturnTime()

CashRegister

The CashRegister class is part of a program that’s used by an
automated convenience store checkout system.

MakeSale()
NoSale()
PumpGas()
Refund()
TotalCashInRegister()
GetTransactionList()
AddCash()
RemoveCash()

you are here 4   109

create a class

Here’s how we corrected the classes. We show just one
possible way to fix the problems—but there are plenty of other ways
you could design these classes depending on how they’ll be used.
This class is part of the candy manufacturing system from earlier.

The class name doesn’t describe what the class does. A programmer
who sees a line of code that calls Class23.Go() will have no idea what
that line does. We’d also rename the method to something that’s more

CandyMaker
CandyBarWeight()
PrintWrapper()
GenerateReport()
MakeTheCandy()

descriptive—we chose MakeTheCandy(), but it could be anything.

These two classes are part of a system that a pizza parlor uses to
track the pizzas that are out for delivery.

It looks like the DeliveryGuy class and the DeliveryGirl class
both do the same thing—they track a delivery person who’s out
delivering pizzas to customers. A better design would replace

DeliveryPerson
Gender
AddAPizza()
PizzaDelivered()
TotalCash()
ReturnTime()

them with a single class that adds a field for gender..

We added the Gender field becauseckwedelivery
assumed there was a reason to trat’s why
guys and girls separately, and tha
there were two classes for them.
The CashRegister class is part of a program that’s used by an
automated convenience store checkout system.

All of the methods in the class do stuff that has to do with
a cash register—making a sale, getting a list of transactions,
adding cash… except for one: pumping gas. It’s a good idea to
pull that method out and stick it in another class.

110   Chapter 3

CashRegister
MakeSale()
NoSale()
Refund()
TotalCashInRegister()
GetTransactionList()
AddCash()
RemoveCash()

objects: get oriented!
public partial class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
String result = “”;
Echo e1 = new Echo();

Pool Puzzle

Your job is to take code snippets from the
pool and place them into the blank
lines in the code. You may use
the same snippet more than once,
and you won’t need to use all the
snippets. Your goal is to make
classes that will compile and run
and produce the output listed.

_________________________
int x = 0;

while ( ___________ ) {

result = result + e1.Hello() + “\n”;
__________________________
if ( ____________ ) {
}

e2.count = e2.count + 1;

Output

if ( ____________ ) {
}

e2.count = e2.count + e1.count;

x = x + 1;

}

}
MessageBox.Show(result + “Count: ” + e2.count);

class ____________ {
public int _________ = 0;

Bonus Question!

public string ___________ {

}

}

}

If the last line of output was
24 instead of 10, how would
you complete the puzzle?
You can do it by changing
just one statement.

return “helloooo...”;

Note: Each
snippet from the
pool can be used
more than once!

x
y
e2
count

e1 = e1 + 1;
e1 = count + 1;
e1.count = count + 1;
e1.count = e1.count + 1;

x<4
x<5
x>0
x>1

Echo
Tester
Echo( )
Count( )
Hello( )

e2 = e1;
Echo e2;
Echo e2 = e1;
Echo e2 = new Echo( );

Answers on page 122.

x == 3
x == 4

you are here 4   111

working class guys

Build a class to work with some guys
Joe and Bob lend each other money all the time. Let’s create a class to
keep track of them. We’ll start with an overview of what we’ll build.

“Bob”
“Joe”

50

100

Gu
y object

Gu
y object

We’ll give cash to the guys and take cash from them
We’ll use each guy’s ReceiveCash() method to increase a guy’s cash,
and we’ll use his GiveCash() method to reduce it.

’s ReceiveCash()
The form calls the objectveC
() because
method. It’s called Recei ash
he’s receiving the cash.

“Joe”

#1

50

Gu
y object
112   Chapter 3

joe.ReceiveCash(25);

The method returns the
number of bucks that the guy
added to his Cash field.

GiveCash()
ReceiveCash()

We chose names for the
methods that make sense.
You call a Guy object’s
GiveCash() method to tell
him to give up some of his
cash, and his ReceiveCash()
method when you want him
to take some cash back.
We could have called them
GiveCashToSomeone() and
ReceiveCashFromSomeone(),
but that would have been
very long!
When you take an instance
of Guy and call its
ReceiveCash() method, you
pass the amount of cash
the guy will take as a
parameter. So calling joe.
ReceiveCash(25) tells Joe
to receive 25 bucks and
add them to his wallet.

“Joe”
75

#1

We’ll set each Guy object’s cash and name fields
The two objects represent different guys, each with his own name and a
different amount of cash in his pocket.

Each guy has a Name
field that keeps track of
his name, and a Cash field
that has the number of
bucks in his pocket.

3

Gu
y object

#2

2

Gu
y object

#2

The new statements
that create the two
instances live in the
code that gets run as
soon as the form is
created. Here’s what
the heap looks like
after the form is
loaded.

#1

We’ll create a Guy class and add two instances of it to a form
The form will have two fields, one called joe (to keep track of the first object),
and the other called bob (to keep track of the second object).

#1

1

Guy
Name
Cash

Gu
y object

objects: get oriented!

Cre ate a project for your guys
Create a new Windows Forms Application project (because we’ll
be using a form). Then use the Solution Explorer to add a new
class to it called Guy. Make sure to add “using System.
Windows.Forms;” to the top of the Guy class file. Then fill
in the Guy class. Here’s the code for it:

class Guy {
public string Name;
public int Cash;

Do this!

The Guy class has two fields. The Name field is
a string, and it’ll contain the guy’s name (“Joe”).
And the Cash field is an int, which will keep
track of how many bucks are in his pocket.

ameter
The GiveCash() method has one par
the
tell
to
use
’ll
called amount that you
.
you
give
guy how much cash to

public int GiveCash(int amount) {
if (amount <= Cash && amount > 0) {
He uses an if statement to checkhe
s
make
Cash -= amount;
The Guy
whether he has enough cash—if and
sure that you’re
return amount;
does, he takes it out of his pocket
asking him for a } else {
returns it as the return value.
positive amount
MessageBox.Show(
of cash, otherwise
“I don’t have enough cash to give you ” + amount,
he’d add to his
Name + “ says...”);
cash instead of
return
0;
If the guy doesn’t have enough cash, he’ll
taking away from
tell
you so with a message box, and then
}
it.
he’ll
make GiveCash() return 0.
}

like
The ReceiveCash() method workssedjustan
public int ReceiveCash(int amount) { the GiveCash() method. It’s pas
make
if (amount > 0) {
amount as a parameter, checks ton zer
o,
Cash += amount;
sure that amount is greater tha
return amount;
and then adds it to his cash.

}
}

} else {
MessageBox.Show(amount + “ isn’t an amount I’ll take”,
Name + “ says...”);
return 0;
If the amount was positive, then the
ReceiveCash() method returns the amount
}

Be careful with your curly brackets. It’s easy to
have the wrong number—make sure that every opening
bracket has a matching closing bracket. When they
all balanced, the IDE will automatically indent them’re
for you when you type the last closing bracket.

added. If it was zero or negative, the guy
shows a message box and then returns 0.

you are here 4   113

joe says, “where’s my money?”

Build a form to interact with the guys
The Guy class is great, but it’s just a start. Now put together
a form that uses two instances of the Guy class. It’s got labels
that show you their names and how much cash they have, and
buttons to give and take cash from them.

1

Add two buttons and three labels to your form
The top two labels show how much cash each guy has. We’ll also add a field called bank to the
form—the third label shows how much cash is in it. We’re going to have you name some of the
labels that you drag onto the forms. You can do that by clicking on each label that you want
to name and changing its “(Name)” row in the Properties window. That’ll make your code a
lot easier to read, because you’ll be able to use “joesCashLabel” and “bobsCashLabel” instead of
“label1” and “label2”.

This button will call
the Joe object’s
ReceiveCash() method,
passing it 10 as
the amount, and
subtracting from the
form’s bank field the
cash that Joe receives.
2

Build this!

Name the top label
joesCashLabel, the label
underneath it bobsCashLabel,
and the bottom label
bankCashLabel. You can
leave their Text properties
alone; we’ll add a method to
the form to set them.
This button will call the Bob
object’s GiveCash() method,
passing it 5 as the amount, and
adding the cash that Bob gives
to the form’s bank field.

Add fields to your form
Your form will need to keep track of the two guys, so you’ll need a field for each of them. Call
them joe and bob. Then add a field to the form called bank to keep track of how much money
the form has to give to and receive from the guys.
namespace Your_Project_Name {

Since we’re using
Guy objects to
keep track of
Joe and Bob,
you declare
their fields in
the form using
the Guy class.

public partial class Form1 : Form {
Guy joe;
Guy bob;

int bank = 100;
public Form1() {
}

114   Chapter 3

InitializeComponent();

The amount of cash
in the form’s bank
field goes up and down
depending on how much
money the form gave to
and received from the
Guy objects.

objects: get oriented!

3

Add a method to the form to update the labels
The labels on the right-hand side of the form show how much cash each guy has and how much
is in the bank field. So add the UpdateForm() method to keep them up to date—make sure
the return type is void to tell C# that the method doesn’t return a value. Type this method
This new method
into the form right underneath where you added the bank field:
public void UpdateForm() {

Notice how the labels
are updated using the
Guy objects’ Name and
Cash fields.
}
4

joesCashLabel.Text = joe.Name + “ has $” + joe.Cash;
bobsCashLabel.Text = bob.Name + “ has $” + bob.Cash;
bankCashLabel.Text = “The bank has $” + bank;

is simple. It just
updates the three
labels by setting
their Text properties.
You’ll have each
button call it to keep
the labels up to date.

Double-click on each button and add the code to interact with the objects
Make sure the left-hand button is called button1, and the right-hand button is called button2.
Then double-click each of the buttons—when you do, the IDE will add two methods called
button1_Click() and button2_Click() to the form. Add this code to each of them:
private void button1_Click(object sender, EventArgs e) {
if (bank >= 10) {

bank -= joe.ReceiveCash(10);
UpdateForm();

} else {

}

}

When the user clicks the “Give $10
Joe” button, the form calls the Joeto
object’s ReceiveCash() method—b
if the bank has enough money. ut only

MessageBox.Show(“The bank is out of money.”);

The bank needs at least $10 to give to
Joe. If there’s not enough, it’ll pop up
this message box.

private void button2_Click(object sender, EventArgs e) {
bank += bob.GiveCash(5);

}

5

UpdateForm();

The “Receive $5 from Bob” button
doesn’t need to check how much is
in the bank, because it’ll just add
If Bob’s out of money,
whatever Bob gives back.
GiveCash() will return zero.

Start Joe out with $50 and start Bob out with $100
It’s up to you to figure out how to get Joe and Bob to start out with their Cash and
Name fields set properly. Put it right underneath InitializeComponent() in the form.
That’s part of that designer-generated method that gets run once, when the form is first initialized.
Once you’ve done that, click both buttons a number of times—make sure that one button takes
$10 from the bank and adds it to Joe, and the other takes $5 from Bob and adds it to the bank.
public Form1() {

InitializeComponent();

}

// Initialize joe and bob here!

Add the lines of code here to
create the two objects and set
their Name and Cash fields.
you are here 4   115

exercise solution

It’s up to you to figure out how to get Joe and Bob to start out with their Cash
and Name fields set properly. Put it right underneath InitializeComponent() in
the form.

first
Here’s where we set up thste line
fir
e
instance of Guy. Th the next
creates the object, and
two set its fields.

Make sure you call UpdateForm() so
the labels look right when the form
first pops up.

public Form1() {
InitializeComponent();
bob = new Guy();
bob.Name = “Bob”;
bob.Cash = 100;
joe = new Guy();
joe.Name = “Joe”;
joe.Cash = 50;
}

UpdateForm();

Q:

Why doesn’t the solution start with “Guy bob = new
Guy()”? Why did you leave off the first “Guy”?

A:

Because you already declared the bob field at the top of the
form. Remember how the statement “int i = 5;” is the same
as the two statements “int i” and “i = 5;”? This is the same
thing. You could try to declare the bob field in one line like this:
“Guy bob = new Guy();”. But you already have the first
part of that statement (“Guy bob;”) at the top of your form. So
you only need the second half of the line, the part that sets the bob
field to create a new instance of Guy().

Q:

OK, so then why not get rid of the “Guy bob;” line at
the top of the form?

A:

Then a variable called bob will only exist inside that special
“public Form1()” method. When you declare a variable
inside a method, it’s only valid inside the method—you can’t access
it from any other method. But when you declare it outside of your
method but inside the form or a class that you added, then you’ve
added a field accessible from any other method inside the form.

116   Chapter 3

Then we do the same for the
second instance of the Guy class.

Q:
A:

Make sure you save the
project now—we’ll come s.
back to it in a few page
What happens if I don’t leave off that first “Guy”?

You’ll run into problems—your form won’t work, because it
won’t ever set the form’s bob variable. Think about it for a minute,
and you’ll see why it works that way. If you have this code at the top
of your form:

public partial class Form1 : Form {
Guy bob;
and then you have this code later on, inside a method:

Guy bob = new Guy();
then you’ve declared two variables. It’s a little confusing, because
they both have the same name. But one of them is valid throughout
the entire form, and the other one—the new one you added—is only
valid inside the method. The next line (bob.Name = “Bob”;)
only updates that local variable, and doesn’t touch the one in the
form. So when you try to run your code, it’ll give you a nasty error
message (“NullReferenceException not handled”), which just means
you tried to use an object before you created it with new.

objects: get oriented!

There’s an e asier way to initialize objects
Almost every object that you create needs to be initialized in some way.
And the Guy object is no exception—it’s useless until you set its Name
and Cash fields. It’s so common to have to initialize fields that C# gives
you a shortcut for doing it called an object initializer. And the IDE’s
IntelliSense will help you do it.

1

Here’s the original code that you wrote to
initialize Joe’s Guy object.

joe = new Guy();
joe.Name = “Joe”;
joe.Cash = 50;
2

3

Object intializers
save you time and
make your code
more compact
and easier to
read…and the
IDE helps you
write them.

Delete the second two lines and the semicolon after “Guy(),” and add a right curly bracket.

joe = new Guy() {

Press space. As soon as you do, the IDE pops up an IntelliSense window that shows you all of
the fields that you’re able to initialize.

joe = new Guy() {

4

5

Press tab to tell it to add the Cash field. Then set it equal to 50.

joe = new Guy() { Cash = 50

Type in a comma. As soon as you do, the other field shows up.

joe = new Guy() { Cash = 50,

5

Finish the object initializer. Now you’ve saved yourself two lines of code!

joe = new Guy() { Cash = 50, Name = “Joe” };

This new declaration does exactly the same
thing as the three lines of code you wrote
originally. It’s just shorter and easier to read.

you are here 4   117

a few helpful tips

A few ideas for designing intuitive classes
± Y ou’re building your program to solve a problem.

Spend some time thinking about that problem. Does it break down into pieces
easily? How would you explain that problem to someone else? These are good
things to think about when designing your classes.
It’d be great if I
could compare a few
routes and figure out
which is fastest....

± W
 hat real-world things will your program use?

A program to help a zoo keeper track her animals’ feeding schedules might have
classes for different kinds of food and types of animals.

± U se descriptive names for classes and methods.

Someone should be able to figure out what your classes and methods do just by
looking at their names.

ob
j

Object

bestRoute

bje
ct

myInst

Na
vigator o

± L ook for similarities between classes.

Sometimes two classes can be combined into one if they’re really similar. The candy
manufacturing system might have three or four turbines, but there’s only one
method for closing the trip valve that takes the turbine number as a parameter.
BlockedRoad
ClosedRoad

Name
Duration

FindDetour()

StreetName
ReasonItsClosed
CalculateDelay()

118   Chapter 3

Detour

Name
Duration
ReasonItsClosed
FindDetour()
CalculateDelay()

objects: get oriented!

Add buttons to the “Fun with Joe and Bob” program to make the guys give each other cash.

1

2

Use an object initializer to initialize Bob’s instance of Guy
You’ve already done it with Joe. Now make Bob’s instance work with an object
initializer too.

If you already clicked the button, just delete
it, add it back to your form, and rename it.
Then delete the old button3_Click() method
that the IDE added before, and use the new
method it adds now.

Add two more buttons to your form
The first button tells Joe to give 10 bucks to Bob, and the second tells Bob to give 5
bucks back to Joe. Before you double-click on the button, go to the Properties
window and change each button’s name using the “(Name)” row—it’s at the top of
the list of properties. Name the first button joeGivesToBob, and the second one
bobGivesToJoe.

This button tells Joe to
give 10 bucks to Bob, so
you should use the “(Name)”
row in the Properties
window to name it
joeGivesToBob.

3

This button tells Bob to
give 5 bucks to Joe. Name
it bobGivesToJoe.

Make the buttons work
Double-click on the joeGivesToBob button in the designer. The IDE will add a
method to the form called joeGivesToBob_Click() that gets run any time the
button’s clicked. Fill in that method to make Joe give 10 bucks to Bob. Then doubleclick on the other button and fill in the new bobGivesToJoe_Click() method
that the IDE creates so that Bob gives 5 bucks to Joe. Make sure the form updates itself
after the cash changes hands.

you are here 4   119

exercise solution

Add buttons to the “Fun with Joe and Bob” program to make the guys give each other cash.

public partial class Form1 : Form {
Guy joe;
Guy bob;
int bank = 100;
public Form1() {
InitializeComponent();

Here are the object initializers for
the two instances of the Guy class.
Bob gets initialized with 100 bucks
and his name.

bob = new Guy() { Cash = 100, Name = “Bob” };
joe = new Guy() { Cash = 50, Name = “Joe” };

}

UpdateForm();

public void UpdateForm()
joesCashLabel.Text =
bobsCashLabel.Text =
bankCashLabel.Text =
}

{
joe.Name + “ has $” + joe.Cash;
bob.Name + “ has $” + bob.Cash;
“The bank has $” + bank;

private void button1_Click(object sender, EventArgs e) {
if (bank >= 10) {
bank -= joe.ReceiveCash(10);
UpdateForm();
} else {
MessageBox.Show(“The bank is out of money.”);
}
}

The trick here is
thinking through
who’s giving the
cash and who’s
receiving it.

private void button2_Click(object sender, EventArgs e) {
bank += bob.GiveCash(5);
UpdateForm();
}

To make Joe give cash
to Bob, we call Joe’s
GiveCash() method and
send its results into
Bob’s ReceiveCash()
method.
Take a close look at
how the Guy methods
are being called. The
results returned
by GiveCash() are
pumped right into
ReceiveCash() as its
parameter.

private void joeGivesToBob_Click(object sender, EventArgs e) {
bob.ReceiveCash(joe.GiveCash(10));
UpdateForm();
}
private void bobGivesToJoe_Click(object sender, EventArgs e) {
joe.ReceiveCash(bob.GiveCash(5));
UpdateForm();
}

}

120   Chapter 3

Before you go on, take a minute and flip to #1 in the “Leftovers” appendix,
because there’s some basic syntax that we haven’t covered yet. You won’t
need it to move forward, but it’s a good idea to see what’s there.

objects: get oriented!

Objectcross
It’s time to give your left brain a break, and put that
right brain to work: all the words are object‑related
and from this chapter.
1

2

3

4

5

6
7

8

9
10

11
12
13

14

Across

Across

15

Down
Down

2. If a method's return type is _____, it doesn't return
1. This form control lets the user choose a number
2. If a method’s returnanything.
type is _____, it doesn’t return anything
1. This
control
from form
a range
you set.lets the user choose a number from a range
7. An object's fields define its _______
It's a great idea to create a class ________ on paper
you3. set
7. An object’s fields define
its _______
9. A good
method __________ makes it clear what the before you start writing code
method does.
4. What
an object
to keepatrack
what it knows
3. It’s
a great
idea uses
to create
classof ________
on paper before
10. Where objects
5. These define what an object does
9. A good method __________
makesliveit clear what the method
you
start
writing
code
11. What you use to build an object
6. An object's methods define its ________
does
13. What you use to pass information into a method
7. Don't use this keyword in your class declaration if
14. The statement you use to create an object
you object
want touses
be able
to create
instances
it
4. An
this
to keep
track ofof what
it knows
10. Where objects live15. A special kind of field that's used by the form
8. An object is an ______________ of a class
controls
12. This define
statement
tells
method does
to immediately exit,
5. These
what
ana object
11. What you use to build an object
and specifies the value that should be passed back to
the object’s
statementmethods
that calleddefine
the method.
6. An
its ________

13. What you use to pass information into a method
14. The statement you use to create an object

15. Used to set an attribute on controls and other classes

7. Don’t use this keyword in your class declaration if you want to
be able to create instances of it
8. An object is an ______________ of a class
12. This statement tells a method to immediately exit, and can
specify the value that should be passed back to the statement
that called the method
you are here 4   121

puzzle solutions

Pool Puzzle Solution
Your job was to take code snippets from
the pool and place them into the
blank lines in the code. Your goal
was to make classes that will
compile and run and produce the
output listed.

public partial class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
String result = “”;
That’s the correct answer.
Echo e1 = new Echo();

_________________________
Echo e2 = new Echo( );
int x = 0;

while ( ___________
) {
x<4

result = result + e1.Hello() + “\n”;
__________________________
e1.count = e1.count + 1;
if ( ____________
) {
x == 3
}

e2.count = e2.count + 1;

if ( ____________
) {
x>0
}

e2.count = e2.count + e1.count;

x = x + 1;

}

}
MessageBox.Show(result + “Count: ” + e2.count);

class ____________
{
Echo
count
public int _________
= 0;

Hello()
public string ___________
{

}

}

}

return “helloooo...”;

122   Chapter 3

And here’s the bonus answer!

Echo e2 = e1;

objects: get oriented!

Objectcross Solution
1

N
U
2

M

V

O

I

E
8

I
C

L

A

N

S

S

T
13

P

D

A

A

N

E

7

E

T

G

L

10

R

D

O

T

V

D

I

I

S

C

O

A

M

M

H

12

R

E

T

E

R

S

T

A

T
E

A

T

B

E

E
H

P

A

T

C
14

6

M

I

A
R

5

F

N

O
W

9

I
N

U
P

4

D
I

R
11

3

R

U
W

15

P

N

R

O

P

E

R

T

Y

N

Across

Down

2. If a method's return type is _____, it doesn't return
anything. [void]
7. An object's fields define its _______ [state]
9. A good method __________ makes it clear what the
method does. [name]
10. Where objects live [heap]
11. What you use to build an object [class]
13. What you use to pass information into a method
[parameters]
14. The statement you use to create an object [new]
15. A special kind of field that's used by the form
controls [property]

1. This form control lets the user choose a number
from a range you set. [numericupdown]
3. It's a great idea to create a class ________ on paper
before you start writing code [diagram]
4. What an object uses to keep track of what it knows
[field]
5. These define what an object does [methods]
6. An object's methods define its ________ [behavior]
7. Don't use this keyword in your class declaration if
you want to be able to create instances of it [static]
8. An object is an ______________ of a class
[instance]
12. This statement tells a method to immediately exit,
and specifies the value that should be passed back to
the statement that called the method. [return]

you are here 4   123

4 types and references

It’s 10:00.
Do you know where your data is?
This data just got garbage collected.

Data type, database, Lieutenant Commander Data…
it’s all important stuff. Without data, your programs are useless. You
need information from your users, and you use that to look up or produce new
information to give back to them. In fact, almost everything you do in programming
involves working with data in one way or another. In this chapter, you’ll learn the
ins and outs of C#’s data types, see how to work with data in your program, and
even figure out a few dirty secrets about objects (pssst…objects are data, too).

this is a new chapter   125

not my type

The variable’s t ype de termine s what
kind of data it can store
There are a bunch of types built into C#, and each one stores a
different kind of data. You’ve already seen some of the most common
ones, and you know how to use them. But there are a few that you
haven’t seen, and they can really come in handy, too.
Types you’ll use all the time
It shouldn’t come as a surprise that int, string, bool, and double are the most
common types.

A whole number doesn’t
have a decimal point.

≥≥ int can store any whole number from –2,147,483,648 to 2,147,483,647.
≥≥ string can hold text of any length (including the empty string “”).
≥≥ bool is a Boolean value—it’s either true or false.
≥≥ double can store real numbers from ±5.0 × 10−324 to ±1.7 × 10308 with up to
16 significant figures. That range looks weird and complicated, but it’s actually
pretty simple. The “significant figures” part means the precision of the number:
35,048,410,000,000, 1,743,059, 14.43857, and 0.00004374155 all have seven
significant figures. The 10308 thing means that you can store any number as large
as 10308 (or 1 followed by 308 zeroes)—as long as it only has 16 or fewer significant
figures. On the other end of the range, 10-324 means that you can store any number
as small as 10-324 (or a decimal point followed by 324 zeroes followed by 1)… but,
you guessed it, as long as it only has 16 or fewer significant figures.

More types for whole numbers
Once upon a time, computer memory was really expensive, and processors were really
slow. And, believe it or not, if you used the wrong type, it could seriously slow down your
program. Luckily, times have changed, and most of the time if you need to store a whole
number you can just use an int. But sometimes you really need something bigger… and
once in a while, you need something smaller, too. That’s why C# gives you more options:
≥≥ byte can store any whole number between 0 and 255.
≥≥ sbyte can store any whole number from –128 to 127

The “u”
stands for
“unsigned”

≥≥ short can store any whole number from –32,768 to 32,767.
≥≥ ushort can store any whole number from 0 to 65,535.
≥≥ uint can store any whole number from 0 to 4,294,967,295.

A lot of times, if
you’re using these
types it’s because
you’re solving a
problem where
it really helps to
have the “wrapping
around” effect that
you’ll read about in
a few minutes.

The “s” in sbyte stands for “signed,”
which means it can be negative (the
“sign” is a minus sign).

≥≥ long can store any whole number between minus and plus 9 billion billion.
≥≥ ulong can store any whole number between 0 and about 18 billion billion.

126   Chapter 4

“float” is short for
“floating point”—as
opposed to a “fixed
point” number, which
always has the same
number of decimal
places.

types and references

HUGE

and really tiny numbers
Types for storing really
Sometimes 7 significant figures just isn’t precise enough. And, believe it or not, sometimes 1038
isn’t big enough and 10-45 isn’t small enough. A lot of programs written for finance or scientific
research run into these problems all the time, so C# gives us two more types:

When your
-45
38
program needs ≥≥ float can store any number from ±1.5. × 10 to ±3.4 × 10 with 7 significant digits.
to deal with ≥≥ decimal can store any number from ±1.0 × 10-28 to ±7.9 × 1028 with 28–29
currency, you
significant digits.
usually want to
use a decimal
A “literal” just means a number that eyou“int
When you used the
the
re
to sto
type into your code. So when you typ
Value property in
number. Literals have types, too
i = 5;”, the 5 is a literal.
your numericUpDown
When you type a number directly into your C# program, you’re using a literal… and
control, you were
every literal is automatically assigned a type. You can see this for yourself—just enter this using a decimal.
line of code that assigns the literal 14.7 to an int variable:
int myInt = 14.7;

Now try to build the program. You’ll get this:
That’s the same error you’ll get if you try to set an int equal to a double variable. What
the IDE is telling you is that the literal 14.7 has a type—it’s a double. You can change its
type to a float by sticking an F on the end (14.7F). And 14.7M is a decimal.
If you

The “M” stands for “money”—seriously!

A few more useful built-in types
Sometimes you need to store a single character like Q or 7 or $, and when you do you’ll
use the char type. Literal values for char are always inside single quotes ('x', '3').
You can include escape sequences in the quotes, too ('\n' is a line break, '\t' is
a tab). You write an escape sequence in your C# code using two characters, but your
program stores each escape sequence as a single character in memory.
And finally, there’s one more important type: object. You’ve already seen how you
can create objects by creating instances of classes. Well, every one of those objects can
be assigned to an object variable. You’ll learn all about how objects and variables
that refer to objects work later in this chapter.

try to assign a
float literal to a double
or a decimal literal to a
float, the IDE will give
you a helpful message
reminding you to add
the right suffix. Cool!
You’ll learn a lot more
about how char and
byte relate to each
other in Chapter 9.

Windows 7 has a really neat feature in Calculator called “Programmer”
mode, where you can see binary and decimal at the same time!

You can use the Windows calculator to convert between decimal (normal, base-10) numbers and
binary numbers (base-2 numbers written with only ones and zeroes)—put it in Scientific mode, enter
a number, and click the Bin radio button to convert to binary. Then click Dec to convert it back. Now
enter some of the upper and lower limits for the whole number types (like –32,768 and 255)
and convert them to binary. Can you figure out why C# gives you those particular limits?

you are here 4   127

i’ll take an ice cream float to go

A variable is like a data to-go cup
All of your data takes up space in memory. (Remember the heap
from last chapter?) So part of your job is to think about how much
space you’re going to need whenever you use a string or a number in
your program. That’s one of the reasons you use variables. They let
you set aside enough space in memory to store your data.
Think of a variable like a cup that you keep your data in. C# uses
a bunch of different kinds of cups to hold different kinds of data.
And just like the different sizes of cups at the coffee shop, there are
different sizes of variables, too.

You’ll use
for whole long
numbers t
are going thoat
really big. be

used for whole
int is commonlylds numbers up to
numbers. It ho 7.
2,147,483,64
numbers
A short will hold whole
up to 32,767.
byte holds numbers
between zero and 255.

long
64

int
32

These are the number of bits of memory set aside

short byte
16
8

for the variable when you declare it.

Numbers that have decimal places are stored differently than
whole numbers. You can handle most of your numbers that have
decimal places using float, the smallest data type that stores
decimals. If you need to be more precise, use a double. And
if you’re writing a financial application where you’ll be storing
currency values, you’ll want to use the decimal type.
It’s not always about numbers, though. (You wouldn’t expect to
get hot coffee in a plastic cup or cold coffee in a paper one.) The
C# compiler also can handle characters and non-numeric types.
The char type holds one character, and string is used for lots
of characters “strung” together. There’s no set size for a string
object, either. It expands to hold as much data as you need to store
in it. The bool data type is used to store true or false values, like
the ones you’ve used for your if statements.

128   Chapter 4

e
Not all data ends up on the heap. Valu
types usually keep their data in anothe’llr
part of memory called the stack. You
learn all about that in Chapter 14.

float double
32
64

decimal
128

for
These types areger
fractions. Lare more
variables stor .
decimal places

bool
8

char
16

string
depends on
the size
of the string

types and references

10 pounds of data in a 5 pound bag
When you declare your variable as one type, that’s how your
compiler looks at it. Even if the value is nowhere near the upper
boundary of the type you’ve declared, the compiler will see the cup
it’s in, not the number inside. So this won’t work:
int leaguesUnderTheSea = 20000;
short smallerLeagues = leaguesUnderTheSea;

20,000 would fit into a short, no problem. But since
leaguesUnderTheSea is declared as an int, the compiler sees
it as int-sized and considers it too big to put in a short container.
The compiler won’t make those translations for you on the fly. You
need to make sure that you’re using the right type for the data
you’re working with.

20,000

All the compiler sees is an
int going into a short (which
doesn’t work). It doesn’t care
about the value in the int cup.

int
short

This makes se
e. What if you
later put a lans
rg
int cup, one tha er value in the
into the short t wouldn’t fit
is trying to protcup? The compiler
ect you.

Three of these statements won’t compile, either because they’re
trying to cram too much data into a small variable or because
they’re putting the wrong type of data in. Circle them.

int hours = 24;

string taunt = “your mother”;

short y = 78000;

byte days = 365;

bool isDone = yes;

long radius = 3;

short RPM = 33;

char initial = ‘S’;

int balance = 345667 - 567;

string months = “12”;

you are here 4   129

casting call

Even when a number is the right size,
you can’t just assign it to any variable
Let’s see what happens when you try to assign
a decimal value to an int variable.
1

Do this

Create a new project and add a button to it. Then add these lines to the
button’s Click() method:
decimal myDecimalValue = 10;
int myIntValue = myDecimalValue;
MessageBox.Show(“The myIntValue is ” + myIntValue);

2

3

Try building your program. Uh oh—you got an error that looks like this:

Make the error go away by casting the decimal to an int. Once you change
the second line so it looks like this, your program will compile and run:
int myIntValue = (int) myDecimalValue;

So what happened?

Here’s where you cast the
decimal value to an int.

The compiler won’t let you assign a value to a variable if it’s the wrong type—even
if that variable can hold the value just fine—because that’s the underlying cause
behind an enormous number of bugs. When you use casting, you’re essentially
making a promise to the compiler that you know the types are different, and that
in this particular instance it’s OK for C# to cram the data into the new variable.

Check out how
the IDE figured
out that you
were probably
missing a cast.

Take a minute to flip back
to the beginning of th
chapter and check outeholaswt
you used casting when you
passed the NumericUpDo
.
Value to the Talker Testewn
r
form.

Three of these statements won’t compile, either because they’re
trying to cram too much data into a small variable or because
they’re putting the wrong type of data in. Circle them.

short y = 78000;
bool isDone = yes;

130   Chapter 4

s
The short type hold76
byte
7
2,
-3
om
fr
s
number
to 32,768. This
number’s too big!
You can only assign a value of
“true” or “false” to a bool.

days = 365;

A byte can only ho
value of up to 256.ldYoa
need a short for this. u’ll

types and references

When you cast a value that’s too
big , C# will adjust it automatically
You’ve already seen that a decimal can be cast to an
int. It turns out that any number can be cast to any other
number. But that doesn’t mean the value stays intact
through the casting. If you cast an int variable that’s set
to 365 to a byte variable, 365 is too big for the byte. But
instead of giving you an error, the value will just wrap
around: for example, 256 cast to a byte will have a value
of 0. 257 would be converted to 1, 258 to 2, etc., up to 365,
which will end up being 109. And once you get back to
255 again, the conversion value “wraps” back to zero.

Hey, I’ve been combining
numbers and strings in my
message boxes since I learned
about loops in Chapter 2! Have I
been converting types all along?

Wrap it yourself!

There’s no mystery
the numbers—you cato how casting “wraps”
pop up the Windows n do it yourself. Just
it to Scientific mod calculator, switch
Mod 256 (using the e, and calculate 365
does a modulo calcul “Mod” button, which
ation). You’ll get 10
9.

You can’t always cast any type to any
other type. Create a new project, drag a
button onto a form, double-click on it, and type
these statements in. Then build your program—it
will give lots of errors. Cross out the ones that
give errors. That’ll help you figure out which
types can be cast , and which can’t!
int myInt = 10;
byte myByte = (byte)myInt;
double myDouble = (double)myByte;

When you’re
assigning a number
value to a double,
you need to add a
D to the end of
the number to tell
the compiler that
it’s a float, and
not a double.

Yes! The + operator converts for
you.
What you’ve been doing is using the +
operator, which does a lot of converting
for you automatically—but it’s especially
smart about it. When you use + to add a
number or Boolean to a string, then it’ll
automatically convert that value to a string,
too. If you use + (or *, /, or -) with two
different types, it automatically converts
the smaller type to the bigger one.
Here’s an example:
int myInt = 36;
double myFloat = 16.4D;
myFloat = myInt + myFloat;

Since an int can fit into a float but a
float can’t fit into an int, the + operator
converts myInt to a float before adding it
to myFloat.

bool myBool = (bool)myDouble;
string myString = “false”;
myBool = (bool)myString;
myString = (string)myInt;
myString = myInt.ToString();
myBool = (bool)myByte;
myByte = (byte)myBool;
short myShort = (short)myInt;
char myChar = ‘x’;
myString = (string)myChar;
long myLong = (long)myInt;
decimal myDecimal = (decimal)myLong;
myString = myString + myInt + myByte
+ myDouble + myChar;
you are here 4   131

a true convert

C# does some casting automatically
There are two important conversions that don’t require
you to do the casting. The first is done automatically any
time you use arithmetic operators, like in this example:
long l = 139401930;
short s = 516;
double d = l - s;

The - operator
subtracted the short
from the long, and the
= operator converted
the result to a double.

d = d / 123.456;
MessageBox.Show(“The answer is ” + d);

When you use + it’s smart enough
to convert the decimal to a string.
The other way C# converts types for you automatically is when
you use the + operator to concatenate strings (which just
means sticking one string on the end of another, like you’ve been
doing with message boxes). When you use + to concatenate
a string with something that’s another type, it automatically
converts the numbers to strings for you. Here’s an example. The
first two lines are fine, but the third one won’t compile.
long x = 139401930;
MessageBox.Show(“The answer is ” + x);
MessageBox.Show(x);
The C# compiler spits out an error that mentions something
about invalid arguments (an argument is what C# calls the
value that you’re passing into a method’s parameter). That’s
because the parameter for MessageBox.Show() is a
string, and this code passed a long, which is the wrong
type for the method. But you can convert it to a string really
easily by calling its ToString() method. That method is a
member of every value type and object. (All of the classes you
build yourself have a ToString() method that returns the
class name.) That’s how you can convert x to something that
MessageBox.Show() can use:
MessageBox.Show(x.ToString());
132   Chapter 4

You can’t always cast any type to any other
type. Create a new project, drag a button onto a
form, and type these statements into its method.
Then build your program—it will give lots of
errors. Cross out the ones that give errors. That’ll
help you figure out which types can be cast , and
which can’t!
int myInt = 10;
byte myByte = (byte)myInt;
double myDouble = (double)myByte;
bool myBool = (bool)myDouble;
string myString = “false”;
myBool = (bool)myString;
myString = (string)myInt;
myString = myInt.ToString();
myBool = (bool)myByte;
myByte = (byte)myBool;
short myShort = (short)myInt;
char myChar = ‘x’;
myString = (string)myChar;
long myLong = (long)myInt;
decimal myDecimal = (decimal)myLong;
myString = myString + myInt + myByte
+ myDouble + myChar;

types and references

When you call a me thod, the arguments must
be compatible with the t ype s of the parame ters
Try calling MessageBox.Show(123)—passing MessageBox.Show()
a literal (123) instead of a string. The IDE won’t let you build your program.
Instead, it’ll show you an error in the IDE: “Argument ‘1’: cannot convert from
‘int’ to ‘string’.” Sometimes C# can do the conversion automatically—like if
your method expects an int, but you pass it a short—but it can’t do that for
ints and strings.
But MessageBox.Show() isn’t the only method that will give you compiler
errors if you try to pass it a variable whose type doesn’t match the parameter.
All methods will do that, even the ones you write yourself. Go ahead and try
typing this completely valid method into a class:
public int MyMethod(bool yesNo) {
if (yesNo) {
return 45;
} else {
return 61;
}
}

calls
e code thatto pass
h
t
—
r
e
d
in
m
e
ave
One r
as
er doesn’t h
this paramelet called yesNo. It justiahble.
it a variab a Boolean value or var
to pass it lace it’s called yesNo is
The only p method’s code.
inside the

It works just fine if you pass it what it expects (a bool)—call MyMethod(true) or
MyMethod(false), and it compiles just fine.
But what happens if you pass it an integer or a string instead? The IDE gives you a
similar error to the one that you got when you passed 123 to MessageBox.Show().
Now try passing it a Boolean, but assigning the return value to a string or passing it on
to MessageBox.Show(). That won’t work, either—the method returns an int, not
a long or the string that MessageBox.Show() expects.

A parameter is what you
define in your method. An
argument is what you pass
to it. A method with an int
parameter can take a byte
argument.

When the
compiler gives
you an “invalid
arguments” error,
it means that
you tried to call
a method with
variables whose
types didn’t match
the method’s
parameters.
You can assign
anything to a variable,
parameter, or field
with the type object.

true
’s
ng
hi
et
m
so
if
e
se
to
st
te
ys
wa
al
if statements

statement like this:
Did you notice how we wrote our if
if (yesNo) {
s because an if statement always
at’
Th
.
e)”
tru
==
sNo
(ye
“if
say
or
We didn’t have to explicitly
’s false using ! (an exclamation point, e
ing
eth
som
if
ck
che
You
e.
tru
’s
ing
In our cod
checks if someth
same thing as “if (yesNo == false)”.)”, and not
the
is
)”
sNo
(!ye
“if
.
or)
rat
ope
T
sNo
the NO
just see us do “if (yesNo)” or “if (!ye
examples from now on, you’ll usually is true or false.
explicitly check to see if a Boolean
you are here 4   133

this table is reserved

Actually, C# does give you a way to use reserved keywords as
variable names, by putting @ in front of the keyword. You can
do that with non-reserved names too, if you want to.
There are about 77 reserved words in C#. These are words reserved by the C# compiler; you
can’t use them for variable names. You’ll know a lot of them really well by the time you finish the
book. Here are some you’ve already used. Write down what you think these words do in C#.

namespace
for
class
public
else
new
using
if
while

Answers on page 164.
134   Chapter 4

types and references

Create a reimbursement calculator for a business trip. It should allow the user to enter a starting
and ending mileage reading from the car’s odometer. From those two numbers, it will calculate
how many miles she’s traveled and figure out how much she should be reimbursed if her
company pays her $.39 for every mile she puts on her car.
1

Start with a new Windows project.
Make the form look like this:

This label is 12
pt bold.

Get rid of
the minimize
and maximize
buttons.
For the two Numeric Do
wn
controls, set the MiniUp
mu
m
to 1 and Maximum to 99 property
9999.

When you’re done with the form, double-click on the
button to add some code to the project.
2

Create the variables you’ll need for the calculator.
Put the variables in the class definition at the top of Form1. You need two whole
number variables to track the starting odometer reading and the ending odometer reading.
Call them startingMileage and endingMileage. You need three numbers
that can hold decimal places. Make them doubles and call them milesTraveled,
reimburseRate, and amountOwed. Set the value for reimburseRate to .39.

3

Make your calculator work.
Add code in the button1_Click() method to:
≥≥ Make sure that the number in the Starting Mileage field is smaller than the number
in the Ending Mileage field. If not, show a message box that says “The starting
mileage must be less than the ending mileage”. Make the title for the message box
“Cannot Calculate”.
≥≥ Subtract the starting number from the ending number and then multiply it by the
reimburse rate using these lines:
milesTraveled = endingMileage -= startingMileage;
amountOwed = milesTraveled *= reimburseRate;
label4.Text = “$” + amountOwed;

4

Run it.
Make sure it’s giving the right numbers. Try changing the starting value to be higher than
the ending value and make sure it’s giving you the message box.

you are here 4   135

something’s wrong…

v

You were asked to create a reimbursement calculator for a business trip. Here’s the code for the
first part of the exercise.

public partial class Form1 : Form
{
int startingMileage;
int endingMileage;
double milesTraveled;
double reimburseRate = .39;

int works great for
whole

numbers. This number could
go all the way up to 999,999
.
So a short or a byte
won’t cut it.

double amountOwed;
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs
startingMileage = (int) numericUpDown1.Value;

Did you remember
that you have
to change the from
ecimal value
e){ d
the numericUpDowtn?
control to an in

endingMileage = (int)numericUpDown2.Value;
if (startingMileage <= endingMileage){
milesTraveled = endingMileage -= startingMileage;
amountOwed = milesTraveled *= reimburseRate;
label4.Text = “$” + amountOwed;
} else {

This block is
supposed to figure
out how many
miles were traveled
and then multiply
them by the
reimbursement rate.

MessageBox.Show(
“The starting mileage must be less than the ending mileage”,
“Cannot Calculate Mileage”);
}

}

}

This button seems to work, but it has a
pretty big problem. Can you spot it?

136   Chapter 4

We used an alternate way
of calling the MessageBox.
Show() method here. We gave
it two parameters: the first
one is the message to display,
and the second one goes in
the title bar.

types and references

1

Now add another button to the form.
Let’s track down that problem by adding a button to your form that shows the value
of the milesTraveled field. (You could also use the debugger for this!)

Clicking this button after
you’ve clicked Calculate should
show the number of miles
traveled in a message box.

When you’re done with the form, double-click on the
Display Miles button to add some code to the project.
2

One line should do it.
All we need to do is get the form to display the milesTraveled variable, right? So this line
should do that:
private void button2_Click(object sender, EventArgs e) {
Messagebox.Show(milesTraveled + “ miles”, “Miles Traveled”);
}

3

Run it.
Type in some values and see what happens. First enter a starting mileage and
ending mileage, and click the Calculate button. Then click the Display Miles
button to see what’s stored in the milesTraveled field.

4

Um, something’s not right…
No matter what numbers you use, the number of miles always matches the amount owed. Why?

you are here 4   137

operators are standing by

Combining = with an operator
Take a good look at the operator we used to subtract ending mileage from
starting mileage (-=). The problem is it doesn’t just subtract, it also assigns
a value to the variable on the left side of the subtraction sign. The same
thing happens in the line where we multiply number of miles traveled by the
reimbursement rate. We should replace the -= and the *= with just - and *:
private void button1_Click(object sender, EventArgs e)
{
startingMileage = (int) numericUpDown1.Value;
endingMileage = (int)numericUpDown2.Value;
if (startingMileage <= endingMileage){
milesTraveled = endingMileage -= startingMileage;
amountOwed = milesTraveled *= reimburseRate;
label4.Text = “$” + amountOwed;

These are
called compound
operators. This
one subtracts
startingMileage
from endingMileage
but also assigns
the new value to
endingMileage and
milesTraveled at
the same time.

} else {
MessageBox.Show(“The starting mileage number must
be less than the ending mileage number”,
“Cannot Calculate Mileage”);
}

This is better—now
your code won’t modify
endingMileage and
milesTraveled.

milesTraveled = endingMileage - startingMileage;

amountOwed = milesTraveled * reimburseRate;

So can good variable names help you out here? Definitely! Take a
close look at what each variable is supposed to do. You already get a lot of
clues from the name milesTraveled—you know that’s the variable that
the form is displaying incorrectly, and you’ve got a good idea of how that
value ought to be calculated. So you can take advantage of that when you’re
looking through your code to try to track down the bug. It’d be a whole lot
harder to find the problem if the incorrect lines looked like this instead:

		
		
138   Chapter 4

mT = eM -= sM;
aO = mT *= rR;

Variables nam
like this are
essentially useled
es
s
what their purp in telling you
ose might be.

types and references

Objects use variable s, too
So far, we’ve looked at objects separate from other types. But
an object is just another data type. Your code treats objects
exactly like it treats numbers, strings, and Booleans. It uses
variables to work with them:

Using an int
1

Using an object

Write a statement to declare the integer.

1

int myInt;

2

Dog spot;

Assign a value to the new variable.

2

myInt = 3761;

3

Write a statement to declare the object.

When you have a class
like Dog, you use it as
the type in a variable
declaration statement.

Assign a value to the object.

spot = new Dog();

3

Use the integer in your code.

while (i < myInt) {

Check one of the object’s fields.

while (spot.IsHappy) {

So it doesn’t matter if I’m
working with an object or a numeric
value. If it’s going into memory, and my
program needs to use it, I use a variable.

Objects are just one more type of
variable your program can use.
If your program needs to work with a whole
number that’s really big, use a long. If it needs
a whole number that’s small, use a short. If it
needs a yes/no value, use a boolean. And if it
needs something that barks and sits, use a Dog. No
matter what type of data your program needs to
work with, it’ll use a variable.

you are here 4   139

get the reference

Refer to your objects with reference variable s
When you create a new object, you use code like new Guy(). But that’s not enough;
even though that code creates a new Guy object on the heap, it doesn’t give you
a way to access that object. You need a reference to the object. So you create
a reference variable: a variable of type Guy with a name, like joe. So joe
is a reference to the new Guy object you created. Any time you want to use that
particular guy, you can reference it with the reference variable called joe.

That’s called
instantiating
the object.

So when you have a variable that is an object type, it’s a reference variable: a
reference to a particular object. Take a look:

ur
Here’s the heap beforeeryoe.
th
ing
th
code runs. No
This variable public partial class Form1 : Form
{
is named
ll
Guy joe;
joe, and wi
reference
public Form1()
an object of
type Guy.
{
InitializeComponent();

}

joe = new Guy();

Creating a reference is like making a label
with a label maker—instead of sticking it
on your stuff, you’re using it to label an
object so you can refer to it later.

Here’s the heap after an
this code runs. There’sble
object, with the varia
Joe referring to it.

140   Chapter 4

Joe

Gu

#1

…and this is the
This is the
reference variable… object that joe
now refers to.

y o b j ec t

The ONLY way to
reference this Guy ob
is through the referencject
e
variable called joe.

types and references

References are like labels for your object
In your kitchen, you probably have a container of salt and sugar. If you
switched their labels, it would make for a pretty disgusting meal—even
though the labels changed, the contents of the containers stayed the same.
References are like labels. You can move labels around and point them at
different things, but it’s the object that dictates what methods and data are
available, not the reference itself.

Form1’s button1_Cl
has a variable calledick“Jmethod
references this object oe” that
.

This object is of type Guy.
It’s a SINGLE object with
MULTIPLE references.

joe

er
programm

mer
o
t
s
cu
r
brothe
ou
heyy

dad
An instance of the Guy
class is keeping a reference
to this object in a variable
called “Dad”.

ejoe
l
c
n
u
Every one of these labels
is a different reference
variable, but they all
point to the SAME Guy
object.

You never refer to your object directly. For example, you can’t write code like
Guy.GiveCash() if Guy is your object type. The C# compiler doesn’t
know which Guy you’re talking about, since you might have several instances
of Guy on the heap. So you need a reference variable, like joe, that you
assign to a specific instance, like Guy joe = new Guy().

Now you can call methods, like joe.GiveCash(). joe refers to a specific
instance of the Guy class, and your C# compiler knows exactly which
instance to use. And, as you saw above, you might have multiple labels
pointing to the same instance. So you could say Guy dad = joe, and
then call dad.GiveCash(). That’s OK, too—that’s what Joe’s kid does
every day.

When your code
needs to work
with an object
in memory, it
uses a reference,
which is a
variable whose
type is a class
of the object it’s
going to point to.
A reference is
like a label that
your code uses
to talk about a
specific object.

There are lots of different
references to this same Guy,
because
a lot of different method
s
use
him for different things.
ch
reference has a different Ea
nam
that makes sense in its conte e
xt.

you are here 4   141

that’s sanitation engineer thank you very much

For an object
to stay in the
heap, it has to
be referenced.
Some time
after the last
reference to
the object
disappears, so
does the object.

If there aren’t any more reference s,
your object ge ts garbage-collected
If all of the labels come off of an object, programs can no longer
access that object. That means C# can mark the object for garbage
collection. That’s when C# gets rid of any unreferenced objects, and
reclaims the memory those objects took up for your program’s use.

Here’s some code that creates an object.
Guy joe = new Guy()
{ Name = “Joe”, Cash = 50 };

JOE

2

Gu

Now let’s create a second object.
Guy bob = new Guy()
{ Name = “Bob”, Cash = 75 };

Now we have tw
instances, and two Guy object
variables: one for o reference
each Guy.
3

y o b j ec t

JOE

bob

Gu

“Bob”
75

#2

When you use the “new” statement,
you’re telling C# to create an object.
When you take a reference variable
like “Joe” and assign it to that
object, it’s like you’re slapping a new
label on it.

“Joe”
50

y o b j ec t

Gu

“Joe”
50

y o b j ec t

But there is no loenger
a reference to th
first Guy object…

Let’s take the reference to the first object, and
change it to point at the second object.
joe = bob;

Now joe is pointing to the same
object as bob.
Gu
142   Chapter 4

“Bob”
75

#2

JOEob
b

y o b j ec t

#1

1

poof!

…so C# marks the
object for garbage
collection, and
eventually trashes it.
It’s gone!

types and references
1

2

3

4

Typecross

5

6

Take a break, sit back, and give
your right brain something
to do. It’s your standard
crossword; all of the solution
words are from this chapter.
When you’re done, turn the
page and take on the rest
of the chapter.

7
8
9
10

11

12

13
14
15

16

Across

17

Down

Across
1. The second part of a variable
2. You can combine theDown
declaration
variable declaration and the _________
1. The second part of a variable declaration
into one statement 2. You can combine the variable declaration and t
4. “namespace”, “for”, “while”,
“using”, and “new”
are examples
4. "namespace",
"for", "while",
"using" and "new" are
____________ into one statement.
of _____________ wordsexamples of _____________ words. 3. A variable that points3.toAanvariable
object that points to an object
6.
What
(int)
does
in
this
line
of
code:
x
=
(int)
y;
5.
What
your
program
usesin to
work with data tha
6. What (int) does in this line of code: x = (int) y;
5. What your program uses to work
with
data that’s
memory
8. When an object no longer has any references
memory
8. When an object no longer
has anytoreferences
pointingfrom
to it,the heap
7. If using
you want to store a7.currency
value,touse
thisatype
pointing
it, it's removed
If you want
store
currency value, use this t
collection.
9. += and -= are this kind of operator
it’s removed from the heap____________
using ____________
collection
9. ++=operator
and -= are
10. What you're doing when you use the
tothis kind
11.ofAoperator
variable declaration always starts with thi
10. What you’re doing when
you
use
the
+
operator
to
stick
two
stick t wo strings together.
12.
Every
object
has
11. A variable declaration always starts
with
thisthis method that converts it
strings together
14. The type that holds the biggest numbers.
string.
object has this
converts
to a stringof this type, you ca
15. The type that stores a single letter12.orEvery
number
13.method
Whenthat
you've
got aitvariable
14. The numeric type that holds the biggest numbers
16. \n and \r are _______ sequences
assign any value to it
When
. Theletter
fourorwhole
number types that13.
only
holdyou’ve got a variable of this type, you can assign any
15. The type that stores a 17
single
number
value
to it
positive numbers
16. \n and \r are _______ sequences
17. The four whole number types that only hold positive
numbers

Answers on page 165.
you are here 4   143

so many labels

Multiple reference s and their side ef fects

Dog rover = new Dog();
rover.Breed = “Greyhound”;

r
Rove

Do

1
Objects:______
1
References:_____

#1

Dog fido = new Dog();
fido.Breed = “Beagle”;
Dog spot = rover;

Fido

2

Fido is another Dog object. Dog object
But Spot is just another
reference to the first object.

3

References:_____

Dog lucky = new Dog();
lucky.Breed = “Dachshund”;
fido = rover;

2

Objects:______

4

References:_____

144   Chapter 4

Lucky is a third object.
But Fido is now pointing
to Object #1. So, Object
#2 has no references.
It’s done as far as the
program is concerned.

r
Rove
SPOT
o
Do Fid ct
g obje

#1

Objects:______

3

r
Rove
SPOT
Do
g o b j ec t

#2

2

g o b j ec t

poof!

y
Luck

Do

#3

1

#1

You’ve got to be careful when you start moving around reference
variables. Lots of times, it might seem like you’re simply pointing
a variable to a different object. But you could end up removing all
references to another object in the process. That’s not a bad thing, but
it may not be what you intended. Take a look:

g o b j ec t

types and references
Now it’s your turn. Here’s one long block of code. Figure out how many
objects and references there are at each stage. On the right‑hand side,
draw a picture of the objects and labels in the heap.

1

Dog rover = new Dog();
rover.Breed = “Greyhound”;
Dog rinTinTin = new Dog();
Dog fido = new Dog();
Dog quentin = fido;
Objects:______
References:_____

2

Dog spot = new Dog();
spot.Breed = “Dachshund”;
spot = rover;
Objects:______
References:_____

3

Dog lucky = new Dog();
lucky.Breed = “Beagle”;
Dog charlie = fido;
fido = rover;
Objects:______
References:_____

4

rinTinTin = lucky;
Dog laverne = new Dog();
laverne.Breed = “pug”;
Objects:______
References:_____

5

charlie = laverne;
lucky = rinTinTin;
Objects:______
References:_____
you are here 4   145

swapping elephants
Now it’s your turn. Here’s one long block of code. Figure out how many
objects and references there are at each stage. On the right‑hand side,
draw a picture of the objects and labels in the heap.

146   Chapter 4

Here the references move
around but no new objects
are created. And setting
Lucky to Rin Tin Tin did
nothing because they already
pointed to the same object.

fido
spot
r
rove

Do

rint

Do

#3

#1

#3

ct

#1

ct
#5

g obje

ct

Do

g obje

ct

Do

#3

tin
quen
lie
char

RNE
LAVE lie
char

Do

#3

ct

#4

ct

RNE
LAVE

#1

g obje

g obje
Y
LUCK tin
in

ct

#2

ct

g obje

n
inti
rint CKY
LU

Do

ct

#1

ct

#2

#2

ct

Do

g obje

g obje

g obje

tin
quen

Do

#3

charlie = laverne;
lucky = rinTinTin;

When Rin Tin Tin
moved to Lucky’s
object, the old Rin Tin
Tin object disappeared.

g obje

fido
spot
r
rove

poof!

Do

#5

8
References:_____

Do

l
char

ct

4

4
Objects:______
8
References:_____

Y
LUCK

ct

rinTinTin = lucky;
Dog laverne = new Dog();
laverne.Breed = “pug”;
Objects:______

5

g obje

g obje

g obje quentin
ie

#4

Dog #2 lost its
last reference, and
it went away.

Do

#4

7

References:_____
4

Do

Do

fido
spot
r
rove

n
inti
rint

g obje

fido

g obje

that, Fido moved to object
#1, leaving Charlie behind.

Objects:______

Do

g obje quentin

ct

4

Do

#1

3

Dog lucky = new Dog();
lucky.Breed = “Beagle”;Charlie was set to Fido
when Fido was still on
Dog charlie = fido;
object #3. Then, after
fido = rover;

Do

n
inti
rint

Here a new Dog object is
created, but when Fido is
set to Rover, Fido’s object
from #1 goes away.

tin
quen
fido

g obje

spot
r
rove

Dog spot = new Dog();
spot.Breed = “Dachshund”;
spot = rover;

3
Objects:______
5
References:_____

g obje

ct

4

References:_____
2

Do

One new Dog object is
created but Spot is the
only reference to it. When
Spot is set = to Rover,
that object goes away.

Objects:______

Do

n
inti
rint

ct

3

r
rove

g obje

ct

Dog rover = new Dog();
rover.Breed = “Greyhound”;
Dog rinTinTin = new Dog();
Dog fido = new Dog();
Dog quentin = fido;

ct

1

types and references

Create a program with an elephant class. Make two elephant instances and then swap
the reference values that point to them, without getting any Elephant instances garbagecollected.
1

Start with a new Windows Application project.
Make the form look like this:

ucinda”
Clicking on the “L
a.WhoAmI(),
nd
button calls luci is message box.
which displays th

Here’s the clas
for the Elephans diagram
you need to creat class
te.

Elephant
Name
EarSize
WhoAmI()

The WhoAmI() method should pop
up this message box. Make sure the
message includes the ear size and the
title bar includes the name.

2

Create the Elephant class.
Add an Elephant class to the project. Have a look at the Elephant class diagram—you’ll need an int
field called EarSize and a String field called Name. (Make sure both are public.) Then add a method
called WhoAmI() that displays a message box that tells you the name and ear size of the elephant.

3

Create two Elephant instances and a reference.
Add two Elephant fields to the Form1 class (in the area right below the class declaration) named
Lloyd and Lucinda. Initialize them so they have the right name and ear size. Here are the
Elephant object initializers to add to your form:
lucinda = new Elephant() { Name = “Lucinda”, EarSize = 33 };
lloyd = new Elephant() { Name = “Lloyd”, EarSize = 40 };

4

Make the “Lloyd” and “Lucinda” buttons work.
Have the Lloyd button call lloyd.WhoAmI() and the Lucinda button call lucinda.WhoAmI().

5

Hook up the swap button.
Here’s the hard part. Make the Swap button exchange the two references, so that when you click
Swap, the Lloyd and Lucinda variables swap objects and a “Objects swapped” box is displayed.
Test out your program by clicking the Swap button and then clicking the other two buttons. The first
time you click Swap, the Lloyd button should pop up Lucinda’s message box, and the Lucinda button
should pop up Lloyd’s message box. If you click the Swap button again, everything should go back.
C# garbage-collects any object with no references to it. So here’s your
hint: If you want to pour a glass of beer into another glass that’s currently
full of water, you’ll need a third glass to pour the water into....
you are here 4   147

hold that reference

Create a program with an elephant class. Make two elephant instances and then swap
the reference values that point to them, without getting any Elephant instances garbagecollected.
using System.Windows.Forms;
class Elephant {
public int EarSize;
public string Name;

}

public void WhoAmI() {
MessageBox.Show(“My ears are ” + EarSize + “ inches tall.”,
Name + “ says…”);
}

t
This is the Elephande
co
class definition
in the Elephant.csthe
file we added to rget
project. Don’t fo .
the “using Systemline
Windows.Forms;” e
at the top of th, the
class. Without it ement
MessageBox stat
won’t work.

public partial class Form1 : Form {
Elephant lucinda;
Elephant lloyd;
public Form1()
{
InitializeComponent();
lucinda = new Elephant()
{ Name = “Lucinda”, EarSize = 33 };
lloyd = new Elephant()
{ Name = “Lloyd”, EarSize = 40 };
}

Here’s the Form1 class code
from Form1.cs.

If you just point Lloyd
to Lucinda, there won’t
be any more references
pointing to Lloyd and
his object will be lost.
That’s why you need
to have the Holder
reference hold onto
the Lloyd object until
Lucinda can get there.

strings and arrays are
different from all of the
other data types you’ve
seen, because they’re the
only ones without a set size
(think about that for a bit).
148   Chapter 4

private void button1_Click(object sender, EventArgs e) {
lloyd.WhoAmI();
}
private void button2_Click(object sender, EventArgs e) {
lucinda.WhoAmI();
}

}

private void button3_Click(object sender, EventArgs e) {
Elephant holder;
There’s no new statement for the
holder = lloyd;
lloyd = lucinda;
reference because we don’t want tot.
lucinda = holder;
create another instance of Elephan
MessageBox.Show(“Objects swapped”);
}

Why do you think we didn’t add a Swap() method to the Elephant class?

types and references

Besides losing all the references to an object, when
you have multiple references to an object, you can
unintentionally change an object. In other words, one
reference to an object may change that object, while
another reference to that object has no idea that
something has changed. Watch:

Do this

1

Add another button to your form.

2

Add this code for the button. Can you guess what’s going to happen when you click it?

This statement
says to set
EarSize to 4321
on whatever
object the lloyd
reference happens
to point to.

After this code runs,
both the lloyd and lucinda
variables reference the
SAME Elephant object.

W
ct.
the lloyd obje

But lloyd points at the same
thing that lucinda does.

OK, go ahead and click the new button. Wait a second, that’s the Lucinda message
box. Didn’t we call the WhoAmI() method from Lloyd?

It’s lucinda’s
message box…

d
Lloy a
nd
Luci
bj
Elephant O

ec
t

3

private void button4_Click(object sender, EventArgs e)
{
lloyd = lucinda;
lloyd.EarSize = 4321;
e
lloyd.WhoAmI();
ou’re calling thhod from
Y
}
hoAmI() met

d
Lloy a
nd
Luci
bj e
Elephant O

ct

Two reference s me ans TWO
ways to change an object’s data

But we set this
EarSize using the
lloyd reference! What
gives?

erchangeable. Changes to
lloyd and lucinda are now intBO
TH are pointing at…
one affect the object thatference between lloyd and
there’s no longer a real dif the SAME object.
lucinda, since they point to

Note that the
data is NOT being
overwritten—the
only things changing
are the references.
you are here 4   149

pick an object out of a line-up

A special case: arrays
If you have to keep track of a lot of data of the same type, like a list of heights
or a group of dogs, you can do it in an array. What makes an array special is
that it’s a group of variables that’s treated as one object. An array gives you
a way of storing and changing more than one piece of data without having to
keep track of each variable individually. When you create an array, you declare
it just like any other variable, with a name and a type:

You declare an array by
specifying its type, followed
by square brackets.
You use the new keyword
to create an array because
it’s an object. So an
array variable is a kind of
reference variable.

You could combine e
declaration
of the myArray vath
ria
bl
initialization—just like e with its
variable. Then it’d look any other
like this:
bool[] myArray = new
bool[15];
This array has 15
elements within it.

bool[] myArray;

myArray = new bool[15];
myArray[4] = true;

This line sets the value of the fifth
nt of myArray to true. It’s the
Use e ach element in an array like eleme
fifth one because the first is myArray[0],
it is a normal variable
the second is myArray[1], etc.

e array
In memory, tohne chunk
is stored as even though
of memory, ultiple int
there are m hin it.
variables wit

When you use an array, first you need to declare a reference
variable that points to the array. Then you need to create the
array object using the new statement, specifying how big you
want the array to be. Then you can set the elements in the
array. Here’s an example of code that declares and fills up an
array—and what’s happening on the heap when you do it. The
first element in the array has an index of zero.

The type
of each
element in
the array.

You
reference
these by
index, but
each one
works
essentially
like a normal
int variable.

int[] heights;

name

7 int variables

heights = new int[7];
heights[0] = 68;
heights[1] = 70;
heights[2] = 63;

int

int

int

int

int

int

int

heights[3] = 60;
heights[4] = 58;
heights[5] = 72;
heights[6] = 74;

150   Chapter 4

hts
heig

Ar

ray

Notice that the array is an object,
even though the 7 elements are just
value types—like the ones on the first
two pages of this chapter.

types and references

Arrays can contain a bunch of
reference variable s, too
You can create an array of object references just like you create an
array of numbers or strings. Arrays don’t care what type of variable
they store; it’s up to you. So you can have an array of ints, or an
array of Duck objects, with no problem.
Here’s code that creates an array of 7 Dog variables. The line that
initializes the array only creates reference variables. Since there are
only two new Dog() lines, only two actual instances of the Dog
class are created.
This line declares

dogs[5] = new Dog();
dogs[0] = new Dog();

These two lines create new
instances of Dog() and put
them at indexes 0 and 5.

ngth
e
l
s
’
y
a
r
r
a
An
ow many

s
d out h
You can finre in an array using itot
elements a perty. So if you’ve g u
Length proalled heights, then yo
an array c hts.Length to find
can use heigng it is. If there are
out how lo in the array, that’ll ay
7 elements which means the arr
give you 7—e numbered 0 to 6.
elements ar

ec t

only
The first line of code
the
t
no
y,
ra
created the ar
a
is
y
ra
instances. The ar ference
list of seven Dog re
variables.

bj

Dog[] dogs = new Dog[7];

a
dogs variable to hold an
array of references to
Dog objects, and then
creates a 7-element
array.

ec t

When you set or
retrieve an element
from an array, the
number inside the
brackets is called
the index. The first
element in the array
has an index of zero.

bj

Dog O

Dog O

7 Dog variables

Dog

Ar

ray

Dog

Dog

Dog

Dog

Dog

Dog

All of the elements in the array are
references. The array itself is an object.
you are here 4   151

sloppy joe sez: “it’s not old, it’s vintage”

Welcome to Sloppy Joe’s Budge t House o’ Discount Sandwiche s!
Sloppy Joe has a pile of meat, a whole lotta bread, and more condiments
than you can shake a stick at. But what he doesn’t have is a menu! Can
you build a program that makes a new random menu for him every day?

1

Start a new project and add a MenuMaker class
If you need to build a menu, you need ingredients. And arrays would be perfect
for those lists. We’ll also need some way of choosing random ingredients to
combine together into a sandwich. Luckily, the .NET Framework has a built-in
class called Random that generates random numbers. So we’ll have four fields
in our class: a Randomizer field that holds a reference to a Random object, and
three arrays of strings to hold the meats, condiments, and breads.

The field called
Randomizer holds
a reference to a
Random object.
Calling its Next()
method will
generate random
numbers.
}
2

Notice how you’re
initializing these
arrays? That’s
called a collection
initializer, and
you’ll learn all
about them in
Chapter 8.

Do this

class MenuMaker {
public Random Randomizer;

MenuMaker
Randomizer
Meats
Condiments
Breads
GetMenuItem()

The class has three fields to
store three different arrays of
strings. It’ll use them to build
the random menu items.

string[] Meats = { “Roast beef”, “Salami”, “Turkey”, “Ham”, “Pastrami” };

string[] Condiments = { “yellow mustard”, “brown mustard”,
“honey mustard”, “mayo”, “relish”, “french dressing” };
string[] Breads = { “rye”, “white”, “wheat”, “pumpernickel”,
“italian bread”, “a roll” };
Remember, use square

brackets to
access a member of an array.The
value of Breads[2] is “wheat”.

Add a GetMenuItem() method to the class that generates a random sandwich
The point of the class is to generate sandwiches, so let’s add a method to do exactly that. It’ll
use the Random object’s Next() method to choose a random meat, condiment, and bread
from each array. When you pass an int parameter to Next(), the method returns a random
that’s less than that parameter. So if your Random object is called Randomizer, then calling
Randomizer.Next(7) will return a random number between 0 and 6.
So how do you know what parameter to pass into the Next() method? Well, that’s easy—just
pass in each array’s Length. That will return the index of a random item in the array.

The GetMenuItem()
method returns
a string that
contains a sandwich
built from random
elements in the
three arrays.

public string GetMenuItem() {
string randomMeat = Meats[Randomizer.Next(Meats.Length)];
string randomCondiment = Condiments[Randomizer.Next(Condiments.Length)];
string randomBread = Breads[Randomizer.Next(Breads.Length)];
return randomMeat + “ with ” + randomCondiment + “ on ” + randomBread;
}
randomMeat by

152   Chapter 4

The method puts a random item from the Meats array into
passing Meats.Length to the Random object’s Next() method. Since there are 5
items in the Meats array, Meats.Length is 5, so Next(5) will return a random
number between 0 and 4.

types and references
I eat all my meals
at Sloppy Joe’s!

How it works…
The randomizer.Next(7) method gets a rand
less than 7. Meats.Length returns the numberom number that’s
Meats. So randomizer.Next(Meats.Le of elements in
you a random number that’s greater than or ngth) gives
but less than the number of elements in the equal to zero,
Meats array.

Meats[Randomizer.Next(Meats.Length)]
s got five elements,
Meats is an array of strings.SoIt’Meats[0] equals
numbered from zero to 4. equals “Ham”.
“Roast Beef”, and Meats[3]

3

Build your form
Add six labels to the form, label1 through label6. Then add code to set each label’s
Text property using a MenuMaker object. You’ll need to initialize the object using a new
instance of the Random class. Here’s the code:
public Form1() {
InitializeComponent();

Use an object initializer to set the
MenuMaker object’s Randomizer field to
a new instance of the Random class.

MenuMaker menu = new MenuMaker() { Randomizer = new Random() };
label1.Text = menu.GetMenuItem();
label2.Text = menu.GetMenuItem();
label3.Text = menu.GetMenuItem();
label4.Text = menu.GetMenuItem();
label5.Text = menu.GetMenuItem();
}

label6.Text = menu.GetMenuItem();

When you run the
program, the six labels
show six different
random sandwiches.

Now you’re all set to
generate six different
random sandwiches using the
GetMenuItem() method.

Here’s something
to think about.
What would
happen if you
forgot to
initialize the
MenuMaker
object’s
Randomizer
field? Can you
think of a way
to keep this
from happening?

you are here 4   153

your object’s a chatty cathy

Objects use references to talk to each other
So far, you’ve seen forms talk to objects by using reference variables to call their
methods and check their fields. Objects can call one another’s methods using
references, too. In fact, there’s nothing that a form can do that your objects can’t do,
because your form is just another object. And when objects talk to each other,
one useful keyword that they have is this. Any time an object uses the this keyword,
it’s referring to itself—it’s a reference that points to the object that calls it.
1

Elephant
Name
EarSize
WhoAmI()
TellMe()
SpeakTo()

Here’s a method to tell an elephant to speak
Let’s add a method to the Elephant class. Its first parameter is a message from an
elephant. Its second parameter is the elephant that said it:
public void TellMe(string message, Elephant whoSaidIt) {
MessageBox.Show(whoSaidIt.Name + “ says: ” + message,);
}

Here’s what it looks like when it’s called. You can add to button4_Click(), but add it
before the statement that resets the references! (lloyd = lucinda;)
lloyd.TellMe(“Hi”, lucinda);

We called Lloyd’s TellMe() method, and passed it two parameters: “Hi” and a reference to
Lucinda’s object. The method uses its whoSaidIt parameter to access the Name parameter
of whatever elephant was passed into TellMe() using its second parameter.
2

Here’s a method that calls another method
Now let’s add this SpeakTo() method to the Elephant class. It uses a special keyword:
this. That’s a reference that lets an object talk about itself.
public void SpeakTo(Elephant whoToTalkTo, string message) {
whoToTalkTo.TellMe(message, this);
This method in the Elephant
}

class calls another
elephant’s TalkTo() method. It lets one elephant
communicate with another one.

Let’s take a closer look at how this works.
lloyd.SpeakTo(lucinda, “Hello”);

When Lloyd’s SpeakTo() method is called, it uses its talkTo parameter (which has a
reference to Lucinda) to call Lucinda’s TellMe() method.
whoToTalkTo.TellMe(message, this);
Lloyd uses whoToTalkTo
(which has a reference to
Lucinda) to call TellMe()

this is replaced

with a reference to
Lloyd’s object

lucinda.TellMe(message, [a reference to Lloyd]);

So Lucinda acts as if she was called with (“Hello”, lloyd), and shows this message:
154   Chapter 4

types and references

Where no object has gone before
There’s another important keyword that you’ll use with objects.
When you create a new reference and don’t set it to anything, it has
a value. It starts off set to null, which means it’s not pointing to
anything.

Right now, there’s only
one object. The fido
reference is set to null.

lucky = null;

y
Luck

Do

g o b j ec t

fido
Do

When we set lucky to null,
it’s no longer pointing at its
object, so it gets garbagecollected.

Q:

One more time—my form is an
object?

A:

Yes! That’s why your class code starts
with a class declaration. Open up code for
a form and see for yourself. Then open up
Program.cs in any program you’ve
written so far and look inside the Main()
method—you’ll find “new Form1()”.

poof!

if (lloyd == null) {
That test will return true if the lloyd
reference is set to null.

Why would I ever use null?

Another way you’ll see the null keyword
used is when you want your object to get
garbage-collected. If you’ve got a reference
to an object and you’re finished with the
object, setting the reference to null will
immediately mark it for collection (unless
there’s another reference to it somewhere).

There are a few ways you see null
used in typical programs. The most common
way is testing for it:

You keep talking about garbage
collecting, but what’s actually doing the
collecting?

Q:
A:

#1

fido = new Dog();

Now that fido’s pointing
to an object, it’s no
longer equal to null.

Q:

g o b j ec t

g o b j ec t

fido

Do

#2

Do

Dog lucky = new Dog();

#1

y
Luck

#2

Dog fido;

g o b j ec t

A:

Remember how we talked about the
Common Language Runtime (or CLR)
back at the beginning of the first chapter?
That’s the virtual machine that runs all .NET
programs. A virtual machine is a way for it
to isolate running programs from the rest of
the operating system. One thing that virtual
machines do is manage the memory that
they use. That means that it keeps track of
all of your objects, figures out when the last
reference to the object disappears, and frees
up the memory that it was using.

you are here 4   155

this and that

Q:

I’m still not sure I get how
references work.

A:

References are the way you use all of the
methods and fields in an object. If you create a
reference to a Dog object, you can then use
that reference to access any methods you’ve
created for the Dog object. If you have a
(non-static) method called Dog.Bark() or
Dog.Beg(), you can create a reference
called spot. Then you can use that to access
spot.Bark() or spot.Beg(). You
could also change information in the fields for
the object using the reference. So you could
change a Breed field using spot.Breed.

Q:

Wait, then doesn’t that mean that
every time I change a value through a
reference I’m changing it for all of the
other references to that object, too?

A:

Yes. If rover is a reference to the
same object as spot, changing rover.
Breed to “beagle” would make it so that
spot.Breed was “beagle.”

Q:

I still don’t get that stuff about
different types holding different sized
values. What’s the deal with that?

A:

OK. The thing about variables is they
assign a size to your number no matter how
big its value is. So if you name a variable
and  give it a long type even though the
number is really small (like, say, 5), the CLR
sets aside enough memory for it to get really
big. When you think about it, that’s really
useful. After all, they’re called variables
because they change all the time.

The CLR assumes you know what you’re
doing and you’re not going to give a variable
a type that you don’t need. So even though
the number might not be big now, there’s a
chance that after some math happens, it’ll
change. The CLR gives it enough memory
to handle whatever type of number you call it.

Q:

Remind me again—what does
“this” do?

A: this

is a special variable that you
can only use inside an object. When you’re
inside a class, you use this to refer
to any field or method of that particular
instance. It’s especially useful when you’re
working with a class whose methods call
other classes. One object can use it to send
a reference to itself to another object. So
if Spot calls one of Rover’s methods
passing this as a parameter, he’s giving
Rover a reference to the Spot object.

Any time you’ve got
code in an object
that’s going to be
instantiated, the
instance can use the
special this variable
that has a reference
to itself.

There’s actually a very specific case where you don’t declare a type – you’ll
learn about it when you use the “var” keyword in Chapter 14.

¢¢

¢¢

¢¢

¢¢

When you declare a variable you ALWAYS give a type.
Sometimes you combine it with setting the value.

There are value types for variables that hold different
sizes of numbers. The biggest numbers should be of the
type long and the smallest ones (up to 255) can be
declared as bytes.
Every value type has a size, and you can’t put a value of
a bigger type into a smaller variable, no matter what the
actual size of the data is.

¢¢

¢¢

¢¢

When you’re using literal values, use the F suffix to
indicate a float (15.6F) and M for a decimal (36.12M).
¢¢

156   Chapter 4

There are a few types (like short to int) that C#
knows how to convert automatically. When the compiler
won’t let you set a variable equal to a value of a different
type, that’s when you need to cast it.
There are some words that are reserved by the
language and you can’t name your variables with them.
They’re words like for, while, using, new, and
others that do specific things in the language.
References are like labels: you can have as many
references to an object as you want, and they all refer to
the same thing.
If an object doesn’t have any references to it, it
eventually gets garbage-collected.

types and references

Here’s an array of Elephant objects and a loop that will go through
it and find the one with the biggest ears. What’s the value of the
biggestEars.Ears after each iteration of the for loop?
private void button1_Click(object sender, EventArgs e)
{
Elephant[] elephants = new Elephant[7];

We’re creating an array of 7
Elephant() references.

elephants[0] = new Elephant() { Name = “Lloyd”, EarSize = 40 };
elephants[1] = new Elephant() { Name = “Lucinda”, EarSize = 33 };
elephants[2] = new Elephant() { Name = “Larry”, EarSize = 42 };
elephants[3] = new Elephant() { Name = “Lucille”, EarSize = 32 };
elephants[4] = new Elephant() { Name = “Lars”, EarSize = 44 };

Every array
starts with
index 0, so the
first elephant
in the array is
Elephants[0].

elephants[5] = new Elephant() { Name = “Linda”, EarSize = 37 };
elephants[6] = new Elephant() { Name = “Humphrey”, EarSize = 45 };

Iteration #1 biggestEars.EarSize = _________
Elephant biggestEars = elephants[0];
for (int i = 1; i < elephants.Length; i++)
{

Iteration #2 biggestEars.EarSize = _________
if (elephants[i].EarSize > biggestEars.EarSize)
{
biggestEars = elephants[i];
}

}

This line makes the biggestEars
reference point at whatever
elephant elephants[i] points to.

Iteration #3 biggestEars.EarSize = _________

MessageBox.Show(biggestEars.EarSize.ToString());

Iteration #4 biggestEars.EarSize = _________

}

Be careful—this loop starts
with the second element of the
array (at index 1) and iterates
six times until i is equal to the
length of the array.

Iteration #5 biggestEars.EarSize = _________

Iteration #6 biggestEars.EarSize = _________

Answers on page 166.
you are here 4   157

code magnets and pool puzzle

Code Magnets

0;
int y =

The code for a button is all scrambled up on the fridge. Can you
reconstruct the code snippets to make a working method that
produces the output listed below?

refNum = index[y];

island
island
island
island

int refNum;

s[0] =
“Bermu

da”;
s[1] =
“Fiji”
;

s[2] =
“Azore

s[3] =
“Cozum

s”;

el”;

while (y < 4) {

;
result += islands[refNum]

MessageBox.Show(resul

index[0]

t);

= 1;

}

= 3;
index[1]
index[2]

= 0;

index[3]

= 2;

}

string[] islands = new string[4];
result += “\nisland =
”;

int[] ind
ex = new
int[4];
y = y + 1;
private void button
1_Click (object se
nder, EventArgs e)
{

string result = “”;

Answers on page 167.
158   Chapter 4

types and references

Pool Puzzle

the

Your job is to take code snippets
from the pool and place them
into the blank lines in the
code. You may use the same
snippet more than once, and
you won’t need to use all the
snippets. Your goal is to make
a class that will compile and run
and produce the output listed.

Output

Bonus Question!
For extra bonus points, use snippets
from the pool to fill in the two blanks
missing from the output.

Note: Each snippet from
the pool can be used
more than once.

x
y

area
ta.area
ta.x.area
ta[x].area

t for
class Triangle
he entry poinit’s in a file with
t
’s
e
r
e
H
{
ssume
application.“uAsing” lines at the top.
double area;
the right
int height;
int length;
public static void Main(string[] args)
{
string results = “”;
__________
___________________________
while ( ________ )
{
_________________________
_____.height = (x + 1) * 2;
_____.length = x + 4;
__________________
results += “triangle ” + x + “, area”;
results += “ = ” + _____.area + “\n”;
___________
}
___________
x = 27;
Hint: SetArea()
Triangle t5 = ta[2];
is NOT a
ta[2].area = 343;
static method.
results += “y = ” + y;
Flip back to
MessageBox.Show(results +
Chapter 3 for
“, t5 area = ” + t5.area); a refresher on
}
what the static
void setArea()
keyword means.
{
____________ = (height * length) / 2;
}
}

4, t5 area = 18
4, t5 area = 343
27, t5 area = 18
27, t5 area = 343

Triangle [ ] ta = new Triangle(4);
Triangle ta = new [ ] Triangle[4];
Triangle [ ] ta = new Triangle[4];

int x;
int y;
int x = 0;
ta[x] = setArea(); int x = 1;
ta.x = setArea(); int y = x;
28
ta[x].setArea();
30.0

x = x + 1;
x = x + 2;
x = x - 1;

ta.x
ta(x)
ta[x]

ta = new Triangle();
ta[x] = new Triangle();
ta.x = new Triangle();

x<4
x<5

Answers on page 168.
you are here 4   159

build something fun!

Build a t yping game
You’ve reached a milestone…you know enough to build a game! Here’s how your game will
work. The form will display random letters. If the player types one of them, it disappears
and the accuracy rate goes up. If the player types an incorrect letter, the accuracy rate
goes down. As the player keeps typing letters, the game goes faster and faster, getting more
difficult with each correct letter. If the form fills up with letters, the game is over!

1

Do this

Build the form.
Here’s what the form will look like in the form designer:

You’ll need to:
≥≥ Turn off the minimize box and maximize box. Then set the form’s FormBorderStyle
property to Fixed3D. That way, the player won’t be able to accidentally drag and resize it.
Then resize it so that it’s much wider than it is tall (we set our form’s size to 876, 174).
≥≥ Drag a ListBox out of the Toolbox onto the form. Set its Dock property to Fill, and its
MultiColumn property to True. Set its Font to 72 point bold.
≥≥ In the Toolbox, expand the “All Windows Forms” group at the top. This will display many
controls. Find the Timer control and double-click on it to add it to your form.

≥≥ Find the StatusStrip in the “All Windows Forms” group in the Toolbox and doubleclick on it to add a status bar to your form. You should now see the StatusStrip and
Timer icons in the gray area at the bottom of the form designer:

160   Chapter 4

See how you can use a Timer to make your
form do more than one thing at once? Take
a minute and flip to #3 in the “Leftovers”
appendix to learn about another way to do that.

types and references

2

Set up the StatusStrip control.
Take a closer look at the status bar at the bottom of the
screenshot. On one side, it’s got a series of labels:
And on the other side, it’s got a label and a progress bar:

You’ll be using three new
controls, but they’re easy
to work with!
Even though you haven’t seen a ListBox,
StatusStrip, or Timer before, you already
know how to set their properties and work
with them in your code. You’ll learn a lot
more about them in the next few chapters.

Add a StatusLabel to your StatusStrip by clicking its drop-down and selecting StatusLabel:

≥≥ Set the StatusStrip’s SizingGrip property to False.
≥≥ Use the Properties window to set its (Name) to correctLabel and its Text to “Correct: 0”.
Add three more StatusLabels: missedLabel, totalLabel, and accuracyLabel.
≥≥ Add one more StatusLabel. Set its Spring to True, TextAlign to MiddleRight, and
Text to “Difficulty”. Finally, add a ProgressBar and name it difficultyProgressBar.
3

Set up the Timer control.
Did you notice how your Timer control didn’t show up on your form? That’s because
the Timer is a non-visual control. It doesn’t actually change the look and feel of the
form. It does exactly one thing: it calls a method over and over again. Set the
Timer control’s Interval property to 800, so that it calls its method every 800
milliseconds. Then double-click on the timer1 icon in the designer. The IDE will
do what it always does when you double-click on a control: it will add a method to
your form. This time, it’ll add one called timer1_Tick. Here’s the code for it:
private void timer1_Tick(object sender, EventArgs e)
{
// Add a random key to the ListBox
listBox1.Items.Add((Keys)random.Next(65, 90));
if (listBox1.Items.Count > 7)
{
listBox1.Items.Clear();
listBox1.Items.Add(“Game over”);
timer1.Stop();
}
}

You’ll add a field called
“random” in just a minute.
Can you guess what its
type will be?

you are here 4   161

the key to a great game

4

Add a class to keep track of the player stats.
If the form is going to display the total number of keys the player pressed, the number that
were missed and the number that were correct, and the player’s accuracy, then we’ll need
a way to keep track of all that data. Sounds like a job for a new class! Add a class called
Stats to your project. It’ll have four int fields called Total, Missed, Correct, and
Accuracy, and a method called Update with one bool parameter: true if the player
typed a correct letter that was in the ListBox, or false if the player missed one.
class Stats
{
public int
public int
public int
public int

Total = 0;
Missed = 0;
Correct = 0;
Accuracy = 0;

public void Update(bool correctKey)
{
Total++;
if (!correctKey)
{
Missed++;
}
else
{
Correct++;
}

}

5

}

Every time the Update() method is
called, it recalculates the % correct
and puts it in the Accuracy field.

Accuracy = 100 * Correct / (Missed + Correct);

Add fields to your form to hold a Stats object and a Random object.
You’ll need an instance of your new Stats class to actually store the information,
so add a field called stats to store it. And you already saw that you’ll need a field
called random—it’ll contain a Random object.
Add the two fields to the top of your form:
public partial class Form1 : Form
{

Random random = new Random();
Stats stats = new Stats();

...

162   Chapter 4

Stats
Total
Missed
Correct
Accuracy
Update()

types and references

6

Handle the keystrokes.
There’s one last thing your game needs to do: any time the player hits a key, it needs to check if that key
is correct (and remove the letter from the ListBox if it is), and update the stats on the StatusStrip.
Go back to the form designer and select the form.
Then go to the Properties window and click on the
lightning bolt button. Scroll to the KeyDown row
and double-click on it. This tells the IDE to add
a method called Form1_KeyDown() that gets
called every time the user presses a key. Here’s the
code for the method:

Click this button to
change the Properties
window’s view. The
button to the left
of it switches the
Properties window
back to showing you
properties.

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
These are called
// If the user pressed a key that's in the ListBox, remove it
This if statement
// and then make the game a little faster
events, and you’ll
checks the ListBox if (listBox1.Items.Contains(e.KeyCode))
learn a lot more
to see if it contains {
about them later
listBox1.Items.Remove(e.KeyCode);
the key the player
listBox1.Refresh();
pressed. If it does,
if (timer1.Interval > 400)
then the key gets
This is the part that increases the difficulty
timer1.Interval -= 10;
removed from the
as the player gets more keys right. You can
if (timer1.Interval > 250)
ListBox and the
make the game easier by reducing the amounts
timer1.Interval -= 7;
game difficulty is
that are subtracted from timer1.Interval, or
if (timer1.Interval > 100)
increased.
make it harder by increasing them.
timer1.Interval -= 2;
difficultyProgressBar.Value = 800 - timer1.Interval;
// The user pressed a correct key, so update the Stats object
// by calling its Update() method with the argument true
stats.Update(true);

When the player
presses a key, the
Form1_KeyDown()
method calls the
Stats object’s
Update() method to
update the player
stats, and then it
displays them in the
StatusStrip.

}
else
{
// The user pressed an incorrect key, so update the Stats object
// by calling its Update() method with the argument false
stats.Update(false);
}

}

7

// Update the labels on the StatusStrip
correctLabel.Text = "Correct: " + stats.Correct;
missedLabel.Text = "Missed: " + stats.Missed;
totalLabel.Text = "Total: " + stats.Total;
accuracyLabel.Text = "Accuracy: " + stats.Accuracy + "%";

Run your game.
Your game’s done! Give it a shot and see how well you do. You may need to adjust the font size of the
ListBox to make sure it holds exactly 7 letters, and you can change the difficulty by adjusting the values that
are subtracted from timer1.Interval in the Form1_KeyDown() method.
you are here 4   163

on.

exercise solutions

There are about 77 reserved words in C#. These are words reserved by the C# compiler; you
can’t use them for variable names. You’ll know a lot of them really well by the time you finish the
book. Here are some you’ve already used. Write down what you think these words do in C#.

namespace

Namespaces make sure that the names you are using in your program don’t collide
with the ones in the .NET Framework or other external classes you’ve used in your
program. All of the classes and methods in a program are inside a namespace.

for

This lets you do a loop that executes three statements. First it declares the
variable it’s going to use, then there’s the statement that evaluates the variable
against a condition. The third statement does something to the value.

class

A class is how you define an object. Classes have properties and methods.
Properties are what they know and methods are what they do.

public

A public class can be used by every other class in the project. When a variable or
method is declared as public, it can be used by classes and called by methods that are
outside of the one it’s being declared in.

else

Code that starts with else will get executed if the if statement preceding it fails.

new

You use this to create a new instance of an object.

using
if
while

164   Chapter 4

This is a way of listing off all of the namespaces you are using in your program. using
lets you use code from the .NET Framework and predefined classes from third parties
as well as classes you can make yourself.
One way of setting up a conditional statement in a program. It says
if one thing is true, do one thing and if not do something else.
while loops are loops that keep on going as long as the condition in them is true.

types and references

Typecross Solution

1
3

N

2

A M

R

S

E

S

F

I

E

G

R

N

E

M

N

E

10

C

O

E

N

E
4

U

E

C

A
8

C

A

B

L

11

T

S

E

G
N

A
A

S

V

E

D

T

I

N

G
7

C

12

T

B

A

G

E
9

L

C

C

E

I

O

M

M

P

S

A

P

E

T

L

O

15

C

A

R

D

O

H

A

E
E

5

Y

J
16

R

A

T
O

S

R
6

O

D

E

A

13
14

R

P

E

T

17

U

R

U

I

N

N

S

I

G

N

E

D

G

Across

Down

1. The second part of a variable declaration [name]
4. "namespace", "for", "while", "using" and "new" are
examples of _____________
6. What (int) does in this line of code: x = (int) y;
[casting]
8. When an object no longer has any references
pointing to it, it's removed from the heap using
____________ collection. [garbage]
10. What you're doing when you use the + operator to

2. You can combine the variable declaration and the
____________ into one statement. [assignment]
n object [reference]
5. What your program uses to work with data that's in
memory [variable]
7. If you want to store a currency value, use this type
[decimal]
you are here 4   165
9. += and -= are this kind of operator [compound]
11. A variable declaration always starts with this.

exercise solutions

Here’s an array of Elephant objects and a loop that will go through
it and find the one with the biggest ears. What’s the value of the
biggestEars.Ears after each iteration of the for loop?
private void button1_Click(object sender, EventArgs e)
{
Elephant[] elephants = new Elephant[7];
elephants[0] = new Elephant() { Name = “Lloyd”, EarSize =
elephants[1] = new Elephant() { Name = “Lucinda”, EarSize

that
Did you remembewrith the
the loop starts of the
40 };
second element you think
Why do
= 33 }; array?
is?
at
th

elephants[2] = new Elephant() { Name = “Larry”, EarSize = 42 };

elephants[3] = new Elephant() { Name = “Lucille”, EarSize = 32 };
elephants[4] = new Elephant() { Name = “Lars”, EarSize = 44 };
elephants[5] = new Elephant() { Name = “Linda”, EarSize = 37 };
elephants[6] = new Elephant() { Name = “Humphrey”, EarSize = 45 };
Elephant biggestEars = elephants[0];

40

Iteration #1 biggestEars.EarSize = _________

for (int i = 1; i < elephants.Length; i++)
{
{
}
}

42

Iteration #2 biggestEars.EarSize = _________

if (elephants[i].EarSize > biggestEars.EarSize)

The biggestEars
reference is used to
biggestEars = elephants[i];keep track of which
42
element we’ve seen while Iteration #3 biggestEars.EarSize = _________
Use the debugger to check
goin through the for
this! Put your breakpoint here loop ghas
the biggest
and watch biggestEars.EarSize. ears so far
.

MessageBox.Show(biggestEars.EarSize.ToString());
}

The for loop starts with the second elephant and
compares it to whatever elephant biggestEars
points to. If its ears are bigger, it points
biggestEars at that elephant instead. Then it
moves to the next one, then the next one…by the
end of the loop biggestEars points to the one
with the biggest ears.
166   Chapter 4

44

Iteration #4 biggestEars.EarSize = _________

44

Iteration #5 biggestEars.EarSize = _________

45

Iteration #6 biggestEars.EarSize = _________

types and references

Code Magnets Solution

The code for a button is all scrambled up on the fridge. Can you
reconstruct the code snippets to make a working method that
produces the output listed below?

private void button
1_Click (object se
nder, EventArgs e)
{
string result = “”;

int[] ind
ex = new
int[4];
;
1
=
]
index[0

Here’s where the
index[] array
gets initialized.

index[1]

= 3;

index[2]

= 0;

= 2;
index[3]
string[] islands = new string[4];
island

island
island

s[0] =
“Bermu
da

s[1] =
“Fiji”

s[2] =
“Azore

”;

;

s”;
s[3] =
“Cozum
el”;
0;
int y =
island

The islands[] array is
initialized here.

int refNum;

This while loop
pulls a value from
the index[] array
and uses it for
the index in the
islands[] array.

The result string is builttoup
using the += operator it.
concatenate lines onto

while (y < 4) {
refNum = index[y];

result += “\nisland =
”;

;
result += islands[refNum]
y = y + 1;
}

}

MessageBox.Show(resul

t);

you are here 4   167

exercise solutions

Pool Puzzle Solution
Notice how this class contains
the entry point, but it also
creates an instance of itself?
That’s completely legal in C#.

After this line,
we’ve got an array
of four Triangle
references—but
there aren’t any
Triangle objects yet!
Bonus Answer

28
4, t5 area = 343

The setArea() method
uses the height and
length fields to set the
area field. Since it’s not
a static method, it can
only be called from inside
an instance of Triangle.

168   Chapter 4

class Triangle
{
double area;
int height;
int length;
public static void Main(string[] args)
{
string results = “”;
int x = 0;
__________
The while loop
Triangle[] ta = new Triangle[4];
___________________________
creates the four
while ( ________
)
x<4
instances of
{
Triangle by calling
ta[x] = new Triangle();
_________________________
the new statement
_____.height
= (x + 1) * 2;
ta[x]
four times.
_____.length
= x + 4;
ta[x]
ta[x].setArea();
__________________
results += “triangle ” + x + “, area”;
results += “ = ” + _____.area
+ “\n”;
ta[x]
x = x + 1;
___________
}
int y = x;
___________
x = 27;
Triangle t5 = ta[2];
ta[2].area = 343;
results += “y = ” + y;
MessageBox.Show(results +
“, t5 area = ” + t5.area);
}
void setArea()
{
area
____________
= (height * length) / 2;
}
}

Name:

Date:

C# Lab
A Day at the Races
This lab gives you a spec that describes a program
for you to build, using the knowledge you’ve gained
over the last few chapters.
This project is bigger than the ones you’ve seen so far.
So read the whole thing before you get started, and
give yourself a little time. And don’t worry if you get
stuck—there’s nothing new in here, so you can move
on in the book and come back to the lab later.
We’ve filled in a few design details for you, and we’ve
made sure you’ve got all the pieces you need…and
nothing else.
It’s up to you to finish the job. You can download
an executable for this lab from the website…but we
won’t give you the code for the answer.

C# Lab   169

A Day at the Races
The spec: build a race track simulator
Joe, Bob, and Al love going to the track, but they’re
tired of losing all their money. They need you to build a
simulator for them so they can figure out winners before
they lay their money down. And, if you do a good job,
they’ll cut you in on their profits.
Here’s what you’re going to build for them....

The Guys
Joe, Bob, and Al want to bet on a dog race. Joe starts with 50 bucks,
Bob starts with 75 bucks, and Al starts with 45 bucks. Before
each race, they’ll each decide if they want to bet, and how
much they want to put down. The guys can change their bets
right up to the start of the race…but once the race starts, all
bets are final.

The Be t ting Parlor
The betting parlor keeps track of how much cash each
guy has, and what bet he’s placed. There’s a minimum
bet of 5 bucks. The parlor only takes one bet per person
for any one race.
The parlor checks to make
sure that the guy who’s betting
has enough cash to cover his
bet—so the guys can’t place a
bet if they don’t have the cash
to cover the bet.

170  

Welcome to Curly’s
Betting Parlor
Minimum Bet: $5
One bet per person per race
Got enough cash?

A Day at the Races

Be t ting
Every bet is double-or-nothing—either the winner doubles
his money, or he loses what he bet. There’s a minimum
bet of 5 bucks, and each guy can bet up to 15 bucks on a
single dog. If the dog wins, the bettor ends up with twice
the amount that he bet (after the race is complete). If he
loses, that amount disappears from his pile.

Say a guy places a $10 bet at the window. At
the end of the race, if his dog wins, his cash
goes up by $10 (because he keeps the original $10
he bet, plus he gets $10 more from winning). If
he loses, his cash goes down by $10.

All bets: double-or-nothing
Minimum Bet: $5
Up to $15 per dog
Win: $$ added
Lose: $$ removed

The Race
There are four dogs that run on a straight track. The
winner of the race is the first dog to cross the finish line.
The race is totally random, there are no handicaps or
odds, and a dog isn’t more likely to win his next race
based on his past performance.

If you want to build
system, by all means doa handicap
be really good practice it! It’ll
writing
some fun code.

Sound fun? We’ve got more details coming up…

   171

A Day at the Races
You’ll need three classe s and a form
You’ll build three main classes in the project, as well as a GUI for the
simulator. You should have an array of three Guy objects to keep track
of the three guys and their winnings, and an array of four Greyhound
objects that actually run the race. Also, each instance of Guy should
have its own Bet object that keeps track of his bet and pays out (or
takes back) cash at the end of the race.
We’ve gotten you started with class descriptions and some snippets of
code to work from. You’ve got to finish everything up.

Greyhound
StartingPosition
RacetrackLength
MyPictureBox
Location
Randomizer

We’ve given you the skeleton of
the class you need to build. Your
job is to fill in the methods.

class Greyhound {
public int StartingPosition; // Where my PictureBox starts
public int RacetrackLength; // How long the racetrack is
public PictureBox MyPictureBox = null; // My PictureBox object
public int Location = 0; // My Location on the racetrack
public Random Randomizer; // An instance of Random

You only need one instance of Random—each Greyhound’s
object.

public bool Run() { Randomizer reference should point to the same Random
// Move forward either 1, 2, 3 or 4 spaces at random
// Update the position of my PictureBox on the form
// Return true if I won the race
We’ve added comments
}
to give

Run()
TakeStartingPosition()

agram
See how the classthdie code?
th
matches up wi

You’ll need to add “using
System.Windows.Forms” to
the top of the Greyhound
and Guy classes. And you’ll
need to add “using System.
Drawing;” to Greyhound,
because it uses Point.

you an idea of what

}

public void TakeStartingPosition() {
// Reset my location to the start line
}

The Greyhound object initializer is pretty
straightforward. Just make sure you pass a
reference to the right PictureBox on the
form to each Greyhound object.

to do.

is…
Don’t overthink th
need to set
st
ju
sometimes you you’re done.
a variable, and

Your object can control things on your form…
The Greyhound class keeps track of its position on the racetrack during the race. It also
updates the location of the PictureBox representing the dog moving down the race
track. Each instance of Greyhound uses a field called MyPictureBox to reference
the PictureBox control on the form that shows the picture of the dog. Suppose the
distance variable contains the distance to move the dog forward. Then this code will
update the location of MyPictureBox by adding distance to its X value:

You’ll have to make sure
the form passes the
right picture box into
each Greyhound’s object
initializer.

t
You get the currpiencture…
location of the
…add the value to move forward
to its X coordinate…
picture
the
update
…and then
box location on the form.

Point p = MyPictureBox.Location;
p.X += distance;
MyPictureBox.Location = p;

172  

A Day at the Races
Guy
Name
MyBet
Cash
MyRadioButton
MyLabel

class Guy
public
public
public

// The last two fields are the guy’s GUI controls on the form
public RadioButton MyRadioButton; // My RadioButton
public Label MyLabel; // My Label Once you set MyLabel to one of the

UpdateLabels()
PlaceBet()
ClearBet()
Collect()

nge
labels on the form, you’ll be able to .cha
And
ext
el.T
Lab
My
the label’s text using
the same goes for MyRadioButton!

public void UpdateLabels() {
// Set my label to my bet’s description, and the label on my
// radio button to show my cash (“Joe has 43 bucks”)
}v
Add your

When you initialize
the Guy object, make
sure you set its MyBet
field to null, and call
its UpdateLabels()
method as soon as it’s
initialized.

code here.

public void ClearBet() { } // Reset my bet so it’s zero

public bool PlaceBet(int Amount, int Dog) {
// Place a new bet and store it in my bet field
// Return true if the guy had enough money to bet
}
}

This is the object that
Guy uses to represent
bets in the application.
Bet
Amount
Dog
Bettor

{
string Name; // The guy’s name
Bet MyBet; // An instance of Bet() that has his bet
int Cash; // How much cash he has

Remember that bets
are represented by
instances of Bet.

public void Collect(int Winner) { } // Ask my bet to pay out

class Bet
public
public
public

The key here is to use the Bet
object…let it do the work.
The object initializer for Bet just
sets the amount, dog, and bettor.

{
int Amount; // The amount of cash that was bet
int Dog; // The number of the dog the bet is on
Guy Bettor; // The guy who placed the bet

public string GetDescription() {
// Return a string that says who placed the bet, how much
// cash was bet, and which dog he bet on (“Joe bets 8 on
// dog #4”). If the amount is zero, no bet was placed
task:
// (“Joe hasn’t placed a bet”).
common programmingeg from
a
is
s
hi
T
}
string or messa

GetDescription
PayOut

assembling a
of data.
several individual bits

Hint: You’ll instantiate Bet
in the Guy code. Guy willl
use the this keyword to
pass a reference to himself
to the Bet’s initializer.

}

public int PayOut(int Winner) {
// The parameter is the winner of the race. If the dog won,
// return the amount bet. Otherwise, return the negative of
// the amount bet.
}

   173

A Day at the Races

obj
ect

d
Greyhoun

d
Greyhoun

d
Greyhoun

[]
array

w
s.F
orm

object

d
Greyhoun

obj
ect

obj
ect

Spend some time looking closely at the architecture. It
looks pretty complicated at first, but there’s nothing here
you don’t know. Your job is to recreate this architecture
yourself, starting with the Greyhound and Guy arrays in
your main form.

ntains four
The dogs array coof which points
references, each stance of the
to a separate in
Greyhound class.

obj
ect

Here’s your application architecture

o
System.Wind

Greyhound

a
Guy[]

je
ct

b
Guy o

je
ct

Array of Guy references

ec
t

ec
t

bj
Bet o

174  

b
Guy o

b
Guy o

ec
t

Among the visual objects will be
four PictureBox controls for
the pictures of the dogs. You’ll
pass references to them to the
object initializers of the four
Greyhound objects. It’ll also have
three RadioButton controls and
three labels, which you’ll pass to
the object initializers of the
three Guy objects.

The guys array cont
references to three ains
objects. Each of th Guy
objects has a field ose
bet, which is a refe called
to a Bet object. rence

je
ct

Visual ob

Array of Greyhound references

rr
ay

je
cts

The form needs to initialize
both of these arrays when
it starts up.

bj
Bet o

bj
Bet o

A Day at the Races
When a Guy place s a be t, he
cre ate s a ne w Be t object

…so Guy #2 create
instance of Bet, usins a new
keyword to tell the g the this
that he’s the bettor Bet object
…

First the form tells Guyck#2
on
to place a bet for 7 bu s
dog #3…

MyBet = new Bet()
{ Amount = 7, dog = 3, Bettor = this };

bj
Bet o

b
Guy o

…and since the Guy
had enough money to
place the bet, PlaceB
et() returns true.

true

The form tells the dogs to keep
running until there’s a winner

Each dog’s Run() meth ch
ecks to
see if that dog won thod
e
ra
ce
the loops should end immedia , so
soon as one of the dog wins. tely as
while ( there’s no winner ) {
for ( loop through each dog, making
sure there’s still no winner ) {
have the dog run one pace
}
}

object
w
s.F
orm

When the user
tells the form to
start the race,
the form starts
a loop to animate
each dog running
along the track.

ec
t

ob

o
System.Wind

Form

ob

The Guy will add the result of Bet.
Payout() to his cash. So if the dog won,
it should return Amount; otherwise, it’ll
return -Amount.

MyBet.PayOut(winningDog)

b
Guy o

ec
t

jec
t

Guy[1].Collect(winningDog)

Greyhound

je
ct

The Be t object figure s out if it
should pay out

The betting parlor in the form tells
each Guy which dog won so he can
collect any winnings from his bet.

[]
array

Form

je
ct

jec
t

Guy[1].PlaceBet(7, 3)

if ( my dog won ) {
return Amount;
} else {
return -Amount;
}

bj
Bet o

   175

A Day at the Races
Here’s what your GUI should look like
The graphical user interface for the “Day at the Races” application
consists of a form that’s divided into two sections. The top is the
racetrack: a PictureBox control for the track, and four more for
the dogs. The bottom half of the form shows the betting parlor, where
three guys (Joe, Bob, and Al) can bet on the outcome of the race.

You’ll use the Length property
of the racetrack PictureBox
control to set the racetrack
length in the Greyhound object
n
he
W
l.
wh
ro
ich it’ll use to figure out if ,
ox cont
eB
ur
ct
Pi
n
ow
its
s
ha
gs
it won the race.
Each of the four do the four Greyhound objects, each one’s s.
ct
of
je
ch
ob
ea
e
e
es
Ma
liz
th
ke
sure you set each
of
you initia
have a reference to one
PictureBox’s SizeMode
MyPicturebox field winclle (along with the racetrack length and
property to Zoom.
You’ll pass the refere the Greyhound’s object initializer.
to
)
ion
sit
po
g
startin

The form should update this
label with the minimum bet
using the Minimum property
of the NumericUpDown
control for the bet amount.

All three guys can bet on
the race, but there’s only
one betting window so
only one guy can place a
bet at a time.These radio
buttons are used to select
which guy places the bet.

When a Guy places a bet, it overwrites
any previous bet he placed. The current
bets show up in these label controls.
Each label has AutoSize set to False
and BorderStyle set to FixedSingle.

Once all bets are
placed, click this
button to start
the race.

You can download the graphics files from www.headfirstlabs.com/books/hfcsharp/
176  

A Day at the Races
Placing be ts
Use the controls in the Betting Parlor group box to place
each guy’s bet. There are three distinct stages here:
1

No bets have been placed yet
When the program first starts up, or if a race has just finished, no bets
have been placed in the betting parlor. You’ll see each guy’s total cash
next to his name on the left.

Each guy’s cash
shows up here.

2

3

When a guy plac
his Guy object upes a bet,
label using the M dates this
reference. He alsoyLabel
the cash he has us updates
MyRadioButton ing his
reference.

The minimum bet
should be the same
as the minimum value
in the bet control.

Each guy places his bets
To place a bet, select the guy’s radio button, select an amount and a dog, and click
the Bets button. His PlaceBet() method will update the label and radio button.

After the race, each guy collects his winnings (or pays up!)
Once the race is complete and there’s a winner, each Guy object calls his
Collect() method and adds his winnings or losses to his cash.

Once Bob places
his bet, his Guy
object updates this
label and the radio
button text.

s
Since Al bet 12 bug,ckhis
do
g
on the winnin
he
cash goes up by 12se. Tthe
lo
ys
other two gu
money they bet.

Make sure all the Greyhound objects share one Random object! If each dog
creates its own new instance of Random, you might see a bug where all of the dogs
generate the same sequence of random numbers.
   177

A Day at the Races
The Finished Product
You’ll know your “Day at the Races” application is
done when your guys can place their bets and watch
the dogs race.

g
During the race, the fourcetdorack
ra
e
th
s
ros
images run ac
ce.
until one of them wins the ra

During the race, no bets can be
You can download a finished executable,
placed…and make sure you can’t
start a new race while the dogs
as well as the graphics files for the
are running!
four dogs and the racetrack, from the
But you won’t find the source code! In real life, you
Head First Labs website:
don’t get a solution to your programming problems.
test your C# knowledge
www.headfirstlabs.com/books/hfcsharp Here’s your chance to really
you’ve learned!
and see just how much

178  

5 encapsulation

Keep your privates…
private
No peeking!

Ever wished for a little more privacy?
Sometimes your objects feel the same way. Just like you don’t want anybody you
don’t trust reading your journal or paging through your bank statements, good objects
don’t let other objects go poking around their fields. In this chapter, you’re going to
learn about the power of encapsulation. You’ll make your object’s data private,
and add methods to protect how that data is accessed.

this is a new chapter   179

kathleen needs your help

Kathleen is an event planner
She’s been planning dinner parties for
her clients and she’s doing really well.
But lately she’s been having a hard time
responding to clients fast enough with an
estimate for her services.

nd
Kathleen would rathertsspe
t
no
,
en
ev
her time planning
.
planning estimates

When a new client calls Kathleen to do a party, she needs to find
out the number of guests, what kind of drinks to serve, and what
decorations she should buy. Then she uses a pretty complicated
calculation to figure out the total cost, based on a flow chart she’s
been using for years. The bad news is that it takes her a long time
to work through her chart, and while she’s estimating, her potential
clients are checking out other event planners.
It’s up to you to build her a C#-driven event estimator and save
her business. Imagine the party she’ll throw you when you succeed!

180   Chapter 5

encapsulation

What does the e stimator do?
Kathleen runs down some of the basics of her system
for figuring out the costs of an event. Here’s part of
what she came up with:

Kathleen’s Party Planning Program—Cost Estimate

for a Dinner Party

food charge.
• For each person on the guest list there’s a $25
parties serve alcohol, which
• Clients have a choice when it comes to drinks. Most
a party without alcohol.
have
to
se
choo
costs $20 per person. But they can also
costs $5 per person to have
Kathleen calls that the “Healthy Option,” and it only
hy Option is a lot easier for
Healt
the
sing
soda and juice instead of alcohol. Choo
party, too.
her, so she gives the client a 5% discount on the entire
ns. If a client goes with the
• There are two options for the cost of decoratio
decorating fee. A client can
normal decorations, it’s $7.50 per person with a $30
y Option”—that costs $15 per
also upgrade the party decorations to the “Fanc
person with a $50 one-time decorating fee.

Here’s another look at this same set of costs, broken
down into a little flow chart to help you see how it works:

Number of
people.
Food ($25 per
person)

Healthy
Option?

Yes

Some of these choices involve
a change to the final price of
the event, as well as individual
per-person costs.

Juice and soda
($5 per person +
5% discount on
total cost)

Yes
Fancy
decorations?

No

Alcohol
($20 per
person)

No

Fancy
Decorations
($15 per person
+$50 decorating
fee)
Normal
Decorations
($7.50 per
person +$30
decorating fee)

While most choices affect the
cost for each guest, there are
also one-time fees to figure in.
you are here 4   181

ok, no problem

v

Build a program to solve Kathleen’s party estimating problem.
1

Create a new Windows Application project and add a class file to it called
DinnerParty.cs, and build the DinnerParty class using the class diagram
to the left. It’s got three methods: CalculateCostOfDecorations(),
SetHealthyOption(), and CalculateCost(). For the fields, use
decimal for the two costs, int for the number of people, and bool to keep
track of whether or not the Healthy Option was selected. Make sure you add an
M after every literal you assign to a decimal value (10.0M).

2

Here’s a useful C# tool. Since the cost of food won’t be changed by the
program, you can declare it as a constant, which is like a variable except
that its value can never be changed. Here’s the declaration to use:

DinnerParty
NumberOfPeople
CostOfBeveragesPerPerson
CostOfDecorations

SetHealthyOption()
CalculateCostOfDecorations()
CalculateCost()

diagram forl
ss
la
c
e
h
t
’s
e
Her
y class you’l
t
r
a
P
r
e
n
in
D
the
te.
need to crea

public const int CostOfFoodPerPerson = 25;
3

Flip back to the previous page to be sure you’ve got all of the logic right for
the methods. Only one of them returns a value (a decimal)—the other
two are void. The CalculateCostOfDecorations() method figures
out the cost of decorations for the number of people attending the party.
Use the CalculateCost() method to figure out the total cost by adding
the cost of the decorations to the cost of drinks and food per person. If
the client wants the Healthy Option, you can apply the discount inside the
CalculateCost()method after you’ve figured out the total cost.

4

Add this code to your form:

The SetHealthy
a bool parameterOption() method uses
update the CostO (healthyOption) to
field based on whefBeveragesPerPerson
client wants the ther or not the
Healthy Option.
5

You don’t need to add “using
System.Windows.Forms;” to
DinnerParty class, because ityour
doesn’t use MessageBox.Show()
or anything else from that .NE
T
Framework namespace.

You’ll declare the dinnerParty field in
the form, and then add these four lines
below InitializeComponent().

DinnerParty dinnerParty;
public Form1() {
InitializeComponent();
dinnerParty = new DinnerParty() { NumberOfPeople = 5 };
dinnerParty.SetHealthyOption(false);
dinnerParty.CalculateCostOfDecorations(true);
DisplayDinnerPartyCost();
}

Set the default
to 5. The
value
Here’s what the form
should be
minimum
should look like. Use
maximum
the
and
1
the NumericUpDown
20.
be
should
control’s properties to set
the maximum number
Set the Fancy
of people to 20, the
Decorat
ions
minimum to 1, and the
checkbo
x’s
Checked
default to 5. Get rid of the
property to True.
maximize and minimize
buttons, too.

This is a label named labelCost. The Text Property is empty, the BorderStyle
property set to Fixed3D, and the AutoSize property set to false.
182   Chapter 5

encapsulation

6

Instead of using a button to calculate the costs, this form will update the cost label
automatically as soon as you use a checkbox or the NumericUpDown control. The first
thing you need to do is create a method in the form that displays the cost.

This method will
get called by all of Add this method to Form1( ). It’ll get called when the NumericUpDown control is clicked:
the other methods
Add this method to the form—it’ll
you create on the
recalculate the cost of the party
form. It’s how you private void DisplayDinnerPartyCost() and put it in the Cost label.
{
update the cost
ht
rig
e
th
decimal Cost = dinnerParty.CalculateCost(checkBox2.Checked);
label with
er
costLabel.Text = Cost.ToString(“c”);
ev
value when
This is true if the
s.
ge
an
}
ch
anything
Change the name of the
Passing “c” to ToString() tells checkbox for the Healthy
Option is checked.
label that displays the cost
it to format the cost as a
to costLabel.
currency value. If you’re in a
country that uses dollars, it’ll
add a dollar sign.
Now hook up the NumericUpDown field to the NumberOfPeople variable you
You’ve been using 7
created in the DinnerParty class and display the cost in the form. Double-click on
event handlers
the
NumericUpDown control—the IDE will add an event handler to your code.
all along—when
That’s
a method that gets run every time the control is changed. It’ll reset the number
you double-click
of
people
in the party. Fill it in like this:
on a button,
the IDE adds
private void numericUpDown1_ValueChanged(
a Click event
object sender, EventArgs e)
handler. Now
{
you know what
dinnerParty.NumberOfPeople = (int) numericUpDown1.Value;
it’s called.
DisplayDinnerPartyCost();
You need to cast numericUpDown.Value to
}
an int because it’s a Decimal property.
Uh-oh—there’s a problem with this code. Can you spot it? Don’t worry if you
don’t see it just yet. We’ll dig into it in just a couple of minutes!

The value you send from the form to the
method will be fancyBox.Checked. That will
be passed as a boolean parameter to the
method in the class.
8

These are just two-line
line will call the method methods. The first
class to figure out the coyou created in the
will display the total cost sts, and the second
on the form.

Double-click on the Fancy Decorations checkbox on the form and make
sure that it first calls CalculateCostOfDecorations() and then
DisplayDinnerPartyCost(). Next, double-click the Healthy Option
checkbox and make sure that it calls the SetHealthyOption() method in
the DinnerParty class and then calls the DisplayDinnerPartyCost()
method.
you are here 4   183

exercise solution

wv

Here’s the code that goes into DinnerParty.cs.

Using a constant for CostOfFoodPerPerson
ensures the value can’t be changed. It also
makes the code easier to read—it’s clear that
this value never changes.
class DinnerParty {
When the form first creates
const int CostOfFoodPerPerson = 25;
the object, it uses the initializer
public int NumberOfPeople;
to set NumberOfPeople. Then
public decimal CostOfBeveragesPerPerson;
it calls SetHealthyOption() and
public decimal CostOfDecorations = 0;
CalculateCostOfDecorations() to
set the other fields.

public void SetHealthyOption(bool healthyOption) {
if (healthyOption) {
CostOfBeveragesPerPerson = 5.00M;
} else {
We used “if (Fancy)” instead of
CostOfBeveragesPerPerson = 20.00M;
typing “if (Fancy == true)” because
}
the if statement always checks if the
}
is true.

condition

public void CalculateCostOfDecorations(bool fancy) {
if (fancy)
{
CostOfDecorations = (NumberOfPeople * 15.00M) + 50M;
} else {
CostOfDecorations = (NumberOfPeople * 7.50M) + 30M;
}
}
public decimal CalculateCost(bool healthyOption) {
decimal totalCost = CostOfDecorations +
((CostOfBeveragesPerPerson + CostOfFoodPerPerson)
* NumberOfPeople);

}

}

184   Chapter 5

if (healthyOption) {
return totalCost * .95M;
} else {
return totalCost;
}

We used parentheses to make sure the
math works out properly.

This applies the 5% discount to
the overall event cost if the
non‑alcoholic option was chosen.

encapsulation

We had you use a decimal for the prices because it’s designed for monetary values. Just make
sure you always put an “M” after every literal—so if you want to store $35.26, make sure you
write 35.26M. You can remember this because the M stands for Money!

We call DisplayDinnerPartyCost to

public partial class Form1 : Form {
initialize the label that shows the
DinnerParty dinnerParty;
cost as soon as the form’s loaded.
public Form1() {
InitializeComponent();
dinnerParty = new DinnerParty() { NumberOfPeople = 5 };
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
dinnerParty.SetHealthyOption(healthyBox.Checked);
Changes to the checkboxes on the form set
DisplayDinnerPartyCost();
healthyOption and Fancy booleans to
the
}
and

true or false in the SetHealthyOption()
CalculateCostOfDecorations() methods.

private void fancyBox_CheckedChanged(object sender, EventArgs e) {
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
We named our checkboxes “healthyBox”
DisplayDinnerPartyCost();
and
“fancyBox” so you could see what’s
}

going on in their event handler methods.

private void healthyBox_CheckedChanged(object sender, EventArgs e) {
dinnerParty.SetHealthyOption(healthyBox.Checked);
DisplayDinnerPartyCost();
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e) {
dinnerParty.NumberOfPeople = (int)numericUpDown1.Value;
DisplayDinnerPartyCost();
The new dinner party cost needs to be
}
recalculated and displayed any time the number

changes or the checkboxes are checked.

}

private void DisplayDinnerPartyCost() {
decimal Cost = dinnerParty.CalculateCost(healthyBox.Checked);
costLabel.Text = Cost.ToString(“c”);
}

String formatting

You’ve already seen how you can convert any variable to a string using its ToString() method.
If you pass “c” to ToString(), it converts it to the local currency. You can also pass it “f3” to
format it as a decimal number with three decimal places, “0” (that’s a zero) to convert it to
a whole number, “0%” for a whole number percentage, and “n” to display it as a number with
comma separator for thousands. Take a minute and see how each of these looks in your programa
!
you are here 4   185

something’s gone terribly wrong

Kathleen’s Te st Dri ve
This rocks!
Estimating is about to
get a whole lot easier.

n’s
Rob’s one of Kathleee did his
Sh
favorite clients. , and now
wedding last yearimportant
she’s planning an him.
dinner party for

Rob (on phone): Hi Kathleen. How are the arrangements
for my dinner party going?
Kathleen: Just great. We were out looking at decorations this
morning and I think you’ll love the way the party’s going to
look.
Rob: That’s awesome. Listen, we just got a call from my wife’s
aunt. She and her husband are going to be visiting for the next
couple of weeks. Can you tell me what it does to the estimate
to move from 10 to 12 people on the guest list?

When you start the
program, the Fancy
Decorations box should
already be checked
because you set its
Checked property
to true. Setting the
number of people to 10
gives a cost of $575.

Kathleen: Sure! I’ll have that for you in just one minute.

Changing the Number of
People value from 10 to 12
and hitting enter shows $665
as the total cost. Hmm, that
seems a little low....

Kathleen: OK. It looks like the total cost for the dinner will
go from $575 to $665.
Rob: Only $90 difference? That sounds like a great deal! What
if we decide to cut the fancy decorations? What’s the cost then?

186   Chapter 5

encapsulation

Turning off the Fancy
Decorations checkb
reduces the amountoxbyonly
That can’t be right! $5.

Kathleen: Um, it looks like…um, $660.
Rob: $660? I thought the decorations were $15 per person. Did you change your
pricing or something? If it’s only $5 difference, we might as well go with the fancy
decorations. I’ve gotta tell you though, this pricing is confusing.
Kathleen: We just had this new program written to do the estimation for us.
But it looks like there might be a problem. Just one second while I add the fancy
decorations back to the bill.

ncy
When you turn the Fa
e
th
,
Decorations back on $770.
number shoots up tojust wrong.
These numbers are

Kathleen: Rob, I think there’s been a mistake. It looks like the cost with the fancy
decorations just shot up to $770. That does seem to make more sense. But I am
beginning not to trust this application. I’m going to send it back for some bug fixes
and work up your estimate by hand. Can I get back to you tomorrow?
Rob: I am not paying $770 just to add two people to the party. The price you
quoted me before was a lot more reasonable. I’ll pay you the $665 you quoted me in
the first place, but I just can’t go higher than that!

Why do you think the numbers are coming out wrong every time Kathleen makes a change?

you are here 4   187

wasn’t expecting that

Each option should be calculated individually
Even though we made sure to calculate all of the amounts according
to what Kathleen said, we didn’t think about what would happen when
people made changes to just one of the options on the form.
When you launch the program, the form sets the number of people to 5
and Fancy Decorations to true. It leaves Healthy Option unchecked and
it calculates the cost of the dinner party as $350. Here’s how it comes up
with the initial total cost:

		Don’t worry!
This one
wasn’t your
fault.
We built a nasty little bug into the
code we gave you to show you just
how easy it is to have problems
with how objects use one another’s
fields…and just how hard those
problems are to spot.

5 people.
$20 per person for drinks

Total cost of drinks = $100

$25 per person for food

Total cost of food = $125

$15 per person for decorations
plus $50 fee.

Total cost of decorations = $125

So far, so
good.
$100 + $125 + 125 = $350

When you change the number of guests, the application should
recalculate the total estimate the same way. But it doesn’t:

10 people.
$20 per person for drinks

Total cost of drinks = $200

$25 per person for food

Total cost of food = $250

$15 per person for decorations
plus $50 fee.

Total cost of decorations = $200

$200 + $250+ 200 = $650
Uncheck the Fancy Decorations
checkbox and then check it again.
This will cause the DinnerParty object’s
CostOfDecorations field to be updated,
and then the correct cost of $650 will show up.
188   Chapter 5

This is the t
al
we should getot
.
But we’re no
getting it! t

The program is adding the old cost of
decorations up with the new cost of
food and drink.
It’s doing $200 + $250 + $125= $575.
New food and d
Old decorations.
rink cost.

encapsulation

The Problem Up Close
Take a look at the method that handles changes to the value in the numericUpDown
control. It sets the value from the field to the NumberofPeople variable and then
calls the DisplayDinnerPartyCost() method. Then it counts on that method
to handle recalculating all the individual new costs.

This line sets the value
of NumberofPeople
in this instance of e
DinnerParty to th
value in the form.

private void numericUpDown1_ValueChanged(
object sender, EventArgs e) {
dinnerParty.NumberOfPeople = (int)numericUpDown1.Value;
DisplayDinnerPartyCost();
}

This method calls the CalculateCost() method, but not
the CalculateCostofDecorations() method.

So, when you make a change to the value in the NumberofPeople
field, this method never gets called:
public void CalculateCostOfDecorations(bool Fancy) {
if (Fancy) {

This variable is set to $125 from when the
form first called it, and since this method
doesn’t get called again, it doesn’t change.

CostOfDecorations = (NumberOfPeople * 15.00M) + 50M;
} else {
CostOfDecorations = (NumberOfPeople * 7.50M) + 30M;
}
}

That’s why the number corrects itself when you turn
fancy decorations back on. Clicking the checkbox makes
the program run CalculateCostOf Decorations() again.

Hold on! I assumed Kathleen would
always set all three options at once!

People won’t always use your classes in
exactly the way you expect.
Luckily, C# gives you a powerful tool to make sure your
program always works correctly—even when people do
things you never thought of. It’s called encapsulation
and it’s a really helpful technique for working with objects.

…and sometimes
those “people” who
are using your classes
are you! You might
be writing a class
today that you’ll be
using tomorrow.

you are here 4   189

protect your objects

It’s e asy to accidentally misuse your objects
Kathleen ran into problems because her form ignored the convenient
CalculateCostOfDecorations() method that you set up and instead
went directly to the fields in the DinnerParty class. So even though your
DinnerParty class worked just fine, the form called it in an unexpected way…
and that caused problems.

How the DinnerParty class expected to be called
The DinnerParty class gave the form a perfectly good method to
calculate the total cost of decorations. All it had to do was set the number
of people and then call CalculateCostOfDecorations(), and then
CalculateCost() will return the correct cost.

Di
Fo

2

rm

0
CalculateCost() returns $65

ject

NumberOfPeople = 10;
ns(true);
CalculateCostOfDecoratio

nn

ob

1

erParty

How the DinnerParty class was actually called
The form set the number of people, but just called the CalculateCost()
method without first recalculating the cost of the decorations. That threw off
the whole calculation, and Kathleen ended up giving Rob the wrong price.

rm
CalculateCost() returns $575

190   Chapter 5

nn

ob

Fo

Di

ject

;
NumberOfPeople = 10

erParty

Even though the form didn’t set up
the party properly, CalculateCost() still
returned a number…and there was no
way for Kathleen to know that the
number was wrong.

encapsulation

Encapsulation me ans keeping some of
the data in a class pri vate
There’s an easy way to avoid this kind of problem: make sure that there’s only one
way to use your class. Luckily, C# makes it easy to do that by letting you declare
some of your fields as private. So far, you’ve only seen public fields. If you’ve
got an object with a public field, any other object can read or change that field.
But if you make it a private field, then that field can only be accessed from
inside that object (or by another object of the same class).

Also, a class’s static methods can access the
private field in any instance of that class.
class DinnerParty {

private int numberOfPeople;

...

Use your laziness to your
own benefit—if you leave
off the “private” or
“public”, then C# will just
assume that your field is
private.

If you want to make a field priv , all
you need
to do is use the private keyword ate
whe
n
you
declare
it. That tells C# that if you’ve got
an
inst
of DinnerParty, its numberOfPeople fiel ance
be read and written by that instance— d can only
instance of DinnerParty. Other object or another
s won’t even
know it’s there.

public void SetPartyOptions(int people, bool fancy) {
numberOfPeople = people;
}

y to set the

CalculateCostOfDecorations(fancy); Other objects still need a wa ner party. One
din

public int GetNumberOfPeople() {
return numberOfPeople;

number of people for thace cess to it is to
good way to give them get the number of
add methods to set or n make sure that
people. That way you cacorations() method
the CalculateCostOfDee number of people is
gets run every time th re of that pesky bug.
changed. That’ll take ca

}
By making the field that holds the number
of party guests private, we only give the
form one way to tell the DinnerParty class
how many people are at the party—and
we can make sure the cost of decorations
is recalculated properly. When you make
some data private and then write code to
use that data, it’s called encapsulation.

en-cap-su-la-ted, adj.

enclosed by a protective coating
or membrane. The divers were fully
encapsulated by their submersible,
and could only enter and exit through
the airlock.
you are here 4   191

spy versus spy

Use encapsulation to control acce ss to your
class’s me thods and fields
When you make all of your fields and methods public, any other class
can access them. Everything your class does and knows about becomes
an open book for every other class in your program…and you just saw
how that can cause your program to behave in ways you never expected.
Encapsulation lets you control what you share and what you keep private
inside your class. Let’s see how this works:

SecretAgent
1

Super-spy Herb Jones is defending life, liberty, and the pursuit of
happiness as an undercover agent in the USSR. His ciaAgent object is
an instance of the SecretAgent class.



cia

Alias
RealName
Password

RealName: “Herb Jones”

AgentGreeting()

Alias: “Dash Martin”

Password: “the crow flies at midnight”

A g e nt

EnemyAgent
2

3

Borscht
Vodka

Agent Jones has a plan to help him evade the enemy KGB agents. He
added an AgentGreeting() method that takes a password as its
parameter. If he doesn’t get the right password, he’ll only reveal his
alias, Dash Martin.

ContactComrades()
OverthrowCapitalists()

Seems like a foolproof way to protect the agent’s identity, right? As
long as the agent object that calls it doesn’t have the right password,
the agent’s name is safe.

is an
The ciaAgent objeSectcretAgent
instance of the nt is an
class, while kgbAgeAgent.
instance of Enemy

kg

bA gent

192   Chapter 5

is parked outside”)
AgentGreeting(“the jeep

“Dash Martin”

The KGB only gets th
the CIA agent. Perfec e alias of
t. Right?

e wrong
The KGB agent usestithng.
password in his gree



cia

A g e nt

encapsulation

But is the re alName field REALLY protected?
So as long as the KGB doesn’t know any CIA agent passwords, the
CIA’s real names are safe. Right? But what about the field declaration
for the realName field:

Setting your variables
public means they can be
accessed, and even changed,
from outside the class.

He left the field public...
Why go through all of
the trouble to guess his
password? I can just get
his name directly!

kg

bA gent

public string RealName;

Setting your va
they can be acceriables as public means
from outside thessed, and even changed,
class.
lName;
string name = ciaAgent.Rea

call any
There’s no need to am
field is
method. The realN nee to see!
wide open for everyo

Agent Jones can use private fields to keep his identity secret from
enemy spy objects. Once he declares the realName field as private, the
only way to get to it is by calling methods that have access to the
private parts of the class. So the KGB agent is foiled!

Just replace public with
private, and boom, ur
fields are now hiddyo
from the world. en



cia

A g e nt

The kgbAgent object can’t
access the ciaAgent’s private
fields because they’re instances
of different classes.

private string realName;

Keeping your fields and methods
private makes sure no outside
code is going to make changes to
the values you’re using when you
don’t expect it.

sure that the field
You’d also want to make
ord is private, otherwise
that stores the passwge
to it.
the enemy agent can t
you are here 4   193

keeping secrets

Pri vate fields and me thods can only be
accessed f rom inside the class
There’s only one way that an object can get at the data stored inside another
object’s private fields: by using the public fields and methods that return the data.
But while KGB and MI5 agents need to use the AgentGreeting() method,
friendly spies can see everything—any class can see private fields in other
instances of the same class.

mi5agent is an
instance of the
BritishAgent class,
so it doesn’t have
access to ciaAgent’s
private fields either.
Only another
ciaAgent object
can see them.

flies at midnight”)
AgentGreeting(“the crow

mi

OK, so I need to access private data through
public methods. What happens if the class with the
private field doesn’t give me a way to get at that
data, but my object needs to use it?

A:

Then you can’t access the data from outside the
object. When you’re writing a class, you should always
make sure that you give other objects some way to
get at the data they need. Private fields are a very
important part of encapsulation, but they’re only part
of the story. Writing a class with good encapsulation
means giving a sensible, easy-to-use way for other
objects to get the data they need, without giving them
access to hijack data your class needs.

Q:

Why would I ever want to keep a field with
no way for another class to access?

Sometimes a class needs to keep track of
information that is necessary for it to operate, but that
no other object really needs to see. Here’s an example.
When computers generate random numbers, they use
special values called seeds. You don’t need to know
how they work, but every instance of

194   Chapter 5

“Herb Jones”

5A gent

Q:

A:

Now that the fields are priyvate,
this is pretty much the onl the
way the mi5Agent can get
ciaAgent’s real name.

Random actually contains an array of several dozen
numbers that it uses to make sure that Next()
always gives you a random number. If you create an
instance of Random, you won’t be able to see that
array. That’s because you don’t need it—but if you
had access to it, you might be able to put values in it
that would cause it to give non-random values. So the
seeds have been completely encapsulated from you.

Q:

Hey, I just noticed that all of the event
handlers I’ve been using have the private
keyword. Why are they private?

A:

Because C# forms are set up so that only the
controls on the forms can trigger event handlers.
When you put the private keyword in front of
any method, then that method can only be used from
inside your class. When the IDE adds an event handler
method to your program, it declares it as private so
other forms or objects can’t get to it. But there’s no rule
that says that an event handler must be private. In fact,
you can check this out for yourself—double-click on a
button, then change its event handler declaration to
public. The code will still compile and run.



cia

A g e nt

The only
way that
one object
can get to
data stored
in a private
field inside
another
object is by
using public
methods
that return
the data.

encapsulation

Here’s a class with some private fields. Circle the statements
below that won’t compile if they’re run from outside the
class using an instance of the object called mySuperChef.

class SuperChef
{
public string cookieRecipe;
private string secretIngredient;
private const int loyalCustomerOrderAmount = 60;
public int Temperature;
private string ingredientSupplier;
public string GetRecipe (int orderAmount)
{
		
if (orderAmount >= loyalCustomerOrderAmount)
		
{
			
return cookieRecipe + “ ” + secretIngredient;
		
}
		
else
		
{
			
return cookieRecipe;
		
}
}
}
1. string ovenTemp = mySuperChef.Temperature;
2. string supplier = mySuperChef.ingredientSupplier;
3. int loyalCustomerOrderAmount = 94;
4. mySuperChef.secretIngredient = “cardamom”;
5. mySuperChef.cookieRecipe = “get 3 eggs, 2 1/2 cup flour, 1 tsp salt,

1 tsp vanilla and 1.5 cups sugar and mix them together. Bake for 10
minutes at 375. Yum!”;

6. string recipe = mySuperChef.GetRecipe(56);
7. After running all of the lines that will compile above, what’s the value of recipe?

you are here 4   195

leaving something to the imagination

Here’s a class with some private fields. Circle the statements below
that won’t compile if they’re run from outside the class using an
instance of the object called mySuperChef.

class SuperChef
{
public string cookieRecipe;
private string secretIngredient;
private const int loyalCustomerOrderAmount = 60;
public int Temperature;
private string ingredientSupplier;

public string GetRecipe (int orderAmount)
{
		
if (orderAmount >= loyalCustomerOrderAmount)
		
{
			
return cookieRecipe + “ ” + secretIngredient;
		
}
		
else
ret
		
{
The only way to get the secole
wh
a
er
ord
			
return cookieRecipe;
to
is
ingredient
e
		
}
lot of cookies. Outside codect
ly.
dir
ld
fie
}
is
th
can’t access
}
1. string ovenTemp = mySuperChef.Temperature;
2. string supplier = mySuperChef.ingredientSupplier;
3. int loyalCustomerOrderAmount = 54;
4. mySuperChef.secretIngredient = “cardamom”;

#1 doesn’t compile because you
can’t just assign an int to a
string.

#2 and #4 don’t compile
because ingredientSupplier and
secretIngredient are private.

5. mySuperChef.cookieRecipe = “Get 3 eggs, 2 1/2 cup flour, 1 tsp salt,

1 tsp vanilla and 1.5 cups sugar and mix them together. Bake for 10
Even though you created a local variabl
minutes at 375. Yum!”;
e

6. string recipe =

loyalCustomerAmount and set it to 54, called
that
mySuperChef.GetRecipe(56); didn’t change the object’s loyalCustomerA
value, which is still 60—so it won’t prin mount
t the
secret ingredient.

7. After running all of the lines that will compile above, what’s the value of recipe?

“Get 3 eggs, 2 1/2 cup flour, 1 tsp salt, 1 tsp vanilla and 1.5 cups sugar and mix them together.
Bake for 10 minutes at 375. Yum!”

196   Chapter 5

encapsulation
Something’s really not right here. If I make a
field private, all that does is keep my program from
compiling another class that tries to use it. But if I
just change the “private” to “public” my program builds
again! Adding “private” just broke my program. So why
would I ever want to make a field private?

Because sometimes you want your class
to hide information from the rest of the
program.
A lot of people find encapsulation a little odd the first time
they come across it because the idea of hiding one class’s
fields, properties, or methods from another class is a little
counterintuitive. But there are some very good reasons that
you’ll want to think about what information in your class
to expose to the rest of the program.

Encapsulation make s your classe s…
≥≥ Easy to use
You already know that classes use fields to keep track of their state. And a lot
of them use methods to keep those fields up to date—methods that no other
class will ever call. It’s pretty common to have a class that has fields, methods,
and properties that will never be called by any other class. If you make those
members private, then they won’t pop up in the IntelliSense window later
when you need to use that class.
≥≥ Easy to maintain
Remember that bug in Kathleen’s program? It happened because the form
accessed a field directly rather than using a method to set it. If that field had
been private, you would have avoided that bug.
≥≥ Flexible
A lot of times, you’ll want to go back and add features to a program you
wrote a while ago. If your classes are well encapsulated, then you’ll know
exactly how to use them later on.

Encapsulation
means having
one class hide
information
from another.
It helps you
prevent bugs in
your programs.

How could building a poorly encapsulated class now
make your programs harder to modify later?

you are here 4   197

mike’s mess

Mike’s navigator program could use be t ter encapsulation
Remember Mike’s street navigation program from Chapter 3? Mike joined a
geocaching group, and he thinks his navigator will give him an edge. But it’s been a
while since he’s worked on it, and now he’s run into a little trouble. Mike’s navigator
program has a Route class that stores a single route between two points. But he’s
running into all sorts of bugs because he can’t seem to figure out how it’s supposed
to be used! Here’s what happened when Mike tried to go back to his navigator and
modify the code:

≥≥ Mike set the StartPoint property to the GPS coordinates of his home
and the EndPoint property to the coordinates of his office, and checked
the Length property. It said the length was 15.3. When he called the
GetRouteLength() method, it returned 0.

Geocaching is a sport where people
use their GPS navigators to hide
and seek containers that can be
hidden anywhere in the world.
Mike is really into GPS stuff, so
you can see why he likes it so much.
Ugh, I can’t
remember if
I was supposed to set the
StartPoint field or use the
SetStartPoint() method. I know
I had this all working before!

≥≥ He uses the SetStartPoint() property to set the start point to the
coordinates of his home and the SetEndPoint() property to set the end
point to his office. The GetRouteLength() method returned 9.51, and
the Length property contained 5.91.
≥≥ When he tried using the StartPoint property to set the starting point and
the SetEndPoint() method to set the ending point, GetRouteLength()
always returned 0 and the Length property always contained 0.
≥≥ When he tried using the SetStartPoint() method to set the starting point
and the EndPoint property to set the ending point, the Length property
contained 0, and the GetRouteLength() method caused the program to
crash with an error that said something about not being able to divide by zero.

Route

Here’s the Route object from Mike’s navigator program. Which properties or
methods would you make private in order to make it easier to use?

StartPoint
EndPoint
Length
GetRouteLength()
GetStartPoint()
GetEndPoint()
SetStartPoint()
SetEndPoint()
ChangeStartPoint()
ChangeEndPoint()

There are lots of ways to solve this problem, all potentially correct! Write down the one you think is best.
198   Chapter 5

encapsulation

Think of an object as a black box
Sometimes you’ll hear a programmer refer to an object as a “black box,”
and that’s a pretty good way of thinking about them. When you call an
object’s methods, you don’t really care how that method works—at least,
not right now. All you care about is that it takes the inputs you gave it and
does the right thing.

When you come back to
code that you haven’t looked
at in a long time, it’s easy
to forget how you intended
it to be used. That’s where
encapsulation can make
your life a lot easier!

thinking
Back in Chapter 3, Mike wastor
.
about how to build his navigaabout how
That’s when he really cared t that
the Route object worked. Bu
was a while ago.

I know my Route object
works! What matters
to me now is figuring
out how to use it for my
geocaching project.

working,
Since then, he got his navigator
time. He
g
lon
a
and he’s been using it for to be really
knows it works well enough m. Now he
useful for his geocaching teaect.
wants to reuse his Route obj

If you
encapsulate
your classes
well today,
that makes
them a lot
easier to reuse
tomorrow.

ut
If only Mike had thought abo
built
ally
gin
ori
he
encapsulation when
n it
the
,
had
he
If
his Route object!
today!
he
dac
hea
a
him
wouldn’t be giving
Right now, Mike just wants to think
about his Route object as a black box.
He wants to feed his coordinates into it
and get a length out of it. He doesn’t
want to think about how the Route
calculates that length…at least, not
right now.

Start Point

Rout

e

Length

End Point
you are here 4   199

good ideas for easy encapsulation

So a well-encapsulated class does
exactly the same thing as one
that has poor encapsulation!

Exactly! The difference is that the wellencapsulated one is built in a way that
prevents bugs and is easier to use.
It’s easy to take a well-encapsulated class and turn it into a poorly
encapsulated class: do a search-and-replace to change every
occurrence of private to public.
And that’s a funny thing about the private keyword: you can
generally take any program and do that search-and-replace, and
it will still compile and work in exactly the same way. That’s one
reason that encapsulation is difficult for some programmers to
understand.
Until now, everything you’ve learned has been about making
programs do things—perform certain behaviors. Encapsulation
is a little different. It doesn’t change the way your program
behaves. It’s more about the “chess game” side of programming:
by hiding certain information in your classes when you design
and build them, you set up a strategy for how they’ll interact later.
The better the strategy, the more flexible and maintainable your
programs will be, and the more bugs you’ll avoid.

And just like chess, there are an almost unlimited number
of possible encapsulation strategies!

200   Chapter 5

encapsulation

A few ideas for encapsulating classes
± Think about ways the fields can be misused.
What can go wrong if they’re not set properly?

± Is everything in your class public?

If your class has nothing but public fields and methods, you probably
need to spend a little more time thinking about encapsulation.

± What fields require some processing or calculation to
happen when they’re set?

Those are prime candidates for encapsulation. If someone writes
a method later that changes the value in any one of them, it could
cause problems for the work your program is trying to do.

The cost of decorations
needs to be figured out first.
Once you know that, you can just add
it up with the cost of the food and
drink to get the total cost.

± Only make fields and methods public if you need to.

If you don’t have a reason to declare something public, don’t. You could
make things really messy for yourself by making all of the fields in your
program public—but don’t just go making everything private, either.
Spending a little time up front thinking about which fields really need to
be public and which don’t can save you a lot of time later.
you are here 4   201

get it, set it, got it, good

Encapsulation keeps your data pristine
Sometimes the value in a field changes as your program does
what it’s supposed to do. If you don’t explicitly tell your program
to reset the value, you can do your calculations using the old
one. When this is the case, you want to have your program
execute some statements any time a field is changed—like
having Kathleen’s program recalculate the cost every time
you change the number of people. We can avoid the problem
by encapsulating the data using private fields. We’ll provide a
method to get the value of the field, and another method to set
the field and do all the necessary calculations.

A quick e xample of encapsulation
A Farmer class uses a field to store the number of cows, and
multiplies it by a number to figure out how many bags of cattle
feed are needed to feed the cows:
class Farmer
{
private int numberOfCows;
}

We’d better make this field private
so nobody can change it without also
changing bagsOfFeed—if they get
out of sync, that’ll create bugs!

The farmer
needs 30 bags
of feed for
each cow.

We used camelCase for the private fields and PascalCase for the
public ones. PascalCase means capitalizing the first letter in every
word in the variable name. camelCase is similar to PascalCase,
except that the first letter is lowercase. That makes the
uppercase letters look like “humps” of a camel.

202   Chapter 5

hi
et

am

public const int FeedMultiplier = 30;
h
lis
We’ll add a method to give
public int GetNumberOfCows()
p
other classes a way to get ccom
{
a
the number of cows.
return numberOfCows;
se
e
}
h

s
the

T

public void SetNumberOfCows(int newNumberOfCows)
{
numberOfCows = newNumberOfCows;
BagsOfFeed = numberOfCows * FeedMultiplier;
}

!

ng

When you create a form to let a user enter the number of cows into a numeric field,
you need to be able to change the value in the numberOfCows field. To do that,
you can create a method that returns the value of the field to the form object:

And here’s a method to set thee
number of cows that makes sur d
the BagsOfFeed field is change
too. Now there’s no way for the
two to get out of sync.

encapsulation

Properties make encapsulation e asier
You can use properties, which are methods that look just like fields to other
objects. A property can be used to get or set a backing field, which is just a
name for a field set by a property.

d to numberOfCows
We’ll rename the private fielThi
s will become the
(notice the lowercase “n”). OfC
ty.
king field for the Number ows proper
private int numberOfCows; bac
You’ll often use proper s by
combining
them with a normal fietie
ld
de
cla
public int NumberOfCows
the declaration for NumberO ration. Here’s
fCows.
{
e
tim
any
t’s run
This is a get accessor. It’s a method .tha
has a return value
It
read
is
y
pert
pro
get
the NumberOfCows
—in this case it
that matches the type of the variable
{
ows property.
returns the value of the private numberOfC

}

set
{

}

}

return numberOfCows;

This is a set accessor that’s called eve
ry time the
NumberOfCows property is set. Even tho
doesn’t look like it has any parameters, ugh the method
called value that contains whatever valu it actually has one
e the field was set to.

numberOfCows = value;
BagsOfFeed = numberOfCows * FeedMultiplier;

You use get and set accessors exactly like fields. Here’s code for a button that sets the
numbers of cows and then gets the bags of feed:
private void button1_Click(object sender, EventArgs e) {
Farmer myFarmer = new Farmer();
myFarmer.NumberOfCows = 10;

int howManyBags = myFarmer.BagsOfFeed;
myFarmer.NumberOfCows = 20;
}

howManyBags = myFarmer.BagsOfFeed;

When this line sets
NumberOfCows to 10, the
set accessor sets the
private numberOfCows field
and then updates the public
BagsOfFeed field.

Since the NumberOfCows set
accessor updated BagsOfFeed,
now you can get its value.

berOfCows like
Even though the code treats Numpas
it 20.
a field, it runs the set accessor, dsing
d it runs
fiel
And when it queries the BagsOfFee .
the get accessor, which returns 300
you are here 4   203

private property (no trespassing)

Build an application to te st the Farmer class
Create a new Windows Forms application that we can use to test the Farmer class and
see properties in action. We’ll use the Console.WriteLine() method to write the
results to the output window in the IDE.
1

Do this

Add the Farmer class to your project:
class Farmer {
public int BagsOfFeed;
public const int FeedMultiplier = 30;

}

2

private int numberOfCows;
public int NumberOfCows {
(add the get and set accessors from the previous page)
}

Build this form:

Name this button “calculate”—it
uses the public Farmer data to
write a line to the output.
3

Set the NumericUpDown
control’s Value to 15, its
Minimum to 5, and its
Maximum to 300.

Here’s the form for the code. It uses Console.WriteLine() to send its output to the Output
window (which you can bring up by selecting “Output” from the Debug >> Windows menu). You
can pass several parameters to WriteLine()—the first one is the string to write. If you include
“{0}” inside the string, then WriteLine() replaces it with the first parameter. It replaces “{1}”
with the second parameter, “{2}” with the third, etc.
public partial class Form1 : Form {
Farmer farmer;
public Form1() {
InitializeComponent();
farmer = new Farmer() { NumberOfCows = 15 };
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e) {
farmer.NumberOfCows = (int)numericUpDown1.Value;
}
private void calculate_Click(object sender, EventArgs e) {
Console.WriteLine(“I need {0} bags of feed for {1} cows”,
farmer.BagsOfFeed, farmer.NumberOfCows);
}
Use the Console.WriteLine()
WriteLine() replaces “{0}” with the
}

method to send a line of text
to the IDE’s Output window.

204   Chapter 5

value in the first parameter, and “{1}”
with the second parameter.

encapsulation

Use automatic properties to finish the class
It looks like the Cow Calculator works really well. Give it a shot—run it and click the button. Then change the number
of cows to 30 and click it again. Do the same for 5 cows and then 20 cows. Here’s what your Output window should
look like:

But there’s a problem with the class. Add a button to the form that executes this statement:

Can you see how this
could lead you to
accidentally add a
really irritating bug
in your program?

farmer.BagsOfFeed = 5;
Now run your program again. It works fine until you press the new button. But press that button and then press
the Calculate button again. Now your ouput tells you that you need 5 bags of feed—no matter how many cows
you have! As soon as you change the NumericUpDown, the Calculate button should work again.

Fully encapsulate the Farmer class
The problem is that your class isn’t fully encapsulated. You used properties to encapsulate
NumberOfCows, but BagsOfFeed is still public. This is a common problem. In fact, it’s so common that C#
has a way of automatically fixing it. Just change the public BagsOfFeed field to an automatic property.
And the IDE makes it really easy for you to add automatic properties. Here’s how:
The prop-tab-tab

code snippet
adds an automatic property to
your code.

1

Remove the BagsOfFeed field from the Farmer class. Put your cursor where the field used to
be, and then type prop and press the tab key twice. The IDE will add this line to your code:

public int MyProperty { get; set; }
2

Press the tab key—the cursor jumps to MyProperty. Change its name to BagsOfFeed:

public int BagsOfFeed { get; set; }

Now you’ve got a property instead of a field. When C# sees this, it works exactly the same as if you had
used a backing field (like the private numberOfCows behind the public NumberOfCows property).
3

That hasn’t fixed our problem yet. But there’s an easy fix—just make it a read-only property:

public int BagsOfFeed { get; private set; }
Try to rebuild your code—you’ll get an error on the line in the button that sets BagsOfFeed telling
you that the set accessor is inaccessible. You can’t modify BagsOfFeed from outside the
Farmer class—you’ll need to remove that line in order to get your code to compile, so remove the
button from the form. Now your Farmer class is better encapsulated!
you are here 4   205

set it up

What if we want to change the feed multiplier?
We built the Cow Calculator to use a const for the feed multiplier. But what if we
want to use the same Farmer class in different programs that need different feed
multipliers? You’ve seen how poor encapsulation can cause problems when you
make fields in one class too accessible to other classes. That’s why you should only
make fields and methods public if you need to. Since the Cow Calculator
never updates FeedMultiplier, there’s no need to allow any other class to set it.
So let’s change it to a read-only property that uses a backing field.
This property
1

Remove this line from your program:
public const int FeedMultiplier = 30;

Use prop-tab-tab to add a read-only property. But instead of adding
an automatic property, use a backing field:

Do this!

acts just like an int field,t
value it jus
except instead of storing afee
dMultiplier.
returns the backing field,accessor, it’s
And since there’s no set get, which
read-only. It has a public read the value
means any other class can ce its set is
of FeedMultiplier. But sind-only— it can
private, that makes it rea of Farmer.
only be set by an instance

private int feedMultiplier;
public int FeedMultiplier { get { return feedMultiplier; } }

we changed its name, so it
Since we changed FeedMultiplier from a public const to a private int field,you’ll
see throughout the book.
starts with a lowercase “f”. That’s a pretty standard naming convention
2

Go ahead and make that change to your code. Then run it. Uh-oh—something’s wrong!
BagsOfFeed always returns 0 bags.

Wait, that makes sense. FeedMultiplier never got initialized. It starts out with the
default value of zero and never changes. When it’s multiplied by the number of cows,
it still gives you zero. So add an object initializer:

public Form1() {
InitializeComponent();
farmer = new Farmer() { NumberOfCows = 15, feedMultiplier = 30 };

Uh-oh—the program won’t compile! You should get this error:

You can only initialize public fields and properties inside an object initializer.
So how can you make sure your object gets initialized properly if some of
the fields that need to be initialized are private?

206   Chapter 5

encapsulation

Use a constructor to initialize private fields
If you need to initialize your object, but some of the fields that need to be initialized
are private, then an object initializer just won’t do. Luckily, there’s a special method that
you can add to any class called a constructor. If a class has a constructor, then that
constructor is the very first thing that gets executed when the class is created with
the new statement. You can pass parameters to the constructor to give it values that need
to be initialized. But the constructor does not have a return value, because you don’t
actually call it directly. You pass its parameters to the new statement. And you already
know that new returns the object—so there’s no way for a constructor to return anything.
1

All you have to do to
add a constructor
to a class is add a
method that has the
same name as the
class and no return
value.

Add a constructor to your Farmer class
This constructor only has two lines, but there’s a lot going on here. So let’s take it step by step. We already know
that we need the number of cows and a feed multiplier for the class, so we’ll add them as parameters to the
constructor. Since we changed feedMultiplier from a const to an int, now we need an initial value for
it. So let’s make sure it gets passed into the constructor. We’ll use the constructor to set the number of cows, too.

after
Notice how there’s no “void” or “int” or another type
n value.
retur
a
have
The “this”
don’t
rs
“public”. That’s because constructo
keyword in this.
feedMultiplier tells public Farmer(int numberOfCows, int feedMultiplier) {
C# that you’re
this.feedMultiplier = feedMultiplier; The first thing we’ll do
talking about the
is set the feed multi er
,
field, not the
NumberOfCows = numberOfCows;
because it needs to bepliset
parameter with the
} If we just set the private numberOfCows field, the NumberOfCows set accessor before we can call the
same name.
NumberOfCows set accesso
r.
would never be called. Setting NumberOfCows makes sure it’s called.
This is the error
you’ll get if
your constructor
takes parameters
but your new
doesn’t have any.
2

Now change the form so that it uses the constructor
The only thing you need to do now is change the form so that the new statement that creates the Farmer
object uses the constructor instead of an object initializer. Once you replace the new statement, both errors will
go away, and your code will work!
form is an

You already know that the
object. Well, it’s got a constructor too!
That’s what this method is—notice how
it’s named Form1 (like the class) and it
doesn’t have a return value.

public Form1() {
InitializeComponent();
farmer = new Farmer(15, 30);
}
Here’s where the new statement calls the constructor. It looks just like any other new
statement, except that it has parameters that it passes into the constructor method.
When you type it in, watch for the IntelliSense pop-up—it looks just like any other method.

you are here 4   207

constructors deconstructed

Constructors
Way Up Close
Constructors don’t
return anything, so
there’s no return type.

Let’s take a closer look at the Farmer constructor so we can get a good sense
of what’s really going on.

This constructor has two parameters, which work just likecows,
ordinary parameters. The first one gives the number of
and the second one is the feed multiplier.

public Farmer(int numberOfCows, int feedMultiplier) {
We need to set the feed multiplier first,
this.feedMultiplier = feedMultiplier; because the second statement calls the
NumberOfCows set accessor, which needs
NumberOfCows = numberOfCows;
feedMultiplier to have a value in order to
set BagsOfFeed.
} We need a way to differentiate the field called Since “this” is
always a reference to the current object, this.feedMultiplier
feedMultiplier from the parameter with the
refers to the field. If you leave “this” off, then feedMultiplier refers
same name. That’s where the “this” keyword
to the parameter. So the first line in the constructor sets the private
comes in really handy.
feedMultiplier field equal to the second parameter of the constructor.

Q:

Is it possible to have a constructor without any
parameters?

A:

Yes. It’s actually very common for a class to have a
constructor without a parameter. In fact, you’ve already seen an
example of it—your form’s constructor. Look inside a newly
added Windows form and find its constructor’s declaration:

public Form1() {
InitializeComponent();
}
That’s the constructor for your form object. It doesn’t take
any parameters, but it does have to do a lot. Take a minute
and open up Form1.Designer.cs. Find the
InitializeComponent() method by clicking on the plus
sign next to “Windows Form Designer generated code”.
That method initializes all of the controls on the form and sets
all of their properties. If you drag a new control onto your form
in the IDE’s form designer and set some of its properties in the
Properties window, you’ll see those changes reflected inside the
InitializeComponent() method.

208   Chapter 5

The InitializeComponent() method is called inside
the form’s constructor so that the controls all get initialized as soon as
the form object is created. (Remember, every form that gets displayed
is just another object that happens to use methods that the .NET
Framework provides in the System.Windows.Forms
namespace to display windows, buttons, and other controls.)

When a method’s parameter
has the same name as a
field, then it masks the
field.
Did you notice how the constructor’s
feedMultiplier parameter looks just like
the backing field behind the FeedMultiplier
property? If you wanted to use the backing
field inside the constructor, you’d use the this
keyword: feedMultiplier refers to the
parameter, and this.feedMultiplier is how
you’d access the private field.

encapsulation

Q:

Why would I need complicated
logic in a get or set accessor? Isn’t it just
a way of creating a field?

A:

Because sometimes you know that
every time you set a field, you’ll have to do
some calculation or perform some action.
Think about Kathleen’s problem—she ran
into trouble because the form didn’t run
the method to recalculate the cost of the
decorations after setting the number of
people in the DinnerParty class. If we
replaced the field with a set accessor, then
we could make sure that the set accessor
recalculates the cost of the decorations. (In
fact, you’re about to do exactly that in just a
couple of pages!)

Q:

Wait a minute—so what’s the
difference between a method and a get or
set accessor?

A:

There is none! Get and set accessors
are a special kind of method—one that looks
just like a field to other objects, and is called
whenever that field is set. Get accessors
always return a value that’s the same type
as the field, and set accessors always take
exactly one parameter called value
whose type is the same as the field. Oh,
and by the way, you can just say “property”
instead of “get and set accessor.”

Q:

If a set accessor always takes a
parameter called value, why doesn’t
its declaration have parentheses
with “int value” in them, like you’d
have with any other method that takes a
parameter called value?

A:

Because C# was built to keep you from
having to type in extra information that the
compiler doesn’t need. The parameter gets
declared without you having to explicitly type
it in, which doesn’t sound like much when
you’re only typing one or two—but when you
have to type a few hundred, it can be a real
time saver (not to mention a bug preventer).

Every set accessor always has exactly one
parameter called value, and the type of
that parameter always matches the type
of the property. C# has all the information
it needs about the type and parameter as
soon as you type “set {”. So there’s no
need for you to type any more, and the C#
compiler isn’t going to make you type more
than you have to.

Q:
A:

Wait a sec—is that why I don’t add a
return value to my constructor?

Q:

Exactly! Your constructor doesn’t have
a return value because every constructor
is always void. It would be redundant to
make you type “void” at the beginning of
each constructor, so you don’t have to.

A:

Can I have a get without a set or a
set without a get?

So you can have ANY kind of
statement in a property?

Absolutely. Anything you can do in a
method, you can do in a property. They can
call other methods, access other fields, even
create objects and instances. But they only
get called when a property gets accessed,
so it doesn’t make sense to have any
statements in them that don’t have to do with
getting or setting the property.

Q:

A:

Yes! When you have a get accessor
but no set, you create a read-only property.
For example, the SecretAgent class
might have a ReadOnly field for the
name:

string name = “Dash Martin”;
public string Name {
get { return name; }
}
And if you create a property with a set
accessor but no get, then your backing
field can only be written, not read. The
SecretAgent class could use that for a
Password property that other spies could
write to but not see:
public string Password {
set {
if (value == secretCode) {
name = “Herb Jones”;
}
}
Both of those techniques can come in really
handy when you’re doing encapsulation.

Q:

I’ve been using objects for a while,
but I haven’t written a constructor. Does
that mean some classes don’t need one?

A:

No, it just means that C# automatically
makes a zero-parameter constructor if
there’s none defined. If you define a
constructor, then it doesn’t do that. That’s a
valuable tool for encapsulation, because it
means that you have the option—but not the
requirement—to force anyone instantiating
your class to use your constructor.

Properties (get and set
accessors) are a special
kind of method that’s
only run when another
class reads or writes a
property.
you are here 4   209

what’s in a name?

Take a look at the get and set accessors here. The form that is using this
class has a new instance of CableBill called thisMonth and calls
the GetThisMonthsBill() method with a button click. Write down
the value of the amountOwed variable after the code below executed.

class CableBill {
private int rentalFee;
public CableBill(int rentalFee) {
this.rentalFee = rentalFee;
discount = false;
}
private int payPerViewDiscount;
private bool discount;
public bool Discount {
set {
discount = value;
if (discount)
payPerViewDiscount = 2;
else
payPerViewDiscount = 0;
}
}

}

public int CalculateAmount(int payPerViewMoviesOrdered) {
return (rentalFee - payPerViewDiscount) * payPerViewMoviesOrdered;
}

1. CableBill january = new CableBill(4);
MessageBox.Show(january.CalculateAmount(7).ToString());

What’s the value of
amountOwed?

2. CableBill february = new CableBill(7);
february.payPerViewDiscount = 1;
What’s the value of
MessageBox.Show(february.CalculateAmount(3).ToString());
amountOwed?

3. CableBill march = new CableBill(9);
march.Discount = true;
MessageBox.Show(march.CalculateAmount(6).ToString());

210   Chapter 5

What’s the value of
amountOwed?

encapsulation

Q:

I noticed that you used uppercase
names for some fields but lowercase
ones for others. Does that matter?

A:

Yes—it matters to you. But it doesn’t
matter to the compiler. C# doesn’t care what
you name your variables, but if you choose
weird names then it makes your code hard to
read. Sometimes it can get confusing when
you have variables that are named the same,
except one starts with an uppercase letter and
the other starts with a lowercase one.

Case matters in C#. You can have two
different variables called Party and
party in the same method. It’ll be
confusing to read, but your code will compile
just fine. Here are a few tips about variable
names to help you keep it straight. They’re
not hard-and-fast rules—the compiler
doesn’t care whether a variable is uppercase
or lowercase—but they’re good suggestions
to help make your code easier to read.
1. When you declare a private field, it should
be in camelCase and start with a lowercase
letter. (It’s called camelCase because it
starts with a lowercase letter and additional
words are uppercase, so they resemble
humps on a camel.)

2. Public properties and methods are in
PascalCase (they start with an uppercase
letter).
3. Parameters to methods should be in
camelCase.
4. Some methods, especially constructors,
will have parameters with the same names
as fields. When this happens, the parameter
masks the field, which means statements
in the method that use the name end up
referring to the parameter, not the field. Use
the this keyword to fix the problem—add
it to the variable to tell the compiler you’re
talking about the field, not the parameter.

This code has problems. Write down what you think is wrong with
the code, and what you’d change.

class GumballMachine {
private int gumballs;
private int price;
public int Price
{
get
{
		
return price;
}
}

public GumballMachine(int gumballs, int price)
{
		
gumballs = this.gumballs;
		
price = Price;
}

public string DispenseOneGumball(int price, int coinsInserted)
{
		
if (this.coinsInserted >= price) { // check the field
			
gumballs -= 1;
			
return “Here’s your gumball”;
		
} else {
			
return “Please insert more coins”;
		
}
}
}
you are here 4   211

encapsulation prevents bugs

Write down the value of the amountOwed variable after the code
below executed.
What’s the value of

1. CableBill january = new CableBill(4);
amountOwed?
MessageBox.Show(january.CalculateAmount(7).ToString());

28

2. CableBill february = new CableBill(7);
february.payPerViewDiscount = 1;
What’s the value of
MessageBox.Show(february.CalculateAmount(3).ToString());
amountOwed?

3. CableBill march = new CableBill(9);
march.Discount = true;
MessageBox.Show(march.CalculateAmount(6).ToString());

won’t compile
What’s the value of
amountOwed?

42

This code has problems. Write down what you think is wrong with
the code, and what you’d change.

Lowercase price refers to the parameter
to
the constructor, not the field. This line
sets
the PARAMETER to the value returne
by the
Price get accessor, but Price hasn’t evend bee
set yet! So it doesn’t do anything useful. n
change the constructor’s parameter to uppeIf you
rcase
Price, this line will work properly.

e wrong
The “this” keyword is onrefthers to the
lls
“gumballs.” this.gumba s refers to the
property, while gumball
parameter.
public GumballMachine(int gumballs, int price) This parameter masks the
private field called Price, and
{
the comment says the method is
		
gumballs = this.gumballs;
supposed to be checking the value
		
price = Price;
of
the price backing field.
}

public string DispenseOneGumball(int price, int coinsInserted)
{
“this” keyword if (this.coinsInserted >= price) { // check the field
The		
a parameter,
is on
			
gumballs -= 1;
re it doesn’t
whe			
return “Here’s your gumball”;
ng. It should be } else {
belo		
price, because
on			
return “Please insert more coins”;
field is masked }
that
		
er.
by a paramet
}

212   Chapter 5

encapsulation

Use what you’ve learned about properties and constructors to fix Kathleen’s Party Planner program.

1

How to fix the Dinner Party calculator
To fix the DinnerParty class, we’ll need to make sure the CalculateCostOfDecorations()
method is called every time NumberOfPeople changes.
;
NumberOfPeople = 10

rm

CalculateCost() returns $650

2

Di

nn

ob

Fo

We need to recalculate the decoration cost
every time the number of people changes.

ject

orations()
CalculateCostOfDec

erParty

If we make sure that the cost of the
decorations is recalculated every time
the number of people is updated, then
CalculateCost() will always return the
right amount.

Add properties and a constructor
All you need to do to fix Kathleen’s problem is make sure the DinnerParty class is well
encapsulated. You’ll start by changing NumberOfPeople to a property that calls
CalculateCostOfDecorations() any time it’s called. Then you’ll add a constructor that
makes sure the instance is initialized properly. Finally, you’ll change the form so it uses the new
constructor. If you do this right, that’s the only change you’ll need to make to the form.
≥≥ You’ll need to create a new property for NumberOfPeople that has a set accessor that calls
CalculateCostOfDecorations(). It’ll need a backing field called numberOfPeople.
≥≥ The NumberOfPeople set accessor needs to have a value to pass as the parameter to
the CalculateCostOfDecorations() method. So add a private bool field called
fancyDecorations that you set every time CalculateCostOfDecorations() is called.
≥≥ Add a constructor that sets up the class. It needs to take three parameters for the number of people,
Healthy Option, and fancy decorations. The form currently calls two methods when it initializes
the DinnerParty object—move them into the constructor:
dinnerParty.CalculateCostOfDecorations(fancyBox.Checked);
dinnerParty.SetHealthyOption(healthyBox.Checked);
≥≥ Here’s the constructor for the form—everything else in the form stays the same:
public Form1() {
InitializeComponent();
dinnerParty = new DinnerParty((int)numericUpDown1.Value,
healthyBox.Checked, fancyBox.Checked);
DisplayDinnerPartyCost();
}

you are here 4   213

exercise solution

Use what you’ve learned about properties and constructors to fix Kathleen’s Party Planner
program.

class DinnerParty {
const int CostOfFoodPerPerson = 25;

Now that numberOfPeople is private, there’s
no way for the form to change it without
also recalculating the cost of the decorations.
That’ll fix the bug that almost cost Kathleen
one of her best clients!

private int numberOfPeople;
public int NumberOfPeople {
get { return numberOfPeople; }
set {
numberOfPeople = value;
CalculateCostOfDecorations(fancyDecorations);
}
}
private bool fancyDecorations;
public decimal CostOfBeveragesPerPerson;
public decimal CostOfDecorations = 0;

By using a property, you can make
sure that the cost of decorations is
recalculated every time the number
of people changes.

public DinnerParty(int numberOfPeople, bool healthyOption, bool fancyDecorations) {
NumberOfPeople = numberOfPeople;
this.fancyDecorations = fancyDecorations;
Be careful how you use
SetHealthyOption(healthyOption);
You’ll need it to tell
“this.”.
CalculateCostOfDecorations(fancyDecorations);
between the
difference
the
}

parameter and private field

public void SetHealthyOption(bool healthyOption) {
named numberOfPeople.
if (healthyOption) {
CostOfBeveragesPerPerson = 5.00M;
So you’ll need
Make sure you store the
} else {
put “this.”
to
CostOfBeveragesPerPerson = 20.00M; fancy decora
tions in a field
of
front
in
}
so the NumberOfPeople set
}
“fancyDecorations”

accessor can use it.

public void CalculateCostOfDecorations(bool fancy) {
fancyDecorations = fancy;
if (fancy) {
CostOfDecorations = (NumberOfPeople * 15.00M) + 50M;
} else {
CostOfDecorations = (NumberOfPeople * 7.50M) + 30M;
}
}

because the
fancyDecorations
parameter masks
the private field
with the same name.

public decimal CalculateCost(bool healthyOption) {
decimal totalCost = CostOfDecorations
+ ((CostOfBeveragesPerPerson + CostOfFoodPerPerson) * NumberOfPeople);

}

}

if (healthyOption) {
return totalCost * .95M;
} else {
return totalCost;
}

214   Chapter 5

6 inheritance

Your object’s family tree
So there I was riding my bicycle
object down Dead Man’s Curve
when I realized it inherited from
TwoWheeler and I forgot to add a
Brakes() method...long story short,
twenty-six stitches and Mom said I’m
grounded for a month.

Sometimes you DO want to be just like your parents.
Ever run across an object that almost does exactly what you want your object to do?
Found yourself wishing that if you could just change a few things, that object would
be perfect? Well, that’s just one reason that inheritance is one of the most powerful
concepts and techniques in the C# language. Before you’re through with this chapter,
you’ll learn how to subclass an object to get its behavior, but keep the flexibility to
make changes to that behavior. You’ll avoid duplicate code, model the real world
more closely, and end up with code that’s easier to maintain.
this is a new chapter   215

happy birthday baby

Kathleen doe s birthday partie s, too
Now that you got your program working, Kathleen is using it all the
time. But she doesn’t just handle dinner parties—she does birthdays
too, and they’re priced a little differently. She’ll need you to add
birthdays to her program.

I just got a call for a
birthday party for 10 people.
Can your program handle that?

These are both the same
as the dinner party.
Cost Estimate for a Birthday Party
• $25 per person.

ns. If a client
• There are two options for the cost of decoratio
n with a $30
perso
per
$7.50
it’s
ns,
goes with the normal decoratio
rations
deco
party
the
de
upgra
decorating fee. A client can also
$50 onea
with
n
perso
per
$15
to the “Fancy Option”—that costs
time decorating fee.
8-inch cake ($40),
• When the party has four people or less, use an
Otherwise, she uses a 16-inch cake ($75).

Most of the change
have to do with cakess
and writing.

216   Chapter 6

The 8-inch cake can
• Writing on the cake costs $.25 for each letter.
one can have up
ch
16-in
the
and
g,
have up to 16 letters of writin
to 40 letters of writing.
es. Use a tab control,
The application should handle both types of parti
one tab for each kind of party.

inheritance

We need a BirthdayPart y class
Modifying your program to calculate the cost of Kathleen’s
birthday parties means adding a new class and changing the
form to let you handle both kinds of parties.

Here’s what we’re going to do:
1

Q:

Create a new BirthdayParty class
Your new class will need to calculate the costs, deal with
decorations, and check the size of the writing on the cake.

BirthdayParty
NumberOfPeople
CostOfDecorations
CakeSize
CakeWriting
CalculateCostOfDecorations()
CalculateCost()

2

Add a TabControl to your form
Each tab on the form is a lot like the GroupBox control you used
to choose which guy placed the bet in the Betting Parlor lab. Just
click on the tab you want to display, and drag controls into it.

3

Label the first tab and move the Dinner Party controls into it
You’ll drag each of the controls that handle the dinner party into the new tab.
They’ll work exactly like before, but they’ll only be displayed when the dinner
party tab is selected.

4

Label the second tab and add new Birthday Party controls to it
You’ll design the interface for handling birthday parties just like you did for the
dinner parties.

5

Wire your birthday party class up to the controls
Now all you need to do is add a BirthdayParty reference to the form’s fields, and
add the code to each of your new controls so that it uses its methods and properties.

Why can’t we just create a new instance of

DinnerParty, like Mike did when he wanted to compare
three routes in his navigation program?

A:

You’ll do all this in a
minute—but first you’ll
need to get a sense of
what the job involves.

Because if you created another instance of the DinnerParty
class, you’d only be able to use it to plan extra dinner parties. Two
instances of the same class can be really useful if you need to manage
two different pieces of the same kind of data. But if you need to store
different kinds of data, you’ll need different classes to do it.

Q:
A:

How do I know what to put in the new class?

Before you can start building a class, you need to know
what problem it’s supposed to solve. That’s why you had to talk to
Kathleen—she’s going to be using the program. Good thing you took
a lot of notes! You can come up with your class’s methods, fields, and
properties by thinking about its behavior (what it needs to do) and its
state (what it needs to know).

you are here 4   217

another kind of party

Build the Part y Planner version 2.0
Start a new project—we’re going to build Kathleen a new version of her
program that handles birthdays and dinner parties. We’ll start by creating a wellencapsulated BirthdayParty class to do the actual calculation.

Make sure you use decimal as
the type for the fields and
properties that hold currency.

Do this!
1

BirthdayParty
NumberOfPeople
CostOfDecorations
CakeSize
CakeWriting
CalculateCostOfDecorations()
CalculateCost()

Add the new BirthdayParty class to your program
You already know how you’ll handle the NumberOfPeople property
and the CostOfDecorations method—they’re just like their
counterparts in DinnerParty. We’ll start by creating your new class
and adding those, and then we’ll add the rest of the behavior.
≥≥ Add a public int field called CakeSize. You’ll be adding a
private method called CalculateCakeSize() that sets
CakeSize to either 8 or 16 depending on the number of people.
So first we’ll add the constructor and the NumberOfPeople set
accessor. We’ll also add a couple more fields and a constant.

using System.Windows.Forms;

Make sure you’ve added this using statement to the top of
the class, because you’ll be calling MessageBox.Show().

class BirthdayParty {
public const int CostOfFoodPerPerson = 25;
public decimal CostOfDecorations = 0;
private bool fancyDecorations;
public int CakeSize;

When the BirthdayParty object is initialized, it needs
to know the number of people, the kind of decorations,
and the writing on the cake, so it can start out with
the right cake cost when CalculateCost() is called.

public BirthdayParty(int numberOfPeople,
bool fancyDecorations, string cakeWriting)
{
this.numberOfPeople = numberOfPeople;
The constructor’s calling the set accessor to
this.fancyDecorations = fancyDecorations;
set the cake writing, in case the parameter
CalculateCakeSize();
is too long for the cake, so it’s got to
this.CakeWriting = cakeWriting;
the cake size first.
CalculateCostOfDecorations(fancyDecorations); calculate
}

The constructor sets the properties
and then runs the calculations.

218   Chapter 6

inheritance

≥≥ You’ll need a CakeWriting string property to hold the writing on
the cake. The CakeWriting set accessor checks CakeSize because
different sizes of cake can hold different numbers of letters. Then it uses
value.Length to check how long the string is. If it’s too long, instead
of setting the private field, the set accessor pops up a message box that
says, “Too many letters for a 16-inch cake” (or 8-inch cake).
≥≥ And you’ll need that CalculateCakeSize() method, too. Here it is:
private void CalculateCakeSize() {
if (NumberOfPeople <= 4)
ize() method sets
eS
CakeSize = 8;
ak
C
te
la
cu
al
C
The
called by the
else
akeSize field. It’s cessor and the
C
e
th
CakeSize = 16;
t ac
NumberOfPeople seethod.
}
)m

CalculateCost(

This property is a little more
complex than the ones you’ve seen
before. It checks the cake size to
see if it’s too long for the cake,
using the maxLength variable to
store the maximum length. If it’s
too long, it gives an error message
and then cuts the backing field
down to the right size, so it can be
reloaded into the text box.

private string cakeWriting = “”;
public string CakeWriting {
Here’s where the CakeWriting property
get { return this.cakeWriting; }
makes sure that the cake’s writing is
set {
never too long for the cake size. Its set
int maxLength;
accessor checks the cake size, then uses
Did you notice how if (CakeSize == 8)
the backing field’s Length property to
maxLength = 16;
we left out some
make sure it’s not too long. If it is, it
else
of the brackets?
cuts the string down to the right size.
maxLength = 40;
When you only have
one statement in a if (value.Length > maxLength) {
MessageBox.Show(“Too many letters for a ” + CakeSize + “ inch cake”);
code block, you don’t
if (maxLength > this.cakeWriting.Length)
need to add curly
maxLength = this.cakeWriting.Length;
brackets around it.
this.cakeWriting = cakeWriting.Substring(0, maxLength);
Every string has a Substring() method that returns a
}
else
portion of the string. This one cuts it down to the
this.cakeWriting = value;
allowed length, so you’ll need to reload the writing into
}
the textbox when the text or cake size changes.
}

blocks
e
lin
le
ng
si
r
fo
al
on
ti
op
e
ar
ts
ke
Curly brac
that’s just got a single

tement or while loop
A lot of times you’ll have an if sta t happens a lot, you can end up with a whole lot
m
statement inside its block. When tha
e! C# helps you avoid that proble
sor
eye
l
rea
a
be
can
t
tha
and
this is
of curly brackets—
if there’s just one statement. So
ts
cke
bra
ly
cur
the
op
dr
you
g
by lettin
and an if statement:
perfectly valid syntax for a loop
if (myValue == 36)
			
)
i++
;
10
<
i
0;
=
i
for (int
myValue *= 5;
);					
b(i
eJo
Th
Do
		
you are here 4  

219

kathleen’s gonna love this

Keep on going with the BirthdayParty class…
≥≥ Finish off the BirthdayParty class by adding the CalculateCost()
method. But instead of taking the decoration cost and adding the cost of
beverages (which is what happens in DinnerParty), it’ll add the cost of
the cake.

We’re using decimal because we’re dealing with
prices and currency.

public decimal CalculateCost() {
decimal TotalCost = CostOfDecorations + (CostOfFoodPerPerson * NumberOfPeople);
decimal CakeCost;
if (CakeSize == 8)
The CalculateCost() method is a
CakeCost = 40M + CakeWriting.Length * .25M;
lot like the one from DinnerParty,
else
except that it adds the cost of
CakeCost = 75M + CakeWriting.Length * .25M;
the cake instead of the Healthy
return TotalCost + CakeCost;
Choice option.
}

thod cut down

private int numberOfPeople;
Making the CakeWriting me
the
public int NumberOfPeople {
the size of the cake is only half ofsure
get { return numberOfPeople; }
solution. The other half is making gets run
set {
that the CakeWriting set accessor nges.
numberOfPeople = value;
every time the number of people cha
CalculateCostOfDecorations(fancyDecorations);
CalculateCakeSize();
So when the number of people
this.CakeWriting = cakeWriting;
}
changes, the class first
This method is just like the one in
}
recalculates the cake size, and

the DinnerParty class.

}

public void CalculateCostOfDecorations(bool fancy) {
fancyDecorations = fancy;
if (fancy)
CostOfDecorations = (NumberOfPeople * 15.00M) + 50M;
else
CostOfDecorations = (NumberOfPeople * 7.50M) + 30M;
}

220   Chapter 6

then it uses its set accessor for
CakeWriting to cut the text
down—so if a 10-person party
turns into a 4-person one, their
36-letter message will be cut
down to one that’ll fit on the
smaller cake.

inheritance

2

Use a TabControl to add tabs to the form
Drag a TabControl out of the toolbox and onto your form, and
resize it so it takes up the entire form. Change the text of each
tab using the TabPages property: a “…” button shows up in the
Properties window next to the property. When you click it, the IDE
pops up a window that lets you edit the properties of each tab. Set the
Text property of the tabs to “Dinner Party” and “Birthday Party”.

3

Paste the Dinner Party controls onto their tab
Open up the Party Planner program from Chapter 5 in another
IDE window. Select the controls on the tab, copy them, and
paste them into the new Dinner Party tab. You’ll need to
click inside the tab to make sure they get pasted into the right
place (otherwise you’ll get an error about not being able to add a
component to a container of type TabControl).
One thing to keep in mind here: when you copy and paste a control
into a form, you’re only adding the control itself, not the event
handlers for the control. And you’ll need to check to make sure
that the (Name) is set correctly in the Properties window for each of
them. Make sure that each control has the same name as it did in
your Chapter 5 project, and then double-click on each control after
you add it to add a new empty event handler.

4

Click on the tabs to switch
between them. Use the
TabCollection property to
change the text for each
tab. Click the “…” button
next to it and select each
tab’s Text property.

After you drag the Dinner
Party controls onto the tab,
they’ll only be visible when the
Dinner Party tab is selected.

Build the Birthday Party user interface
The Birthday Party GUI has a NumericUpDown control for the number of people, a
CheckBox control for fancy decorations, and a Label control with a 3D border for the cost.
Then you’ll add a TextBox control for the cake writing.

This tab uses the
NumericUpDown, CheckBox,
and Label controls just like
the Dinner Party tab does.
Name them numberBirthday,
fancyBirthday, and
birthdayCost.

Click on the Birthday Party
tab and add the new controls.

Add a TextBox control called
cakeWriting for the writing
on the cake (and a label above
it so the user knows what it’s
for). Use its Text property
to give it a default value of
“Happy Birthday”.
you are here 4   221

finish the form

Keep on going with the code for the form…
5

Put it all together
All the pieces are there—now it’s just a matter of writing a little code to make the controls work.
≥≥ You’ll need fields in your form that have references to a BirthdayParty object and a
DinnerParty object, and you’ll need to instantiate them in the constructor.
≥≥ You already have code for the dinner party controls’ event handlers—they’re in your
Chapter 5 project. If you haven’t double-clicked on the NumericUpDown and CheckBox
controls in the Dinner Party tab to add the event handlers, do it now. Then copy the
contents of each event handler from the Chapter 5 program and paste them in here. Here’s
the code for the form:
public partial class Form1 : Form {
DinnerParty dinnerParty;

BirthdayParty birthdayParty;

The BirthdayParty instance is
initialized in the form’s constructor,
just like the instance of DinnerParty.

public Form1() {

InitializeComponent();

dinnerParty = new DinnerParty((int)numericUpDown1.Value,

healthyBox.Checked, fancyBox.Checked);

DisplayDinnerPartyCost();

birthdayParty = new BirthdayParty((int)numberBirthday.Value,
fancyBirthday.Checked, cakeWriting.Text);

}

DisplayBirthdayPartyCost();

// The fancyBox, healthyBox, and numericUpDown1 event handlers and
// the DisplayDinnerCost() method are identical to the ones in the
// Dinner Party exercise at the end of Chapter 5.

≥≥ Add code to the NumericUpDown control’s event handler method to set the object’s
NumberOfPeople property, and make the Fancy Decorations checkbox work.
private void numberBirthday_ValueChanged(object sender, EventArgs e) {
birthdayParty.NumberOfPeople = (int)numberBirthday.Value;
DisplayBirthdayPartyCost();
The CheckBox and NumericUpDown controls’ event
}
handlers are just like the ones for the dinner party.
private void fancyBirthday_CheckedChanged(object sender, EventArgs e) {
birthdayParty.CalculateCostOfDecorations(fancyBirthday.Checked);
DisplayBirthdayPartyCost();
}

222   Chapter 6

inheritance

≥≥ Use the Events page in the Properties window to add a new
TextChanged event handler to the cakeWriting TextBox. Click
on the lightning bolt button in the Properties window to switch to the
Events page. Then select the TextBox and scroll down until you find the
TextChanged event. Double-click on it to add a new event handler for it.

When you select the
cakeWriting TextBox
and double-click on the
TextChanged row in
the Events page of the
Properties window, the
IDE will add a new event
handler that gets fired
every time the text in
the box changes.
private void cakeWriting_TextChanged(object sender, EventArgs e) {
birthdayParty.CakeWriting = cakeWriting.Text;
DisplayBirthdayPartyCost();
}

≥≥ Add a DisplayBirthdayPartyCost() method and add it to
all of the event handlers so the cost label is updated automatically
any time there’s a change.

}

private void DisplayBirthdayPartyCost() {
cakeWriting.Text = birthdayParty.CakeWriting;
decimal cost = birthdayParty.CalculateCost();
birthdayCost.Text = cost.ToString(“c”);
}

All the intelligence for dealing with the writing, the
number of people, and the cake size is built into the
NumberOfPeople and CakeWriting set accessors, so the
form just has to set and display the values.

The way that the form
handles the cake writing
can be really simple because
the BirthdayParty class
is well encapsulated. All
the form has to do is use
its controls to set the
properties on the object,
and the object takes care
of the rest.

…and you’re done with the form!
you are here 4   223

it lives!

6

Your program’s done—time to run it
Make sure the program works the way it’s supposed to. Check that it
pops up a message box if the writing is too long for the cake. Make sure
the price is always right. If it’s working, you’re done!

Start up the program and go to
the Dinner Party tab. Make sure
that it works just like your old
Party Planner program.

Click on the Birthday Party tab.
Make sure the cost changes when
you change the number of people
or click the Fancy Decorations
checkbox.

When you type in the Cake Writing
text box, the TextChanged event
handler should update the cost
every time you add or remove a
letter.

224   Chapter 6

Does the calculation work
correctly? In this case, 10
people means $25 per person
($250) plus $75 for a 16”
cake plus $7.50 per person
($75) for the non-fancy
decorations plus a $30
decorating fee plus $.25 per
letter for 21 letters on the
cake ($5.25).
So $250 + $75 + $75 + $30
+ $5.25 = $435.25. It works!

inheritance

One more thing…can you add a $100 fee
for parties over 12?
Kathleen’s gotten so much business using your program that she can afford
to charge a little more for some of her larger clients. So what would it take to
change your program to add in the extra charge?
≥≥ Change the DinnerParty.CalculateCost() to check
NumberOfPeople and add $100 to the return value if it’s over 12.
≥≥ Do the exact same thing for BirthdayParty.CalculateCost().
Take a minute and think about how you’d add a fee to both the
DinnerParty and BirthdayParty classes. What code would you write?
Where would it have to go?
Easy enough…but what happens if there are three similar classes? Or four? Or
twelve? And what if you had to maintain that code and make more changes
later? What if you had to make the same exact change to five or six closely
related classes?

Wow, I’d have to write the same
code over and over again. That’s
a really inefficient way to work.
There’s got to be a better way!

You’re right! Having the same code repeated in
different classes is inefficient and error-prone.
Lucky for us, C# gives us a better way to build classes that are
related to each other and share behavior: inheritance.

you are here 4   225

no need to use gold when anything shiny will do

When your classe s use inheritance, you only
need to write your code once
It’s no coincidence that your DinnerParty and BirthdayParty classes have
a lot of the same code. When you write C# programs, you often create classes that
represent things in the real world—and those things are usually related to each other.
Your classes have similar code because the things they represent in the real world—a
birthday party and a dinner party—have similar behaviors.
DinnerParty

Kathleen needs
to figure out
the cost of her
parties, no matter
what kind of
parties they are.

BirthdayParty

NumberOfPeople
CostOfDecorations
HealthyOption
CostOfBeveragesPerPerson

NumberOfPeople
CostOfDecorations
CakeSize
CakeWriting

CalculateCostOfDecorations()
CalculateCost()
SetHealthyOption()

CalculateCostOfDecorations()
CalculateCost()

A birthday party
handles the number
of people and the
cost of decorations
in almost the same
way as a dinner
party.

Dinner partie s and birthday partie s are both parties
When you have two classes that are more specific cases of something more
general, you can set them up to inherit from the same class. When you do that,
each of them is a subclass of the same base class.
Party

Both kinds of parties
have to keep track of the
number of people and the
cost of decorations, so you
can move that into the
base class.
This arrow in
the class diagram
means the
DinnerParty class
inherits from the
Party class.

226   Chapter 6

DinnerParty

NumberOfPeople
HealthyOption
CostOfBeveragesPerPerson
CalculateCost()
SetHealthyOption()

NumberOfPeople
CostOfDecorations

CalculateCostOfDecorations()
CalculateCost()

Both subclasses
inherit the
decoration
calculation from
the base class, so
they don’t need
to include it.

The way both parties handle the
number of people and calculating
the total cost is similar but
distinct. We can break up the
behavior for these things so the
similar part is in the base class,
while putting the distinct pieces
in the two subclasses.
BirthdayParty

NumberOfPeople
CakeSize
CakeWriting
CalculateCost()

inheritance

Build up your class model by starting general
and ge t ting more specific
C# programs use inheritance because it mimics the relationship that the things
they model have in the real world. Real-world things are often in a hierarchy
that goes from more general to more specific, and your programs have their
own class hierarchy that does the same thing. In your class model, classes
further down in the hierarchy inherit from those above it.
General

Food

In a class model,
Cheese might inherit
from DairyProduct,
which would inherit
from Food.

General

Every bird is an
animal, but not every
animal is a bird.

Dairy Product

Cheese

Cheddar

Bird

To someone looking for a
any songbird might do. pet,
to an ornithologist studBut
the mimidae bird family,ying
confusing the Northern
and Southern mockingbi
would be unacceptable. rds

Aged Vermont Cheddar
Specific

If you have a recipe that calls
for cheddar cheese, then you
can use aged Vermont cheddar.
But if it specifically needs aged
Vermont, then you can’t just
use any cheddar—you need that
specific cheese.

Animal

Songbird

Mockingbird

Northern Mockingbird

erits
Something lower on the hierarchy inh hing
most or all of the attributes of everyt
above it. All animals eat and mate, so
Northern Mockingbirds eat and mate.

Specific

in-her-it, verb.

to derive an attribute from one’s
parents or ancestors. She wanted the
baby to inherit her big brown eyes,
and not her husband’s beady blue ones.
you are here 4   227

it’s a jungle out there

How would you de sign a zoo simulator?
Lions and tigers and bears…oh my! Also, hippos, wolves, and the
occasional cat. Your job is to design a program that simulates a zoo. (Don’t
get too excited—we’re not going to actually build the code, just design the
classes to represent the animals.)
We’ve been given a list of some of the animals that will be in the program,
but not all of them. We know that each animal will be represented by
an object, and that the objects will move around in the simulator, doing
whatever it is that each particular animal is programmed to do.
More importantly, we want the program to be easy for other programmers
to maintain, which means they’ll need to be able to add their own classes
later on if they want to add new animals to the simulator.
So what’s the first step? Well, before we can talk about specific animals,
we need to figure out the general things they have in common—the
abstract characteristics that all animals have. Then we can build those
characteristics into a class that all animal classes can inherit from.

1

Look for things the animals have in common
Take a look at these six animals. What do a lion, a hippo, a tiger,
a cat, a wolf, and a dalmatian have in common? How are they
related? You’ll need to figure out their relationships so you can
come up with a class model that includes all of them.

228   Chapter 6

inheritance

Use inheritance to avoid duplicate
code in subclasse s

2

You already know that duplicate code sucks. It’s hard to maintain, and
always leads to headaches down the road. So let’s choose fields and
methods for an Animal base class that you only have to write once,
and each of the animal subclasses can inherit from them. Let’s start with
the public fields:
≥≥ Picture: an image that you can put into a PictureBox.
≥≥ Food: the type of food this animal eats. Right now, there can be only
two values: meat and grass.

Build a base class to give
the animals everything
they have in common
The fields, properties, and methods
in the base class will give all of
the animals that inherit from it
a common state and behavior.
They’re all animals, so it makes
sense to call the base class Animal.

≥≥ Hunger: an int representing the hunger level of the animal. It
changes depending on when (and how much) the animal eats.
≥≥ Boundaries: a reference to a class that stores the height, width, and
location of the pen that the animal will roam around in.
≥≥ Location: the X and Y coordinates where the animal is standing.
In addition, the Animal class has four methods the animals can inherit:
≥≥ MakeNoise(): a method to let the animal make a sound.
≥≥ Eat(): behavior for when the animal encounters its preferred food.
≥≥ Sleep(): a method to make the animal lie down and take a nap.
≥≥ Roam(): the animals like to wander around their pens in the zoo.

Choosing a base class is
about making choices. You
could have decided to
use a ZooOccupant class
that defines the feed
and maintenance costs,
or an Attraction class
with methods for how
the animals entertain the
zoo visitors. But we think
Animal makes the most
sense here. Do you agree?

Animal
Picture
Food
Hunger
Boundaries
Location
MakeNoise()
Eat()
Sleep()
Roam()

Lion
Wolf

Cat
Hippo

Tiger
Dog

you are here 4   229

warning: don’t feed the programmers

Dif ferent animals make dif ferent noise s
Just because a property or a method
is in the Animal base class, that
doesn’t mean every subclass has to use
it the same way…or at all!

Lions roar, dogs bark, and as far as we know hippos don’t
make any sound at all. Each of the classes that inherit from
Animal will have a MakeNoise() method, but each of those
methods will work a different way and will have different code.
When a subclass changes the behavior of one of the methods
that it inherited, we say that it overrides the method.
3

Think about what you need to override
When a subclass changes the behavior of a method it
inherited, we call it overriding. Every animal needs to
eat. But a dog might take little bites of meat, while a hippo
eats huge mouthfuls of grass. So what would the code for
that behavior look like? Both the dog and the hippo would
override the Eat() method. The hippo’s method would have
it consume, say, 20 pounds of hay each time it was called.
The dog’s Eat() method, on the other hand, would reduce
the zoo’s food supply by one 12-ounce can of dog food.

So when you’ve got a subclass
that inherits from a base
class, it must inherit all of
the base class’s behaviors…
but you can modify them in
the subclass so they’re not
performed exactly the same
way. That’s what overriding is
all about.

Figure out what each animal
does that the Animal class does
differently—or not at all
What does each type of animal do that
all the other animals don’t? Dogs eat dog
food, so the dog’s Eat() method will
need to override the Animal.Eat()
method. Hippos swim, so a hippo will have
a Swim() method that isn’t in the Animal
class at all.

Grass is yummy! I
could go for a good
pile of hay right now.
I beg to differ.

Animal
Picture
Food
Hunger
Boundaries
Location
MakeNoise()
Eat()
Sleep()
Roam()

230   Chapter 6

We already know that some animals will override the
MakeNoise() and Eat() methods. Which animals will
override Sleep() or Roam()? Will any of them? What about
the properties—which animals will override some properties?

inheritance

Think about how to group the animals
Aged Vermont cheddar is a kind of cheese, which is a dairy
product, which is a kind of food, and a good class model for food
would represent that. Lucky for us, C# gives us an easy way to do
it. You can create a chain of classes that inherit from each other,
starting with the topmost base class and working down. So you
could have a Food class, with a subclass called DairyProduct
that serves as the base class for Cheese, which has a subclass
called Cheddar, which is what AgedVermontCheddar
inherits from.
4

Look for classes that have a lot
in common
Animal

Don’t dogs and wolves seem pretty similar?
They’re both canines, and it’s a good bet
that if you look at their behavior they have a
lot in common. They probably eat the same
food and sleep the same way. What about
domestic cats, tigers, and lions? It turns out
all three of them move around their habitats
in exactly the same way. It’s a good bet that
you’ll be able to have a Feline class that
lives between Animal and those three cat
classes that can help prevent duplicate code
between them.

Picture
Food
Hunger
Boundaries
Location

There’s a pretty good
chance that we’ll be
able to add a Canine
class that the dogs
and wolves both inherit
from.

MakeNoise()
Eat()
Sleep()
Roam()

Lion

The subclasses
inherit all four
methods from
Animal, but
we’re only having
them override
MakeNoise() and
Eat().

Wolf

MakeNoise()
Eat()
Cat
Hippo

MakeNoise()
Eat()

Tiger
Dog

MakeNoise()
Eat()

MakeNoise()
Eat()

MakeNoise()
Eat()

MakeNoise()
Eat()

That’s why we only
show those two
methods in the
class diagrams.
you are here 4   231

extend your objects

Cre ate the class hierarchy
When you create your classes so that there’s a base class at the top with
subclasses below it, and those subclasses have their own subclasses that
inherit from them, what you’ve built is called a class hierarchy. This is
about more than just avoiding duplicate code, although that is certainly
a great benefit of a sensible hierarchy. But when it comes down to it, the
biggest benefit you’ll get is that your code becomes really easy to understand
and maintain. When you’re looking at the zoo simulator code, when you see
a method or property defined in the Feline class, then you immediately know
that you’re looking at something that all of the cats share. Your hierarchy
becomes a map that helps you find your way through your program.
5

Animal
Picture
Food
Hunger
Boundaries
Location
MakeNoise()
Eat()
Sleep()
Roam()

Finish your class hierarchy
Now that you know how you’ll organize the animals,
you can add the Feline and Canine classes.
Feline

Since Feline overrides Roam(),
anything that inherits from it
gets its new Roam() and not
the one in Animal.

Canine
Roam()
Hippo

Eat()
Sleep()

MakeNoise()
Eat()
Lion

MakeNoise()
Eat()

The three cats roam th
same way, so they shar e
an inherited Roam() e
method. But each on
still eats and makes noe
ise
differently, so they’ll all
override the Eat() d
MakeNoise() methodan
that they inherited s
from Animal.
232   Chapter 6

Dog
Cat
Tiger

MakeNoise()
Eat()

MakeNoise()
Eat()

Our wolves and
dogs eat the
same way, so
we moved their
common Eat()
method up to
the Canine class.

Wolf

MakeNoise()

MakeNoise()

inheritance

Ever y subclass e xtends its
base class
You’re not limited to the methods that a subclass inherits
from its base class…but you already know that! After all,
you’ve been building your own classes all along. When you
add inheritance to a class, what you’re doing is taking the
class you’ve already built and extending it by adding all of
the fields, properties, and methods in the base class. So if you
wanted to add a Fetch() method to the dog, that’s perfectly
normal. It won’t inherit or override anything—only the dog
will have that method, and it won’t end up in Wolf, Canine,
Animal, Hippo, or any other class.

hi-er-ar-chy, noun.

an arrangement or classification
in which groups or things are
ranked one above the other. The
president of Dynamco had worked
his way up from the mailroom to the
top of the corporate hierarchy.

makes a new Dog object

Dog spot = new Dog();

calls the version in Dog

spot.MakeNoise();

calls the version in Animal

spot.Roam();

calls the version in Canine

spot.Eat();

calls the version in Canine

spot.Sleep();

calls the version in Dog

spot.Fetch();

Animal
Picture
Food
Hunger
Boundaries
Location
MakeNoise()
Eat()
Sleep()
Roam()

Canine

Eat()
Sleep()

C# always calls the most specific me thod
If you tell your dog object to roam, there’s only one method that can
be called—the one in the Animal class. But what about telling your
dog to make noise? Which MakeNoise() is called?
Well, it’s not too hard to figure it out. A method in the Dog class tells
you how dogs do that thing. If it’s in the Canine class, it’s telling you
how all canines do it. And if it’s in Animal, then it’s a description of
that behavior that’s so general that it applies to every single animal. So
if you ask your dog to make a noise, first C# will look inside the Dog
class to find the behavior that applies specifically to dogs. If Dog didn’t
have one, it’d then check Canine, and after that it’d check Animal.

Dog

MakeNoise()
Fetch()

you are here 4   233

base how low can you go?

Use a colon to inherit f rom a base class

When a subclass
inherits from a
When you’re writing a class, you use a colon (:) to have it inherit from
a base class. That makes it a subclass, and gives it all of the fields,
base class, all
properties, and methods of the class it inherits from.
of the fields,
class Vertebrate
Vertebrate
NumberOfLegs
{
properties, and
public int NumberOfLegs;
methods in the
public void Eat() {
Eat()
		 // code to make it eat
base class are
}
}
erit from the
automatically
The Bird class uses a colon to inhat it inherits all of
th
ans
Vertebrate class. This me
ods from Vertebrate. added to the
the fields, properties, and meth
subclass.
class Bird : Vertebrate
Bird
Wingspan

Fly()

tweety is an instance
of Bird, so it’s got
the Bird methods
and fields as usual.

{

public double Wingspan;
public void Fly() {
		 // code to make the bird fly
}
}

public button1_Click(object sender, EventArgs e) {
Bird tweety = new Bird();
its
tweety.Wingspan = 7.5;
Since the Bird class inherinstance
tweety.Fly();
from Vertebrate, every s
tweety.NumberOfLegs = 2;
of Bird also has the fieldthe
tweety.Eat();
and methods defined in
}
Vertebrate class.

Q:

Why does the arrow point up, from the subclass to the
base class? Wouldn’t the diagram look better with the arrow
pointing down instead?

A:

It might look better, but it wouldn’t be as accurate. When you
set up a class to inherit from another one, you build that relationship
into the subclass—the base class remains the same. And that makes
sense when you think about it from the perspective of the base class.

234   Chapter 6

You extend a class
by adding a colon to
the end of the class
declaration, followed by
the base class to inherit
from.

Its behavior is completely unchanged when you add a class that
inherits from it. The base class isn’t even aware of this new class
that inherited from it. Its methods, fields, and properties remain
entirely intact. But the subclass definitely changes its behavior. Every
instance of the subclass automatically gets all of the properties, fields,
and methods from the base class, and it all happens just by adding a
colon. That’s why you draw the arrow on your diagram so that it’s part
of the subclass, and points to the base class that it inherits from.

inheritance

Take a look at these class models and declarations, and then
circle the statements that won’t work.
Aircraft

AirSpeed
Altitude

TakeOff()
Land()

class Aircraft {
public double AirSpeed;
public double Altitude;
public void TakeOff() { ... };
public void Land() { ... };
}
class FirePlane : Aircraft {
public double BucketCapacity;
public void FillBucket() { ... };
}

FirePlane

BucketCapacity

FillBucket()

Sandwich

Toasted
SlicesOfBread

CountCalories()

BLT

SlicesOfBacon
AmountOfLettuce

AddSideOfFries()

public void FireFightingMission() {
FirePlane myFirePlane = new FirePlane();
new FirePlane.BucketCapacity = 500;
Aircraft.Altitude = 0;
myFirePlane.TakeOff();
myFirePlane.AirSpeed = 192.5;
myFirePlane.FillBucket();
Aircraft.Land();
}
class Sandwich {
public boolean Toasted;
public int SlicesOfBread;
public int CountCalories() { ... }
}
class BLT
public
public
public
}

: Sandwich {
int SlicesOfBacon;
int AmountOfLettuce;
int AddSideOfFries() { ... }

public BLT OrderMyBLT() {
BLT mySandwich = new BLT();
BLT.Toasted = true;
Sandwich.SlicesOfBread = 3;
mySandwich.AddSideOfFries();
mySandwich.SlicesOfBacon += 5;
MessageBox.Show(“My sandwich has ”
		 + mySandwich.CountCalories + “calories”.);
return mySandwich;
}
you are here 4   235

i can think of one way to make a penguin fly…

Take a look at these class models and declarations, and then
circle the statements that won’t work.
Aircraft

AirSpeed
Altitude

TakeOff()
Land()

class Aircraft {
public double AirSpeed;
public double Altitude;
public void TakeOff() { ... };
public void Land() { ... };
}
class FirePlane : Aircraft {
public double BucketCapacity;
public void FillBucket() { ... };
}

FirePlane

BucketCapacity

FillBucket()

Sandwich

Toasted
SlicesOfBread

CountCalories()

BLT

SlicesOfBacon
AmountOfLettuce

AddSideOfFries()

236   Chapter 6

That’s not how yo
the new keyword. u use

public void FireFightingMission() {
FirePlane myFirePlane = new FirePlane();
new FirePlane.BucketCapacity = 500;
Aircraft.Altitude = 0;
s all use the
myFirePlane.TakeOff();
These statement d of the name
myFirePlane.AirSpeed = 192.5;
class names insteamyFirePlane.
myFirePlane.FillBucket();
of the instance,
Aircraft.Land();
}
class Sandwich {
public boolean Toasted;
public int SlicesOfBread;
public int CountCalories() { ... }
}
class BLT
public
public
public
}

: Sandwich {
int SlicesOfBacon;
int AmountOfLettuce;
int AddSideOfFries() { ...

the
These properties are part of are
instance, but the statements
trying to call them incorrectly
names.
} using the class

public BLT OrderMyBLT() {
CountCalories is a
BLT mySandwich = new BLT();
BLT.Toasted = true;
this statement doemethod, but
Sandwich.SlicesOfBread = 3;
the parentheses () sn’t include
mySandwich.AddSideOfFries();
call to the method after the
mySandwich.SlicesOfBacon += 5;
.
MessageBox.Show(“My sandwich has ”
		 + mySandwich.CountCalories + “calories”.);
return mySandwich;
}

inheritance

We know that inheritance adds the base class
fields, propertie s, and me thods to the subclass…
Inheritance is simple when your subclass
needs to inherit all of the base class
methods, properties, and fields.
Bird

Pigeon is a
subclass of Bird,
so any fields and
methods in Bird
are automatically
part of Pigeon,
too.

Fly()
LayEggs()
PreenFeathers()

public void LayEggs() { ... };
}

Coo()

class Penguin : Bird {
public void Swim() { ... }
}

What do you do if your base class has a
method that your subclass needs to modify?

public void BirdSimulator() {

Izzy is an instance
of Penguin. Since it
inherited the Fly()
method, there’s nothing
stopping it from flying.

Bird

Fly()
LayEggs()
PreenFeathers()

Coo()

public void PreenFeathers() { ... };

class Pigeon : Bird {
public void Coo() { ... }
}

Pigeon

…but some birds don’t fly!

Pigeon

class Bird {
public void Fly() {
// here’s the code to make the bird fly
}

Penguin

Swim()

gs, and
Pigeons fly, lay eghers, so
preen their feat m with the
there’s no probleriting from
Pigeon class inhe
Bird.

}

Pigeon Harriet = new Pigeon();
Penguin Izzy = new Penguin();
Harriet.Fly();
Harriet.Coo();
Izzy.Fly();

Both Pigeon and Penguin
inherit from Bird, so
they both get the
Fly(), LayEggs(), and
PreenFeathers() methods.

Penguin objects shouldn’t be able
But if the Penguin class inherits to fly!
then you’ll have penguins flying from Bird,
all over the
place. So what do we do?

If this were your Bird Simulator code, what would
you do to keep the penguins from flying?

you are here 4   237

manual override

A subclass can override me thods to change
or replace me thods it inherited
Sometimes you’ve got a subclass that you’d like to inherit
most of the behaviors from the base class, but not all of them.
When you want to change the behaviors that a class has
inherited, you can override the methods.
1

Add the virtual keyword to the method in the base class
A subclass can only override a method if it’s marked with the virtual keyword, which
tells C# to allow the subclass to override methods.

class Bird {

public virtual void Fly() {

}
2

}

// code to make the bird fly

Adding the virtual
keyword to the Fly()
method tells C# that
a subclass is allowed to
override it.

Add a method with the same name to the derived class
You’ll need to have exactly the same signature—meaning the same return value and
parameters—and you’ll need to use the override keyword in the declaration.

class Penguin : Bird {

public override void Fly() {

}

}

MessageBox.Show(“Penguins can’t fly!”)

When you override a method, your new
method needs to have exactly the same
signature as the method in the base
class it’s overriding. In this case, that
means it needs to be called Fly, return
void, and have no parameters.

238   Chapter 6

To override the Fly() meth
an identical method to th od, add
and use the override keyw e subclass
ord.

Use the override keyword to
add a method to your subclass
that replaces one that it
inherited. Before you can
override a method, you need to
mark it virtual in the base class.

inheritance
Sandwich

Any place where you can use a base class, you
can use one of its subclasse s inste ad

Toasted
SlicesOfBread

CountCalories()

One of the most useful things you can do with inheritance is use a subclass in
place of the base class it inherits from. So if your Recipe() method takes a
Cheese object and you’ve got an AgedVermontCheddar class that inherits
from Cheese, then you can pass an instance of AgedVermontCheddar to
the Recipe() method. Recipe() only has access to the fields, properties,
and methods that are part of the Cheese class, though—it doesn’t have access
to anything specific to AgedVermontCheddar.
1

BLT

SlicesOfBacon
AmountOfLettuce

Let’s say we have a method to analyze Sandwich objects:

AddSideOfFries()

public void SandwichAnalyzer(Sandwich specimen) {
int calories = specimen.CountCalories();
UpdateDietPlan(calories);
PerformBreadCalculations(specimen.SlicesOfBread, specimen.Toasted);
}
2

You could pass a sandwich to the method—but you could also pass a BLT. Since a BLT is a
kind of sandwich, we set it up so that it inherits from the Sandwich class:
public button1_Click(object sender, EventArgs e) {
BLT myBLT = new BLT();
SandwichAnalyzer(myBLT);
}

3

We’ll talk about this more
in the next chapter!

You can always move down the class diagram—a reference variable can always be set equal
to an instance of one of its subclasses. But you can’t move up the class diagram.
public button2_Click(object sender, EventArgs e) {
You can assign myBLT to any
Sandwich mySandwich = new Sandwich();
Sandwich variable because a BLT
BLT myBLT = new BLT();
is a kind of sandwich.
Sandwich someRandomSandwich = myBLT;
}

BLT anotherBLT = mySandwich;

// <--- THIS WON’T COMPILE!!!

But you can’t assign mySand
wich to a BLT
variable, because not every san
That’s why this last line will dwich is a BLT!
cause an error.
you are here 4   239

get a little practice

Mixed
Messages

a = 6;
b = 5;
a = 5;

56
11
65

A short C# program is listed below. One block of
the program is missing! Your challenge is to match
the candidate block of code (on the left) with
the output—what’s in the message box that the
program pops up—that you’d see if the block were
inserted. Not all the lines of output will be used,
and some of the lines of output might be used more
than once. Draw lines connecting the candidate
blocks of code with their matching output.

Instructions:
1. Fill in the four blanks in the code.
2. Match the code candidates to the output.

class C : B {

class A {
public int ivar = 7;

public ___________ string m1() {
return “A’s m1, ”;
}
public string m2() {
return “A’s m2, ”;
}

}

public ___________ string m3() {
return “A’s m3, ”;
}

class B : A {

}

}

public ___________ string m3() {
return “C’s m3, ” + (ivar + 6);
}

Here’s the entry point for the program—it
doesn’t show a form, it just pops up a message
box

.

class Mixed5 {
public static void Main(string[] args) {
A a = new A();
B b = new B();
Hint: Think really hard about
C c = new C();
what this line really means.
A a2 = new C();
string q = “”;

candidate code
goes here
(three lines)

public ___________ string m1() {
return “B’s m1, ”;
}

code
candidates:

}
}
}
}

q += b.m1();
q += c.m2();
q += a.m3();
q += c.m1();
q += c.m2();
q += c.m3();

}

}

System.Windows.Forms.MessageBox.Show(q);

output:
A’s m1, A’s m2, C’s m3, 6
B’s m1, A’s m2, A’s m3,
A’s m1, B’s m2, A’s m3,
B’s m1, A’s m2, C’s m3, 13

q += a.m1();
q += b.m2();
q += c.m3();

B’s m1, C’s m2, A’s m3,

q += a2.m1();
q += a2.m2();
q += a2.m3();

A’s m1, A’s m2, C’s m3, 13

240   Chapter 6

B’s m1, A’s m2, C’s m3, 6

(Don’t just type this into the IDE—you’ll learn
a lot more if you figure this out on paper!)

inheritance

Pool Puzzle

Your job is to take code snippets from the pool and place them into
the blank lines in the code. You may use the same snippet more
than once, and you might not need to use all the snippets. Your
goal is to make a set of classes that will compile and run together
as a program. Don’t be fooled—this one’s harder than it looks.

class Rowboat

class TestBoats {

{

public

Hint: This is the
entry point for
the program.

Main(){

rowTheBoat() {

xyz = “”;

return “stroke natasha”;

b1 = new Boat();

}
}

Sailboat b2 = new

class

xyz = b1.

Rowboat

();

= new Rowboat();

b2.setLength(32);
{

private int

xyz += b3.

;

void

(

xyz +=

) {

length = len;
}

public int getLength() {

}

: Boat {

class

;
}

public

public
return
}

();
.move();

System.Windows.Forms.MessageBox.Show(xyz);

}

}

();

move() {
“

”;

return “
}

() {
”;

}

OUTPUT:

Rowboat
subclasses
Sailboat
;
override
Boat
Testboats
drift hoist sail
int len
return virtual
rowTheBoat
stroke natasha
continue
int length string
move
int b1
break
b1
setLength
:
void
int b3
public
int b2
b2 b3 length
int static
getLength
int b2
private
len

you are here 4   241

get some practice

Mixed
Messages

class A {

a = 6;
b = 5;
a = 5;

56
11
65

virtual

class B : A {

override

public ___________ string m1() {
...
}

virtual

public ___________ string m3() {

public ___________ string m1() {
...
class C : B {

}
}
}
}

q += c.m1();
q += c.m2();
q += c.m3();

A a2 = new C();

means that you’re instantiating a new C object, and then
creating an A reference called a2 and pointing it at that
object. Names like A, a2, and C make for a good puzzle,
but they’re a little hard to understand. Here are a few lines
that follow the same pattern, but have names that you can
understand:

q += a.m1();
q += b.m2();
q += c.m3();

q += a2.m1();
q += a2.m2();
Cheese ingredient= new AgedVermontCheddar(); q += a2.m3();

Sandwich mySandwich = new BLT();

Songbird tweety = new NorthernMockingbird();

Pool Puzzle Solution
:
string

class Rowboat
public

Boat

Boat

private int

public

void

{

rowTheBoat() {

length ;
setLength

(

int len

) {

242   Chapter 6

A’s m1, B’s m2, A’s m3,
B’s m1, A’s m2, C’s m3, 6
A’s m1, A’s m2, C’s m3, 13

xyz +=

;

virtual string
“
drift
return

}
move() {

move ();
b3. move ();
b2 .move();

System.Windows.Forms.MessageBox.Show(xyz);
}

Sailboat : Boat {
public
override string move
return “ hoist sail
”;

class

”;

}
}

B’s m1, C’s m2, A’s m3,

xyz +=

public int getLength() {

public

B’s m1, A’s m2, C’s m3, 13

b2.setLength(32);

}

}

A’s m1, B’s m2, C’s m3, 6

xyz = b1.

length = len;

return length

B’s m1, A’s m2, A’s m3,

public static void Main(){
string xyz = “”;
Boat b1 = new Boat();
Sailboat b2 = new
Sailboat ();
Rowboat
b3 = new Rowboat();

{

}
class

A’s m1, A’s m2, C’s m3, 6

class TestBoats {

return “stroke natasha”;
}

override

public ___________ string m3() {

q += b.m1();
q += c.m2();
q += a.m3();

You can always substitute a reference to a subclass in place of
a base class. In other words, you can always use something
more specific in place of something more general—so if
you’ve got a line of code that asks for a Canine, you can
send it a reference to a Dog. So this line of code:

}

}

() {

inheritance

Q:

About the entry point that you
pointed out in the Pool Puzzle—does this
mean I can have a program that doesn’t
have a Form1 form?

A:

Yes. When you create a new Windows
Application project, the IDE creates all
the files for that project for you, including
Program.cs (which contains a static class
with an entry point) and Form1.cs (which
contains an empty form called Form1).

Try this: instead of creating a new Windows
Application project, create an empty project
by selecting “Empty Project” instead of
“Windows Application” when you create a
new project in the IDE. Then add a class
file to it in the Solution Explorer and type in
everything in the Pool Puzzle solution. Since
your program uses a message box, you
need to add a reference by right-clicking
on “References” in the Solution Explorer,
selecting “Add Reference”, and choosing
System.Windows.Forms from the .NET tab.
(That’s another thing the IDE does for you
automatically when you create a Windows
Application.) Finally, select “Properties” from
the Project menu and choose the “Windows
Application” output type.
Now run it…you’ll see the results!
Congratulations, you just created a C#
program from scratch.

Flip back to the beginning
of Chapter 2 if you need a
refresher on Main() and the
entry point!

Q:

Can I inherit from the class that
contains the entry point?

A:

Yes. The entry point must be a static
method, but that method doesn’t have
to be in a static class. (Remember, the
static keyword means that the class
can’t be instantiated, but that its methods
are available as soon as the program starts.
So in the Pool Puzzle program, you can
call TestBoats.Main() from any
other method without declaring a reference
variable or instantiating an object using a
new statement.)

Q:

I still don’t get why they’re called
“virtual” methods—they seem real to me!

A:

The name “virtual” has to do with how
.NET handles the virtual methods behind the
scenes. It uses something called a virtual
method table (or vtable). That’s a table that
.NET uses to keep track of which methods
are inherited and which ones have been
overridden. Don’t worry—you don’t need to
know how it works to use virtual methods!

Q:

What did you mean by only being
able to move up the class diagram but
not being able to move down?

A:

When you’ve got a diagram with one
class that’s above another one, the class
that’s higher up is more abstract  than the
one that’s lower down. More specific or
concrete classes (like Shirt or Car)
inherit from more abstract ones (like
Clothing or Vehicle). When you
think about it that way, it’s easy to see how
if all you need is a vehicle, a car or van or
motorcycle will do. But if you need a car, a
motorcycle won’t be useful to you.
Inheritance works exactly the same way. If
you have a method with Vehicle as a
parameter, and if the Motorcycle class
inherits from the Vehicle class, then you
can pass an instance of Motorcycle
to the method. But  if the method takes
Motorcycle as a parameter, you can’t
pass any Vehicle object, because it may
be a Van instance. Then C# wouldn’t know
what to do when the method tries to access
the Handlebars property!

You can always
pass an instance
of a subclass to
any method whose
parameters expect
a class that it
inherits from.

you are here 4   243

you really do need them
Look, I just don’t see why I need to use those
“virtual” and “override” keywords. If I don’t use them, the IDE just
gives me a warning, but the warning doesn’t actually mean anything—my
program still runs! I mean, I’ll put the keywords in if it’s the “right”
thing to do, but it just seems like I’m jumping through hoops for no
good reason.

There’s an important reason for virtual and override!
The virtual and override keywords aren’t just for decoration. They
actually make a real difference in how your program works. But don’t take our
word for it—here’s a real example to show you how they work.

Instead of creating a Windows Forms
application, you’re going to create a
new console application instead! This
means it won’t have a form.

Do this!
1

Create a new console application and add classes.
Right-click on the project in the Solution Explorer and add classes, just like normal. Add the
following five classes: Jewels, Safe, Owner, Locksmith, and JewelThief.

2

Add the code for the new classes.
Here’s the code for the five new classes you added:
class Jewels {
public string Sparkle() {
return "Sparkle, sparkle!";
}
A Safe object keeps a Jewels
}

erence
in its contents field. It doesn’trefret
that reference unless Open() is cal urn
led
with the right combination.

Console applications
don’t use forms

If you create a console application
of a Windows Forms application, all instead
creates for you is a new class called the IDE
with an empty Main() entry point Program
When you run it, it pops up a com method.
window to display the output. Youmand
more about console applications in can read
Appendix A.

class Safe {
private Jewels contents = new Jewels();
Notice how
private string safeCombination = “12345”;
the private
public Jewels Open(string combination)
keyword
{
hides the
if (combination == safeCombination)
contents and
return contents;
combination.
else
return null;
}
public void PickLock(Locksmith lockpicker) {
lockpicker.WriteDownCombination(safeCombination);
}
}

244   Chapter 6

A locksmith can pick the combination
lock and get the combination by calling
the PickLock() method and passing in a
reference to himself. The safe calls his
WriteDownCombination() method with
the combination.

inheritance
class Owner {
private Jewels returnedContents;
public void ReceiveContents(Jewels safeContents) {
returnedContents = safeContents;
Console.WriteLine("Thank you for returning my jewels! " + safeContents.Sparkle());
}
}
Locksmith
3

The JewelThief class inherits from Locksmith.
Jewel thieves are locksmiths gone bad! They can pick the lock on the safe, but
instead of returning the jewels to the owner they steal them!

class Locksmith {
public void OpenSafe(Safe safe, Owner owner) {
safe.PickLock(this);
Jewels safeContents = safe.Open(writtenDownCombination);
ReturnContents(safeContents, owner);
A Locksmith’s OpenSafe() method
picks the lock, opens the safe, and
}

returns the contents to the owner.

private string writtenDownCombination = null;
public void WriteDownCombination(string combination) {
writtenDownCombination = combination;
}

OpenSafe()
WriteDownCombination()
ReturnContents()

JewelThief

private stolenJewels

ReturnContents()

public void ReturnContents(Jewels safeContents, Owner owner) {
owner.ReceiveContents(safeContents);
}

}

class JewelThief : Locksmith {
private Jewels stolenJewels = null;
public void ReturnContents(Jewels safeContents, Owner owner) {
stolenJewels = safeContents;
Console.WriteLine("I'm stealing the contents! " + stolenJewels.Sparkle());
}
A JewelThief object inherits the
}
ombination()

4

Here’s the Main() method for the Program class.
But don’t run it just yet! Before you run the program, try to figure
out what it’s going to print to the console.

class Program {
static void Main(string[] args) {
ReadKey()
Owner owner = new Owner();
waits for the Safe safe = new Safe();

user to press
a key. It keeps
the program
from ending.
}

}

JewelThief jewelThief = new JewelThief();
jewelThief.OpenSafe(safe, owner);
Console.ReadKey();

OpenSafe() and WriteDownC
methods. But when the OpenSafe()
method calls ReturnContents() to
return the jewels to the owner, the
JewelThief steals them instead!

Read through the code for your program. Before
you run it, write down what you think it will
print to the console. (Hint: Figure out what
JewelThief inherits from Locksmith!)

you are here 4   245

hide and seek

A subclass can hide me thods in the superclass
Go ahead and run the JewelThief program. Since it’s a console application, instead
of writing its console output to the Output window, it’ll pop up a command window
and print the output there. Here’s what you should see:

Did you expect the program’s output to be different? Maybe something like this:
I’m stealing the contents! Sparkle, sparkle!

It looks like the JewelThief acted just like a Locksmith! So what happened?

Hiding me thods versus overriding me thods
The reason the JewelThief object acted like a Locksmith object when its
ReturnContents() method was called was because of the way the JewelThief class
declared its ReturnContents() method. There’s a big hint in that warning message
you got when you compiled your program:

Since the JewelThief class inherits from Locksmith and replaces
the ReturnContents() method with its own method, it looks
like JewelThief is overriding Locksmith’s ReturnContents()
method. But that’s not actually what’s happening. You probably
expected JewelThief to override the method (which we’ll talk about
in a minute), but instead JewelThief is hiding it.
There’s a big difference. When a subclass hides the method, it replaces
(technically, it “redeclares”) a method in its base class that has the same
name. So now our subclass really has two different methods that share
a name: one that it inherits from its base class, and another brand-new
one that’s defined in its own class.

246   Chapter 6

If a subclass just adds
a method with the same
name as a method in its
superclass, it only hides
the superclass method
instead of overriding it.

inheritance

Use dif ferent reference s to call hidden me thods
The JewelThief only hides the ReturnContents() method (as opposed to extending it), and that causes
it to act like a Locksmith object whenever it’s called like a Locksmith object. JewelThief inherits one
version of ReturnContents() from Locksmith, and it defines a second version of it, which means that
there are two different methods with the same name. That means your class needs two different ways to call it.
And, in fact, it has exactly that. If you’ve got an instance of JewelThief, you can use a JewelThief
reference variable to call the new ReturnContents() method. But if you use a Locksmith reference
variable to call it, it’ll call the hidden Locksmith ReturnContents() method.

// The JewelThief subclass hides a method in the Locksmith base class,
// so you can get different behavior from the same object based on the
// reference you use to call it!
// Declaring your JewelThief object as a Locksmith reference causes it to
// call the base class ReturnContents() method
Locksmith calledAsLocksmith = new JewelThief();
calledAsLocksmith.ReturnContents(safeContents, owner);
// Declaring your JewelThief object as a JewelThief reference causes it to
// call the JewelThief's ReturnContents() method instead, because it hides
// the base class's method of the same name.
JewelThief calledAsJewelThief = new JewelThief();
calledAsJewelThief.ReturnContents(safeContents, owner);

Use the ne w key word when you’re hiding me thods
Take a close look at that warning message. Sure, we never really read most of our warnings, right? But this
time, actually read what it says: To make the current member override that implementation, add
the override keyword. Otherwise add the new keyword.
So go back to your program and add the new keyword.

new public void ReturnContents(Jewels safeContents, Owner owner) {

As soon as you add new to your JewelThief class’s ReturnContents() method declaration, that
error message will go away. But your program still won’t act the way you expect it to! It still calls the
ReturnContents() method defined in the Locksmith object. Why? Because the ReturnContents()
method is being called from a method defined by the Locksmith class—specifically, from inside
Locksmith.OpenSafe(), even though it’s being initiated by a JewelThief object. If JewelThief
only hides the ReturnContents() method, its own ReturnContents() will never be called.
Can you figure out how to get JewelThief to override the ReturnContents() method
instead of just hiding it? See if you can do it before turning to the next page!
you are here 4   247

and that’s why you need those keywords

Use the override and virtual key words to inherit behavior
We really want our JewelThief class to always use its own ReturnContents()
method, no matter how it’s called. This is the way we expect inheritance to work most
of the time, and it’s called overriding. And it’s very easy to get your class to do it.
The first thing you need to do is use the override keyword when you declare the
ReturnContents() method, like this:

class JewelThief {
...
override public void ReturnContents
(Jewels safeContents, Owner owner)
But that’s not everything you need to do. If you just add that override and try to
compile, you’ll get an error that looks like this:

Again, take a really close look and actually read the error. JewelThief can’t override the
inherited member ReturnContents() because it’s not marked virtual, abstract,
or override in Locksmith. Well, that’s an easy error to fix! Just mark Locksmith’s
ReturnContents() with the virtual keyword:

class Locksmith {
...
virtual public void ReturnContents
(Jewels safeContents, Owner owner)

Now run your program again. Here’s what you should see:

And that’s the output we were looking for.
248   Chapter 6

inheritance

When I come up with my class
hierarchy, I usually want to override
methods and not hide them. But if I
do hide them, I’ll always use the new
keyword, right?

Exactly. Most of the time you want to
override methods, but hiding them is
an option.
When you’re working with a subclass that extends
a base class, you’re much more likely to use
overriding than you are to use hiding. So when you
see that compiler warning about hiding a method,
pay attention to it! Make sure you really want
to hide the method, and didn’t just forget to use
the virtual and override keywords. If you
always use the virtual, override, and new
keywords correctly, you’ll never run into a problem
like this again!

If you want to
override a method in
a base class, always
mark it with the
virtual keyword,
and always use the
override keyword
any time you want
to override the
method in a subclass.
If you don’t, you’ll
end up accidentally
hiding methods
instead.
you are here 4   249

detour: construction ahead

A subclass can acce ss its base class using the base key word
Even when you override a method or property in your base class,
sometimes you’ll still want to access it. Luckily, we can use base, which
lets us access any method in the base class.
1

All animals eat, so the Vertebrate class has an Eat() method that
takes a Food object as its parameter.
class Vertebrate {

public virtual void Eat(Food morsel) {

Vertebrate

NumberOfLegs

Eat()
Swallow()
Digest()

Swallow(morsel);

}

}

Digest();

Chameleon

TongueLength
Color

CatchWithTongue()

2

Chameleons eat by catching food with their tongues. So the Chameleon class inherits
from Vertebrate but overrides Eat().

class Chameleon : Vertebrate {
public override void Eat(Food morsel) {
CatchWithTongue(morsel);
The chameleon needs to swallow and dig
Swallow(morsel);
Digest();
the food, just like any other animal. Doest
}
really need to duplicate this code, tho we
ugh?
}

3

Instead of duplicating the code, we can use the base keyword to call the method that
was overridden. Now we have access to both the old and the new version of Eat().
class Chameleon : Vertebrate {
public override void Eat(Food morsel) {
CatchWithTongue(morsel);
This line calls

}

}

base.Eat(morsel);

se
the Eat() method in the ba
.
om
d fr
class that Chameleon inherite

Now that you’ve had a chance to absorb some of the ideas behind inheritance, here’s something to think
about. While reusing code is a good way to save keystrokes, another valuable part of inheritance is that it
makes it easier to maintain your code later. Can you think of a reason why that’s true?
250   Chapter 6

inheritance

When a base class has a constructor, your subclass needs one, too
If your class has constructors that take parameters, then any class that
inherits from it must call one of those constructors. The subclass’s
constructor can have different parameters from the base class constructor.

class Subclass : BaseClass {

public Subclass(parameter list)

Here’s the
constructor for
the subclass.
}

}

: base(the base class’s parameter list) {

// first the base class constructor is executed
// then any statements here get executed

The base class constructor is e xecuted
before the subclass constructor
But don’t take our word for it—see for yourself !
1

Add this extra
e to the end of
your subclass’s colin
ns
to tell C# that ittructor declaration
base class’s constr needs to call the
subclass is instantiuctor every time the
ated.

Do this!

Create a base class with a constructor that pops up a message box
Then add a button to a form that instantiates this base class and shows a message box:
class MyBaseClass {
public MyBaseClass(string baseClassNeedsThis) {
MessageBox.Show(“This is the base class: ” + baseClassNeedsThis);
}
Keep an eye
This is a parameter that the
}
out for this

base class constructor needs.

2

Try adding a subclass, but don’t call the constructor
Then add a button to a form that instantiates this subclass and shows a message box:
class MySubclass : MyBaseClass{
public MySubclass(string baseClassNeedsThis, int anotherValue) {
MessageBox.Show(“This is the subclass: ” + baseClassNeedsThis
+ “ and ” + anotherValue);
}

Select Build >>
Build Solution in
the IDE and you’ll
get an error from
this code.
}
3

slightly cryptic
error. It means
that your
subclass didn’t
call the base
constructor.

Fix the error by making the constructor call the one from the base class
Then instantiate the subclass and see what order the two message boxes pop up!
class MySubclass : MyBaseClass{
public MySubclass(string baseClassNeedsThis, int anotherValue)
call the constructor in
: base(baseClassNeedsThis)
Add this line to tell C#patorameter list that shows
{
the base class. It has a
ss constructor. Then
// the rest of the subclass is the same what gets passed to the base cla
tton to

This is how
we send the
base class the
parameter its
constructor
needs.

you can make a bu
the error will go away ands pop
up!
boxe
see the two messageyou
are here 4   251

kathleen still needs our help

Now you’re re ady to finish the job for Kathleen!
When you last left Kathleen, you’d finished adding
birthday parties to her program. She needs you to
charge an extra $100 for parties over 12. It seemed
like you were going to have to write the same exact
code twice, once for each class. Now that you know
how to use inheritance, you can have them inherit
from the same base class that contains all of their
shared code, so you only have to write it once.

DinnerParty

BirthdayParty

NumberOfPeople
CostOfDecorations
CostOfBeveragesPerPerson
HealthyOption

NumberOfPeople
CostOfDecorations
CakeSize
CakeWriting

CalculateCostOfDecorations()
CalculateCost()
SetHealthyOption()

CalculateCostOfDecorations()
CalculateCost()

If we play our cards right, we should be able to change the
two classes without making any changes to the form!
1

Let’s create the new class model
We’ll still have the same DinnerParty and BirthdayParty classes, but now they’ll inherit from a
single Party class. We need them to have exactly the same methods, properties, and fields, so we don’t
have to make any changes to the form. But some of those methods, properties, and fields will be moved
into the Party base class, and we may have to override a few of them.

Party
NumberOfPeople
CostOfDecorations

CalculateCostOfDecorations()
CalculateCost()

DinnerParty

252   Chapter 6

BirthdayParty

NumberOfPeople
CostOfDecorations
CostOfBeveragesPerPerson
HealthyOption

NumberOfPeople
CostOfDecorations
CakeSize
CakeWriting

CalculateCostOfDecorations()
CalculateCost()
SetHealthyOption()

CalculateCostOfDecorations()
CalculateCost()

inheritance

2

Build the Party base class
Create the Party class—make sure it’s public. You’ll need to look really closely at the
properties and methods in the class diagram, and figure out what you need to move out of
DinnerParty and BirthdayParty and into Party.

Later on, you’ll
learn about
the “protected”
keyword. A
protected
field is public
to a subclass,
but private to
everyone else.
3

≥≥ Move the NumberOfPeople and CostOfDecorations properties into it so
that they’re compatible with both DinnerParty and BirthdayParty.
≥≥ Do the same for CalculateCostOfDecorations() and CalculateCost().
If those methods need any private fields, you’ll need to move them, too. (Remember,
subclasses can only see public fields—once you move a private field to Party, the
DinnerParty and BirthdayParty classes won’t have access to it.)
≥≥ You’ll also need a constructor. Take a close look at the BirthdayParty and
DinnerParty constructors—anything they have in common should be moved to it.
≥≥ Now add the $100 bonus for parties over 12 people. After all, that’s why we’re
doing this! It’s common to both birthday and dinner parties, so it belongs in Party.

Make DinnerParty inherit from Party
Now that Party does a lot of the things DinnerParty does, you can eliminate the overlap
and only keep the part of DinnerParty that’s unique to dinner parties.
≥≥ Make sure the constructor is working properly. Does it do anything the Party
constructor doesn’t? If so, keep that and then leave everything else to the base class
constructor.
≥≥ Any logic that has to do with setting the Healthy Option should stay in DinnerParty.

You’ll learn all

≥≥ Uh-oh—we can’t override the CalculateCost() method here if we want to
about overloading
keep the form code the same, because our form needs to pass it a bool called
in Chapter
healthyOption. So instead, we’ll overload it—which just means adding a
8—this is just a
new CalculateCost() method to the class that takes different parameters. So
sneak preview to
you’ll use exactly the same declaration for the method that you used at the beginning give you a leg up
of the chapter. But you can still take advantage of inheritance by calling base.
on it later.
CalculateCost() to access the CalculateCost() method in the Party class.
4

Make BirthdayParty inherit from Party
Do the same thing for BirthdayParty—leave anything not specific to birthdays to the
base class, and only keep the birthday-specific functionality in BirthdayParty.
≥≥ What does the BirthdayParty constructor need to do that’s not part of Party?
≥≥ You’ll need to deal with the cost of the cake inside of BirthdayParty. That
touches a method and a property, so you’ll need to override them.
≥≥ Yes, you can override a property! It’s just like overriding a method. When you set the
value of base.NumberOfPeople, it calls the property’s set accessor in the base
class. You’ll need to use the base keyword to both get and set the value.
you are here 4   253

exercise solution

Check it out—you changed the DinnerParty and BirthdayParty
classes so that they inherited from the same base class,
Party. Then you were able to make the change to the cost
calculation to add the $100 fee, and you didn’t have to
change the form at all. Neat!
class Party
{
const int CostOfFoodPerPerson = 25;
private bool fancyDecorations;
public decimal CostOfDecorations = 0;

This code was moved straight out of
the DinnerParty and BirthdayParty
classes and into Party.

public Party(int numberOfPeople, bool fancyDecorations) {
this.fancyDecorations = fancyDecorations;
this.NumberOfPeople = numberOfPeople;
}
private int numberOfPeople;
public virtual int NumberOfPeople {
get { return numberOfPeople; }
set {
numberOfPeople = value;
CalculateCostOfDecorations(fancyDecorations);
}
}

NumberOfPeople needs to be virtual
because BirthdayParty needs to override
it (so that a change to the number of
people calculates a new cake size).

public void CalculateCostOfDecorations(bool fancy) {
fancyDecorations = fancy;
if (fancy)
CostOfDecorations = (NumberOfPeople * 15.00M) + 50M;
else
CostOfDecorations = (NumberOfPeople * 7.50M) + 30M;
}

}

The Party constructor does
everything that was previously
in both the DinnerParty and
BirthdayParty constructors.

The decoration calculation is
identical in both birthday and
dinner parties, so it makes sense
to move it to Party. That way
none of the code is duplicated
in multiple classes.

public virtual decimal CalculateCost() {
decimal TotalCost = CostOfDecorations + (CostOfFoodPerPerson * NumberOfPeople);
if (NumberOfPeople > 12)
{
TotalCost += 100M;
The cost calculation needs to be a virtual met
}
because the birthday party overrides it (and hod
return TotalCost;
extends it by calling the base class method). also
}

254   Chapter 6

inheritance
class BirthdayParty : Party {
public int CakeSize;
public BirthdayParty(int numberOfPeople, bool fancyDecorations, string cakeWriting)
: base(numberOfPeople, fancyDecorations) {
The constructor relies on the bas
CalculateCakeSize();
this.CakeWriting = cakeWriting;
to do most of the work. Then it e class
CalculateCostOfDecorations(fancyDecorations);
CalculateCakeSize(), just like the calls
old
}
Bir
private void CalculateCakeSize() {
if (NumberOfPeople <= 4)
CakeSize = 8;
else
CakeSize = 16;
}

thdayParty constructor did.

The CalculateCakeSize()
method is specific to
birthday parties, so it stays
in the BirthdayParty class.

The CakeWriting
private string cakeWriting = “”;
public string CakeWriting {
property stays intact
get { return this.cakeWriting; }
in the BirthdayParty
set {
class too.
int maxLength;
if (CakeSize == 8)
maxLength = 16;
else
maxLength = 40;
if (value.Length > maxLength) {
MessageBox.Show(“Too many letters for a “ + CakeSize + “ inch cake”);
if (maxLength > this.cakeWriting.Length)
maxLength = this.cakeWriting.Length;
this.cakeWriting = cakeWriting.Substring(0, maxLength);
} else
this.cakeWriting = value;
}
}
public override decimal CalculateCost() {
decimal CakeCost;
if (CakeSize == 8)
CakeCost = 40M + CakeWriting.Length * .25M;
else
CakeCost = 75M + CakeWriting.Length * .25M;
return base.CalculateCost() + CakeCost;
}

}

public override int NumberOfPeople {
get { return base.NumberOfPeople; }
set {
base.NumberOfPeople = value;
CalculateCakeSize();
this.CakeWriting = cakeWriting;
}
}

be
CalculateCost() also needsdstoto
nee
it
use
ca
overridden, be
the cake,
first calculate the cost of
st that’s
and then add it to the co
s
calculated in the Party .class’
od
th
me
()
CalculateCost

The NumberOfPeople property has to
override the one in Party because the set
accessor needs to recalculate the cake
size. The set accessor needs to call base.
NumberOfPeople so that the set accessor
in Party also gets executed.
Continues on page 256.
you are here 4   255

great job!

continued
from p.255

Here’s the last class in Kathleen’s solution.
(There’s no change to the form code.)
This public field is only used in dinner
class DinnerParty : Party
parties, not birthday parties, so it
{
stays
in the class.
public decimal CostOfBeveragesPerPerson;
public DinnerParty(int numberOfPeople, bool healthyOption,
bool fancyDecorations)
To do what the old
: base(numberOfPeople, fancyDecorations) {
DinnerParty class did, the
SetHealthyOption(healthyOption);
calls the
CalculateCostOfDecorations(fancyDecorations); new constructor
and then
or
uct
str
con
Party
}

calls SetHealthyOption().

public void SetHealthyOption(bool healthyOption) {
if (healthyOption)
CostOfBeveragesPerPerson = 5.00M;
The SetHealthyOpt
else
stays exactly the ion()
CostOfBeveragesPerPerson = 20.00M;
same.
}

method

public decimal CalculateCost(bool healthyOption) {
decimal totalCost = base.CalculateCost()
+ (CostOfBeveragesPerPerson * NumberOfPeople);

}

}

if (healthyOption)
return totalCost * .95M;
else
return totalCost;

The program’s
perfect. It’s so much easier to run
my business now—thanks so much!

DinnerParty needs a different CalculateCost()
that takes a parameter, so instead of
overriding it we overloaded it. It calls the
CalculateCost() method in Party using the
base keyword, and then adds the cost of
the beverages and adds in the healthy option
discount.
You’ll learn all about
how overloading works in
Chapter 8.

Uh-oh—there’s still a potential bug in the program!
Now the DinnerParty class has two CalculateCost() methods, one that it inherits from Party
and this new one that we added. We haven’t fully encapsulated the class—someone could easily misuse
this code by calling the wrong CalculateCost() method. So if you do this:
DinnerParty dinner = new DinnerParty(5, true, true);
decimal cost1 = dinner.CalculateCost(true);
decimal cost2 = dinner.CalculateCost();
cost1 will be set to 261.25, while cost2 will be set to 250. This isn’t an academic question—it’s a real problem.
Sometimes there’s code in the base class that you don’t want to call directly. Even worse, we never intended the
Party class to be instantiated…but there’s nothing stopping someone from doing it. Do we even know what will
happen if someone creates an instance of Party? We can be pretty sure it’ll do something we didn’t plan for.
Luckily, C# gives us a really good solution to these problems, which you’ll learn about in the next chapter!
256   Chapter 6

inheritance

Build a beehi ve management system
A queen bee needs your help! Her hive is out of control, and
she needs a program to help manage it. She’s got a beehive full
of workers, and a whole bunch of jobs that need to be done
around the hive. But somehow she’s lost control of which bee
is doing what, and whether or not she’s got the beepower to do
the jobs that need to be done.
It’s up to you to build a beehive management system to help
her keep track of her workers. Here’s how it’ll work:

1

The queen assigns jobs to her workers
There are six possible jobs that the workers can do. Some
know how to collect nectar and manufacture honey, others
can maintain the hive and patrol for enemies. A few bees can
do every job in the hive. So your program will need to give
her a way to assign a job to any bee that’s available to do it.

This drop-down list shows all six jobs that the
workers can do.The queen knows what jobs need
to be done, and she doesn’t really care which bee
does each job. So she just selects which job has to
be done—the program will figure out if there’s a
worker available to do it and assign the job to him.
2

The bees work shifts,
and most jobs require
more than one shift.
So the queen enters
the number of shifts
the job will take, and
clicks the “Assign
this job” button.

If there’s a bee
available to do the job,
the program assigns
the job to the bee and
lets the queen know
it’s taken care of.

When the jobs are all assigned, it’s time to work
Once the queen’s done assigning the work, she’ll tell the bees to work the next
shift by clicking the “Work the next shift” button. The program then generates
a shift report that tells her which bees worked that shift, what jobs they did, and
how many more shifts they’ll be working each job.

you are here 4   257

help the queen

First you’ll build the basic system
This project is divided into two parts. The first part is a bit of a review,
where you’ll create the basic system to manage the hive. It’s got two classes,
Queen and Worker. You’ll build the form for the system, and hook it up
to the two classes. And you’ll make sure the classes are well encapsulated so
they’re easy to change when you move on to the second part.

Sometimes class diagrams
list private fields and types.

Queen

The program has one Queen object that manages the work being done.
≥≥ The Queen uses an array of Worker objects to track each of the
worker bees and whether or not those bees have been assigned jobs.
It’s stored in a private Worker[ ] field called worker.
≥≥ The form calls the AssignWork() method, passing a string for
the job that needs to be performed and an int for the number of
shifts. It’ll return true if it finds a worker to assign the job to, or false
if it couldn’t find a worker to do that job.
≥≥ The form’s “Work the next shift” button calls
WorkTheNextShift(), which tells the workers to work and returns
a shift report to display. It tells each Worker object to work one shift, and
then checks that worker’s status so it can add a line to the shift report.

private workers: Worker[]
private shiftNumber: int

AssignWork()
WorkTheNextShift()

CurrentJob and ShiftsLeft are
read-only properties.
Worker
CurrentJob: string
ShiftsLeft: int

The queen uses an array of Worker objects to keep track of all of the
workers and what jobs they’re doing.

private jobsICanDo: string[]
private shiftsToWork: int
private shiftsWorked: int
DoThisJob()
WorkOneShift()

String.IsNullOrEmpty()

≥≥ CurrentJob is a read-only property that tells the Queen object
what job the worker’s doing (“Sting patrol”, “Hive maintenance”,
etc.). If the worker isn’t doing any job, it’ll return an empty string.
≥≥ The Queen object attempts to assign a job to a worker using its
DoThisJob() method. If that worker is not already doing the
job, and if it’s a job that he knows how to do, then he’ll accept the
assignment and the method returns true. Otherwise, it returns false.
≥≥ When the WorkOneShift() method is called, the worker works
a shift. He keeps track of how many shifts are left in the current
job. If the job is done, then he resets his current job to an empty
string so that he can take on his next assignment.

Each bee stores his current job as a string. So a worker can figur
currently doing a job by checking his CurrentJob property—it’ll e out if he’s
be equal to an
empty string if he’s waiting for his next job. C# gives you an easy
that: String.IsNullOrEmpty(CurrentJob) will return true if the way to do
CurrentJob
string is either empty or null, and false otherwise.
258   Chapter 6

inheritance

A queen bee needs your help! Use what you’ve learned about classes and objects to build a
beehive management system to help her track her worker bees.
1

Build the form
The form is pretty simple—all of the intelligence is in the Queen and Worker classes. The form
has a private Queen field, and two buttons call its AssignWork() and WorkTheNextShift()
methods. You’ll need to add a ComboBox control for the bee jobs (flip back to the previous page
to see its list items), a NumericUpDown control, two buttons, and a multiline text box for the shift
report. You’ll also need the form’s constructor—it’s below the screenshot.

This is a ComboBox control
named “workerBeeJob”.
Use its Items property to
set the list, and set its

DropDownStyle property
to “DropDownList” so
the user is only allowed
to choose items from the
list. The Shifts box is a
NumericUpDown control
called “shifts.”
Name this TextBox “report”
and set its MultiLine
property to true.

The nextShift button
calls the queen’s
WorkTheNextShift()
method, which returns a
string that contains the
shift report.
Look closely at this
shift report, which the
Queen object generates.
It starts with a shift
number, and then reports
what each worker is doing.
Use the escape sequences
“\r\n” to add a line break
in the middle of a string.

public Form1() {
Each Worker object’s constructor takes one
InitializeComponent();
parameter, an array of strings that tell it
what jobs it knows how to do.
Worker[] workers = new Worker[4];
workers[0] = new Worker(new string[] { “Nectar collector”, “Honey manufacturing” });
workers[1] = new Worker(new string[] { “Egg care”, “Baby bee tutoring” });
workers[2] = new Worker(new string[] { “Hive maintenance”, “Sting patrol” });
workers[3] = new Worker(new string[] { “Nectar collector”, “Honey manufacturing”,
“Egg care”, “Baby bee tutoring”, “Hive maintenance”, “Sting patrol” });
queen = new Queen(workers);
Your form will need a Queen field called queen. You’ll pass that array
}

of Worker object references to the Queen object’s constructor.

2

Build the Worker and Queen classes
You’ve got almost everything you need to know about the Worker and Queen classes. There are just a
couple more details. Queen.AssignWork() loops through the Queen object’s worker array and
attempts to assign the job to each worker using its DoThisJob() method. The Worker object checks
its jobsICanDo string array to see if it can do the job. If it can, it sets its private shiftsToWork field
to the job duration, its CurrentJob to the job, and its shiftsWorked to zero. When it works a shift, it
increases shiftsWorked by one. The read-only ShiftsLeft property returns shiftsToWork shiftsWorked—the queen uses it to see how many shifts are left on the job.
you are here 4   259

exercise solution

class Worker {
public Worker(string[] jobsICanDo) {
this.jobsICanDo = jobsICanDo;
}

ShiftsLeft is a read-only
property that calculates
how many shifts are left
on the current job.
CurrentJob is a readonly property that
tells the queen which
job needs to be done.

public int ShiftsLeft {
get {
return shiftsToWork
}
}
private string currentJob =
public string CurrentJob {
get {
return currentJob;
}
}

The constructor just
sets the JobsICanDo
property, which is a
string array. It’s private
because we want the
- shiftsWorked;
queen to ask the worker
to do a job, rather than
make her check whether
“”;
he knows how to do it.

private string[] jobsICanDo;
private int shiftsToWork;
private int shiftsWorked;

The queen uses the worker’s public bool DoThisJob(string job, int numberOfShifts) {
DoThisJob() method to assign if (!String.IsNullOrEmpty(currentJob))
return false;
work to him—he checks his
for (int i = 0; i < jobsICanDo.Length; i++)
JobsICanDo property to see if
if (jobsICanDo[i] == job) {
currentJob = job;
he knows how to do the job.
this.shiftsToWork = numberOfShifts;
shiftsWorked = 0;
We used !—the NOT operator—to
return true;
}
check if the string is NOT null or
return false;
empty. It’s just like checking to see
}
if something’s false.
The queen uses the worker’s
WorkOneShift() method to
tell him to work the next
shift. The method only
returns true if this is the
very last shift that he’s
doing the job. That way the
queen can add a line to the
report that the bee will }be
done after this shift.

260   Chapter 6

public bool WorkOneShift() {
if (String.IsNullOrEmpty(currentJob))
return false;
shiftsWorked++;
if (shiftsWorked > shiftsToWork) {
shiftsWorked = 0;
Take a close look at the logic here. First it
shiftsToWork = 0;
checks the currentJob field: if the worker’s
currentJob = “”;
return true;
not
working on a job, it just returns false,
}
which stops the method. If not, then it
else
return false;
increments ShiftsWorked, and then checks
}

to see if the job’s done by comparing it with
ShiftsToWork. If it is, the method returns
true. Otherwise it returns false.

inheritance
class Queen {
public Queen(Worker[] workers) {
this.workers = workers;
}
private Worker[] workers;
private int shiftNumber = 0;

s private
The queen keeps her array of workerer
class
oth
no
because once they’re assigned,
see
n
should be able to change them…or eve s them
them, since she’s the only one who gived’s value.
orders. The constructor sets the fiel

public bool AssignWork(string job, int numberOfShifts) {
for (int i = 0; i < workers.Length; i++)
if (workers[i].DoThisJob(job, numberOfShifts))
return true;
When she assigns work to her worker bees,
return false;
the
first one and tries assigning him the
}

she starts with
job.
do it, she moves on to the next. When a bee If he can’t
who can do
public string WorkTheNextShift() { the
job is found, the method returns (which stop
shiftNumber++;
s the loop).
string report = “Report for shift #” + shiftNumber + “\r\n”;

for (int i = 0; i < workers.Length; i++)
{
The queen’s
if (workers[i].WorkOneShift())
report += “Worker #” + (i + 1) + “ finished the job\r\n”;
WorkTheNextShift()
method tells each if (String.IsNullOrEmpty(workers[i].CurrentJob))
report += “Worker #” + (i + 1) + “ is not working\r\n”;
worker to work a else
if (workers[i].ShiftsLeft > 0)
shift and adds a
report += “Worker #” + (i + 1) + “ is doing ‘“ + workers[i].CurrentJob
line to the report
+ “’ for “ + workers[i].ShiftsLeft + “ more shifts\r\n”;
else
depending on the
report += “Worker #” + (i + 1) + “ will be done with ‘“
worker’s status.
+ workers[i].CurrentJob + “’ after this shift\r\n”;
}
return report;
}
The form uses its queen field to
}
Queen

We already gave you the constructor. Here’s the rest of the code for the form:
Queen queen;

keep a reference to the
object, which in turn has an array
of references to the worker objects.

private void assignJob_Click(object sender, EventArgs e) {
if (queen.AssignWork(workerBeeJob.Text, (int)shifts.Value) == false)
MessageBox.Show(“No workers are available to do the job ‘”
+ workerBeeJob.Text + “’”, “The queen bee says...”);
else
MessageBox.Show(“The job ‘” + workerBeeJob.Text + “’ will be done in ”
+ shifts.Value + “ shifts”, “The queen bee says...”);
}
The assignJob button
private void nextShift_Click(object sender, EventArgs e) {
report.Text = queen.WorkTheNextShift();
}
t. She

work the next shif
The nextShift button tells the queen to report text box.
generates a report, which it displays in the

calls the
queen’s AssignWork() method
to assign work to a worker,
and displays a message box,
depending on whether or not a
worker’s available to do the job.
you are here 4   261

you’re not done

Inheritancecross
Before you move on to the next part of the exercise,
give your brain a break with a quick crossword.
1
2

1

3
4

2

3

4

5
5

6

8

6

7

7

8

9

9

10

10

11

11

Across

This method gets the value of a property.
Across 5.
7. This method returns true if you pass it “”.
5. This method
the value
a property.
8. Thegets
constructor
in a of
subclass
doesn’t need the same
_____returns
as the constructor
its base
7. This method
true if youinpass
it “”.class.
9. A controlinon
a form thatdoesn’t
lets you need
createthe
tabbed
applications.
8. The constructor
a subclass
same
11. This
type of class
be class.
instantiated.
_____ as the
constructor
in itscan't
base

9. A control on a form that lets you create tabbed applications.
11. This type of class can't be instantiated.

Down

1. A _______ can override methods from its base class.
Down
2. If you want a subclass to override a method, mark the

1.method
A _______
cankeyword
override
methods
from its base class.
with this
in the
base class.
method
class that’storun
as soonaas
it’s instantiated.
2.3.If Ayou
wantinaasubclass
override
method,
mark the
4. Whatwith
a subclass
does to in
replace
a method
in the base
method
this keyword
the base
class.
3.class.
A method in a class that’s run as soon as it’s instantiated.
This contains base classes and subclasses.
4.6.What
a subclass does to replace a method in the base
7. What you’re doing by adding a colon to a class declaration.
class.
10. A subclass uses this keyword to call the members of the
6.class
This itcontains
inherited base
from. classes and subclasses.
7. What you’re doing by adding a colon to a class declaration.
10. A subclass uses this keyword to call the members of the
class it inherited from.

Answers on page 268.
262   Chapter 6

inheritance

Use inheritance to e xtend the
bee management system
Now that you have the basic system in place, use inheritance to let it track how much
honey each bee consumes. Different bees consume different amounts of honey, and
the queen consumes the most honey of all. So you’ll use what you’ve learned about
inheritance to create a Bee base class that Queen and Worker inherit from.

The Bee class has the basic honey
consumption behavior. Since honey
consumption requires the number
of shifts left, we’ll move the
ShiftsLeft property into it and
mark it as virtual so the Worker can
override it.

public ShiftsLeft: int

All bees consume honey, so we’ll add a
GetHoneyConsumption() method to the base
so the queen and workers can inherit it. But class
queens and workers consume honey differently.
We’ll make it a virtual method, so one of the
subclasses can override it.

The queen needs to
change her report to add
honey consumption data.
That means she needs
to add each worker’s
honey consumption—and
since she consumes honey
herself, she’ll need to
inherit from Bee and
override its virtual
GetHoneyConsumption()
method.

Sometimes we’ll show you
return values and private
members in class diagrams.

Bee

virtual
   GetHoneyConsumption():
   double

Queen

The worker just needs to
subclass Bee and override the
ShiftsLeft method with the
one you already wrote.
Worker

private workers: Worker[]
private shiftNumber: int

CurrentJob: string
ShiftsLeft: int

AssignWork()
WorkTheNextShift()

private jobsICanDo: string[]
private shiftsToWork: int
private shiftsWorked: int
DoThisJob()
WorkOneShift()

Add Existing Itertm exercise, it’s always a good idea to start a newuprneojedectit.foAnr

yo
pa
Whenever you have a two-y you can always get back to the first solution ifect’s Solution
the second part. That wa right-click on the project name in the new projto the old project’s
easy way to do that is to t “Add Existing Item” from the menu, navigate s of those files in
Explorer in the IDE, selec you want to add. The IDE will make new copie ings to watch out
folder, and select the filesand add them to the project. There are a few th
it each class file
the new project’s folder, NOT change the namespace, so you’ll need to edto add its designer
for, though. The IDE will line by hand. And if you add a form, make sure mespaces, too.
and change its namespace (.resx) files—and make sure you change their na
(.Designer.cs) and resource

you are here 4   263

we’re all just bees

We’re not done yet! The queen needs to keep track of how much honey the hive is spending on
its workers. Here’s a perfect chance to use your new inheritance skills!
1

The queen needs to know how much honey the hive uses
The queen just got a call from her accountant bees, who told her that the hive isn’t producing enough
honey. She’ll need to know how much honey she and her workers are using so she can decide whether to
divert workers from egg maintenance to honey production.
≥≥ All bees eat honey, so the hive runs through a lot of honey. That’s why they need to keep making
more of it.
≥≥ Worker bees use more honey when they’re working. They need the most honey when the job starts,
to give them plenty of energy for the job. They consume less and less as the job goes on. On the last
shift the bee uses 10 units of honey; on the second-to-last shift he uses 11 units; on the shift before
that he uses 12 units, etc. So if the bee is working (meaning his ShiftsLeft is greater than zero),
then you can find out how many units of honey to consume by adding 9 to ShiftsLeft.

≥≥ If a bee doesn’t have a job (i.e., its ShiftsLeft is zero), he only uses 7.5 units of honey for the shift.
≥≥ These numbers are all for normal bees. If a bee weighs over 150 milligrams, it uses 35% more
honey. This doesn’t include queens, though (see below).

≥≥ Queens require a lot of honey. A queen uses more honey when she’s got more workers doing
jobs, because it’s a lot of work overseeing them. She needs to consume as much honey as if she’d
worked as many shifts as the worker with the most shifts left on his job.
≥≥ Then she needs even more honey: she uses 20 extra units of honey per shift if there are 2 or fewer
workers working, or 30 extra units of honey if there are 3 or more worker bees doing jobs. The
queen’s consumption isn’t subject to the 35% rule, since all queens weigh 275 milligrams.
≥≥ The queen needs all the honey consumption numbers added to the end of each shift report.
2

Create a Bee class to handle the honey calculations
Since the workers and queen all do their honey calculations in similar ways, you’ll be able to avoid
duplicating your code by having a Bee base class that Worker and Queen can inherit from. You know
that each bee needs to know its weight (so it knows whether to multiply its honey expenditure by 35%).
≥≥ Create a GetHoneyConsumption() method that calculates the amount of honey that a
worker uses. Since the workers and queen all need to do this calculation but the queen needs to do
extra calculations as well, it makes sense for the worker to inherit it and the queen to override it.
≥≥ The GetHoneyConsumption() method needs the number of shifts left, so add a virtual readonly property called ShiftsLeft that returns zero. The worker’s ShiftsLeft will override it.

≥≥ The honey consumption calculation needs to know the bee’s weight, so the Bee constructor will
need to take the weight as a parameter and store it in a field. Since no other class needs to use it,
you should make it private.
Here’s a good rule of thumb. You should make fields and methods

private by default, and only make them public if another class needs
them. That way you avoid bugs in your programs caused by one class
accessing another class’s properties or methods incorrectly.

264   Chapter 6

inheritance

Hint: You can use the slightly cryptic “no
overload” error
message to your advantage! Have the
Wor
ker
class inherit
from Bee, then build your project. Wh
en
the
the error, double-click on it and the IDE IDE displays
to the Worker constructor automatically. will jump right
How convenient!

3

Make the Worker class inherit from Bee
You’ll need to set up the constructor to call the base class constructor, like you did with
Kathleen. You’ll need to change the Worker constructor so that it takes the bee’s weight as
a parameter, and pass that parameter on to the base class constructor. Then, just add the
override keyword to the Worker’s ShiftLeft method. Once you do that, each worker
will be able to calculate his honey consumption for the queen…and you don’t have to make
any more changes to the Worker class!

4

Make the Queen class inherit from Bee
The Queen class needs a little more alteration than the Worker class, since she needs to actually do the
honey calculation and add it to the shift report.
≥≥ Override the Bee.GetHoneyConsumption() method and add the queen’s extra calculation.
She’ll need to figure out whether she has 2 or fewer workers with jobs, so she knows whether she
needs 20 or 30 units. Then she’ll need to add that to the number of units she’d use if she had the
same number of shifts left as the worker with the most shifts left.
≥≥ Update the queen’s WorkTheNextShift() method by adding the honey consumption line
to the report. Add a loop to add up the honey consumption for each worker and also to find the
worker with the largest honey consumption—do it before the queen tells each worker to work
the shift (so she gets the consumption numbers for the current shift). She’ll add those up, add
her own consumption, and then add a line to the end of the shift report that says, “Total Honey
Consumption: xxx units” (where xxx is the number of units of honey consumed).
≥≥ You’ll need to update the Queen constructor just like you did for Worker.

Go to the Queen class and type “public
override”—when you press the space
bar, the IDE automatically lists all the
methods you can override. Select the
method you want to override and it’ll fill
in the base method call automatically.
5

Update the form to instantiate the bees properly
Since you changed the Queen and Worker constructors, you’ll also need to change the way they’re called.
Each constructor has a new Weight parameter, so you’ll need the weights to use:
≥≥ Worker Bee #1: 175mg; Worker Bee #2: 114mg; Worker Bee #3: 149mg;
Worker Bee #4: 155mg; Queen Bee: 275mg
That’s the only change you’ll need to make to the form!

you are here 4   265

exercise solution

Here’s the Bee class. It does the
basic honey
consumption calculation that’s
use
d
by both
the Worker and Queen classes.

Inheritance made
it easy for you to
update your code
public virtual int ShiftsLeft {
and add the new
get { return 0; }
}
honey consumption
private double weight;
behavior to the
public virtual double GetHoneyConsumption() {
Queen and Worker
double consumption;
If a bee has 1 shift ;
10
es
um
if (ShiftsLeft == 0)
left, he cons
consumption = 7.5;
if 2 left, he consumesjob, classes. It would
else
11, etc. If he has no5. If have been a lot
consumption = 9 + ShiftsLeft;
then he consumes 7., then
if (weight > 150)
ShiftsLeft is zero
harder to make
consumption *= 1.35;
the bee has no job.
return consumption;
If the bee weighs more
this change if
}
150mg, then consumptionthan
goes up by 35%.
you’d had a lot of
duplicated code.

class Bee {
public Bee(double weight) {
this.weight = weight;
}

}

The Bee class has a constructor
that sets its Weight field and
a HoneyConsumption() method
that calculates how much honey
a worker consumes.

Only the form constructor changed—
the
rest of the form is exactly the sam
e.

public Form1() {
InitializeComponent();

}

Worker[] workers = new Worker[4];
workers[0] = new Worker(new string[] { “Nectar collector”, “Honey manufacturing” }, 175);
workers[1] = new Worker(new string[] { “Egg care”, “Baby bee tutoring” }, 114);
workers[2] = new Worker(new string[] { “Hive maintenance”, “Sting patrol” }, 149);
workers[3] = new Worker(new string[] { “Nectar collector”, “Honey manufacturing”,
“Egg care”, “Baby bee tutoring”, “Hive maintenance”, “Sting patrol” }, 155);
queen = new Queen(workers);

266   Chapter 6

The only change to the form is that the
weights need to be added to the Worker
constructors.

inheritance
class Worker : Bee {
public Worker(string[] jobsICanDo, int weight)
: base(weight) {
this.jobsICanDo = jobsICanDo;
}
public override int ShiftsLeft {

// ... the rest of the class is the same ...

All the Worker class ne ed
was to inherit
from Bee and have its ed
co
nst
ru
so that it takes a Weight ctor adjusted
passes it on to the base claparameter and
and overrides the Bee.Shif ss constructor,
by adding the override keywtsLeft property
ord to the
property declaration.

The Queen class needed a few changes,
starting with inheriting from Bee.
class Queen : Bee {
The queen weighs 275mg, so her constructor
public Queen(Worker[] workers)
calls the base Bee constructor and passes it a
: base(275) {
weight of 275.
this.workers = workers;
The WorkTheNextShift()
}
added to the top that ca has a loop
worker’s GetHoneyConsumplls each
public string WorkTheNextShift()
method, and then calls he tion()
{
GetHoneyConsumption() mer own
double totalConsumption = 0;
thod to
for (int i = 0; i < workers.Length; i++) come up with a total consumptio
n.
totalConsumption += workers[i].GetHoneyConsumption();
totalConsumption += GetHoneyConsumption();

// ... here’s where the original code for this method goes, minus the return statement

}

report += “Total honey consumption: ” + totalConsumption + “ units”;
return report;

The rest of WorkTheNextShift() is the same, t.
except that it adds the honey line to the repor

The queen overrides the Bee’s
GetHoneyConsumption() method to
do her honey calculation. It finds the
worker with the largest consumption
and adds either 20 or 30 to it based
on how many workers are working.

public override double GetHoneyConsumption() {
double consumption = 0;
double largestWorkerConsumption = 0;
int workersDoingJobs = 0;
for (int i = 0; i < workers.Length; i++) {
if (workers[i].GetHoneyConsumption() > largestWorkerConsumption)
This loop
largestWorkerConsumption = workers[i].GetHoneyConsumption();
looks at the
if (workers[i].ShiftsLeft > 0)
consumption
workersDoingJobs++;
of all the
workers and }
finds the consumption += largestWorkerConsumption;
if (workersDoingJobs >= 3)
one with
consumption += 30;
t
ges
the lar
If there are 3 or more workers
else
on.
pti
consum
doing jobs, the queen needs 30
consumption += 20;
more units of honey; otherwise,
return consumption;
she needs 20 more units.
}
}

you are here 4   267

crossword solution

Inheritancecross Solution
1

S
2

U
B
5

A

C

C

E

S
7

S

O

P

A

R

R

V

N

T

E

S

S

N

A

R

R

E

S

H

L

I

U

D

C

E

T

C

N

O

I

R

S

O

A

A M E

I

C

H

R
8

4

I

L
6

3

V

U

L

L

O

E
T

E

R

S

R

E

M P

I
T

T

Y

O
9

T

H

A

10

B

C

O

N

T

R

T

A

T

I

C

O

L

A
11

Y

S
E

Across

Down

5. This method gets the value of a property. [ACCESSOR]
7. This method returns true if you pass it “”.
[ISNULLOREMPTY]
8. The constructor in a subclass class doesn’t need the same
_____ as the constructor in its base class. [PARAMETERS]
9. A control on a form that lets you create tabbed applications.
[TABCONTROL]
11. This type of class can't be instantiated. [STATIC]

1. A _______ can override methods from its base class.
[SUBCLASS]
2. If you want a subclass to override a method, mark the
method with this keyword in the base class. [VIRTUAL]
3. A method in a class that’s run as soon as it’s instantiated.
[CONSTRUCTOR]
4. What a subclass does to replace a method in the base
class. [OVERRIDE]
6. This contains base classes and subclasses [HIERARCHY]
7. What you’re doing when add a colon to a class declaration.
[INHERIT]
10. A subclass uses this keyword to call the members of the
class it inherited from. [BASE]

268   Chapter 6

7 interfaces and abstract classes

Making classes
keep their promises

OK, OK, I know I implemented
the BookieCustomer interface,
but I can’t code the PayMoney()
method until next weekend.

You’ve got three days before
I send some Thug objects by to
make sure you implement the
WalksWithALimp() method.

Actions speak louder than words.
Sometimes you need to group your objects together based on the things they can
do rather than the classes they inherit from. That’s where interfaces come in—they
let you work with any class that can do the job. But with great power comes great
responsibility, and any class that implements an interface must promise to fulfill all of
its obligations…or the compiler will break their kneecaps, see?

this is a new chapter   269

worker bees, unite!

Le t’s ge t back to bee-sics
The General Bee-namics corporation wants to make the
Beehive Management System you created in the last chapter
into a full‑blown Hive Simulator. Here’s an overview of the
specification for the new version of the program:

General Bee-namics Hive Simulator

, we’ll need to add specialized
To better represent life in the hive
capabilities to the worker bees.
e a weight.
• All bees consume honey and hav
t reports, and tell workers to
• Queens assign work, monitor shif
work the next shift.
• All worker bees work shifts.
able to sharpen their stingers,
• Sting patrol bees will need to be
look for enemies, and sting them.
onsible for finding flowers,
• Nectar collector bees are resp
g to the hive.
gathering nectar, and then returnin

Looks like we’ll need to be able to
store different data for the worker
bees depending on the job they do.

Lots of things are still the same
The bees in the new Hive Simulator will still consume honey
in the same way they did before. The queen still needs to be
able to assign work to the workers and see the shift reports
that tell who’s doing what. The workers work shifts just like
they did before, too, it’s just that the jobs they are doing have
been elaborated a little bit.

270   Chapter 7

The Bee and Worke
classes don’t look likr
they’ll change much. e
We can extend th
classes we already e
have to handle th
new features. ese

interfaces and abstract classes

We can use inheritance to cre ate
classes for dif ferent t ype s of bee s
Here’s a class hierarchy with Worker and Queen classes
that inherit from Bee, and Worker has subclasses
NectarCollector and StingPatrol.

Here’s where
information about
weight and hone
consumption is styor
ed.

Weight

Bee

HoneyConsumption()

This is what the new
subclasses will look like.

Here’s where all
of the information
about working shifts
is kept.
Worker

Queen

Job
ShiftsToWork
ShiftsWorked
ShiftsLeft

Worker[]
ShiftNumber

DoThisJob()
WorkOneShift()

AssignWork()
WorkTheNextShift()
HoneyConsumption()

StingPatrol

StingerLength
EnemyAlert

SharpenStinger()
LookForEnemies()
Sting()

Remember how the ee
n
needed extra honey?quHe
where we overrode her re’s
HoneyConsumption() me
thod.

NectarCollector
Nectar

StingPatrol an
NectarCollectord
from the Worke inherit
r class.

class StingPatrol : Worker
{
int StingerLength;
bool enemyAlert;
public bool SharpenStinger (int Length)
{...}
public bool LookForEnemies(){...}
public void Sting(string Enemy){...}
}
class NectarCollector : Worker
{
int Nectar;
public void FindFlowers (){...}
public void GatherNectar(){...}
public void ReturnToHive(){...}
}

FindFlowers()
GatherNectar()
ReturnToHive()

And these classe
hold the informats io
particular to each n
job.

What happens if you have a bee that
needs to sting and collect nectar?

you are here 4   271

interfaces for jobs

An interface tells a class that it must
implement certain me thods and propertie s
A class can only inherit from one other class. So creating two separate subclasses for
the StingPatrol and NectarCollector bees won’t help us if we have a bee
that can do both jobs.
The queen’s DefendTheHive() method can only tell StingPatrol
objects to keep the hive safe. She’d love to train the other bees to use
their stingers, but she doesn’t have any way to command them to attack:

en o bje

ec

tarC ll ec
o

N

ec

r o b j ect

N

to

ue

r o b j ect

Q

to

I wish you guys
could help defend
the hive.

ct

class Queen {
private void DefendTheHive(StingPatrol patroller) { ... }
}

tarC ll ec
o

You use an
interface to
require a class
to include all
of the methods
and properties
listed inside the
interface—if
it doesn’t, the
compiler will
throw an error.

There are NectarCollector objects that know how to collect nectar from flowers, and instances
of StingPatrol that can sharpen their stingers and patrol for enemies. But even if the queen could
teach the NectarCollector to defend the hive by adding methods like SharpenStinger() and
LookForEnemies() to its class definition, she still couldn’t pass it into her DefendTheHive()
method. She could use two different methods:
private void DefendTheHive(StingPatrol patroller);
private void AlternateDefendTheHive(NectarCollector patroller);
But that’s not a particularly good solution. Both of those methods
would be identical, because they’d call the same methods in the objects
passed to them. The only difference is that one method would take a
StingPatrol, and the other would take a NectarCollector
that happens to have the methods necessary for patrolling the hive. And
you already know how painful it is to maintain two identical methods.
Luckily, C# gives us interfaces to handle situations like that.
Interfaces let you define a bunch of methods that a class must have.
An interface requires that a class has certain methods, and the way
that it does that is by making the compiler throw errors if it
doesn’t find all the methods required by the interface in every class
that implements it. Those methods can be coded directly in the class,
or they can be inherited from a base class. The interface doesn’t care
how the methods or properties get there, as long as they’re there
when the code is compiled.
272   Chapter 7

Even if the queen adds sting patrol methods
to a NectarCollector object, she still can’t
pass it to her DefendTheHive() method
because it expects a StingPatrol reference.
She can’t just set a StingPatrol reference
equal to a NectarCollector object.
She could add a second method called
AlternateDefendTheHive() that takes a
NectarCollector reference instead, but that would
be cumbersome and difficult to work with.
Plus, the DefendTheHive() and
AlternateDefendTheHive() methods would be identical
except for the type of the parameter. If she wanted
to teach the BabyBeeCare or Maintenance objects to
defend the hive, she’d need to keep adding new methods.
What a mess!

interfaces and abstract classes

Use the interface key word to define an interface
Adding an interface to your program is a lot like adding a class,
except you never write any methods. You just define the methods’
return type and parameters, but instead of a block of statements
inside curly brackets you just end the line with a semicolon.

t with I
Interface names star, you
should make

Whenever you create an interface
ere’s no rule
its name start with an uppercase I. Th es your code
that says you need to do it, but it mak for yourself
a lot easier to understand. You can see r life. Just
just how much easier that can make you any method
go into the IDE to any blank line insideinterfaces.
and type “I”—IntelliSense shows .NET

Interfaces do not store data, so you can’t add any fields. But
you can add definitions for properties. The reason is that get and set
accessors are just methods, and interfaces are all about forcing classes
to have certain methods with specific names, types, and parameters.
So if you’ve got a problem that looks like it could be solved by adding
a field to an interface, try using a property instead—odds are, it’ll
do what you’re looking for.
interface IStingPatrol
You declare an
{
interface like this:
int AlertLevel { get;}
Interfaces don’t st
int StingerLength { get; set;}
data. So they do ore
bool LookForEnemies();
fields…but they can’t have
n have } int SharpenStinger(int length);
properties.

Any class that implements
this interface will need a
SharpenStinger() method that
takes an int parameter.

interface INectarCollector
{
void FindFlowers();
void GatherNectar();
void ReturnToHive();
}

code for the
e
h
t
e
t
ri
w
’t
You don the interface, just
methods in You write the code
their names. that implements it.
in the class

So how does this help the queen? Now she can make one single method that takes any
object that knows how to defend the hive:
private void DefendTheHive(IStingPatrol patroller)

Since this takes an IStingPatrol reference, you can pass it
ANY object that implements IStingPatrol.
This gives the queen a single method that can take a StingPatrol, NectarStinger,
and any other bee that knows how to defend the hive—it doesn’t matter which class she passes
to the method. As long as it implements IStingPatrol, the DefendTheHive() method
is guaranteed that the object has the methods and properties it needs to defend the hive.

ue

ct

Q

Now that I know you can
defend the hive, we’ll all
be a lot safer!

en o bje

Any class that
implements this
method must
have all of these
methods and
properties, or the
program won’t
compile.

Everything in a
public interface
is automatically
public, because
you’ll use it to
define the public
methods and
properties of
any class that
implements it.

you are here 4   273

a little bit nectarcollector and a little bit stingpatrol

Now you can cre ate an instance of
NectarStinger that doe s both jobs

Q:

You use the colon operator to implement an interface, just like
you do for inheritance. It works like this: the first thing after the colon
is the class it inherits from, followed by a list of interfaces—unless it
doesn’t inherit from a class, in which case it’s just a list of interfaces
This class inherits from Worker and
(in no particular order).

A:

You implement an interface with a colon implements INectarCollector and
IStingPatrol.
operator, just like you inherit.

class NectarStinger : Worker, INectarCollector,
IStingPatrol {
You can use
public int AlertLevel {
more than one
get { return alertLevel; } interface if you
separate them
NectarStinger }

The
sets the backing
field for the
AlertLevel
property in its
LookForEnemies()
method.
Every method
in the interface
has a method
in the class.
Otherwise it
wouldn’t compile.
}

with commas.

public int StingerLength {
get { return stingerLength; }
set {
stingerLength = value;
}
}

public bool LookForEnemies() {...}
public int SharpenStinger(int length)
{...}
public void FindFlowers() {...}
public void GatherNectar() {...}
public void ReturnToHive() {...}

The bee retracts its
stinger when there
ar
e no enemies around,
ect,
When you create a NectarStinger obj
so
the backing field
ha
it will be able to do the job of bot
ch
an
ges its value over
ker bee.
NectarCollector and a StingPatrol wor
time.
When you’ve got a class that implements an interface, it acts just like
any other class. You can instantiate it with new and use its methods:
NectarStinger bobTheBee = new NectarStinger();
bobTheBee.LookForEnemies();
bobTheBee.FindFlowers();

274   Chapter 7

I still don’t quite get how interfaces improve
the beehive code. You’ll still need to add a
NectarStinger class, and it’ll still have
duplicate code…right?
Interfaces aren’t about preventing you from duplicating
code. They’re about letting you use one class in more than
one situation. The goal is to create one worker bee class that
can do two different jobs. You’ll still need to create classes
for them—that’s not the point. The point of the interfaces
is that now you’ve got a way to have a class that does any
number of jobs. Say you have a PatrolTheHive()
method that takes a StingPatrol object
and a CollectNectar() method that
takes a NectarCollector object. But
you don’t want StingPatrol to inherit from
NectarCollector or vice versa—each class has
public methods and properties that the other one shouldn’t
have. Now take a minute and try to think of a way to create
one single class whose instances could be passed to both
methods. Seriously, put the book down, take a minute and
try to think up a way! How do you do it?
Interfaces fix that problem. Now you can create an
IStingPatrol reference—and it can point to any object that
implements IStingPatrol, no matter what the
actual class is. It can point to a StingPatrol, or a
NectarStinger, or even a totally unrelated object.
If you’ve got an IStingPatrol reference pointing
to an object, then you know you can use all of the methods
and properties that are part of the IStingPatrol
interface, regardless of the actual type of the object.
But the interface is only part of the solution. You’ll still need to
create a new class that implements it, since it doesn’t actually
come with any code. Interfaces aren’t about avoiding the
creation of extra classes or avoiding duplicate code. They’re
about making one class that can do more than one job
without relying on inheritance, as inheritance brings a lot of
extra baggage—you’ll have to inherit every method, property,
and field, not just those that have to do with the specific job.

Can you think of ways that you could still avoid duplicating
code while using an interface? You could create a separate
class called Stinger or Proboscis to contain
the code that’s specific to stinging or collecting nectar.
NectarStinger and NectarCollector
could both create a private instance of Proboscis, and
any time they needed to collect nectar, they’d call its methods
and set its properties.

interfaces and abstract classes

Classes that implement interface s have to
include ALL of the interface’s me thods
Implementing an interface means that you have to have a method in the class
for each and every property and method that’s declared in the interface—if it
doesn’t have every one of them, it won’t compile. If a class implements more
than one interface, then it needs to include all of the properties and methods in
each of the interfaces it implements. But don’t take our word for it...

Do this!

1

Create a new application and add a new class file called IStingPatrol.cs
Instead of adding a class, type in the IStingPatrol interface from two pages ago.
Your program should compile.

2

Add a Bee class to the project
Don’t add any properties or methods yet. Just have it implement IStingPatrol:
class Bee : IStingPatrol
{
}

3

Try to compile the program
Select “Rebuild” from the Build menu. Uh-oh—the compiler won’t let you do it:

implement” errors for
You’ll see one of these “does not
t’s not implemented
every member of IStingPatrolllythawants you to
in the class. The compiler rea interface.
implement every method in the
4

Add the methods and properties to the Bee class
Add a LookForEnemies method and a SharpenStinger method—they don’t have to do anything,
they just need to compile. Then add a get accessor for an int called AlertLevel and get and set
accessors for an int called StingerLength. Now the program will compile!

you are here 4   275

clowning around

Ge t a lit tle practice using interface s
Interfaces are really easy to use, and the best way to understand them
is to start using them. So create a new Windows Forms Application
project, drag a button onto the form, and get started!
1

Do this!

Here’s the TallGuy class, and the code for a button that creates it using an object initializer
and calls its TalkAboutYourself() method. Nothing new here—we’ll use it in a minute:
class TallGuy {
public string Name;
public int Height;

}

public void TalkAboutYourself() {
MessageBox.Show(“My name is ” + Name + “ and I’m ”
+ Height + “ inches tall.”);
}

private void button1_Click(object sender, EventArgs e) {
TallGuy tallGuy = new TallGuy() { Height = 74, Name = “Jimmy” };
tallGuy.TalkAboutYourself();
}
2

Let’s create an IClown interface for the class.
You already know that everything inside an interface has to be public. But don’t take our
word for it. Create a new project and declare an interface on your own, like this:
interface IClown
Now try to declare a private method inside the interface:
private void Honk();
Select Build>>Build Solution in the IDE. You’ll see this error:

You don’t need to
type “public” inside the
interface, because it
automatically makes
every property and
method public.

Now go ahead and delete the private access modifier—the error will go away and
your program will compile just fine.
3

Before you go on to the next page, see if you can create the rest of the IClown interface, and modify the
TallGuy class to implement this interface. Add your interface to your project just like you add a class:
right-click on the project in the Solution Explorer and add a class file called IClown.cs.
Your new IClown interface should have a void method called Honk that doesn’t take any parameters, and
a string read-only property called FunnyThingIHave that has a get accessor but no set accessor.

276   Chapter 7

interfaces and abstract classes

4

Here’s the interface—did you get it right?
interface IClown
{
string FunnyThingIHave { get; }
void Honk();
}

Here’s an example of an interface
that has a get accessor without a
set accessor. Remember, interfaces
can’t contain fields, but when you
implement this read-only property in
a class, it’ll look like a field to other
objects.

OK, now modify the TallGuy class so that it implements IClown.
Remember, the colon operator is always followed by the base class to inherit
from (if any), and then a list of interfaces to implement, all separated by
commas. Since there’s no base class and only one interface to implement, the
declaration looks like this:
TallGuy

class TallGuy : IClown

will implement the IClown int

erface.

Then make sure the rest of the class is the same, including the two fields and
the method. Select “Build Solution” from the Build menu in the IDE to compile
and build the program. You’ll see two errors, including this one:
X

5

‘TallGuy’ does not implement interface
member ‘IClown.Honk()’

The errors will go away as soon as you add all of the methods and properties
defined in the interface. So go ahead and implement the interface. Add a readonly string property called FunnyThingIHave with a get accessor that always
returns the string “big shoes”. Then add a Honk() method that pops up a
message box that says, “Honk honk!”
that a
Here’s what it’ll look like:
public string FunnyThingIHave {
get { return “big shoes”; }
}
public void Honk() {
MessageBox.Show(“Honk honk!”);
}

6

What the IDE is telling
you is that when you said
TallGuy would implement
IClown, you promised to
add all of the properties
and methods in that
interface…and then you
broke that promise!

class that ave
is
es
ir
qu
re
ngIH
ce
fa
er
All the int has a property called FunnyTachicessor in
it
t
s
implement cessor. You can put any ge e string every
with a get ac e that just returns the sam t this will
there, even on t accessors won’t do this, bu to do.
time. Most gee if it does what you need it
work just fin
The interface says that you need a public
void method called Honk, but it doesn’t say
what that method needs to do. It can do
anything at all—no matter what it does, the
code will compile as long as some method is
there with the right signature.

Now your code will compile! Update your button so that it calls the
TallGuy object’s Honk() method.
you are here 4   277

interfaces don’t make objects

You can’t instantiate an interface,
but you can reference an interface
Say you had a method that needed an object that could perform
the FindFlowers() method. Any object that implemented the
INectarCollector interface would do. It could be a Worker
object, Robot object, or Dog object, as long as it implements the
INectarCollector interface.
That’s where interface references come in. You can use one
to refer to an object that implements the interface you need
and you’ll always be sure that it has the right methods for your
purpose—even if you don’t know much else about it.

This won’t work…

rker
You can create an array of IWo
antiate an
references, but you can’t instdo
point
interface. But what you can ancesis of classes
those references at new instw you can have
that implement IWorker. No ferent kinds of
an array that holds many dif
objects!

tiate
If you try to inste an
mpiler
an interface, th co
will complain.

IStingPatrol dennis = new IStingPatrol();
You can’t use the new keyword with an interface, which makes sense—the
methods and properties don’t have any implementation. If you could
create an object from an interface, how would it know how to behave?

…but this will.

NectarStinger ginger = fred;
You know what this third statement does—it creates a new NectarStinger
reference called ginger and points it at whatever object fred is pointing to.
The george statement uses IStingPatrol the same way.
So what happened?
There’s only one new statement, so only one object was created. The
second statement created a reference variable called george that can
point to an instance of any class that implements IStingPatrol.

278   Chapter 7

fred
george
ginger

N

ec

ect

The second line is where things start to get interesting, because that line of
code creates a new reference variable using IStingPatrol. That
line may look a little odd when you first see it. But look at this:

object can do
more, when you
use an interface ly
reference you on
have access to
the methods in
the interface.

obj

The first line is an ordinary new statement, creating a reference called Fred
and pointing it to a NectarStinger object.

tarSti nge

r

Remember how you
could pass a BLT
reference into any
class that expects a
Sandwich, because BLT
inherits from Sandwich?
Well, this is the same
thing—you can use a
NectarStinger in any
method or statement
that expects an
IStingPatrol.

NectarStinger fred = new NectarStinger();
IStingPatrol george = fred;
Even though this

interfaces and abstract classes

Interface reference s work just like object reference s
You already know all about how objects live on the heap.
When you work with an interface reference, it’s just another
way to refer to the same objects you’ve already been dealing
with. Look—it’s easy!

StingPatrol biff = new StingPatrol();
NectarCollector bertha = new NectarCollector();

St

ing

HA
BERT

N

P a t r ol

ec

or

Create a couple of bees
This is totally familiar stuff by now.

ct

1

BIFF

tarColl e

Let’s assume that StingPatrol implements the
IStingPatrol interface and NectarCollector
implements the INectarCollector interface.

biff = null;

4

This object didn’t disappear
because defender is still
pointing to it.

Assign a new instance to an interface reference
You don’t actually need an object reference—you can create a new
object and assign it straight to an interface reference variable.
INectarCollector gatherer = new NectarStinger();

der
efen
d
St
ing
P a t r ol

or

ct

Pie
cutie
HA
BERT
N
ec
tarColl e

or

An interface reference will keep an object alive
When there aren’t any references pointing to an object, it
disappears. But there’s no rule that says those references all have
to be the same type! An interface reference is just as good as an
object reference when it comes to keeping track of objects.

ct

3

Pie
cutie
HA
der BERT
n
e
f
e
N
Sd
ec
tin
tarColl e
g P a t r ol

or

These two statements use interfaces to
create new references to existing objects. You
can only point an interface reference at an
instance of a class that implements it.

Pie
cutie
A
ERTH
B
N
ec
tarColl e

ct

IStingPatrol defender = biff;
INectarCollector cutiePie = bertha;

BIFF r
e
fend
Sdt e
ing
P a t r ol

gatherer
N
ec
tarStin

r

Add IStingPatrol and INectarCollector references
You can use interface references just like you use any other
reference type.

ge

2

you are here 4   279

we’re expecting a big inheritance

You can find out if a class implements
a certain interface with “is”
Sometimes you need to find out if a certain class implements an interface. Suppose
we have all our worker bees in an array, called Bees. We can make the array hold
the type Worker, since all worker bees will be Worker classes, or subclasses of
that type.
But which of the worker bees can collect nectar? In other words, we want to know
if the class implements the INectarCollector interface. We can use the is
keyword to find out exactly that.

All the workers are in an
array of Workers. We’ll use
“is” to sort out which type of
worker each bee is.

y of
We’ve got an arraar
e all
ho
w
Worker bees a nectar
on
eligible to go
So we’ll
collecting mission. ar
ray,
Worker[] bees = new Worker[3];
loop through the gure out
fi
to
“is”
bees[0] = new NectarCollector(); and use es have the right
which on
ties
bees[1] = new StingPatrol();
methods and proper
b.
to do the jo

bees[2] = new NectarStinger();
for (int i = 0; i < bees.Length; i++)
re interfaces
is lets you compaty
{
pes, too!
AND also other
if (bees[i] is INectarCollector)

This is like saying, if this bee implements
the
INectarCollector interface…do this.

{

Q:

Wait a minute. When I put a
property in an interface, it looks just
like an automatic property. Does
that mean I can only use automatic
properties when I implement an
interface?

A:

No, not at all. It’s true that a
property inside an interface looks very
similar to an automatic property—like
Job and ShiftsLeft in the
IWorker interface on the next page.
But they’re definitely not automatic
properties. You could implement Job
like this:
public Job { get; private
set; }
You need that private set, because
automatic properties require you to
have both a set and a get (even
if they’re private). But you could also
implement it like this:
public job { get { return
“Accountant”; } }
and the compiler will be perfectly happy

}

}

bees[i].DoThisJob(“Nectar Collector”, 3); with that, too. You can also add a set
accessor—the interface requires a

the bee is a nectar
Now that we knowassign it the job of
collector, we can .
collecting nectar

get, but it doesn’t say you can’t have
a set, too. (If you use an automatic
property to implement it, you can
decide for yourself whether you want
the set to be private or public.)

If you have some other class that doesn’t inherit from Worker but does implement the
INectarCollector interface, then it’ll be able to do the job, too! But since it doesn’t
inherit from Worker, you can’t get it into an array with other bees. Can you think of a
way to get around the problem and create an array with both bees and this new class?

280   Chapter 7

interfaces and abstract classes

Interfaces can inherit from other interfaces
When one class inherits from another, it gets all of the methods and
properties from the base class. Interface inheritance is even simpler.
Since there’s no actual method body in any interface, you don’t have
to worry about calling base constructors or methods. The inherited
interfaces simply accumulate all of the methods and properties from
the interfaces they inherit from.
interface IWorker

{

string Job { get; }

We’ve created a new
IWorker interface that
the other interfaces
inherit from.

(interface)
IWorker
Job
ShiftsLeft
DoThisJob()
WorkOneShift()

int ShiftsLeft { get; }

void DoThisJob(string job, int shifts)
}

When we draw an
interface on a class
diagram, we’ll show
inheritance using
dashed lines.

void WorkOneShift()

(interface)
IStingPatrol

(interface)
INectarCollector

Any class that implements an interface that inherits
from IWorker must implement its methods and properties

StingerLength
EnemyAlert

Nectar

When a class implements an interface, it has to include every property and
method in that interface. And if that interface inherits from another one, then all
of those properties and methods need to be implemented, too.

SharpenStinger()
LookForEnemies()
Sting()

FindFlowers()
GatherNectar()
ReturnToHive()

interface IStingPatrol : IWorker
{
int AlertLevel { get;}
int StingerLength { get; set;}
bool LookForEnemies();
int SharpenStinger(int length);
}

plements
A class that im
ust not only
IStingPatrol mse
methods…
implement the

...but the methods of the
IWorker interface this interface
inherits from, too.

Here’s the same IStingPatrol
interface, but now it inherits from
the IWorker interface. It looks
like a tiny change, but it makes a
huge difference in any class that
implements IStingPatrol.
(interface)
IWorker
Job
ShiftsLeft
DoThisJob()
WorkOneShift()

you are here 4   281

Icanhascheezburger

The RoboBee 4000 can do a worker bee’s job
without using valuable honey
RoboBee
Let’s create a new bee, a RoboBee 4000, that runs on gas. We can
have it inherit from the IWorker interface, though, so it can do
everything a normal worker bee can.

Robot
This is our basic ca
n run
ts
bo
class, so ro
on gasoline.

ShiftsToWork
ShiftsWorked
ShiftsLeft
Job
DoThisJob()

class Robot
{
public void ConsumeGas() {...}
}

The RoboBee class
inherits from Robot and
implements IWorker. That
means it’s a robot, but can
do the job of a worker
bee. Perfect!
The RoboBee clases
implements all th e
methods from the.
IWorker interfac

class RoboBee : Robot, IWorker
{
private int shiftsToWork;
private int shiftsWorked;
public int ShiftsLeft
{get {return shiftsToWork - shiftsWorked;}}
public string Job { get; private set; }
public bool DoThisJob(string job, int shiftsToWork){...}
public void WorkOneShift() {...}
}
everything in the IWorker
If RoboBee didn’t implement com
pile.
interface, the code wouldn’t
Remember, for other classes in the application, there’s no
functional difference between a RoboBee and a normal worker
bee. They both implement the IWorker interface, so both act
like worker bees as far as the rest of the program is concerned.
But, you could distinguish between the types by using is:
if (workerBee is Robot) {
// now we know workerBee
// is a Robot object
}
282   Chapter 7

We can see what class
or interface workerBee
implements or subclasses
with “is”.

Any class can implement
ANY interface as long
as it keeps the promise
of implementing the
interface’s methods and
properties.

interfaces and abstract classes

is tells you what an object implements,
as tells the compiler how to treat your object
Sometimes you need to call a method that an object gets from an interface it
implements. But what if you don’t know if that object is the right type? You
use is to find that out. Then, you can use as to treat that object—which
you now know is the right type—as having the method you need to call.

IWorker[] bees = new IWorker[3];
bees[0] = new NectarStinger();
bees[1] = new RoboBee();
bees[2] = new Worker();

All these bees
but we don’t knimowplement IWorker,
implement other which ones
INectarCollector. interfaces, like

We’re looping through each bee…

for (int i = 0; i < bees.Length; i++) {
if (bees[i] is INectarCollector) {

…and checking to
see if it implements
INectarCollector.

INectarCollector thisCollector;

We can’t call
INectarCollector methods
on the bees. They’re of
type IWorker, and don’t
know about INectarCollector
methods.

thisCollector = bees[i] as INectarCollector;
thisCollector.GatherNectar();
...

y,
We use “as” tojesa
AS
ct
ob
s
treat thi lector
NOW we can call INectarCollector methods. an INectarCol
implementation.
Take a look at the array on the left. For each of these statements,
write down which values of i would make it evaluate to true.
Also, two of them won’t compile—cross those lines out.

IWorker[]
Bees[0] =
Bees[1] =
Bees[2] =
Bees[3] =
Bees[4] =
Bees[5] =
Bees[6] =
Bees[7] =

Bees = new IWorker[8];
new NectarStinger();
new RoboBee();
new Worker();
Bees[0] as IWorker;
IStingPatrol;
null;
Bees[0];
new INectarCollector();

1. (Bees[i] is INectarCollector)

2. (Bees[i] is IStingPatrol)

3. (Bees[i] is IWorker)

you are here 4   283

it looks like one thing, but it’s really another!

A Cof feeMaker is also an Appliance

Appliance

PluggedIn
Color

If you’re trying to figure out how to cut down your energy bill each month, you
don’t really care what each of your appliances does. You only really care that they
consume power. So if you were writing a program to monitor your electricity
consumption, you’d probably just write an Appliance class. But if you needed
to be able to distinguish a coffee maker from an oven, you’d have to build a class
hierarchy. So you’d add the methods and properties that are specific to a coffee
maker or oven to some CoffeeMaker and Oven classes, and they’d inherit from
an Appliance class that has their common methods and properties.

ConsumePower()

CoffeeMaker

public void MonitorPower(Appliance appliance) {

}

// code to add data to a household Here’s a method
// power consumption database
in the program to

This code would appear later on in the
program to monitor the coffee maker’s
power consumption.

monitor the power
consumption for a
house.

Oven

CoffeeLeft

Capacity

FillWithWater()
MakeCoffee()

Preheat()
HeatUp()
Reheat()

CoffeeMaker misterCoffee = new CoffeeMaker();
MonitorPower(misterCoffee);

Even though the MonitorPower() method takes
a reference to an Appliance object, you can
pass it the misterCoffee reference because
CoffeeMaker is a subclass of Appliance.

You already saw this
in the last chapter,
when you saw how
you could pass a
BLT reference to
a method that
expected a Sandwich.

Take a look at the array on the left. For each of these statements,
write down which values of i would make it evaluate to true.
Also, two of them won’t compile—cross them out.

IWorker[]
Bees[0] =
Bees[1] =
Bees[2] =
Bees[3] =
Bees[4] =
Bees[5] =
Bees[6] =
Bees[7] =

284   Chapter 7

1. (Bees[i] is INectarCollector)
Bees = new IWorker[8];
new NectarStinger();
NectarStinger() 0 and 6
new RoboBee();
imple
ments the
new Worker();
IStingPatrol 2. (Bees[i] is IStingPatrol)
Bees[0] as IWorker;
interface.
IStingPatrol;
0, 6
null;
3. (Bees[i] is IWorker)
Bees[0];
new INectarCollector();

0, 1, 2, 3, and 6

interfaces and abstract classes

Upcasting works with both objects and interface s
When you substitute a subclass for a base class—like substituting a coffee maker for an
appliance or a BLT for a sandwich—it’s called upcasting. It’s a really powerful tool
that you get when you build class hierarchies. The only drawback to upcasting is that
you can only use the properties and methods of the base class. In other words, when you
treat a coffee maker like an appliance, you can’t tell it to make coffee or fill it with water.
But you can tell whether or not it’s plugged in, since that’s something you can do with
any appliance (which is why the PluggedIn property is part of the Appliance class).
1

Let’s create some objects
We can create a CoffeeMaker and Oven class as usual:
CoffeeMaker misterCoffee = new CoffeeMaker();
Oven oldToasty = new Oven();

2

We’ll start by instantiating
an Oven object and a
CoffeeMaker object as usual.

What if we want to create an array of appliances?
You can’t put a CoffeeMaker in an Oven[ ] array, and you can’t put an Oven in a
CoffeeMaker[ ] array. But you can put both of them in an Appliance[ ] array:
Appliance[] kitchenWare = new Appliance[2];

But you can’t treat an appliance like an oven
When you’ve got an Appliance reference, you can only access the methods and properties
that have to do with appliances. You can’t use the CoffeeMaker methods and properties
through the Appliance reference even if you know it’s really a CoffeeMaker. So these
statements will work just fine, because they treat a CoffeeMaker object like an Appliance:
Appliance powerConsumer = new CoffeeMaker();
powerConsumer.ConsumePower();

But as soon as you try to use it like a CoffeeMaker:
powerConsumer.MakeCoffee();

This line won’t compile because
powerConsumer is an Appliance
reference, so it can only be used
to do Appliance things.

r
wem
pos
u er
n
o
c

your code won’t compile, and the IDE will display an error:
X

powerConsumer
is an Appliance
reference
pointing to a
CoffeeMaker
object.

‘Appliance’ does not contain a
definition for ‘MakeCoffee’

Co

ject

3

ff

ob

kitchenWare[1] = oldToasty;

g to create an
You can use upcastesin that can hold
array of appliancers and ovens.
both coffee mak

eeMake

r

kitchenWare[0] = misterCoffee;

because once you upcast from a subclass to a base class, then you can only access the
methods and properties that match the reference that you’re using to access the object.
you are here 4   285

upcasting is easy downcasting is risky

Downcasting le ts you turn your
appliance back into a cof fee maker

2

But what if we want to turn the Appliance back into a CoffeeMaker?
The first step in downcasting is using the is keyword to check if it’s even an option.
if (powerConsumer is CoffeeMaker)
// then we can downcast!

3

Now that we know it’s a CoffeeMaker, let’s use it like one
The is keyword is the first step. Once you know that you’ve got an Appliance reference
that’s pointing to a CoffeeMaker object, you can use as to downcast it. And that lets
you use the CoffeeMaker class’s methods and properties. And since CoffeeMaker
inherits from Appliance, it still has its Appliance methods and properties.
if (powerConsumer is CoffeeMaker) {

CoffeeMaker javaJoe = powerConsumer as CoffeeMaker;

}

javaJoe.MakeCoffee();

So what happens if you try to use as to convert an Oven object into a
CoffeeMaker? It returns null—and if you try to use it, .NET will cause
your program to break.
powerConsumer
Uh-oh, these

don’t match!

Oven foodWarmer = powerConsumer as Oven;
foodWarmer.Preheat();
}

286   Chapter 7

ff

eeMake

The javaJoe reference
points to the
same CoffeeMaker
object as
powerConsumer. But
it’s a CoffeeMaker
reference, so it can
call the MakeCoffee()
method.
r r
wem
e
pos
u
n
co
oe
javaJ
Co

When downcasting fails, as re turns null

if (powerConsumer is CoffeeMaker) {

ject

Co

ob

powerConsumer.ConsumePower();

r

Appliance powerConsumer = new CoffeeMaker();

r r
wem
e
pos
u
con

ject

We’ll start with the CoffeeMaker we already upcast
Here’s the code that we used:

ff

ob

1

Here’s our Appliance
reference that points
to a CoffeeMaker
object from the last
page.

eeMake

r

Upcasting is a great tool, because it lets you use a coffee maker or an oven
anywhere you just need an appliance. But it’s got a big drawback—if you’re
using an Appliance reference that points to a CoffeeMaker object, you
can only use the methods and properties that belong to Appliance. And that’s
where downcasting comes in: that’s how you take your previously upcast
reference and change it back. You can figure out if your Appliance is really a
CoffeeMaker using the is keyword. And once you know that, you can convert
the Appliance back to a CoffeeMaker using the as keyword.

is NOT an Oven object. So when
you try to downcast it with “as”, the foodWarmer
reference ends up set to null. And when you try to
use a null reference, this happens....

interfaces and abstract classes

Upcasting and downcasting work with interface s, too
You already know that is and as work with interfaces. Well, so do all of the upcasting
and downcasting tricks. Let’s add an ICooksFood interface for any class that can heat
up food. And we’ll add a Microwave class—both Microwave and Oven implement
the ICooksFood interface. Now there are three different ways that you can access an
Oven object. And the IDE’s IntelliSense can help you figure out exactly what you
can and can’t do with each of them:

(interface)
ICooksFood
Capacity

Oven misterToasty = new Oven();

HeatUp()
Reheat()

misterToasty.

As soon as you
type the dot,
the IntelliSense
window will pop
up with a list
of all of the
members you can
use.

misterToasty is an Oven reference
pointing to an Oven object, so
it can access all of the methods
and properties…but it’s the least
general type, so you can only
point it at Oven objects.

Any class that
implements
ICooksFood is
an appliance
that can heat
up food.

Oven
Capacity

Microwave
Capacity

Preheat()
HeatUp()
Reheat()

HeatUp()
Reheat()
MakePopcorn()

ICooksFood cooker;

if (misterToasty is ICooksFood)

cooker = misterToasty as ICooksFood;
cooker.

cooker is an ICooksFood reference
pointing to that same Oven object. It
can only access ICooksFood members,
but it can also point to a Microwave
object.
Appliance powerConsumer;

if (misterToasty is Appliance)

powerConsumer = misterToasty;
powerConsumer.

powerConsumer is an
Appliance reference. It
only lets you get to the
public fields, methods, and
properties in Appliance.
You can also point it at
a CoffeeMaker object if
you want.

Three different
references that
point to the
same object can
access different
methods and
properties,
depending on
the reference’s
type.
you are here 4   287

no dumb questions

Q:

So back up—you told me that I
can always upcast but I can’t always
downcast. Why?

A:

Because the compiler can warn you
if your upcast is wrong. The only time an
upcast won’t work is if you’re trying to set an
object equal to a class that it doesn’t inherit
from or an interface that it doesn’t implement.
And the compiler can figure out immediately
that you didn’t upcast properly, and will give
you an error.

On the other hand, the compiler doesn’t
know how to check if you’re downcasting
from an object or interface reference to a
reference that’s not valid. That’s because it’s
perfectly legal to put any class or interface
name on the right-hand side of the as
keyword. If the downcast is illegal, then the
as statement will just return null. And
it’s a good thing that the compiler doesn’t
stop you from doing that, because there are
plenty of times when you’d want to do it.

Q:

Someone told me that an interface
is like a contract, but I don’t really get
why. What does that mean?

A:

Yes, we’ve heard that too—a lot
of people like to say that an interface is
like a contract. (That’s a really common
question on job interviews.) And it’s true, to
some extent. When you make your class
implement an interface, you’re telling the
compiler that you promise to put certain
methods into it. The compiler will hold you to
that promise.

But we think that it’s easier to remember
how interfaces work if you think of an
interface as a kind of checklist. The compiler
runs through the checklist to make sure that
you actually put all of the methods from the
interface into your class. If you didn’t, it’ll
bomb out and not let you compile.

288   Chapter 7

Q:

What if I want to put a method body
into my interface? Is that OK?

A:

No, the compiler won’t let you do that. An
interface isn’t allowed to have any statements
in it at all. Even though you use the colon
operator to implement an interface, it’s not
the same thing as inheriting from a class.
Implementing an interface doesn’t add any
behavior to your class at all, or make any
changes to it. All it does is tell the compiler
to make sure that your class has all of the
methods that the interface says it should have.

Q:

Then why would I want to use an
interface? It seems like it’s just adding
restrictions, without actually changing
my class at all.

A:

Because when your class implements
an interface, then an interface reference can
point to any instance of that class. And that’s
really useful to you—it lets you create one
reference type that can work with a whole
bunch of different kinds of objects.

Here’s a quick example. A horse, an ox, a
mule, and a steer can all pull a cart. But in
our zoo simulator, Horse, Ox, Mule,
and Steer would all be different classes.
Let’s say you had a cart-pulling ride in your
zoo, and you wanted to create an array of
any animal that could pull carts around. Uhoh—you can’t just create an array that will
hold all of those. If they all inherited from the
same base class, then you could create an
array of those. But it turns out that they don’t.
So what’ll you do?
That’s where interfaces come in handy. You
can create an IPuller interface that has
methods for pulling carts around. Now you
could declare your array like this:

IPuller[] pullerArray;

Now you can put a reference to any
animal you want in that array, as long as it
implements the IPuller interface.

Q:

Is there an easier way to implement
interfaces? It’s a lot of typing!

A:

Why yes, there is! The IDE gives you
a very powerful shortcut that automatically
implements an interface for you. Just start
typing your class:

class
Microwave : ICooksFood
{ }
Click on ICooksFood—you’ll see a small bar
appear underneath the “I”. Hover over it and
you’ll see an icon appear underneath it:

Sometimes it’s hard to click
on the icon, but Ctrl-period
will work, too.

Click on the icon and choose “Implement
Interface ‘ICooksFood’” from the menu. It’ll
automatically add any members that you
haven’t implemented yet. Each one has a
single throws statement in it—they’ll
cause your program to halt, as a reminder
in case you forget to implement one of them.
(You’ll learn about throws in Chapter 10.)

An interface is like
a checklist that the
compiler runs through
to make sure your
class implemented a
certain set of methods.

interfaces and abstract classes

Extend the IClown interface and use classes that implement it.
1

IClown
(interface)
FunnyThingIHave

Start with the IClown interface from the last “Do This!” on page 277:

Honk()

interface IClown {
string FunnyThingIHave { get; }
void Honk();
}

2

3

Extend IClown by creating a new interface, IScaryClown, that
inherits from IClown. It should have an additional string
property called ScaryThingIHave with a get accessor but no set
accessor, and a void method called ScareLittleChildren().

FunnyFunny
FunnyThingIHave

IScaryClown
(interface)
ScaryThingIHave

Honk()

ScareLittleChildren()

Create these classes:
≥≥ A funny clown class called FunnyFunny that uses a private
string variable to store a funny thing. Use a constructor that takes
a parameter called FunnyThingIHave and uses it to set the
private field. The Honk()method should say, “Honk honk! I have
a ” followed by the funny thing it has. The FunnyThingIHave
set accessor should return the same thing.
≥≥ A scary clown class called ScaryScary that uses a private variable to
store an integer that was passed to it by its constructor in a parameter
called numberOfScaryThings. The ScaryThingIHave get
accessor should return a string consisting of the number from the
constructor followed by “spiders”. The ScareLittleChildren()
pops up a message box that says, “Boo! Gotcha!”

4

ScaryScary
ScaryThingIHave

ScareLittleChildern()

Here’s code for a button—but it’s not working. Can you figure out how to fix it?
private void button1_Click(object sender, EventArgs e) {
ScaryScary fingersTheClown = new ScaryScary(“big shoes”, 14);
FunnyFunny someFunnyClown = fingersTheClown;
IScaryClown someOtherScaryclown = someFunnyClown;
someOtherScaryclown.Honk();

}

Fingers the Clown is

scary.

You better get this
one right…or else!

you are here 4   289

no no! nooo! noo! no more scary clowns!

Extend the IClown interface and use classes that implement it.

interface IClown {
string FunnyThingIHave { get; }
void Honk();
}
interface IScaryClown : IClown {
string ScaryThingIHave { get; }
void ScareLittleChildren();
}

The Honk()
method just uses
class FunnyFunny : IClown {
this set accessor
public FunnyFunny(string funnyThingIHave) { to display its
this.funnyThingIHave = funnyThingIHave; message—no need You could have
}
to have the same implemented the
private string funnyThingIHave;
IClown method and
code twice.
public string FunnyThingIHave {
property again, but
get { return “Honk honk! I have ” + funnyThingIHave; } why not just inherit
}
from FunnyFunny?

}

public void Honk() {
MessageBox.Show(this.FunnyThingIHave);
}
Since ScaryScary is a

subclass of FunnyFunny and FunnyFunny
implements IClown, ScaryScary implements IClown too.

class ScaryScary : FunnyFunny, IScaryClown {
public ScaryScary(string funnyThingIHave, int numberOfScaryThings)
: base(funnyThingIHave) {
this.numberOfScaryThings = numberOfScaryThings;
}
private int numberOfScaryThings;
public string ScaryThingIHave {
get { return “I have ” + numberOfScaryThings + “ spiders”; }
You can set a FunnyFunny reference
}

}

public void ScareLittleChildren() {
MessageBox.Show(“Boo! Gotcha!”);
}

equal
to a ScaryScary object because ScaryS
inherits from FunnyFunny. But you can cary
any IScaryClown reference to just any ’t set
because you don’t know if that clow clown,
That’s why you need to use the as keyn is scary.
word.
EventArgs e) {

private void button1_Click(object sender,
ScaryScary fingersTheClown = new ScaryScary(“big shoes”, 14);
FunnyFunny someFunnyClown = fingersTheClown;
IScaryClown someOtherScaryclown = someFunnyClown as ScaryScary;
someOtherScaryclown.Honk();
You can also use the someOtherScaryClown reference to
}

call
ScareLittleChildren()—but you can’t get to it from the
someFunnyClown reference.

290   Chapter 7

interfaces and abstract classes

There’s more than just public and pri vate
You already know how important the private keyword is, how you use it, and
how it’s different from public. C# has a name for these keywords: they’re
called access modifiers. The name makes sense, because when you change
an access modifier on a property, field, or method of a class—its members—or
the entire class, you change the way other classes can access it. There are a few
more access modifiers that you’ll use, but we’ll start with the ones you know:

We call a class’s methods,
fields, and properties its
members. Any member can be
marked with the public or
private access modifier.

(as long as they can access the declaring class)

≥

public means that anyone can access it
When you mark a class or class member public, you’re telling C# that any instance of any
other class can access it. It’s the least restrictive access modifier. And you’ve already seen how
it can get you in trouble—only mark class members public if you have a reason. That’s how
you make sure your classes are well encapsulated.

≥

private means that only other members can access it
When you mark a class member private, then it can only be accessed from other members
inside that class or other instances of that class. You can’t mark a class private—
unless that class lives inside another class, in which case it’s only available to instances
of its container class. Then it’s private by default, and if you want it to be public you need to
mark it public.

≥

protected means public to subclasses, private to everyone else
You’ve already seen how a subclass can’t access the private fields in its base class—it has
to use the base keyword to get to the public members of the base object. Wouldn’t it
be convenient if the subclass could access those private fields? That’s why you have the
protected access modifier. Any class member marked protected can be accessed by
any other member of its class, and any member of a subclass of its class.

≥

internal means public only to other classes in an assembly
The built-in .NET Framework classes are assemblies—libraries of classes that are in your
project’s list of references. You can see a list of assemblies by right-clicking on “References”
in the Solution Explorer and choosing “Add Reference…”—when you create a new
Windows Forms application, the IDE automatically includes the references you need to build
a Windows application. When you build an assembly, you can use the internal keyword
to keep classes private to that assembly, so you can only expose the classes you want. You can
combine this with protected—anything you mark protected internal can only be
accessed from within the assembly or from a subclass.

≥

sealed says that this class can’t be subclassed
There are some classes that you just can’t inherit from. A lot of the .NET Framework classes
are like this—go ahead, try to make a class that inherits from String (that’s the class whose
IsEmptyOrNull() method you used in the last chapter). What happens? The compiler
won’t let you build your code—it gives you the error “cannot derive from sealed type ‘string’”.
You can do that with your own classes—just add sealed after the access modifier.

There’s a little more to all of these definitions. Take a peek at
leftover #2 in the appendix to learn more about them.

If you leave off
the access modifier
when you declare
a class member, it
defaults to private.
If you leave off the access
modifier when you declare
a class or an interface,
then by default it’s set to
internal. And that’s just
fine for most classes—it
means that any other class
in the assembly can read it.
If you’re not using multiple
assemblies, internal will
work just as well as public
for classes and interfaces.
Give it a shot—go to an
old project, change some
of the classes to internal,
and see what happens.
r,
Sealed is a modifaciecess
an
t
but it’s no
modifier. That’saffects
because it only doesn’t
inheritance—it the class
change the way .
can be accessed

you are here 4   291

minty fresh scope

Access modifiers change visibilit y
Let’s take a closer look at the access modifers and how they affect the scope of the
various class members. We made two changes: the funnyThingIHave backing
field is now protected, and we changed the ScareLittleChildren()
method so that it uses the funnyThingIHave field:
1

Here are two interfaces. IClown defines a clown who honks his
horn and has a funny thing. IScaryClown inherits from clown. A
scary clown does everything a clown does, plus he has a scary thing
and scares little children.

interface IClown {
string FunnyThingIHave { get; }
void Honk();
}
interface IScaryClown : IClown {
string ScaryThingIHave { get; }
void ScareLittleChildren();
}

2

Make these two changes to
your own exercise solution.
Then change the protected
access modifier back to private
and see what errors you get.

The “this” keyword also changes what variable
you’re referring to. It says to C#, “Look
at the current instance of the class to find
whatever I’m connected to—even if that
matches a parameter or local variable.”
This is a really common way to
use “this”, since the parameter
and backing field have the same
name. funnyThingIHave refers
to the parameter, while this.
funnyThingIHave is the backing field.

The FunnyFunny class implements the IClown interface. We made the funnyThingIHave
field protected so that it can be accessed by any instance of a subclass of FunnyFunny.

class FunnyFunny : IClown {
public FunnyFunny(string funnyThingIHave) {
this.funnyThingIHave = funnyThingIHave;
We changed FunnyThingIHave
}
to protected. Look and see
protected string funnyThingIHave;
how it affects the ScaryScary.
public string FunnyThingIHave {
ScareLittleChildren() method.
get { return “Honk honk! I have ” + funnyThingIHave; }
}

By adding
“this”, we told
C# that we’re
talking about
the backing
field, not the
parameter that
has the same
name.

}

public void Honk() {
MessageBox.Show(this.FunnyThingIHave);
}

292   Chapter 7

When you use “this” with a property, it
tells C# to execute the set or get
accessor.

interfaces and abstract classes

3

The ScaryScary class implements the IScaryClown
interface. It also inherits from FunnyFunny, and since
FunnyFunny implements IClown, that means ScaryScary
does, too. Take a look at how the ScareLittleChildren()
method accesses the funnyThingIHave backing field—it can
do that because we used the protected access modifier. If we’d
made it private instead, then this code wouldn’t compile.

Access Modifiers
Up Close
numberOfScaryThings
is private, which is
typical of a backing
field. So only another
instance of ScaryScary
would be able to see it.

class ScaryScary : FunnyFunny, IScaryClown {
public ScaryScary(string funnyThingIHave,
int numberOfScaryThings)
: base(funnyThingIHave) {
this.numberOfScaryThings = numberOfScaryThings;
}

private int numberOfScaryThings;
public string ScaryThingIHave {
get { return “I have ” + numberOfScaryThings + “ spiders”; }
The protected keyword
}

tells C# to make something
private to everyone except
instan
ces of a subclass.
MessageBox.Show(“You can’t have my ”
+ base.funnyThingIHave);
The “base” keyword tells C# to use
If we’d left funnyThingIHave private,
the value from the base class. But
this
would cause the compiler to give
we could also use “this” in this case.
you
an
error. But when we changed
Can you figure out why?
it to protected, that made it visible
to any subclass of FunnyFunny.

public void ScareLittleChildren() {

}
4

}

Here’s a button that instantiates FunnyFunny and ScaryScary. Take a look at how it uses as to
downcast someFunnyClown to an IScaryClown reference.

private void button1_Click(object sender, EventArgs e) {
ScaryScary fingersTheClown = new ScaryScary(“big shoes”, 14);
FunnyFunny someFunnyClown = fingersTheClown;
IScaryClown someOtherScaryclown = someFunnyClown as ScaryScary;
someOtherScaryclown.Honk();
We put in some extra steps to show you that you could
}

Since this button click
event handler is not
part of FunnyFunny and
ScaryScary, it can’t
access the protected
funnyThingIHave field.

upcast ScaryScary to FunnyFunny, and then downcast
that to IScaryClown. But all three of those lines could
be collapsed into a single line. Can you figure out how?

It’s outside of both classes, so the statements
inside it only have access to the public members
of any FunnyFunny or ScaryScary objects.

you are here 4   293

eww, duplicate code!

Q:

Why would I want to use an
interface instead of just writing all of the
methods I need directly into my class?

A:

You might end up with a lot of different
classes as you write more and more
complex programs. Interfaces let you group
those classes by the kind of work they do.
They help you be sure that every class that’s
going to do a certain kind of work does it
using the same methods. The class can do
the work however it needs to, and because
of the interface, you don’t need to worry
about how it does it to get the job done.
Here’s an example: you can have a
truck class and a sailboat class that
implement ICarryPassenger. Say
the ICarryPassenger interface
stipulates that any class that implements
it has to have a ConsumeEnergy()
method.  Your program could use them
both to carry passengers even though the
sailboat class’s ConsumeEnergy()
method uses wind power and the truck
class’s method uses diesel fuel.
Imagine if you didn’t have the

ICarryPassenger interface. Then it

would be tough to tell your program which
vehicles could carry people and which
couldn’t. You would have to look through
each class that your program might use
and figure out whether or not there was a
method for carrying people from one place to
another. Then you’d have to call each of the
vehicles your program was going to use with
whatever method was defined for carrying
passengers.  And since there’s no standard
interface, they could be named all sorts of
things or buried inside other methods. You
can see how that’ll get confusing pretty fast.

294   Chapter 7

Q:
A:

Why do I need to use a property?
Can’t I just include a field?

Good question. An interface only defines
the way a class should do a specific kind of job.  
It’s not an object by itself, so you can’t instantiate
it and it can’t store information. If you added a
field that was just a variable declaration, then C#
would have to store that data somewhere—and
an interface can’t store data by itself. A property
is a way to make something that looks like a field
to other objects, but since it’s really a method, it
doesn’t actually store any data.

Q:

What’s the difference between a
regular object reference and an interface
reference?

A:

You already know how a regular,
everyday object reference works.  If you
create an instance of Skateboard
called VertBoard, and then a new
reference to it called HalfPipeBoard,
they both point to the same thing.  But if
Skateboard implements the interface
IStreetTricks and you create an
interface reference to Skateboard called
StreetBoard, it will only know the
methods in the Skateboard class that are  
also in the IStreetTricks interface.
All three references are actually pointing to the
same object. If you call the object using the
HalfPipeBoard or VertBoard
references, you’ll be able to access any
method or property in the object. If you call
it using the StreetBoard reference,
you’ll only have access to the methods and
properties in the interface.  

Q:

Then why would I ever want to use
an interface reference if it limits what I
can do with the object?

A:

Interface references give you a way
of working with a bunch of different kinds
of objects that do the same thing.  You
can create an array using the interface
reference type that will let you pass
information to and from the methods in
ICarryPassenger whether you’re
working with a truck object, a horse object,
a unicycle object, or a car object. The
way each of those objects does the job is
probably a little different, but with interface
references, you know that they all have
the same methods that take the same
parameters and have the same return types.
So, you can call them and pass information
to them in exactly the same way.

Q:

Why would I make something
protected instead of private or public?

A:

Because it helps you encapsulate your
classes better. There are a lot of times that a
subclass needs access to some internal part
of its base class. For example, if you need
to override a property, it’s pretty common to
use the backing field in the base class in the
get accessor, so that it returns some sort of
variation of it. But when you build classes,
you should only make something public
if you have a reason to do it. Using the
protected access modifier lets you expose it
only to the subclass that needs it, and keep
it private from everyone else.

Interface references
only know about
the methods and
properties that
are defined in the
interface.

interfaces and abstract classes

Some classe s should never be instantiated
Remember our zoo simulator class hierarchy? You’ll definitely end up
instantiating a bunch of hippos, dogs, and lions. But what about the
Canine and Feline classes? How about the Animal class? It turns out
that there are some classes that just don’t need to be instantiated…and, in
fact, don’t make any sense if they are. Here’s an example.

Shopper
TotalSpent
CreditLimit
ShopTillYouDrop()
BuyFavoriteStuff()

Let’s start with a basic class for a student shopping at the student bookstore.
class Shopper {

ArtStudent

Engineering
Student

BuyFavoriteStuff()

BuyFavoriteStuff()

public void ShopTillYouDrop()

while (TotalSpent < CreditLimit)

}

BuyFavoriteStuff();

public virtual void BuyFavoriteStuff () {

// No implementation here - we don’t know

}

}

// what our student likes to buy!

Here’s the ArtStudent class—it subclasses Shopper:

class ArtStudent : Shopper {

The ArtStudent and
EngineeringStudent
classes both override
the BuyFavoriteStuff()
method, but they buy
very different things.

public override void BuyFavoriteStuff () {
BuyArtSupplies();

BuyBlackTurtlenecks();

}

}

BuyDepressingMusic();

And the EngineeringStudent class also inherits from Shopper:
class EngineeringStudent : Shopper {

public override void BuyFavoriteStuff () {
BuyPencils();

BuyGraphingCalculator();

}

}

BuyPocketProtector();

So what happens when you instantiate Shopper? Does it ever make sense to do it?
you are here 4   295

i can’t believe it’s not an interface!

An abstract class is like a cross
be t ween a class and an interface
Suppose you need something like an interface, that requires classes to
implement certain methods and properties. But you need to include some
code in that interface, so that certain methods don’t have to be implemented
in each inheriting class. What you want is an abstract class. You get the
features of an interface, but you can write code in it like a normal class.
≥

≥

≥

An abstract class is like a normal class
You define an abstract class just like a normal one. It has fields and
methods, and you can inherit from other classes, too, exactly like with
a normal class. There’s almost nothing new to learn here, because
you already know everything that an abstract class does!

An abstract class is like an interface
When you create a class that implements an interface, you agree to
implement all of the properties and methods defined in that interface.
An abstract class works the same way—it can include declarations
of properties and methods that, just like in an interface, must be
implemented by inheriting classes.

But an abstract class can’t be instantiated
The biggest difference between an abstract class and a concrete
class is that you can’t use new to create an instance of an abstract
class. If you do, C# will give you an error when you try to compile
your code.

X

296   Chapter 7

Cannot create an instance of the
abstract class or interface ‘MyClass’

A method that has a declaration but
no statements or method body is
called an abstract method. Inheriting
classes must implement all abstract
methods, just like when they inherit
from an interface.
Only abstract classes can have abstract
methods. If you put an abstract
method into a class, then you’ll have
mark that class abstract or it won’t to
compile. You’ll learn more about how
mark a class abstract in a minute. to

The opposite of abstract
is concrete. A concrete
method is one that has a
body, and all the classes
you’ve been working with so
far are concrete classes.

This error is because you have
abstract methods without any
code! The compiler won’t let you
instantiate a class with missing
code, just like it wouldn’t let you
instantiate an interface.

interfaces and abstract classes
Wait, what? A class that I can’t instantiate?
Why would I even want something like that?

Because you want to provide some code, but
still require that subclasses fill in the rest of the code.
Sometimes bad things happen when you create objects that should never be
created. The class at the top of your class diagram usually has some fields that it
expects its subclasses to set. An Animal class may have a calculation that depends
on a Boolean called HasTail or Vertebrate, but there’s no way for it to set that itself.

Here’s a class that the Objectville Here’s an example…
Astrophysics Club uses to send
their rockets to different planets.
It doesn’t make sense to
class PlanetMission {
set these fields in the
public long RocketFuelPerMile;
base class, because we
public long RocketSpeedMPH;
don’t know what rocket
public int MilesToPlanet;
or planet we’ll be using.
public long UnitsOfFuelNeeded() {
return MilesToPlanet * RocketFuelPerMile;
}

public int TimeNeeded() {
return MilesToPlanet / (int) RocketSpeedMPH;
}

}

public string FuelNeeded() {
return “You’ll need ”
+ MilesToPlanet * RocketFuelPerMile
+ “ units of fuel to get there. It’ll take ”
+ TimeNeeded() + “ hours.”;
}

The astrophysicists have two
missions—one to Mars, and
one to Venus.

class Venus : PlanetMission {
public Venus() {
MilesToPlanet = 40000000;
RocketFuelPerMile = 100000;
RocketSpeedMPH = 25000;
}
}
class Mars : PlanetMission {
public Mars() {
MilesToPlanet = 75000000;
RocketFuelPerMile = 100000;
RocketSpeedMPH = 25000;
}
} The constructors for the Mars and Venus

subclasses set the three fields they inherited
from Planet. But those fields won’t get set
if you instantiate Planet directly. So what
happens when FuelNeeded() tries to use them?

private void button1_Click(object s, EventArgs e) {
Mars mars = new Mars();
MessageBox.Show(mars.FuelNeeded());
}
private void button2_Click(object s, EventArgs e) {
Venus venus = new Venus();
MessageBox.Show(venus.FuelNeeded());
}
private void button3_Click(object s, EventArgs e) {
PlanetMission planet = new PlanetMission();
MessageBox.Show(planet.FuelNeeded());
}

Before you flip the page, try to
figure out what will happen when
the user clicks the third button....
you are here 4   297

abstract classes avoid this mess

Like we said, some classe s should never be instantiated
The problems all start when you create an instance of the
PlanetMission class. Its FuelNeeded() method
expects the fields to be set by the subclass. But when they
aren’t, they get their default values—zero. And when C#
tries to divide a number by zero…
private void button3_Click(object s, EventArgs e) {
PlanetMission planet = new PlanetMission();
MessageBox.Show(planet.FuelNeeded());
}

The PlanetMission class
wasn’t written to be
instantiated. We were only
supposed to inherit from
it. But we did instantiate
it, and that’s where the
problems started.

When the FuelNeeded()
method tried to divide
by RocketSpeedMPH,
it was zero. And whenis
you divide by zero, th
happens.

Solution: use an abstract class
When you mark a class abstract, C# won’t let you write
code to instantiate it. It’s a lot like an interface—it acts like a
template for the classes that inherit from it.

Adding the abstract keyword to the class
declaration tells C# this is an abstract class,
and can’t be instantiated.

abstract class PlanetMission {
Now C# will
public long RocketFuelPerMile;
refuse to compile
public long RocketSpeedMPH;
our program until
public int MilesToPlanet;
we remove the
line that creates
public long UnitsOfFuelNeeded() {
an instance of
return MilesToPlanet * RocketFuelPerMile;
PlanetMission.
}

}

// the rest of the class is defined here

Flip back to the solution to Kathleen’s party planning program in the
previous chapter on pages 254–256, and take another look at the
encapsulation problems that we left in the code. Can you figure out
how you’d use an abstract class to solve them?
298   Chapter 7

interfaces and abstract classes

An abstract me thod doe sn’t have a body
You know how an interface only has declarations for methods and properties, but
it doesn’t actually have any method bodies? That’s because every method in an
interface is an abstract method. So let’s implement it! Once we do, the error
will go away. Any time you extend an abstract class, you need to make sure that
you override all of its abstract methods. Luckily, the IDE makes this job easier.
Just type “public override”—as soon as you press space, the IDE will display
a drop-down box with a list of any methods that you can override. Select the
SetMissionInfo() method and fill it in:

abstract class PlanetMission {

Every method in
an interface is
automatically abstract,
so you don’t need to use
the abstract keyword
in an interface, just in
an abstract class. Only
abstract classes can
have abstract methods…
but they can have
concrete methods too.

public abstract void SetMissionInfo(
		
int milesToPlanet, int rocketFuelPerMile,
		
long rocketSpeedMPH);
// the rest of the class...

It really sucks to be
an abstract method.
You don’t have a body.

u’d
just like what yody,
is
d
ho
et
m
ct
ra
bo
a
This abst
e—it doesn’t have
see in an interfacat inherits from PlanetMissiond
but any class tht the SetMissionInfo() metho
has to implemenm won’t compile.
or the progra
If we add that method in and try to build
the program, the IDE gives us an error:
X

‘VenusMission’ does not implement inherited abstract
member ‘PlanetMission.SetMissionInfo(long, int, int)’

So let’s implement it! Once we do, the error will go away.
class Venus : PlanetMission {
public Venus() {
SetMissinInfo(40000000, 100000, 25000);
}

}

When you inherit
from an abstract
class, you need to
override all of its
abstract methods.

public override SetMissionInfo(int milesToPlanet, long rocketFuelPerMile,
int rocketSpeedMPH) {
this.MilesToPlanet = milesToPlanet;
this.RocketFuelPerMile = rocketFuelPerMile;
this.RocketSpeedMPH = rocketSpeedMPH;
}
you are here 4   299

worth a thousand words

Here’s your chance to demonstrate your artistic abilities. On the left you’ll find sets
of class and interface declarations. Your job is to draw the associated class diagrams
on the right. We did the first one for you. Don’t forget to use a dashed line for
implementing an interface and a solid line for inheriting from a class.

Given:
1) interface Foo { }

What’s the Picture ?
1)

(interface)
Foo

class Bar : Foo { }

Bar

2) interface Vinn { }

2)

abstract class Vout : Vinn { }

3) abstract class Muffie : Whuffie { }

3)

class Fluffie : Muffie { }
interface Whuffie { }

4)

4)

class Zoop { }
class Boop : Zoop { }
class Goop : Boop { }

5)

5)
class Gamma : Delta, Epsilon { }
interface Epsilon { }
interface Beta { }
class Alpha : Gamma,Beta { }
class Delta { }

300   Chapter 7

interfaces and abstract classes

On the left you’ll find sets of class diagrams. Your job is to turn
these into valid C# declarations. We did number 1 for you.

What’s the Declaration ?

Given:

1) public class Click { }

Click

1

public class Clack : Click { }

Top

2

2)

Clack

Tip

3)

Fee

3
4

Foo

4)

Fi

Bar

5)

Zeta

5
Baz

Beta

KEY

Alpha

extends
implements
Delta

Clack

class

Clack

interface

Clack

abstract class

you are here 4   301

them’s fightin’ words

Tonight’s talk: An abstract class and an interface butt heads
over the pressing question, “Who’s more important?”

Abstract Class:

Interface:

I think it’s obvious who’s more important between the
two of us. Programmers need me to get their jobs done.
Let’s face it. You don’t even come close.
Nice. This oughta be good.
You can’t really think you’re more important than
me. You don’t even use real inheritance—you only get
implemented.
Great, here we go again. Interfaces don’t use real
inheritance. Interfaces only implement. That’s just plain
ignorant. Implementation is as good as inheritance, in
fact it’s better!
Better? You’re nuts. I’m much more flexible than you.
I can have abstract methods or concrete ones. I can
even have virtual methods if I want. Sure, I can’t be
instantiated but then, neither can you. And I can do
pretty much anything else a regular class does.
Yeah? What if you want a class that inherits from
you and your buddy? You can’t inherit from two
classes. You have to choose which class to inherit from.
And that’s just plain rude! There’s no limit to the number
of interfaces a class can implement. Talk about flexible!
With me, a programmer can make a class do anything.

2)

(interface)
Vinn

Vout

3)

(interface)
Whuffie

Muffie

Fluffie

What’s the Picture ?
302   Chapter 7

4)

Zoop

Boop

Goop

5)

(interface)
Epsilon

Delta

(interface)
Beta

Gamma

Alpha

interfaces and abstract classes

Abstract Class:

Interface:

You might be overstating your power a little bit.
You think that just because you can contain code,
you’re the greatest thing since sliced bread. But
you can’t change the fact that a program can only
inherit from one class at a time. So you’re a little
limited. Sure, I can’t include any code. But really,
code is overrated.
That’s exactly the kind of drivel I’d expect from an
interface. Code is extremely important! It’s what
makes your programs run.
Nine times out of ten, a programmer wants to make
sure an object has certain properties and methods,
but doesn’t really care how they’re implemented.
Really? I doubt that—programmers always care
what’s in their properties and methods.
OK, sure. Eventually. But think about how many
times you’ve seen a programmer write a method
that takes an object that just needs to have a certain
method, and it doesn’t really matter right at that
very moment exactly how the method’s built. Just
that it’s there. So bang! The programmer just needs
to write an interface. Problem solved!
Yeah, sure, tell a coder he can’t code.
Whatever!

2) abstract class Top { }
class Tip : Top { }

3) abstract class Fee { }
abstract class Fi : Fee { }

4) interface Foo { }
class Bar : Foo { }
class Baz : Bar { }

5) interface Zeta { }
class Alpha : Zeta { }
interface Beta { }
class Delta : Alpha, Beta { }

s
Delta inheritand
a
h
from Alp Beta.
implements

What’s the Declaration ?
you are here 4   303

multiple inheritance sucks
I’m still hung up on not being able to inherit from two classes. I
can’t inherit from more than one class, so I have to use interfaces.
That’s a pretty big limitation of C#, right?

It’s not a limitation, it’s a protection.
If C# let you inherit from more than one base class, it would
open up a whole can of worms. When a language lets one
subclass inherit from two base classes, it’s called multiple
inheritance. And by giving you interfaces instead, C# saves
you from a big fat mess that we like to call....

The Deadly Diamond of Death!
MoviePlayer
int ScreenWidth

Television and MovieTheater both inherit
from MoviePlayer, and both override the
ShowAMovie() method. Both inherit the
ScreenWidth property, too.

ShowAMovie()

MovieTheater

Television

ShowAMovie()

ShowAMovie()

HomeTheater

?

Avoid ambiguit y!

Which Sho
when you cwallAMovie() method runs
HomeTheate ShowAMovie() on the
r object?

A language that allows the Deadly Diamond of Death can lead to some
pretty ugly situations, because you need special rules to deal with this kind
of ambiguous situation…which means extra work for you when you’re
building your program! C# protects you from having to deal with this by
giving you interfaces. If Television and MovieTheater are interfaces
instead of classes, then the same ShowAMovie() method can satisfy both
of them. All the interface cares about is that there’s some method called
ShowAMovie().
304   Chapter 7

h
he ScreenWidtev
ision and
Imagine that ted
el
T
h
t
bo
by
us
is
y
t
er
values.
op
pr
with differenter needs to
,
er
at
he
T
ie
ov
M
HomeTheat
What happensesifof ScreenWidth—say,
use both valu made-for-TV movies and
to show both
feature films?

interfaces and abstract classes

Pool Puzzle

Your job is to take code snippets from the pool and place them
into the blank lines in the code and output. You may use the
same snippet more than once, and you won’t need to use all the
snippets. Your goal is to make a set of classes that will compile
and run and produce the output listed.

}

class
:
{
public Acts() : base(“Acts”) { }
public override
{
return 5;
}
Here’s the entry
}
complete

Nose {
;
string Face { get; }

point—this is a
C# program.

abstract class
:
{
public virtual int Ear()
{
return 7;
}
public Picasso(string face)
{
= face;
}
public virtual string Face {
{
; }
}
string face;
}

class
:
{
public override string Face {
} get { return “Of76”; }

class
:
{
public Clowns() : base(“Clowns”) { }
}

}

public static void Main(string[] args) {
string result = “”;
Nose[] i = new Nose[3];
i[0] = new Acts();
i[1] = new Clowns();
i[2] = new Of76();
for (int x = 0; x < 3; x++) {
result += (
+ “ ”
+
) + “\n”;
}
MessageBox.Show(result);
}

Output

Note: Each snippet
from the pool can
be used more than
once!

Acts( );
Nose( );
Of76( );
Clowns( );
Picasso( );
Of76 [ ] i = new Nose[3];
Of76 [ 3 ] i;
Nose [ ] i = new Nose( );
Nose [ ] i = new Nose[3];

:
;
class
abstract
interface

i
i( )
i(x)
i[x]

int Ear()
this
this.
face
this.face

get
set
return

class
5 class
7 class
7 public class

Answers on page 324.

i.Ear(x)
i[x].Ear()
i[x].Ear(
i[x].Face

Acts
Nose
Of76
Clowns
Picasso

you are here 4   305

form of…a bucket of eagles!

OK, I think I’ve got a
pretty good handle on
objects now!

The idea that you could com
your data and your code intobine
classes and objects was a
revolutionary one when it was
first introduced—but tha how
you’ve been building all yourt’sC#
programs so far, so you can thi
nk
of it as just plain programming
.

You’re an object oriented programmer.
There’s a name for what you’ve been doing. It’s called
object oriented programming, or OOP. Before
languages like C# came along, people didn’t use
objects and methods when writing their code. They
just used functions (which is what they call methods in
a non-OOP program) that were all in one place—as
if each program were just one big static class that only
had static methods. It made it a lot harder to create
programs that modeled the problems they were solving.
Luckily, you’ll never have to write programs without
OOP, because it’s a core part of C#.

The four principle s of object oriented programming
When programmers talk about OOP, they’re referring to four important principles.
They should seem very familiar to you by now because you’ve been working
with every one of them. You’ll recognize the first three principles just from their
names: inheritance, abstraction, and encapsulation. The last one’s called
polymorphism. It sounds a little odd, but it turns out that you already know all
about it too.

Inheritance

This just means having one
class or interface that
inherits from another.

Encapsulation mean
an object that keepsscreating
of its state internallytrack
private fields, and us using
properties and methodes public
other classes work wi s to let
the part of the inte th only
that they need to se rnal data
e.

Encapsulation
Abstraction

you
You’re using abstraction when rts
with
sta
t
tha
del
create a class mo
sses,
more general—or abstract—classe
s
cla
ic
cif
spe
re
and then has mo
it.
m
that inherit fro
306   Chapter 7

Polymorphism

The word “polymorphism”
literally means “many
forms”. Can you think of
a time when an object
has taken on many forms
in your code?

interfaces and abstract classes

Polymorphism me ans that one object
can take many dif ferent forms

You’re using
polymorphism
when you take an
instance of one
class and use it
in a statement
or a method that
expects a different
type, like a
parent class or an
interface that the
class implements.

Any time you use a mockingbird in place of an animal or aged
Vermont cheddar in a recipe that just calls for cheese, you’re using
polymorphism. That’s what you’re doing any time you upcast or
downcast. It’s taking an object and using it in a method or a statement
that expects something else.

Keep your eye s open for polymorphism in the ne xt
e xercise!
You’re about to do a really big exercise—the biggest one you’ve seen so
far—and you’ll be using a lot of polymorphism in it, so keep your eyes
open. Here’s a list of four typical ways that you’ll use polymorphism. We
gave you an example of each of them (you won’t see these particular lines
in the exercise, though). As soon as you see similar code in what you write
for the exercise, check it off the following list:
Taking any reference variable that uses one class and setting it
equal to an instance of a different class.
NectarStinger bertha = new NectarStinger();
INectarCollector gatherer = bertha;
Upcasting by using a subclass in a statement or method that expects its
base class.
spot = new Dog();
zooKeeper.FeedAnAnimal(spot);

If FeedAnAnimal() expects
imal object,
and Dog inherits from Animaanl, An
the
n you can
pass Dog to FeedAnAnimal().

Creating a reference variable whose type is an interface and
pointing it to an object that implements that interface.
IStingPatrol defender = new StingPatrol();
Downcasting using the as keyword.
void MaintainTheHive(IWorker worker) {
if (worker is HiveMaintainer) {

This is upcasting, too!

od takes any
The MaintainTheHive() methuse
s as to
IWorker as a parameter. Iterence to the
point a HiveMaintainer ref
worker.

HiveMaintainer maintainer = worker as HiveMaintainer;
...
you are here 4   307

let’s get started

Let’s build a house! Create a model of a house using classes to represent the
rooms and locations, and an interface for any place that has a door.

1

Start with this class model
Every room or location in your house will be represented by its
own object. The interior rooms all inherit from Room, and the
outside places inherit from Outside, and both subclass the same
base class, Location. It has two fields: Name is the name of the
location (“Kitchen”), and Exits is an array of Location objects
that the current location connects to. So diningRoom.Name will
be equal to “Dining Room”, and diningRoom.Exits will be
equal to the array { LivingRoom, Kitchen }.
 Create a Windows Application project and add
Location, Room, and Outside classes to it.

2

You’ll need the blueprint for the house
This house has three rooms, a front yard, a back yard, and
a garden. There are two doors: the front door connects the
living room to the front yard, and the back door connects
the kitchen to the back yard.

The living room
connects to
the dining room,
which also
connects to
the kitchen.

Living Room
Front Yard

This symbol is an exterior door
between the front yard and the living
room. There’s also an exterior door
between the kitchen and back yard.
3

Dining
Room

Location
Name
Exits
Description()

Room
Decoration

Outside
Hot

Inside locations each have
some kind of a decoration
in a read-only property.
Outside locations can be hot,
so the Outside class has a
read-only Boolean property
called Hot.

Kitchen
Back Yard

Garden

Location is an
abstract class.
That’s why
we shaded it
darker in the
class diagram.

You can move
between the back
yard and the front
yard, and both of
them connect to the
garden.

All rooms have doors, but only a few
rooms have an exterior door that
leads inside or outside the house.

Use the IHasExteriorDoor interface for rooms with an exterior door IHasExteriorDoor
There are two exterior doors in the house, the front door and the back door. Every
DoorDescription
location that has one (the front yard, back yard, living room, and kitchen) should
DoorLocation
implement IHasExteriorDoor. The DoorDescription read-only property
contains a description of the door (the front door is “an oak door with a brass
knob”, the back door is “a screen door”). The DoorLocation property contains a
reference to the Location where the door leads (kitchen).

308   Chapter 7

interfaces and abstract classes

4

Here’s the Location class
To get you started, here’s the Location class:

abstract class Location {
public Location(string name) {
this.name = name;
is a }

Description
virtual method.
You’ll need to
override it.

public Location[] Exits;

The constructor sets the name
field, which is the read-only Name
property’s backing field.
an array ofck
is
ld
ie
f
s
it
x
a
The public Eeferences that keeps ttrhis
Location r he other places that
of all of t nnects to.
location co

private string name;
The Room
public string Name {
class will
get { return name; }
}
override
public virtual string Description {
and extend
get {
Description
The Description property
string description = “You’re standing in the “ + name to add the
+ “. You see exits to the following places: ”;
returns a string that
decoration,
for (int i = 0; i < Exits.Length; i++) {
describes the room, including
and Outside
description += “ ” + Exits[i].Name;
the name and a list of all
will add the
if (i != Exits.Length - 1)
of the locations it connects
temperature.
description += “,”;
to (which it finds in the
}
Remember, Location is an
Exits[] field). Its subclasses
description += “.”;
ab
the
stract class—you can
ge
chan
to
will need
return description;
inh
so
erit from it and declare
tly,
sligh
ion
descript
}
re
fe
it.
rence variables of type
ride
they’ll over
}
Lo
ca
tion, but you can’t
}

instantiate it.

5

Create the classes
First create the Room and Outside classes based on the class model. Then
create two more classes: OutsideWithDoor, which inherits from Outside
and implements IHasExteriorDoor, and RoomWithDoor, which subclasses
Room and implements IHasExteriorDoor.
Get the classes started
Here are the class declarations to give you a leg up:

now—we’ll give you more
details about them on the next page.

class OutsideWithDoor : Outside, IHasExteriorDoor
{
// The DoorLocation property goes here
// The read-only DoorDescription property goes here
}
class RoomWithDoor : Room, IHasExteriorDoor
{
// The DoorLocation property goes here
// The read-only DoorDescription property goes here
}

This one’s going
to be a pretty big
exercise…but we
promise it’s a lot
of fun! And you’ll
definitely know this
stuff once you get
through it.

We’re not done yet—flip the page!
you are here 4   309

watch your objects do stuff!

(continued)
Now that you’ve got the class model, you can create the objects for all of the parts of the
house, and add a form to explore it.
How your house objects work
Here’s the architecture for two of your objects, frontYard and diningRoom. Since each of
them has a door, they both need to be instances of a class that implements IHasExteriorDoor.
The DoorLocation property keeps a reference to the location on the other side of the door.

O

ut

side

Exits[]

h
Wi t

om

obj ec

t

Ro

DoorLocation
LivingRoom

Ro

Do

FrontYard

DiningRoom

object

s i d e o bj

LivingRoom is an instance of
RoomWithDoor, which inherits
from Room and implements
IHasExteriorDoor.

DoorLocation

om

or

ut

t

s i d e o bj

ec

O

t

ut

ec

O

BackYard

or obj ec

Garden

FrontYard is an
OutsideWithDoor
object, which is a
subclass of Outside
that implements
IHasExteriorDoor.
t

6

W i t h Do

You started building the IHasExteriorDoor
interface and added these two classes that
implement it. One inherits from Room, the other is
a subclass of Outside. Now it’s time to finish them.

7

Exits[]

Exits is an array of Location
references. LivingRoom has
one exit, so its Exits array
has a length of 1.

Finish building the classes, and instantiate their instances
You’ve got all the classes—now it’s time to finish them and build your objects.
≥≥ You’ll need to make sure that the constructor for the Outside class sets the read-only Hot property and
overrides the Description property to add the text “It’s very hot here.” if Hot is true. It’s hot in the
back yard but not the front yard or garden.
≥≥ The constructor for Room needs to set the Decoration, and should override the Description property
to add, “You see (the decoration) here.” The living room has an antique carpet, the dining room has a crystal
chandelier, and the kitchen has stainless steel appliances and a screen door that leads to the back yard.
≥≥ Your form needs to create each of the objects and keep a reference to each one. So add a method to the
form called CreateObjects() and call it from the form’s constructor.
Every location
≥≥ Instantiate each of the objects for the six locations in the house. Here’s one of those lines: will have its
own field in
RoomWithDoor livingRoom = new RoomWithDoor(“Living Room”,
form class.
the
“an antique carpet” , “an oak door with a brass knob”);
Exits is an
array of ≥≥ Your CreateObjects() method needs to populate the Exits[] field in each object:

Location
references, frontYard.Exits
so this line
creates one that has
two references in it.

310   Chapter 7

= new Location[] { backYard, garden };

These are
curly brackets.
Anything else will
cause an error.

interfaces and abstract classes

8

Build a form to explore the house
Build a simple form to let you explore the house. It’ll have a big multiline text box called
description to show the description of the current room. A ComboBox called exits lists
all of the exits in the current room. It’s got two buttons: goHere moves to the room selected in
the ComboBox, and goThroughTheDoor is only visible when there’s an exterior door.

Click the goHere
button to move to
another location.

This is a multiline TextBox that
displays the Description() of
the current location. Its name is
description.
This is a ComboBox

9

Now you just need to make the form work!
You’ve got all the pieces, now you just need to put them together.

u’ll
Here’s where yopu
lates
po
t
ha
set up w
the ComboBox.
The ComboBox contains a
list of all of the exits, so
name it exits. Make sure
its DropDownStyle is set
to DropDownList.
This button is only visible
when you’re in a room with
an exterior door. You can
make it visible or invisible by
setting its Visible property
to true or false. It’s called
goThroughTheDoor.

≥≥ You’ll need a field in your form called currentLocation to keep track of your current location.
≥≥ Add a MoveToANewLocation() method that has a Location as its parameter. This
method should first set currentLocation to the new location. Then it’ll clear the combo
box using its Items.Clear() method, and then add the name of each location in the
Exits[ ] array using the combo box’s Items.Add() method. Finally, reset the combo box
so it displays the first item in the list by setting its SelectedIndex property to zero.
≥≥ Set the text box so that it has the description of the current location.
≥≥ Use the is keyword to check if the current location has a door. If it does, make the “Go
through the door” button visible using its Visible property. If not, make it invisible.
≥≥ If the “Go here:” button is clicked, move to the location selected in the combo box.
≥≥ If the “Go through the door” button is clicked, move to the location that the door connects to.

Hint: When you choose an item in the combo box, its
selected index in the combo box will be the same as the .
index of the corresponding location in the Exits[] array

Another hint: Your form’s currentLocation field is
a Location reference. So even though it’s pointing
to an object that implements IHasExteriorDoor,
you can’t just type “currentLocation.DoorLocation”
because DoorLocation isn’t a field in Location.
You’ll need to downcast if you want to get the door
location out of the object.
you are here 4   311

exercise solution

Here’s the code to model the house. We used classes to represent the rooms
and locations, and an interface for any place that has a door.
interface IHasExteriorDoor {
string DoorDescription { get; }
Location DoorLocation { get; set; }
}
class Room : Location {
private string decoration;
public Room(string name, string decoration)
: base(name) {
this.decoration = decoration;
}

}

Here’s the IHasExteriorDoor

interface.

The Room class inherits from Locat
and adds a backing field for the ion
read-only Decoration property. Its
constructor sets the field.

public override string Description {
get {
return base.Description + “ You see ” + decoration + “.”;
}
}

class RoomWithDoor : Room, IHasExteriorDoor {
public RoomWithDoor(string name, string decoration, string doorDescription)
: base(name, decoration)
{
this.doorDescription = doorDescription;
}
private string doorDescription;
public string DoorDescription {
get { return doorDescription; }
}

}

private Location doorLocation;
public Location DoorLocation {
get { return doorLocation; }
set { doorLocation = value; }
}

312   Chapter 7

The RoomWithDoor class inherits
from Room and implements
IHasExteriorDoor. It does everything
that the room does, but it adds a
description of the exterior door
to the constructor. It also adds
DoorLocation, a reference to the
location that the door leads to.
DoorDescription and DoorLocation
are required by IHasExteriorDoor.

interfaces and abstract classes

class Outside : Location {
private bool hot;
public bool Hot { get { return hot; } }

Outside is a lot like Room—it
inherits from Location, and adds a
backing field for the Hot property,
which is used in the Description()
method extended from the base
class.

public Outside(string name, bool hot)
: base(name)
{
this.hot = hot;
}

}

public override string Description {
get {
string NewDescription = base.Description;
if (hot)
NewDescription += “ It’s very hot.”;
return NewDescription;
}
}

class OutsideWithDoor : Outside, IHasExteriorDoor {
public OutsideWithDoor(string name, bool hot, string doorDescription)
: base(name, hot)
{
this.doorDescription = doorDescription;
OutsideWithDoor inherits
}
private string doorDescription;
public string DoorDescription {
get { return doorDescription; }
}
private Location doorLocation;
public Location DoorLocation {
get { return doorLocation; }
set { doorLocation = value; }
}

}

from Outside and implements
IHasExteriorDoor, and it looks a lot
like RoomWithDoor.

The base class’s Description property
fills in whether or not the location
is hot. And that relies on the original
Location class’s Description property
to add the main description and exits.

public override string Description {
get {
return base.Description + “ You see ” + doorDescription + “.”;
}
}

We’re not done yet—flip the page!
you are here 4   313

exercise solution

(continued)
Here’s the code for the form. It’s all in the Form1.cs, inside the Form1 declaration.

This is how the form keeps track
of which room is being displayed.

public partial class Form1 : Form
{
Location currentLocation;
RoomWithDoor livingRoom;
Room diningRoom;
RoomWithDoor kitchen;
OutsideWithDoor frontYard;
OutsideWithDoor backYard;
Outside garden;

The form uses these reference
variables to keep track of each
of the rooms in the house.

public Form1() {
InitializeComponent();
CreateObjects();
MoveToANewLocation(livingRoom);
}

The form’s constructor creates
the objects and then uses the
MoveToANewLocation method.

When the form creates
the objects, first it
needs to instantiate
the classes and pass the
right information to
each one’s constructor.

private void CreateObjects() {
livingRoom = new RoomWithDoor(“Living Room”, “an antique carpet”,
“an oak door with a brass knob”);
diningRoom = new Room(“Dining Room”, “a crystal chandelier”);
kitchen = new RoomWithDoor(“Kitchen”, “stainless steel appliances”, “a screen door”);
frontYard = new OutsideWithDoor(“Front Yard”, false, “an oak door with a brass knob”);
backYard = new OutsideWithDoor(“Back Yard”, true, “a screen door”);
garden = new Outside(“Garden”, false);
Here’s where we pass
diningRoom.Exits = new Location[] { livingRoom, kitchen };
livingRoom.Exits = new Location[] { diningRoom };
kitchen.Exits = new Location[] { diningRoom };
frontYard.Exits = new Location[] { backYard, garden };
backYard.Exits = new Location[] { frontYard, garden };
garden.Exits = new Location[] { backYard, frontYard };
livingRoom.DoorLocation = frontYard;
frontYard.DoorLocation = livingRoom;

}

kitchen.DoorLocation = backYard;
backYard.DoorLocation = kitchen;

314   Chapter 7

the door description to
the OutsideWithDoor
constructors.

Here’s where the Exits[] array
for each instance is populated.
We need to wait to do this
until after all the instances are
created, because otherwise we
wouldn’t have anything to put into
For the IHasExteriorDoor each array!
objects, we need to set
their door locations.

interfaces and abstract classes

private void MoveToANewLocation(Location newLocation) {
The
currentLocation = newLocation;

MoveToANewLocation() met
displays a new location in the forhod
m.

exits.Items.Clear();
for (int i = 0; i < currentLocation.Exits.Length; i++)
exits.Items.Add(currentLocation.Exits[i].Name);
First we need to clear the combo box,
exits.SelectedIndex = 0;
then we can add each of the locations’
description.Text = currentLocation.Description;

}

if (currentLocation is IHasExteriorDoor)
goThroughTheDoor.Visible = true;
else
goThroughTheDoor.Visible = false;

This makes the “Go through the door” button invisible if the
current location doesn’t implement IHasExteriorDoor.

names to it. Finally, we set its selected
index (or which line is highlighted)
to zero so it shows the first item
in the list. Don’t forget to set the
ComboBox’s DropDownStyle property
to “DropDownList”—that way the
user won’t be able to type anything
into the combo box.

private void goHere_Click(object sender, EventArgs e) {
MoveToANewLocation(currentLocation.Exits[exits.SelectedIndex]);
}

}

private void goThroughTheDoor_Click(object sender, EventArgs e) {
IHasExteriorDoor hasDoor = currentLocation as IHasExteriorDoor;
MoveToANewLocation(hasDoor.DoorLocation);
}

When the user clicks
the “Go here:” button,
it moves to the
location selected in
the combo box.

We need to use the as keyword in order
to downcast currentLocation to an
IHasExteriorDoor so we can get access to
the DoorLocation field.

But we’re not done ye t!
It’s fine to create a model of a house, but wouldn’t it be cool to turn it into a game?
Let’s do it! You’ll play Hide and Seek against the computer. We’ll need to add an
Opponent class and have him hide in a room. And we’ll need to make the house a
lot bigger. Oh, and he’ll need someplace to hide! We’ll add a new interface so that
some rooms can have a hiding place. Finally, we’ll update the form to let you check
the hiding places, and keep track of how many moves you’ve made trying to find
your opponent. Sound fun? Definitely!

Let’s get started!
you are here 4   315

build your opponent

Time for hide and seek! Build on your original house program to add more rooms, hiding
places, and an opponent who hides from you.

1

IDE’s
Create a new project, and use the
the
add
to
e
“Add Existing Item” featur the exe
rcise.
of
t
classes from the first par

Add an IHidingPlace interface
We don’t need to do anything fancy here. Any Location subclass that implements IHidingPlace
has a place for the opponent to hide. It just needs a string to store the name of the hiding place (“in
the closet”, “under the bed”, etc.).
≥≥ Give it a get accessor, but no set accessor—we’ll set this in the constructor, since once a room
has a hiding place we won’t ever need to change it.

2

3

Add classes that implement IHidingPlace
You’ll need two more classes: OutsideWithHidingPlace (which inherits from Outside) and
RoomWithHidingPlace (which inherits from Room). Also, let’s make any room with a door have a
hiding place, so it’ll have to inherit from RoomWithHidingPlace instead of Room.
h an

exterior
So every room wit
place.
door will also have a hiding

Add a class for your opponent
The Opponent object will find a random hiding place in the house, and it’s your job to find him.

≥≥ He’ll need a private Location field (myLocation) so he can keep track of where he is,
and a private Random field (random) to use when he moves to a random hiding place.
≥≥ The constructor takes the starting location and sets myLocation to it, and sets random
to a new instance of Random. He starts in the front yard (that’ll be passed in by the form),
and moves from hiding place to hiding place randomly. He moves 10 times when the game
starts. When he encounters an exterior door, he flips a coin to figure out whether or not to go
through it.
≥≥ Add a Move() method that moves the opponent from his current location to a new location.
First, if he’s in a room with a door, then he flips a coin to decide whether or not to go through
the door, so if random.Next(2) is equal to 1, he goes through it. Then he chooses one of
the exits from his current location at random and goes through it. If that location doesn’t have
a hiding place, then he’ll do it again—he’ll choose a random exit from his current location
and go there, and he’ll keep doing it over and over until he finds a place to hide.

4

≥≥ Add a Check() method that takes a location as a parameter and returns true if he’s hiding
in that location, or false otherwise.
Add more rooms to the house
Update your CreateObjects() method to add more rooms:
≥≥ Add stairs with a wooden bannister that connect the living room to the upstairs hallway,
which has a picture of a dog and a closet to hide in.
≥≥ The upstairs hallway connects to three rooms: a master bedroom with a large bed, a
second bedroom with a small bed, and a bathroom with a sink and a toilet. Someone
could hide under the bed in either bedroom or in the shower.
≥≥ The front yard and back yard both connect to the driveway, where someone could hide in
the garage. Also, someone could hide in the shed in the garden.

316   Chapter 7

interfaces and abstract classes

5

OK, time to update the form
You’ll need to add a few buttons to the form. And we’ll get a little more intricate with
making them visible or invisible, depending on the state of the game.
ddle button’s

ttons and the
You use the top twothbue same way as
combo box exactly they’re only visible
before, except thatnning.
while the game is ru

When the game first starts, the
hide button is the only one dis
yed.
When you click it, the form coupla
nts
to 10 in the text box, and ls
the
opponent’s Move() method 10caltim
Then it makes this button invisib es.
le.
6

called check. You
The mi
property.
don’t need to set its Text

use to
This is the button you’ll pla
ce. It’s
check the room’s hidinga room that
only visible if you’re in en it’s shown,
has a place to hide. Wh anged
the Text property is ch rd “Check”
from “check” to the woof the hiding
followed by the name h a hiding
place—so for a room wite button will
place under the bed, thbed”.
say, “Check under the

Make the buttons work
There are two new buttons to add to the form.

Flip back to
Chapter 2 for
a refresher on
DoEvents() and
Sleep()—they’ll
come in handy.

≥≥ The middle button checks the hiding place in the current room and is only visible when
you’re in a room with a place to hide using the opponent’s Check() method. If you found
him, then it resets the game.
≥≥ The bottom button is how you start the game. It counts to 10 by showing “1…”, waiting 200
milliseconds, then showing “2…”, then “3…”, etc., in the text box. After each number, it tells
the opponent to move by calling his Move() method. Then it shows, “Ready or not, here I
come!” for half a second, and then the game starts.

7

Add a method to redraw the form, and another one to reset the game
Add a RedrawForm() method that puts the right text in the description text box, makes the buttons
visible or invisible, and puts the correct label on the middle button. Then add a ResetGame()
method that’s run when you find your opponent. It resets the opponent object so that he starts in the
front yard again—he’ll hide when you click the “Hide!” button. It should leave the form with nothing
but the text box and “Hide!” button visible. The text box should say where you found the opponent,
and how many moves it took.

8

Keep track of how many moves the player made
Make sure the text box displays the number of times you checked a hiding
place or moved between rooms. When you find the opponent, he should pop
up a mesage box that says, “You found me in X moves!”

9

Make it look right when you start the program
When you first start the program, all you should see is an empty text box
and the “Hide!” button. When you click the button, the fun begins!

you are here 4   317

exercise solution

Build on your original house program to add more rooms, hiding places, and an opponent who
hides from you.
Here’s the new IHidingPla

ce interface. It
just has one string field with a get accessor
that returns the name of the hiding place.

interface IHidingPlace {
string HidingPlaceName { get; }
}
class RoomWithHidingPlace : Room, IHidingPlace {
public RoomWithHidingPlace(string name, string decoration, string hidingPlaceName)
: base(name, decoration)
{
this.hidingPlaceName = hidingPlaceName;
}
ace class inherits
private string hidingPlaceName;
public string HidingPlaceName {
get { return hidingPlaceName; }
}

}

The RoomWithHidingPl
lace by
from Room and implements IHidingPty.
adding the HidingPlaceName proper The
constructor sets its backing field.

public override string Description {
get {
return base.Description + “ Someone could hide “ + hidingPlaceName + “.”;
}
}

class RoomWithDoor : RoomWithHidingPlace, IHasExteriorDoor {
public RoomWithDoor(string name, string decoration,
string hidingPlaceName, string doorDescription)
: base(name, decoration, hidingPlaceName)
{
Since we decided every room with a
this.doorDescription = doorDescription;
doo
r also needed a hiding place, we
}
private string doorDescription;
public string DoorDescription {
get { return doorDescription; }
}

}

private Location doorLocation;
public Location DoorLocation {
get { return doorLocation; }
set { doorLocation = value; }
}

318   Chapter 7

made RoomWithDoor inherit from
RoomWithHidingPlace. The only
change to it is that its constructor
takes a hiding place name and sends
it on to the RoomWithHidingPlace
constructor.

interfaces and abstract classes
class OutsideWithHidingPlace : Outside, IHidingPlace {
public OutsideWithHidingPlace(string name, bool hot, string hidingPlaceName)
: base(name, hot)
{ this.hidingPlaceName = hidingPlaceName; }
private string hidingPlaceName;
public string HidingPlaceName {
get { return hidingPlaceName; }
}

}

The OutsideWithHidingPlace class inherits
from Outside and implements IHidingPlace
just like RoomWithHidingPlace does.

public override string Description {
get {
return base.Description + “ Someone could hide ” + hidingPlaceName + “.”;
}
}

The Opponent class constructor takes a

class Opponent {
starting location. It creates a new instance
private Random random;
of Random, which it uses to move randomly
private Location myLocation;
between rooms.
public Opponent(Location startingLocation) {
myLocation = startingLocation;
The Move() method first checks if the current
random = new Random();
room has a door using the is keyword—if so, it
}
has a 50% chance of going through it. Then it
public void Move() {
moves to a random location, and keeps moving
if (myLocation is IHasExteriorDoor) {
until it finds a hiding place.
IHasExteriorDoor LocationWithDoor =
myLocation as IHasExteriorDoor;
if (random.Next(2) == 1)
myLocation = LocationWithDoor.DoorLocation;
e loop. It
}
The guts of the Move() method is thisiswhil
e—and it sets
tru
en
hidd
bool hidden = false;
keeps looping until the variable
place.
ng
hidi
a
with
while (!hidden) {
it to true when it finds a room
int rand = random.Next(myLocation.Exits.Length);
myLocation = myLocation.Exits[rand];
if (myLocation is IHidingPlace)
hidden = true;
}
}
The Check() method just checks the
public bool Check(Location locationToCheck) {
opponent’s location against the location
if (locationToCheck != myLocation)
that
was passed to it using a Location
return false;
reference.
If they point to the same
else
object,
then
he’s been found!
return true;
}
}

We’re not done yet—flip the page!

you are here 4   319

exercise solution

Here’s all the code for the form. The only things
that stay the same are the goHere_Click() and
goThroughTheDoor_Click() methods.

(continued)

Here are all the fields in the Form1
class. It uses them to keep track of
the locations, the opponent, and the
number of moves the player has made.

The Form1 constructor creates the objects,
sets up the opponent, and then resets the game.
We added a boolean parameter to
Game()
so that it only displays its messageReset
when
you
win, not when you first start up the progr
am.

public Form1() {
InitializeComponent();
CreateObjects();
opponent = new Opponent(frontYard);
ResetGame(false);
}

int Moves;
Location currentLocation;
RoomWithDoor livingRoom;
RoomWithHidingPlace diningRoom;
RoomWithDoor kitchen;
Room stairs;
RoomWithHidingPlace hallway;
RoomWithHidingPlace bathroom;
RoomWithHidingPlace masterBedroom;
RoomWithHidingPlace secondBedroom;
OutsideWithDoor frontYard;
OutsideWithDoor backYard;
OutsideWithHidingPlace garden;
OutsideWithHidingPlace driveway;
Opponent opponent;

private void MoveToANewLocation(Location newLocation) {
Moves++;
currentLocation = newLocation;
RedrawForm();
}

d sets the

The MoveToANewLocation() metho

form.
private void RedrawForm() {
new location and then redraws the
exits.Items.Clear();
for (int i = 0; i < currentLocation.Exits.Length; i++)
exits.Items.Add(currentLocation.Exits[i].Name);
exits.SelectedIndex = 0;
description.Text = currentLocation.Description + “\r\n(move #” + Moves + “)”;
if (currentLocation is IHidingPlace) {
IHidingPlace hidingPlace = currentLocation as IHidingPlace; We need the hiding place
name but we’ve only got the
check.Text = “Check “ + hidingPlace.HidingPlaceName;
Curr
entLocation object, which
check.Visible = true;
does
n’t
have a HidingPlaceName
}
prop
erty
. So we can use as
else
to
copy
the
reference to an
check.Visible = false;
IHidingPlace variable.
if (currentLocation is IHasExteriorDoor)
goThroughTheDoor.Visible = true;
else
RedrawForm() populates the combo box list, sets the
goThroughTheDoor.Visible = false;
text (adding the number of moves), and then makes
}
the buttons visible or invisible depending on whether
or not there’s a door or the room has a hiding place.

320   Chapter 7

interfaces and abstract classes

Wow—you could add an entire wing onto the house just
by adding a couple of lines! That’s why well-encapsulated
classes and objects are really useful.

private void CreateObjects() {
livingRoom = new RoomWithDoor(“Living Room”, “an antique carpet”,
“inside the closet”, “an oak door with a brass handle”);
diningRoom = new RoomWithHidingPlace(“Dining Room”, “a crystal chandelier”,
“in the tall armoire”);
kitchen = new RoomWithDoor(“Kitchen”, “stainless steel appliances”,
“in the cabinet”, “a screen door”);
stairs = new Room(“Stairs”, “a wooden bannister”);
hallway = new RoomWithHidingPlace(“Upstairs Hallway”, “a picture of a dog”,
“in the closet”);
bathroom = new RoomWithHidingPlace(“Bathroom”, “a sink and a toilet”,
“in the shower”);
masterBedroom = new RoomWithHidingPlace(“Master Bedroom”, “a large bed”,
“under the bed”);
secondBedroom = new RoomWithHidingPlace(“Second Bedroom”, “a small bed”,
“under the bed”);
frontYard = new OutsideWithDoor(“Front Yard”, false, “a heavy-looking oak door”);
backYard = new OutsideWithDoor(“Back Yard”, true, “a screen door”);
garden = new OutsideWithHidingPlace(“Garden”, false, “inside the shed”);
driveway = new OutsideWithHidingPlace(“Driveway”, true, “in the garage”);
diningRoom.Exits = new Location[] { livingRoom, kitchen };
livingRoom.Exits = new Location[] { diningRoom, stairs };
kitchen.Exits = new Location[] { diningRoom };
stairs.Exits = new Location[] { livingRoom, hallway };
hallway.Exits = new Location[] { stairs, bathroom, masterBedroom, secondBedroom };
bathroom.Exits = new Location[] { hallway };
masterBedroom.Exits = new Location[] { hallway };
secondBedroom.Exits = new Location[] { hallway };
frontYard.Exits = new Location[] { backYard, garden, driveway };
backYard.Exits = new Location[] { frontYard, garden, driveway };
garden.Exits = new Location[] { backYard, frontYard };
driveway.Exits = new Location[] { backYard, frontYard };
livingRoom.DoorLocation = frontYard;
frontYard.DoorLocation = livingRoom;

}

kitchen.DoorLocation = backYard;
backYard.DoorLocation = kitchen;

The new CreateObjects() method
creates all the objects to build the
house. It’s a lot like the old one, but it
has a whole lot more places to go.
We’re still not done—flip the page!
you are here 4   321

exercise solution

(continued)

Here’s the rest of the code for the form. The goHere and
goThroughTheDoor button event handlers are identical to
the ones in the first part of this exercise, so flip back a few
pages to see them.

private void ResetGame(bool displayMessage) {
if (displayMessage) {
MessageBox.Show(“You found me in ” + Moves + “ moves!”);
IHidingPlace foundLocation = currentLocation as IHidingPlace;
description.Text = “You found your opponent in “ + Moves
+ “ moves! He was hiding ” + foundLocation.HidingPlaceName + “.”;
}
The ResetGame() method resets the gam
Moves = 0;
displays the final message, then makes all e. It
hide.Visible = true;
buttons except the “Hide!” one invisible. the
goHere.Visible = false;
check.Visible = false;
goThroughTheDoor.Visible = false;
We want to display the name of the
exits.Visible = false;
hiding place, but CurrentLocation is a
}
Location reference, so it
private void check_Click(object sender, EventArgs e) {
Moves++;
if (opponent.Check(currentLocation))
ResetGame(true);
else
RedrawForm();
}
private void hide_Click(object sender, EventArgs e) {
hide.Visible = false;
for (int i = 1; i <= 10; i++) {
opponent.Move();
description.Text = i + “... “;
Application.DoEvents();
System.Threading.Thread.Sleep(200);
}
description.Text = “Ready or not, here I come!”;
Application.DoEvents();
System.Threading.Thread.Sleep(500);

}

goHere.Visible = true;
exits.Visible = true;
MoveToANewLocation(livingRoom);

322   Chapter 7

doesn’t
us access to the HidingPlaceName give
d.
Luckily, we can use the as keywordfiel
to
downcast it to an IHidingPlace ref
that points to the same object. erence

When you click the check
button, it checks whether or
not the opponent is hiding in
the current room. If he is, it
resets the game. If not, it
redraws the form (to update
the number of moves).

Remember DoEvents() from FlashyThing
in Chapter 2? Without it, the text box
doesn’t refresh itself and the program looks
frozen.
The hide button is the one that starts thef
game. The first thing it does is make itsel
invisible. Then it counts to 10 and tells the
opponent to move. Finally, it makes the first
button and the combo box visible, and then
starts off the player in the living room.
The MoveToANewLocation() method calls
RedrawForm().

interfaces and abstract classes
1

OOPcross

2
3

4

5

1

6

7

2
3

4

5

8
6

7

9

10

8
9

11

10

12

13
11

14

12

13
14

15

16
15

16

17

17

18

18

Across

Across
3. What an
abstractdoesn't
method have
doesn't have
3. What an abstract
method
4. C# doesn't allow _____________ inheritance
4. C# doesn't6.allow
When_____________
you pass a subclassinheritance
to a method that expects its
6. When you base
to athis
method
that expects its
passclass,
a subclass
you're using
OOP principle
8. The using
OOP principle
where
you hide private data and only
base class, you're
this OOP
principle
expose those
methods
that other
need
8. The OOP principle
where
youand
hidefields
private
dataclasses
and only
to
expose thoseaccess
methods
and fields that other classes need
10. One of the four principles of OOP that you implement using
access to the colon operator
10. One of the
principles
thatis automatically
you implement
using
14.four
Every
method in of
an OOP
interface
___________
15. If your class implements an interface that __________
the colon operator
from another
interface, then
you need to implement
all of its
14. Every method
in an interface
is automatically
___________
members, too
implements an interface that __________
15. If your class
17. An access modifier that's not valid for anything inside an
from another interface
interface, then you need to implement all of its
members, too18. Object __________ Programming means creating programs
combinethat's
your data
code
intoinside
classesan
and
17. An accessthatmodifier
notand
valid
fortogether
anything
objects
interface
18. Object __________ Programming means creating programs
that combine your data and code together into classes and
objects

Down
Down

When you
common
methods
from specific
classes toclasses to
1.1.When
youmove
move
common
methods
from specific
a more general class that they all inherit from, you're using this
aOOP
more
general class that they all inherit from, you're using this
principle
OOP
2. If aprinciple
class that implements an interface doesn't implement all
getters,
and setters,
the project
won't implement all
2.ofIfitsamethods,
class that
implements
anthen
interface
doesn't
of___________
its methods, getters, and setters, then the project won't
5. Everything in an interface is automatically ___________
___________
7. An abstract class can include both abstract and
5.____________
Everything in
an interface is automatically ___________
methods
7.9.An
class can an
include
Youabstract
can't ____________
abstractboth
classabstract and
11. A class that implements
____________
methodsthis must include all of the methods,
and setters
that it definesan abstract class
9.getters,
You can't
____________
12. What you do with an interface
11.
A class that implements this must include all of the methods,
13. The is keyword returns true if an __________ implements
getters,
and setters that it defines
an interface
12.
you do
with
an interface
16. What
An interface
can't
technically
include a __________, but it
canThe
define
getters
and setters
thattrue
look ifjust
one from the implements
13.
is
keyword
returns
anlike
__________
outside
an
interface
16. An interface can't technically include a __________, but it
can define getters and setters that look just like one from the
outside

you are here 4   323

exercise solutions

Pool Puzzle Solution from page 305
Your job is to take code snippets from the pool and place them
into the blank lines in the code and output. You may use the
same snippet more than once, and you won’t need to use all the
snippets. Your goal is to make a set of classes that will compile
and run and produce the output listed.

Here’s where the Acts class calls the cons tor
in Picasso, which it inherits from. It passestruc
“Acts”
into the constructor, which gets stored in the
face
property.

}

interface
Nose {
int Ear()
;
string Face { get; }

class
Acts : Picasso
{
public Acts() : base(“Acts”) { }
public override
int Ear()
{
return 5;
}
}

abstract class
Picasso : Nose
{
public virtual int Ear()
class
Of76 : Clowns
{
{
public override string Face {
return 7;
Properties can
}
} get { return “Of76”; }
in
re
whe
any
ear
app
public Picasso(string face)
static void Main(string[] args) {
the class! It’s easier public
{
string
result = “”;
to read your code if
this.face
= face;
Nose[]
i = new Nose[3];
they’re at the top,
}
i[0] = new Acts();
public virtual string Face { but it’s perfectly
i[1] = new Clowns();
get {
return face
; }
valid to have the
i[2] = new Of76();
}
face property at
for (int x = 0; x < 3; x++) {
string face;
the bottom of the
result += (
i[x].Ear()
+ “ ”
}
Picasso class.
+
i[x].Face
) + “\n”;
class
Clowns : Picasso
{
public Clowns() : base(“Clowns”) { }
}

324   Chapter 7

}

}

}
MessageBox.Show(result);

Face is a get accessor that
returns the value of the
face property. Both of the
are defined in Picasso and m
inherited into the subclasses.

interfaces and abstract classes

OOPcross solution
1

A

2
3

B

C

O

B
D

Y

M
6

P

4

S

M U

L

T

I

T
O

L

Y M O

I

R

L
9

E
10

I

E

N

I

N

P

H

I

S M

H

E

R

P

S

U

L

A

T

I

T

A

N

C

A

B

S

O

H

E

R

R
E
12

I

T

R

A

C

I

T

S

C
T

N
C

E
11

J
N

C

O

C

O

14

T

T

A

N

N

A

L

13

A

E
7

O

T

I

I

L

B

T

S

15

C

P

U

A
8

5

17

P

R

I

V

E

I

T

N

M

E

T

P

E

L

R

E

F

M

I

E

E

N

L

A

T

C
18

O

R

I

E

N

T

16

F

E

D

Across

Down

3. What an abstract method doesn't have [BODY]
4. C# doesn't allow _____________ inheritance. [MULTIPLE]
6. When you use a pass subclass to a method that expects its
base class, you're using this OOP principle. [POLYMORPHISM]
8. The OOP principle where you hide private data and only
expose those methods and fields that other classes need
access to. [ENCAPSULATION]
10. One of the four principles of OOP that you implement using
the colon operator [INHERITANCE]
14. Every method in an interface is automatically ___________.

1. When you move common methods from specific classes to
more a general class that they all inherit from, you're using this
OOP principle. [ABSTRACTION]
2. If a class that implements an interface doesn't implement all
of its methods, getters and setters, then the project won't
___________. [COMPILE]
5. Everything in an interface is automatically [PUBLIC]
7. An abstract class can include bothyou
abstract
and 4   325
are here
____________ methods. [CONCRETE]
9. You can't ____________ an abstract class. [INSTANTIATE]

8 enums and collections

Storing lots of data
Finally, a way to organize
my Boyfriend objects!

When it rains, it pours.
In the real world, you don’t get to handle your data in tiny little bits and
pieces. No, your data’s going to come at you in loads, piles, and bunches.
You’ll need some pretty powerful tools to organize all of it, and that’s where
collections come in. They let you store, sort, and manage all the data that
your programs need to pore through. That way, you can think about writing
programs to work with your data, and let the collections worry about keeping
track of it for you.

this is a new chapter   327

nurse sharks and carpenter ants

Strings don’t always work for
storing categorie s of data
Suppose you have several worker bees, all represented by
Worker classes. How would you write a constructor that took
a job as a parameter? If you use a string for the job name, you
might end up with code that looks like this:

track
Our bee management software keptlike
ng
of each worker’s job using a stri
“Sting Patrol” or “Nectar Collector”.

Our code would allow these values to be passed
in a constructor even though the program only
supports Sting Patrol, Nectar Collector, and
other jobs that a bee does.

Worker buzz = new Worker(“Attorney General”);
Worker clover = new Worker(“Dog Walker”);
Worker gladys = new Worker(“Newscaster”);
This code compiles, no
make any sense for a problem. But these jobs don’t
shouldn’t allow these bee. The Worker class really
types as valid data.

You could probably add code to the Worker constructor to check each
string and make sure it’s a valid bee job. However, if you add new jobs
that bees can do, you’ve got to change this code and recompile the
Worker class. That’s a pretty short-sighted solution. What if you have
other classes that need to check for the types of worker bees they can be?
Now you’ve got to duplicate code, and that’s a bad path to go down.
What we need is a way to say, “Hey, there are only certain values that are
allowed here.” We need to enumerate the values that are OK to use.

328   Chapter 8

enums and collections

Enums le t you work with a se t
of valid value s
An enum is a data type that only allows certain values for that piece
of data. So we could define an enum called Jobs, and define the
allowed jobs:
f the

ame o
is is the n

Th

enum Job {
NectarCollector,
The last enumerator
d
en
to
ve
ha
n’t
does
StingPatrol,
with a comma, but
HiveMaintenance,
using one makes it
e
ng
ra
ar
re
to
r
easie
BabyBeeTutoring,
them using cut and
EggCare,
paste.
HoneyManufacturing,
}
Now, you can reference these with types like this:

enum.

The stuff inside the brackets is
called the enumerator list, and
each item is an enumerator. The
whole thing together is called an
enumeration.
But most people just
call them enums.

Each of these
valid job. Any caisn a
used as a Jobs valube
e.

lue
Separate each va
end
an
with a comma, wdith a
g
the whole thin
curly brace.

This is the
name of the
enum.

Finally, the va
you want fromlue
the enum.

Worker nanny = new Worker(Job.EggCare);

Worker constructor
We’ve changed thr.eJobs as its
to accept Worke.
parameter type

But you can’t just make up a new value for the enum! If you do,
the program won’t compile.
private void button1_Click(object sender EventArgs e)
{
Worker buzz = new Worker(Jobs.AttorneyGeneral);
}

u get
Here’s the error r.yo
le
pi
from the com

‘Jobs’ does not contain a definition for

X ‘AttorneyGeneral’

you are here 4   329

names are better than numbers

Enums le t you repre sent numbers with name s
Sometimes it’s easier to work with numbers if you have names for them. You can assign
numbers to the values in an enum and use the names to refer to them. That way, you don’t
have a bunch of unexplained numbers floating around in your code. Here’s an enum to keep
track of the scores for tricks at a dog competition:
You can cast an int
to an enum, and
you can cast an
(int-based) enum
back to an int.

public enum TrickScore {
hav
These don’t e Sit = 7,
to be in any
particular order, Beg = 25,
Supply a name, then
“=”,
Some enums use a different type,
and you can give RollOver = 50,
then the number th
at
like
byte or long—like the one at
na
to
m
es
e
multiple nam
stands in for.
Fetch
=
10,
the
bottom
of this page—and you
.
ber
num
the same
can
cast
those
back to their type.
ComeHere = 5,
Speak = 30,
The (int) cast tells the compiler to turn this into the
}
number it represents. So since TrickScore.Fetch has a
value of 10, (int)TrickScore.Fetch turns it into the
Here’s an excerpt from a method that uses the
int value 10.
Since Fetch has a value of
TrickScore enum by casting it to and from an int.
10, this statement sets
int value = (int)TrickScore.Fetch * 3;
value to 30.
MessageBox.Show(value.ToString());
to
You can cast an int back
is
ue
TrickScore score = (TrickScore)value;
a TrickScore. Since val set
equal to 30, score gets when
MessageBox.Show(score.ToString());
to TrickScore.Fetch. So , it
you call score.ToString()
You can cast the enum as a number and do calculations with it, or you can use the
returns “Fetch”.
ToString() method to treat the name as a string. If you don’t assign any number
to a name, the items in the list will be given values by default. The first item will be
assigned a 0 value, the second a 1, etc.

But what happens if you want to use really big numbers for one of the enumerators?
The default type for the numbers in an enum is int, so you’ll need to specify the type
you need using the : operator, like this:

public enum TrickScore : long {
Sit = 7,
Beg = 2500000000025
}

330   Chapter 8

This tells the compiler to treat
values in the TrickScore enum as
longs, not ints.

If you tried to compile this code without specifying long as the

type, you’d get this message:

g’ to ‘int’.
Cannot implicitly convert type ‘lon

enums and collections

Use what you’ve learned about enums to build a class that holds a playing card.

v

Suit
Value
Name

Card

1

Create a new project and add a Card class
You’ll need two public fields: Suit (which will be Spades, Clubs, Diamonds, or
Hearts) and Value (Ace, Two, Three…Ten, Jack, Queen, King). And you’ll
need a read-only property, Name (“Ace of Spades”, “Five of Diamonds”).

2

Use two enums to define the suits and values
Use the familiar Add >> Class feature in the IDE to add them, replacing the word class
with enum in the newly added files. Make sure that (int)Suits.Spades is equal
to 0, followed by Clubs (equal to 1), Diamonds (2), and Hearts (3). Make the values
equal to their face values: (int)Values.Ace should equal 1, Two should be 2, Three
should be 3, etc. Jack should equal 11, Queen should be 12, and King should be 13.

3

Add a property for the name of the card
Name should be a read-only property. The get accessor should return a string that describes the card.
This code will run in a form that calls the Name property from the card class and displays it:
Card card = new Card(Suits.Spades, Values.Ace);
string cardName = card.Name;

The value of cardName should be “Ace of Spades”.
4

To make this work, your Card
class will need a constructor
that takes two parameters.

Add a form button that pops up the name of a random card
You can get your program to create a card with a random suit and value by casting a random
number between 0 and 3 as a Suits and another random number between 1 and 13 as a
Values. To do this, you can take advantage of a feature of the built-in Random class that gives
it three different ways to call its Next() method:

When you’ve got more
than one way to call Random random = new Random();
a method, it’s called int numberBetween0and3 = random.Next(4);
numberBetween1and13 = random.Next(1, 14);
overloading. More on int
int anyRandomInteger = random.Next();
that later....
This tells Random to return a value at least 1 but under 14.

Q:

Hold on a second. When I was typing in that code, I
noticed that an IntelliSense window popped up that said
something about “3 of 3” when I used that Random.Next()
method. What was that about?

A:

What you saw was a method that was overloaded. When a
class has a method that you can call more than one way, it’s called
overloading. When you’re using a class with an overloaded method,
the IDE lets you know all of the options that you have. In this case,
the Random class has three possible Next() methods. As

soon as you type “random.Next(” into the code window, the IDE pops
up its IntelliSense box that shows the parameters for the different
overloaded methods. The up and down arrows next to the “3 of 3” let
you scroll between them. That’s really useful when you’re dealing
with a method that has dozens of overloaded definitions. So when
you’re doing it, make sure you choose the right overloaded Next()
method! But don’t worry too much now—we’ll talk a lot about
overloading later on in the chapter.

you are here 4   331

arrays…who needs ’em?

A deck of cards is a great example of where limiting values is important. Nobody
wants to turn over their cards and be faced with a Joker of Clubs, or a 13 of
Hearts. Here’s how we wrote the Card class.
enum Suits {
Spades,
Clubs,
Diamonds,
Hearts
}
enum Values {
Ace = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
Nine = 9,
Ten = 10,
Jack = 11,
Queen = 12,
King = 13
}

When you don’t specify values, the
first item in the list is equal to
zero, the second is 1, the third is
2, etc.

Here’s where we set the value of
Values.Ace to 1.

The Card class ha
Suit property of s a
Suits, and a Value type
property of type
Values.

class Card {
public Suits Suit { get; set; }
public Values Value { get; set; }

public Card(Suits suit, Values value) {
this.Suit = suit;
this.Value = value;
}

}

perty
The get accessor for the Name pro
enum’s
an
can take advantage of the wayname
ToString() method returns its
converted to a string.

public string Name {
get { return Value.ToString() + “ of “ + Suit.ToString(); } Here’s where we use the
overloaded Random.Nex
}

Here’s the code for the button that pops
up the name of a random card.

method to generate a t()
random number that
cast to the enum. we

Random random = new Random();
private void button1_Click(object sender, EventArgs e) {
Card card = new Card((Suits)random.Next(4), (Values)random.Next(1, 14));
MessageBox.Show(card.Name);
}

332   Chapter 8

enums and collections

We could use an array to cre ate a deck of cards…
What if you want to create a class to represent a deck of cards? It would need a
way to keep track of every card in the deck, and it’d need to know what order they
were in. A Card array would do the trick—the top card in the deck would be at
value 0, the next card at value 1, etc. Here’s a starting point—a Deck that starts
out with a full deck of 52 cards.

class Deck {
private Card[] cards = {
new Card(Suits.Spades, Values.Ace),
new Card(Suits.Spades, Values.Two),
new Card(Suits.Spades, Values.Three),
// ...
new Card(Suits.Diamonds, Values.Queen),
new Card(Suits.Diamonds, Values.King),
};

}

This array decl
would continue alarl ation
way through the dethe
It’s just abbreviate ck.
here to save space. d

public void PrintCards() {
for (int i = 0; i < cards.Length; i++)
Console.WriteLine(cards[i].Name());
}

…but what if you wanted to do more?
Think of everything you might need to do with a deck of cards, though. If
you’re playing a card game, you routinely need to change the order of the
cards, and add and remove cards from the deck. You just can’t do that with
an array very easily.

How would you add a Shuffle() method to the Deck class that
rearranges the cards in random order? What about a method to deal the
first card off the top of the deck? How would you add a card to the deck?

you are here 4   333

fine collectibles

Arrays are hard to work with
An array is fine for storing a fixed list of values or references. But once you need
to move array elements around, or add more elements than the array can hold,
things start to get a little sticky.
1

Every array has a length, and you need to know the length to work with it. You could use
null references to keep some array elements empty:

Ca

Ca

rd

obj ect

rd

C
ob j ect ard o
t
bjec

Indexes 3, 4
6 are equal to, 5, and
they’re not ho null, so
lding any
cards.

This array has a Length of 7,
but it’s only storing 3 cards.

2

You’d need to keep track of how many cards are being held. So you’d need an int field,
which we could call topCard that would hold the index of the last card in the array. So
our 3-card array would have a Length of 7, but we’d set topCard equal to 3.

We’ll add a topCard field to keep
track of how many cards are in the
array. Any index above topCard has a
null Card reference.

3

There’s actually an Array.Resize()
method built into the .NET that.
Framework that does exactly

But now things get complicated. It’s easy enough to add a Peek() method that just returns a
reference to the top card—so you can peek at the top of the deck. But what if you want to add
a card? If topCard is less than the array’s Length, you can just put your card in the array at
that index and add 1 to topCard. But if the array’s full, you’ll need to create a new, bigger array
and copy the existing cards to it. Removing a card is easy enough—but after you subtract 1 from
topCard, you’ll need to make sure to set the removed card’s array index back to null. And what
if you need to remove a card from the middle of the list? If you remove card 4, you’ll need to
move card 5 back to replace it, and then move 6 back, then 7 back…wow, what a mess!

334   Chapter 8

enums and collections

Lists make it e asy to store collections of…anything
The .NET Framework has a bunch of collection classes that handle all of those
nasty issues that come up when you add and remove array elements. The most
common sort of collection is a List. Once you create a List object, it’s
easy to add an item, remove an item from any location in the list, peek at an item,
and even move an item from one place in the list to another. Here’s how a list works:
First you create a new instance of List
Every array has a type—you don’t just have an array, you have an int array, a Card
array, etc. Lists are the same way. You need to specify the type of object or value that the
list will hold by putting it in angle brackets <> when you use the new keyword to create it.

1

2

st<

bj

Li

ect

List cards = new List();

Card> o

You specified  when you
created the list, so now this
list only holds references to
Card objects.

We’ll sometimes
leave the  off
because it can
make the book a
little hard to read.
When you see List,
think List!

The  at the end
of List means
it’s generic.
The T gets replaced with a type—so
List just means a List of
ints.You’ll get plenty of practice with
generics over the next few pages.

Now you can add to your List
Once you’ve got a List object, you can add as many items to it as you want (as long as they’re
polymorphic with whatever type you specified when you created your new List).

Which means
they’re
cards.Add(new
assignable
cards.Add(new
to the type: cards.Add(new
interfaces,
abstract classes,
base classes, etc.

Card(Suits.Diamonds, Values.King);

A list keeps its elements
in order, just like an
array. King of Diamonds
is first, 3 of Clubs
is second, and Ace of
Hearts is third.

Card(Suits.Clubs, Values.Three);
Card(Suits.Hearts, Values.Ace);

You can add as many
cards as you want to
the List - just call its
Add() method. It’ll make L
ist
sure it’s got enough
 o
“slots” for the items. If
it starts to run out, it’ll
automatically resize itself.

rd

obj ect

bj

ect

Ca

King of
Diamonds

Ca

Ace of
Hearts

rd

Ca

Three of
Clubs

rd

obj ect

obj ect
you are here 4   335

wow, what an improvement!

Lists are more fle xible than arrays
The List class is built into the .NET Framework, and it lets you do a lot of
things with objects that you can’t do with a plain old array. Check out some
of the things you can do with a List.
1

You can make one.
List myCarton = new List();

bject is
A new List othe heap. But
created on hing in it yet.
there’s not

2

Add something to it.
Egg x = new Egg();
myCarton.Add(x);

hold
Now the List expands to
…
the Egg object

x
3

Add something else to it.
Egg y = new Egg();

…and expands agai to
hold
the second Egg objen ct
.

myCarton.Add(y);
4

Find out how many things are in it.
int theSize = myCarton.Count;

5

Find out if it has something in particular in it.
bool Isin = myCarton.Contains(x);

6

Figure out where that thing is.
int idx = myCarton.IndexOf(y);

7

Take something out of it.
myCarton.Remove(y);

x

Now you can search
Egg inside the list. Tfohir any
definitely come back trs would
ue.

The index for x would be 0 and the
index for y would be 1.

poof!

x
336   Chapter 8

y

When we removed y, we left only x in
the List, so it shrank! And eventually
it will get garbage-collected.

enums and collections
Fill in the rest of the table below by looking at the List code on
the left and putting in what you think the code might be if it were
using a regular array instead. We don’t expect you to get all of
them exactly right, so just make your best guess.

Assume these statements are all
executed in order, one after another.
We filled in a couple for you....

List

regular array

List myList =
new List ();

String [] myList = new String[2];

String a = “Yay!”;

String a = “Yay!”;

myList.Add(a);
String b = “Bummer”;

String b = “Bummer”;

myList.Add(b);
int theSize = myList.Count;
Guy o = myList[1];
bool isIn = myList.Contains(b);

Hint: You’ll need more than one
line of code here.

you are here 4   337

one size fits all

Your job was to fill in the rest of the table by looking at the List code
on the left and putting in what you think the code might be if it were
using a regular array instead.

List

regular array

List myList =
new List ();

String[] myList = new String[2];

String a = “Yay!”
myList.Add(a);

String a = “Yay!”;

myList[0] = a;

String b = “Bummer”;
myList.Add(b);

myList[1] = b;

int theSize = myList.Count;

int theSize = myList.Length;

Guy o = myList[1];

Guy o = myList[1];

bool isIn = myList.Contains(b);

bool isIn = false;
for (int i = 0; i < myList.
Length; i++) {
if (b == myList[i]) {
isIn = true;
}
}

Lists are objects that use methods just like every
other class you’ve used so far. You can see the list
of methods available from within the IDE just by
typing a . next to the List name, and you pass
parameters to them just the same as you would for
a class you created yourself.

338   Chapter 8

String b = “Bummer”;

With arrays you’re a lot more limited. You need
to set the size of the array when you create it, and
any logic that’ll need to be performed on it will
need to be written on your own.

The .NET Framework does have an
Array class, which makes some of these
things a little easier to do, but we’re
concentrating on List objects because
they’re a lot easier to use.

enums and collections

Lists shrink and grow dynamically

Do this!

The great thing about a List is that you don’t need to know how long it’ll be when you
create it. A List automatically grows and shrinks to fit its contents. Here’s an example
of a few of the methods that make working with Lists a lot easier than arrays. Create
a new Console Application and add this code to the Main() method. It won’t print
anything—use the debugger to step through the code and see what’s going on.
List shoeCloset = new List();
shoeCloset.Add(new Shoe()

{ Style = Style.Sneakers, Color = “Black” });

shoeCloset.Add(new Shoe()

{ Style = Style.Clogs, Color = “Brown” });

shoeCloset.Add(new Shoe()

{ Style = Style.Wingtips, Color = “Black” });

shoeCloset.Add(new Shoe()

{ Style = Style.Loafers, Color = “White” });

shoeCloset.Add(new Shoe()

{ Style = Style.Loafers, Color = “Red” });

shoeCloset.Add(new Shoe()

{ Style = Style.Sneakers, Color = “Green” });

We’re declaring a
of Shoe objects caLlleist
d
ShoeCloset.

You can use a new statement inside
the List.Add() method.
foreach is a special kind of

loop for Lists. It will execute
a statement for each object
in the List. This loop creates
an identifier called shoe. As
the loop goes through the
items, it sets shoe equal to
the first item in the list, then
the second, then the third,
until the loop is done.

This returns the
! In
total number of foreach loops work on arraysect, too
ion.
fact, they work on any coll
Shoe objects in
foreach (Shoe shoe in shoeCloset) {
the List.
shoe.Style = Style.Flipflops;
Here’s the Shoe class we’re using,
shoe.Color = “Orange”;
and the Style enum it uses.
This foreach loop goes
}
through each of the
The Remove() method will
class Shoe {
shoes in the closet.
remove the object by its
public Style Style;
reference; RemoveAt() does
public string Color;
it by index number.
}
The Clear() method
shoeCloset.RemoveAt(4);
removes all of the
enum Style {
obje
cts in a List.
Shoe thirdShoe = shoeCloset[3];
Sneakers,
Shoe secondShoe = shoeCloset[2];
s
Loafers,
nce
We saved refere
shoeCloset.Clear();
ore
bef
Sandals,
to two shoes
we cleared the list. We
Flipflops,
shoeCloset.Add(thirdShoe);
added one back, but
Wingtips,
sing.
if (shoeCloset.Contains(secondShoe))the other’s still mis
Clogs,
int numberOfShoes = shoeCloset.Count;

Console.WriteLine(“That’s surprising.”);

This line will never run, because Contains() will return false. We
only added thirdShoe into the cleared list, not fifthShoe.

}

you are here 4   339

membership has its privileges

Generics can store any t ype
You’ve already seen that a List can store strings or Shoes.
You could also make Lists of integers or any other object
you can create. That makes a List a generic collection.
When you create a new List object, you tie it to a specific
type: you can have a List of ints, or strings, or Shoe objects.
That makes working with Lists easy—once you’ve created
your list, you always know the type of data that’s inside it.

This doesn’t actually mean that you add the letter T. It’s a
notation that you’ll see whenever a class or interface works
with all types. The  part means you can put a type in
there, like List, which limits its members to that type.

List name = new List();

xible (allowing any
Lists can be either very .fle
they do what arrays
type) or very restrictivew So
ings more.
do, and then quite a fe th

¢¢
¢¢

¢¢

¢¢

¢¢

The .NET Framework comes with some generic
interfaces that let the collections you’re building work
with any and all types. The List class implement those
interfaces, and that’s why you could create a List of
integers and work with it in pretty much the same way
that you would work with a List of Shoe objects.

Check it out for yourself. Type the word List into
the IDE, and then right-click on it and select “Go To
Definition”. That will take you to the declaration for
the List class. It implements a few interfaces:

This is where RemoveAt(), IndexOf(), and
Insert() come from.
class List : IList,
ICollection, IEnumerable, IList,
ICollection, IEnumerable

e lets you use .
This
. is where Add(), Clear(), This interfac
her things
CopyTo(), and Remove()
foreach, among ot
come from. It’s the basis
for all generic collections.
340   Chapter 8

¢¢

¢¢

¢¢

¢¢

List is a class in the .NET Framework.

A List resizes dynamically to whatever
size is needed. It’s got a certain capacity—
once you add enough data to the list, it’ll grow
to accommodate it.
To put something into a List, use Add().
To remove something from a List, use
Remove().
You can remove objects using their index
number using RemoveAt().

You declare the type of the List using a
type argument, which is a type name in
angle brackets. Example: List
means the List will be able to hold only
objects of type Frog.
To find out where something is (and if it is) in
a List, use IndexOf().
To get the number of elements in a List,
use the Count property.

You can use the Contains() method to
find out if a particular object is in a List.
foreach is a special kind of loop that
will iterate through all of the elements in a
List and execute code on it. The syntax
for a foreach loop is foreach (string s in
StringList). You don’t have to tell the
foreach loop to increment by one; it will go
through the entire List all on its own.

enums and collections

Code Magnets

Can you reconstruct the code snippets to make
a working Windows Form that will pop up the
message box below when you click a button?

a.RemoveAt(2);
ng>();
List a = new List a){
wo”)) {
if (a.Contains(“t
o);
a.Add(twopointtw

private void button1_Click(object sender,
EventArgs e){

}

a.Add(zilch);
}
a.Add(first);
);
nd
co
se
a.Add(
a.Add(third);
string res
ult = “”;
if (a.Contains(“three”)){
a.Add(“four”);
}

{
}

foreach (string
element in a)
result += “\n”
+ element;

MessageBox.Show(result);

}

if (a.IndexOf(“
four”) != 4) {
a.Add(fourth);		
}

printL(a);

}

string
string
string
string
string
string

zilch = “zero”;
first = “one”;
second = “two”;
third = “three”;
fourth = “4.2”;
twopointtwo = “2.2”;
you are here 4   341

exercise solution

Code Magnets Solution

Remember how we talked about using
intuitive names back in Chapter 3? Well,
that may make for good code, but it makes
these puzzles way too easy. Just don’t use
cryptic names like “printL()” in real life!

private void button1_Click(object sender, EventArgs e)

{

ng>();
List a = new List a){
string res
ult = “”;
foreach (string
element in a)
{
result += “\n”
+ element;
}

The foreach loop goes
through all of the
elements in the list
and prints them.

MessageBox.Show(result);

342   Chapter 8

list of strings, add each of
them to one big string, and
then show it in a message box.

}

}

enums and collections

Q:

So why would I ever use an enum
instead of a List? Don’t they solve the
same problem?

A:
List

Enums are a little different than
s. First and foremost, enums are
types, while Lists are objects.

You can think of enums as a handy way to
store lists of constants so you can refer
to them by name. They’re great for keeping
your code readable and making sure that
you are always using the right variable
names to access values that you use really
frequently.
A List can store just about anything.
Since it’s a list of objects, each element in a
list can have its own methods and properties.
Enums, on the other hand, have to be
assigned one of the value types in C# (like
the ones on the first page of Chapter 4). So
you can’t store reference variables in them.
Enums can’t dynamically change their size
either. They can’t implement interfaces or
have methods, and you’ll have to cast them
to another type to store a value from an
enum in another variable. Add all of that up
and you’ve got some pretty big differences
between the two ways of storing data. But
both are really useful in their own right.  

Q:

OK, it sounds like Lists are
pretty powerful. So why would I ever want
to use an array?

A:

If you know that you have a fixed
number of items to work with, or if you want

Arrays also take up less memory
and CPU time for your programs,
but that only accounts for a tiny
performance boost. If you have to
do the same thing, say, millions of
times a second, you might want to
use an array and not a list. But if
your program is running slowly, it’s
pretty unlikely that switching from
lists to arrays will fix the problem.

a fixed sequence of values with a fixed
length, then an array is perfect. Luckily, you
can easily convert any list to an array using
the ToArray() method…and you can
convert an array to a list using one of the
overloaded constructors for the List
object.

Q:

I don’t get the name “generic”. Why
is it called a generic collection? Why isn’t
an array generic?

A:

A generic collection is a collection
object (or a built-in object that lets you store
and manage a bunch of other objects) that’s
been set up to store only one type (or more
than one type, which you’ll see in a minute).

Q:

OK, that explains the “collection”
part. But what makes it “generic”?

A:

Supermarkets used to carry generic
items that were packaged in big white
packages with black type that just said the
name of what was inside (“Potato Chips”,
“Cola”, “Soap”, etc.). The generic brand was
all about what was inside the bag, and not
about how it was displayed.
The same thing happens with generic data
types. Your List will work exactly the
same with whatever happens to be inside
it. A list of Shoe objects, Card objects,
ints, longs, or even other lists will still act at
the container level. So you can always add,
remove, insert, etc., no matter what’s inside
the list itself.

The term “generic” refers to the
fact that even though a specific
instance of List can only store
one specific type, the List class in
general works with any type.

Q:

Can I have a list that doesn’t have
a type?

A:

No. Every list—in fact, every generic
collection (and you’ll learn about the other
generic collections in just a minute)—must
have a type connected to it. C# does have
non-generic lists called ArrayLists
that can store any kind of object. If you
want to use an ArrayList, you
need to include a “using System.
Collections;” line in your code. But
you really shouldn’t ever need to do this,
because a List will work
just fine!

When you create
a new List object,
you always supply
a type—that tells
C# what type of
data it’ll store. A
list can store a
value type (like int,
bool, or decimal) or
a class.

the way that you tie
That’s what the  stuff is all about. It’s
the List class as a
But
type.
one
to
List
a
a specific instance of
That’s why generic
whole is generic enough to work with ANY type.
so far.
seen
e
you’v
collections are different from anything
you are here 4   343

initial here

Collection initializers work just like object initializers
C# gives you a nice bit of shorthand to cut down on typing when you need to
create a list and immediately add a bunch of items to it. When you create a
new List object, you can use a collection initializer to give it a starting list
of items. It’ll add them as soon as the list is created.

List shoeCloset = new
shoeCloset.Add(new Shoe() {
shoeCloset.Add(new Shoe() {
shoeCloset.Add(new Shoe() {
shoeCloset.Add(new Shoe() {
shoeCloset.Add(new Shoe() {
shoeCloset.Add(new Shoe() {

List();
Style = Style.Sneakers, Color = “Black” });
Style = Style.Clogs, Color = “Brown” });
Style = Style.Wingtips, Color = “Black” });
Style = Style.Loafers, Color = “White” });
Style = Style.Loafers, Color = “Red” });
Style = Style.Sneakers, Color = “Green” });

Th
es
am
ec
od
er
ew
ritt
en
us
ing
a

Notice how each Shoe object is
initialized with its own object
initializer? You can nest them inside
a collection initializer, just like this.

You saw this code a few
pages ago—it creates a new
List and fills it with
new Shoe objects.

co
lle
cti
on
ini
tia
lize
r

You can create a collection
initializer by taking each item
that was being added using Add()
and adding it to the statement
that creates the list.

List shoeCloset = new List() {
new Shoe() { Style = Style.Sneakers, Color = “Black” },
The statement to create
new Shoe() { Style = Style.Clogs, Color = “Brown” },
the list is followed by
that
kets
brac
curly
new Shoe() { Style = Style.Wingtips, Color = “Black” },
contain separate new
new Shoe() { Style = Style.Loafers, Color = “White” },
statements, separated by
new Shoe() { Style = Style.Loafers, Color = “Red” },
commas.
new Shoe() { Style = Style.Sneakers, Color = “Green” },
You’re not limited to };
new statements

using
in the initializer—you
can include variables,
too.

344   Chapter 8

A collection initializer makes your code more
compact by letting you combine creating a list
with adding an initial set of items.

enums and collections

Le t’s cre ate a List of Ducks

Do this!

Here’s a Duck class that keeps track of your extensive
duck collection. (You do collect ducks, don’t you?) Create
a new Console Application and add a new Duck class
and KindOfDuck enum.

Each duck has a size—this
one is 17 inches long.
Some of the ducks
are mallards.

You’ve got some
Muscovy ducks.

And you’ve got a few
wooden decoys.

Here’s the initializer for your List of Ducks
We’ve got six ducks, so we’ll create a List that has a
collection initializer with six statements. Each statement in the
initializer creates a new duck, using an object initializer to set
each Duck object’s Size and Kind field. Add this code to
your Main() method in Program.cs:

Size
Kind

Duck

Quack()
Swim()
Eat()
Walk()

class Duck {
public int Size;
public KindOfDuck Kind;
}

The class has two public
fields. It’s also got some
methods, which we’re not
showing here.

enum KindOfDuck {
Mallard,
Muscovy,
Decoy,
}

We’ll use an enum
called KindOfDuck to
keep track of what
sort of ducks are in
your collection.

List ducks = new List() {
new Duck() { Kind = KindOfDuck.Mallard, Size = 17 },
new Duck() { Kind = KindOfDuck.Muscovy, Size = 18 },

Add Duck and
KindOfDuck to
your project.

new Duck() { Kind = KindOfDuck.Decoy, Size = 14 },
new Duck() { Kind = KindOfDuck.Muscovy, Size = 11 },
new Duck() { Kind = KindOfDuck.Mallard, Size = 14 },
new Duck() { Kind = KindOfDuck.Decoy, Size = 13 },
};

You’ll be adding code to your Main()
method to print to the console. Mak
sure you keep this line at the end so ethe
program stays open until you hit a key.

// This keeps the output from disappearing before you can read it
Console.ReadKey();

you are here 4   345

getting your ducks in a row

Lists are e asy, but SORTING can be trick y
It’s not hard to think about ways to sort numbers or letters. But what do you
sort two objects on, especially if they have multiple fields? In some cases you
might want to order objects by the value in the name field, while in other
cases it might make sense to order objects based on height or date of birth.
There are lots of ways you can order things, and lists support any of them.

Sorted smallest to biggest....

You could sort a list of ducks by size…

Sorted by kind of duck....

…or by kind.

Lists know how to sort themselve s
Every list comes with a Sort() method that rearranges all of the items
in the list to put them in order. Lists already know how to sort most
built-in types and classes, and it’s easy to teach them how to sort your own
classes.

Technically, it’s not the List that
knows how to sort itself. It depends on
an IComparer object, which you’ll
learn about in a minute.

17” duck

14” duck

Du

ck

346   Chapter 8

objec

t

ck

objec

Sort()

Li

11” duck

Du

Du

t

st<

ck

ect

Duck> o

t
objec

bj

st<

bj

Li

ck

ect

Du

11” duck

Duck> o

After the list of ducks is
sorted, it’s got the same
items in it—but they’re in
a different order.

14” duck

Du
17” duck

Du

objec

ck

objec

t

ck

objec

t

t

enums and collections

IComparable helps your list sort its ducks

You can make
The List.Sort() method knows how to sort any type or class that implements the
any class
IComparable interface. That interface has just one member—a method called
CompareTo(). Sort() uses an object’s CompareTo() method to compare it with
work with the
other objects, and uses its return value (an int) to determine which comes first.
List’s built-in
But sometimes you need to sort a list of objects that don’t implement IComparable,
and .NET has another interface to help with that. You can pass Sort() an instance of a
Sort() method
class that implements IComparer. That interface also has one method. The List
object’s Sort() method uses the comparer object’s Compare() method to compare pairs
by having it
of objects, in order to figure out which one comes first in the sorted list.
implement
IComparable
An object’s CompareTo() method compares it to another object
One way to let our List object sort is to modify the Duck class to implement
and adding a
IComparable. To do that, we’d add a CompareTo() method that takes a Duck
reference as a parameter. If the duck to compare should come after the current duck in the CompareTo()
sorted list, CompareTo() returns a positive number.
Update your project’s Duck class by implementing IComparable so that it sorts method.
itself based on duck size:

class Duck : IComparable {
public int Size;
public KindOfDuck Kind;

When you implement IComparable, you
specify the type being compared when you
have the class implement the interface.

thods
Most CompareTo() me
is
Th
is.
th
e
public int CompareTo(Duck duckToCompare) {
look a lot lik
the
es
ar
mp
co
if (this.Size > duckToCompare.Size)
method first
her
Size field against thethotis
return 1;
duck’s Size field. Ifturns 1.
else
if (this.Size < duckToCompare.Size)
duck is bigger, it returns -1.
return -1;
If it’s smaller, it re same size,
If you want to sort your list from smallest
e
th
’re
else
And if they
biggest, have CompareTo() return a
to
return 0;
it returns zero.
positive number if it’s comparing to a
}
smaller duck, and a negative number if it’s
comparing to a bigger one.
}
Add this code to the end of your Main() method above the call to Console.
ReadKey() to tell your list of ducks to sort itself. Use the debugger to see this at
work by putting a breakpoint in the CompareTo() method.

ducks.Sort();

you are here 4   347

sort it out amongst yourselves

Use IComparer to tell your List how to sort

Your List will
sort differently
depending on how
you implement
IComparer.

Lists have a special interface built into the .NET Framework that lets
you build a separate class to help the List sort out its members.
By implementing the IComparer interface, you can tell
your List exactly how you want it to sort your objects. You do that by
implementing the Compare() method in the IComparer interface.
It takes two object parameters, x and y, and returns an int. If x is less than
y, it should return a negative value. If they’re equal, it should return zero.
And if x is greater than y, it should return a positive value.
Here’s an example of how you’d declare a comparer class to compare
Duck objects by size. Add it to your project as a new class:

This class implements ICompare
r,
and specifies the type of object
it
can sort: Duck objects.

class DuckComparerBySize : IComparer
These will always match:
{
the same type in each.
public int Compare(Duck x, Duck y)
an
{
method returnsboth
()
re
pa
om
C
if (x.Size < y.Size)
he
s:
T
rameter
You can do wh
and has two pa sorting.
,
t
at
in
ev
er
return -1;
u’re
types of com
of the type yo
you want in thparisons
if (x.Size > y.Size)
e method.
Any negative number means
return 1;
object x should go before
object y. x is “less than” y.
return 0;
Any positive va
lu
x should go af e means object
}
is “greater th ter object y. x
}
o
an”
tw
e

es
0 means that th
treated
be
ld
ou
objects sh sing this
as the same (u ulation).
comparison calc

Here’s a method to print the
ducks in a List.

y.

Add this PrintDucks method to
your Program class in your project
so you can print the ducks in a list.
Update your Main() method to call

public static void PrintDucks(List ducks)
it before and after you sort the
{
list so you can see the results!
foreach (Duck duck in ducks)
Console.WriteLine(duck.Size.ToString() + “-inch ” + duck.Kind.ToString());
Console.WriteLine(“End of ducks!”);
}
348   Chapter 8

enums and collections

Cre ate an instance of your comparer object
When you want to sort using IComparer, you need to create a new
instance of the class that implements it. That object exists for one reason—
to help List.Sort() figure out how to sort the array. But like any other
(non-static) class, you need to instantiate it before you use it.

We left out the code you already
saw a few pages ago to initialize
the list. Make sure you initialize
your list before you try to sort
it! If you don’t, you’ll get a null
pointer exception.

DuckComparerBySize sizeComparer = new DuckComparerBySize();
ducks.Sort(sizeComparer);
You’ll pass Sort() a reference to the
PrintDucks(ducks);
new DuckComparerBySize object as its

Add this code to your program’s
Main() method to see how the
ducks get sorted.

parameter.

Sorted smallest to biggest....

Multiple IComparer implementations, multiple ways
to sort your objects
You can create multiple IComparer classes with different sorting
logic to sort the ducks in different ways. Then you can use the comparer
you want when you need to sort in that particular way. Here’s another duck
comparer implementation to add to your project:

This compare
type. Remembr sorts by duck
compare the eer, when you
comparing the num Kind, you’re
ir index values.

class DuckComparerByKind : IComparer {
So Mallard
public int Compare(Duck x, Duck y) {
Muscovy, whiccomes before
if (x.Kind < y.Kind)
before Decoy h comes
ed the ducks’ Kind
par
com
We
.
return -1;
ted
properties, so the ducks are sor
e
if (x.Kind > y.Kind)
based on the index value of th
nums
mple of how e
return 1;
KindOfDuck enum.
Here’s an exaork together. Enums
else
Notice how “greater than
and Lists wr numbers, and are used
”
an
d
return 0;
“less than” have a differ
stand in fo f lists.
en
t
meaning here. We used <
in sorting o
}
an
d
>
to
compare enum index value
}
s, which

lets us put the ducks in

order.

DuckComparerByKind kindComparer = new DuckComparerByKind();
ducks.Sort(kindComparer);
Sorted by kind of duck....
PrintDucks(ducks);

More duck sorting
code for your
Main() method.

you are here 4   349

pick a card any card

IComparer can do comple x comparisons
One advantage to creating a separate class for sorting your ducks is
that you can build more complex logic into that class—and you can
add members that help determine how the list gets sorted.
enum SortCriteria {
SizeThenKind,
KindThenSize,
}

This enum tells the object which
way to sort the ducks.

If you don’t provide Sort() with
an IComparer object , it uses
a default one that can sort value
types or compare references. Flip
to Leftover #5 in the Appendix to
learn a little more about comparing
objects.

Here’s a more complex class to
compare ducks. Its Compare() method
takes the same parameters, but it
looks at the public SortBy field to
determine how to sort the ducks.

class DuckComparer : IComparer {
public SortCriteria SortBy = SortCriteria.SizeThenKind;

}

public int Compare(Duck x, Duck y) {
if (SortBy == SortCriteria.SizeThenKind)
if (x.Size > y.Size)
This if statement checks the SortBy
return 1;
field. If it’s set to SizeThenKind,
else if (x.Size < y.Size)
then it first sorts the ducks by size,
return -1;
and then within each size it’ll sort
else
the ducks by their kind.
if (x.Kind > y.Kind)
return 1;
else if (x.Kind < y.Kind)
Instead of just returning 0 if the two
return -1;
ducks are the same size, the comparer
else
checks their kind, and only returns 0
return 0;
the two ducks are both the same
if
else
and the same kind.
size
if (x.Kind > y.Kind)
return 1;
else if (x.Kind < y.Kind)
return -1;
else
If SortBy isn’t set to SizeThenKind,
if (x.Size > y.Size)
then the comparer first sorts by the
return 1;
kind of duck. If the two ducks are the
else if (x.Size < y.Size)
same kind, then it compares their size.
return -1;
else
return 0;
}
comparer object.

DuckComparer comparer = new DuckComparer();
comparer.SortBy = SortCriteria.KindThenSize;
ducks.Sort(comparer);
PrintDucks(ducks);
comparer.SortBy = SortCriteria.SizeThenKind;
ducks.Sort(comparer);
PrintDucks(ducks);

350   Chapter 8

Here’s how we’d use this as usual. Then
First we’d instantiate itSortBy field
we can set the object’s t(). Now you
before calling ducks.Sor list sorts its
can change the way theone field in the
ducks just by changing the end of
object. Add this code tow it sorts and
your Main() method. No h of times!
re-sorts the list a bunc

enums and collections

vv

Create five random cards and then sort them.

1

Create code to make a jumbled set of cards
Create a new Console Application and add code to the Main() method that creates five random
Card objects. After you create each object, use the built-in Console.WriteLine() method to
write its name to the output. Use Console.ReadKey() at the end of the program to keep your
window from disappearing when the program finishes.

2

Create a class that implements IComparer to sort the cards
Here’s a good chance to use that IDE shortcut to implement an interface:
class CardComparer_byValue : IComparer

Then click on IComparer and hover over the I. You’ll see a box appear underneath it.
When you click on the box, the IDE pops up its “Implement interface” window:

Sometimes it’s a little hard to
get this box to pop up, so the
IDE has a useful shortcut.: just
press ctrl-period.
Click on “Implement interface IComparer” in the box to tell the IDE to automatically fill
in all of the methods and properties that you need to implement. In this case, it creates an empty
Compare() method to compare two cards, x and y. Write the method so that it returns 1 if x is
bigger than y, –1 if it’s smaller, and 0 if they’re the same card. In this case, make sure that any king
comes after any jack, which comes after any four, which comes after any ace.
3

Make sure the output looks right
Here’s what your output window should look like after you click the button.

When you use the built‑in
Console.WriteLine()
method, it adds a line
to this output. Console.
ReadKey() waits for you
to press a key before the
program ends.

Your IComparer
object needs to sort
the cards by value,
so the cards with
the lowest values are
first in the list.

you are here 4   351

look it up

Create five random cards and then sort them.

Here’s the “gut
card sorting, whis”chof the
built-in List.Sort( uses the
Sort() takes an IC ) method.
object, which has omparer
Compare(). This imone method:
takes two cards plementation
compares their vaand first
lues, then
their suits.

class CardComparer_byValue : IComparer {
public int Compare(Card x, Card y) {
If x has a bigger value, if (x.Value < y.Value) {
return 1. If x’s value
return -1;
is smaller, return -1.
}
Remember, both return if (x.Value > y.Value) {
statements end the
return 1;
method immediately.
}
These statements only get the
if (x.Suit < y.Suit) {
executed if x and y have e
return -1;
same value—that means th s
}
first two return statement
if (x.Suit > y.Suit) {
weren’t executed.
return 1;
}
return 0;
If none of the other fo
}
statements were hit ur return
}

, th
the same—so return zeroe . cards must be

Here’s a generic List

static void Main(string[] args)
of Card objects to
{
store the cards. Once
Random random = new Random();
they’re in the list, it’s
Console.WriteLine(“Five random cards:”);
easy to sort them
List cards = new List();
using an IComparer.
for (int i = 0; i < 5; i++)
{
cards.Add(new Card((Suits)random.Next(4),
(Values)random.Next(1, 14)));
Console.WriteLine(cards[i].Name);
}

}

352   Chapter 8

Console.WriteLine();
Console.WriteLine(“Those same cards, sorted:”);
cards.Sort(new CardComparer_byValue());
foreach (Card card in cards)
We’re using Console.ReadKey() to keep console
{
applications from exiting after they finish. This
Console.WriteLine(card.Name);
is great for learning, but not so great if you want
}
to write real command-line applications. If you
use Ctrl-F5 to start your program, the IDE runs
Console.ReadKey();
it without debugging. When it finishes, it prints
“Press any key to continue…” and waits for a
keypress. But it doesn’t debug your program
(because it’s running without debugging), so
your breakpoints and watches won’t work.

enums and collections

Overriding a ToString() me thod le ts an object de scribe itself
Every .NET object has a method called ToString() that converts it to a string. By default, it just returns the
name of your class (MyProject.Duck). The method is inherited from Object (remember, that’s the base class for every
object). This is a really useful method, and it’s used a lot. For example, the + operator to concatenate strings automatically
calls an object’s ToString(). And Console.WriteLine() or String.Format() will automatically call it
when you pass objects to them, which can really come in handy when you want to turn an object into a string.
Go back to your duck sorting program. Put a breakpoint in the Main() method anywhere after the list is initialized
and debug your program. Then hover over any ducks variable so it shows the value in a window. Any time you
look at a variable in the debugger that’s got a reference to a List, you can explore the contents of it by clicking the +
button:

The IDE calls the ToString() method when it displays
an object in its Watch window. But the ToString()
method that Duck inherited from Object just returns
its class name. It would be really useful if we could
make ToString() more informative.
Hmm, that’s not as useful as we’d hoped. You can see that there are six Duck objects in the list
(“MyProject” is the namespace we used). If you click the + button next to a duck, you can see
its Kind and Size values. But wouldn’t it be easier if you could see all of them at once?

So instead of
passing a value to
Console.WriteLine(),
String.Format(),
etc., you can pass
an object—its
ToString() method is
called automatically.
That also works with
value types like ints
and enums, too!

Luckily, ToString() is a virtual method on Object, the base class of every object. So all you need to do is
override the ToString() method—and when you do, you’ll see the results immediately in the IDE’s Watch
window! Open up your Duck class and start adding a new method by typing override. As soon as you press space,
the IDE will show you the methods you can override:

Click on ToString() to tell the IDE to add a new ToString() method. Replace the contents so it looks like this:
public override string ToString()
{
return "A " + Size + " inch " + Kind.ToString();
}

Run your program and look at the list again. Now the IDE shows you the contents of your Ducks!

When the IDE’s debugger shows
you an object, it calls the
object’s ToString() method and
shows you its contents.
you are here 4   353

foreach loopy

Update your fore ach loops to le t your
Ducks and Cards print themselve s
You’ve seen two different examples of programs looping through a list of objects and calling Console.
WriteLine() to print a line to the console for each object—like this foreach loop that prints every card
in a List:
foreach (Card card in cards)
{
Console.WriteLine(card.Name);
}

The PrintDucks() method did something similar for Duck objects in a List:

The + operator automatically
calls the KindOfDuck enum’s
ToString() method.

foreach (Duck duck in ducks)
{
Console.WriteLine(duck.Size.ToString() + “-inch ” + Kind);
}

This is a pretty common thing to do with objects. But now that your Duck has a ToString() method,
your PrintDucks() method should take advantage of it:
public static void PrintDucks(List ducks) {
foreach (Duck duck in ducks) {
If you pass Console.WriteLine()
Console.WriteLine(duck);
a
reference to an object, it will
}
call
that object’s ToString()
Console.WriteLine(“End of ducks!”);
method
automatically.
}
Add this to your Ducks program and run it again. It prints the same output. And now if you want to add, say,
a Gender property to your Duck object, you just have to update the ToString() method, and everything
that uses it (including the PrintDucks() method) will reflect that change.

Add a ToString() me thod to your Card object, too
Your Card object already has a Name property that returns the name of the card:

You’re still allowed to call
ToString() like this, but now
you know it’s not necessary in
this case, because + calls it
automatically.

public string Name
{
get { return Value.ToString() + “ of ” + Suit.ToString(); }
}

That’s exactly what its ToString() method should do. So add a ToString() method to the Card class:
public override string ToString()
{
return Name;
}

Now your programs that use Card objects will be easier to debug.
354   Chapter 8

ToString() is useful for a lot more than just IDE.
making your objects easier to identify in the
Keep your eyes open over the next few chapters,to
and you’ll see how useful it is for every object ’s
have a way to convert itself to a string. That
why every object has a ToString() method.

enums and collections

When you write a fore ach loop,
you’re using IEnumerable

foreach Loops
Up Close

Go to the IDE, find a List variable, and use IntelliSense to take a look at its
GetEnumerator() method. Start typing “.GetEnumerator” and see what comes up:

Collection initializers work
with ANY IEnumerable
object!

Add a line to create a new array of Duck objects:
Duck[] duckArray = new Duck[6];

Then type duckArray.GetEnumerator—the array also has a GetEnumerator() method.
That’s because all List, and arrays implement an interface called IEnumerable, which
contains one method. That method, GetEnumerator(), returns an Enumerator object.
It’s the Enumerator object that provides the machinery that lets you loop through a list in order.
Here’s a foreach loop that loops through a List with a variable called duck:
foreach (Duck duck in ducks) {
Console.WriteLine(duck);
}
And here’s what that loop is actually doing behind the scenes:
IEnumerator enumerator = ducks.GetEnumerator();
while (enumerator.MoveNext()) {
Duck duck = enumerator.Current;
Console.WriteLine(duck);
}
IDisposable disposable = enumerator as IDisposable;
if (disposable != null) disposable.Dispose();

When a collection
implements
IEnumerable,
it’s giving you a way
to write a loop that
goes through its
contents in order.

(Don’t worry about the last two lines for now. You’ll learn about IDisposable in Chapter 9.)

Those two loops print out the same ducks. You can see this for yourself by running both of them;
they’ll both have the same output.

Technically, there’s a
little more than this,
but you get the idea....

Here’s what’s going on. When you’re looping through a list or array (or any other collection), the
MoveNext() method returns true if there’s another element in the list, or false if the enumerator
has reached the end of the list. The Current property always returns a reference to the current
element. Add it all together, and you get a foreach loop!

Try experimenting with this by changing your Duck’s ToString() to increment the Size property. Debug your program
and hover over a Duck. Then do it again. Remember, each time you do it, the IDE calls its ToString() method.

What do you think would happen during a foreach loop if your ToString()
method changes one of the object’s fields?
you are here 4   355

nobody here but us ducks

You can upcast an entire list using IEnumerable
Remember how you can upcast any object to its superclass? Well, when you’ve got a
List of objects, you can upcast the entire list at once. It’s called covariance, and all
you need for it is an IEnumerable interface reference.

Name

Bird

Fly()

Create a Console Application and add a base class, Bird (for Duck to extend), and a
Penguin class. We’ll use the ToString() method to make it easy to see which class is which.
class Bird {
public string Name { get; set; }
public void Fly() {
Console.WriteLine("Flap, flap");
}
public override string ToString() {
return "A bird named " + Name;
}
}
class Penguin : Bird
{
public void Fly() {
Console.WriteLine(“Penguins can’t fly!”);
}
public override string ToString() {
return “A penguin named ” + base.Name;
}
}

Size
Kind

Duck

Penguin

Here’s a Bird class, and a Penguin class that
inherits from it. Add them to a new Console
Application project, then copy your existing Duck
class into it. Just change its declaration so that
it extends Bird.
class Duck : Bird, IComparable {
// The rest of the class is the same
}

Here are the first few lines of your Main() method to initialize your list and then upcast it.
List ducks = new List() { // initialize your list as usual }
IEnumerable upcastDucks = ducks;

Copy the same collection
initializer you’ve been
using to initialize your
List of ducks.

Take a close look at that last line of code. You’re taking a reference to your List and assigning it to an
IEnumerable interface variable. Debug through it and you’ll see it’s pointing to the same object.

Combine your birds into a single list
Covariance is really useful when you want to take a collection of objects and add them to a more general list. Here’s an
example: if you have a list of Bird obects, you can add your Duck list to it in one easy step. Here’s an example that
uses the List.AddRange() method, which you can use to add the contents of one list into another.
List birds = new List();
birds.Add(new Bird() { Name = “Feathers” });
birds.AddRange(upcastDucks);
birds.Add(new Penguin() { Name = “George” });
foreach (Bird bird in birds) {
Console.WriteLine(bird);
}
Once the

356   Chapter 8

ducks were upcast
rable,
IEnume
an
into
to a list
them
add
could
you
.
objects
Bird
of

enums and collections

You can build your own overloaded me thods
You’ve been using overloaded methods and even an overloaded
constructor that were part of the built-in .NET Framework classes and
objects, so you can already see how useful they are. Wouldn’t it be cool
if you could build overloaded methods into your own classes? Well, you
can—and it’s easy! All you need to do is write two or more methods that
have the same name but take different parameters.
1

2

You can also use a using
instead of changing the statement
If you want to learn mo namespace.
re about
namespaces, take a minute
to Leftover #2 in the and flip
Appendix.

Do this!

Create a new project and add the Card class to it.
You can do this easily by right-clicking on the project in the Solution Explorer and selecting “Existing
Item” from the Add menu. The IDE will make a copy of the class and add it to the project. The file
will still have the namespace from the old project, so go to the top of the Card.cs file and
change the namespace line to match the name of the new project you created. Then do the same
y be
for the Values and Suits enums.
If you don’t do this, you’ll onl

able
g its
yin
cif
spe
by
to access the Card class ace.Card).
namespace (like oldnamesp

Add some new overloaded methods to the card class.
Create two static DoesCardMatch() methods. The first one should check a card’s suit. The
second should check its value. Both return true only if the card matches.
public static bool DoesCardMatch(Card cardToCheck, Suits suit) {
if (cardToCheck.Suit == suit) {
Overloaded methods don’t have
return true;
to be static, but it’s good to get
} else {
return false;
a little practice writing static
}
methods.
}

public static bool DoesCardMatch(Card cardToCheck, Values value) {
if (cardToCheck.Value == value) {
return true;
You’ve seen overloading already. Flip
} else {
back to the solution to Kathleen’s
return false;
party planning program in Chapter
}
on pages 253–256—you added an
6
}

3

Add a button to the form to use the new methods.
Add this code to the button:

overloaded CalculateCost() method to
the DinnerParty class.

Card cardToCheck = new Card(Suits.Clubs, Values.Three);
bool doesItMatch = Card.DoesCardMatch(cardToCheck, Suits.Hearts);
MessageBox.Show(doesItMatch.ToString()); Notice how you’re using ToString()

here. That’s because
not a bool or object..
string,
a
takes
how()
MessageBox.S

As soon as you type “DoesCardMatch(” the IDE will show you that you really did build an
overloaded method:

Take a minute and play around with the two methods so you can get used to overloading.
you are here 4   357

all hands on deck

Get some practice using Lists by building a class to store a deck of cards,
along with a form that uses it.

v
1

Build a form that lets you move cards between two decks
You’ve built a card class already. Now it’s time to build a class to hold any number of cards, which we’ll call
Deck. A real-life deck has 52 cards, but the Deck class can hold any number of cards—or no cards at all.
 hen you’ll build a form that shows you the contents of two Deck objects. When you first start the program,
T
deck #1 has up to 10 random cards, and deck #2 is a complete deck of 52 cards, both sorted by suit and
then value—and you can reset either deck to its initial state using two Reset buttons. The form also has
buttons (labeled “<<” and “>>”) to move cards between the decks.

These buttons are named moveToDeck2 (top) and moveToDeck1
(bottom). They move cards from one deck to the other.

Remember, you can use a
control’s Name property to
give it a name to make your
code easier to read. Then
when you double-click on
the button, its event handler
is given a matching name.

The reset1 and reset2
buttons first call the
ResetDeck() method and then
the RedrawDeck() method.

Use two ListBox controls to
show the two decks. When the
moveToDeck1 button is clicked,
it moves the selected card
from deck #2 to deck #1.
These buttons are
named shuffle1 and
shuffle2. They call
the appropriate Deck.
Shuffle() method, and
then redraw the deck.

In addition to the event handlers for the six buttons, you’ll need to add two methods for the form. First add a
ResetDeck() method, which resets a deck to its initial state. It takes an int as a parameter: if it’s passed 1, it
resets the first Deck object by reinitializing it to an empty deck and a random number of up to 10 random cards;
if it’s passed 2, it resets the second Deck object so that it contains a full 52-card deck. Then add this method:

private void RedrawDeck(int DeckNumber) {
if (DeckNumber == 1) {
listBox1.Items.Clear();
Take a look at
foreach (string cardName in deck1.GetCardNames())
how we used the
listBox1.Items.Add(cardName);
foreach loop to label1.Text
= “Deck #1 (“ + deck1.Count + “ cards)”;
add each of the
}
else
{
cards in the
listBox2.Items.Clear();
deck to the
foreach (string cardName in deck2.GetCardNames())
listbox.
listBox2.Items.Add(cardName);
label2.Text = “Deck #2 (“ + deck2.Count + “ cards)”;
}
}

358   Chapter 8

The RedrawDeck() method
shuffles the deck, draws
random cards from it, and
updates the two listbox
controls with whatever
happens to be in the two
Deck objects.

enums and collections

2

Build the Deck class

When you have the declarations for a class
without the implementation, it’s called a “skeleton”.

Here’s the skeleton for the Deck class. We’ve filled in several of the methods for you. You’ll need to finish it
by writing the Shuffle() and GetCardNames() methods, and you’ll have to get the Sort() method
to work. We also added two useful overloaded constructors: one that creates a complete deck of 52
cards, and another that takes an array of Card objects and loads them into the deck.

The Deck stores its cards in a List—but it keeps
it’s well encapsulated.

class Deck {
it private to make sure
private List cards;
private Random random = new Random();

Count

If you don’t pass parameters
into the constructor, it creates
a complete deck of 52 cards.

Deck

Add()

Deal()
The parameter
public Deck() {
GetCardNames()
has the type d>,
cards = new List();
Shuffle()
ar
}
This overloaded constructor takes one
not just a List
initialCards)
{
y.
ra
or an ar
cards = new List(initialCards);
it loads as the initial deck.
}
Hint: The ListBox
public int Count { get { return cards.Count; } }
control’s SelectedIndex
property will be the
public void Add(Card cardToAdd) {
same as the index of
The Deal method deals one card the card in the list.
cards.Add(cardToAdd);
out of the deck—it removes the You can pass it directly
}
Card object from the deck and to the Deal() method.
public Card Deal(int index) {
returns a reference to it. You
If no card is selected,
Card CardToDeal = cards[index]; can deal from
the
top of the
it’ll be less than zero.
cards.RemoveAt(index);
deck by passing it 0, or deal
In that case, the
return CardToDeal;
from
the
midd
le
by
passing it
moveToDeck button
}
the
inde
x
of
the
card to deal.
Again, even though
should do nothing.
GetCardNames() public void Shuffle() {
returns an
// this method shuffles the cards by rearranging them in a random order
array, we expose }
IEnumerable.

public IEnumerable GetCardNames() {
// this method returns a string array that contains each card’s name
}

}

public void Sort() {
cards.Sort(new CardComparer_bySuit());
}

Another hint: The form makes it really
to test your Shuffle() method.
Keep clicking the “Reset Deck #1” butteasy
on
unti
That’ll make it easy to see if your shuffling l you get a three-card deck.
code works.

You’ll need to write the Shuffle()
method and the GetCardNames()
method, and add a class that
implements IComparer to make the
Sort() method work. And you’ll
need to add the Card class you
already wrote. If you use “Add
Existing Item” to add it, don’t
forget to change its namespace.
you are here 4   359

exercise solution

Build a class to store a deck of cards, along with a form that uses it.

class Deck {
private List cards;
private Random random = new Random();

Here’s the constructor that creates a complete
deck of 52 cards. It uses a nested for loop. The
outside one loops through the four suits. That
means the inside loop that goes through the 13
values runs four separate times, once per suit.

public Deck() {
cards = new List();
for (int suit = 0; suit <= 3; suit++)
for (int value = 1; value <= 13; value++)
cards.Add(new Card((Suits)suit, (Values)value));
}

s class
Here’s the other constructor—orsthi, each
uct
has two overloaded constr
with different parameters.

public Deck(IEnumerable initialCards) {
cards = new List(initialCards);
}

public int Count { get { return cards.Count; } }
public void Add(Card cardToAdd) {
cards.Add(cardToAdd);
}

public Card Deal(int index) {
Card CardToDeal = cards[index];
cards.RemoveAt(index);
return CardToDeal;
}

The Add and Deal methods
straightforward—they use are pretty
for the Cards list. The Dealthe methods
removes a card from the list method
Add method adds a card to , and the
the list.

public void Shuffle() {
List NewCards = new List();
while (cards.Count > 0) {
int CardToMove = random.Next(cards.Count);
NewCards.Add(cards[CardToMove]);
cards.RemoveAt(CardToMove);
}
cards = NewCards;
}
public IEnumerable GetCardNames() {
string[] CardNames = new string[cards.Count];
for (int i = 0; i < cards.Count; i++)
CardNames[i] = cards[i].Name;
return CardNames;
}

}

public void Sort() {
cards.Sort(new CardComparer_bySuit());
}

360   Chapter 8

The Shuffle() method creates a
new instance of List called
NewCards. Then it pulls random cards
out of the Cards field and sticks
them in NewCards until Cards is empty.
Once it’s done, it resets the Cards
field to point to the new instance.
The old instance won’t have any more
references pointing to it, so it’ll get
collected by the garbage collector.

od needs to
Your GetCardNames() mebigthenough to
create an array that’s This one uses a
hold all the card names. o use foreach.
for loop, but it could als

enums and collections

class CardComparer_bySuit : IComparer
{
public int Compare(Card x, Card y)
{
Sorting by suit is a lot like
if (x.Suit > y.Suit)
sorting by value. The only
return 1;
if (x.Suit < y.Suit)
difference is that in this
return -1;
case the suits are compared
if (x.Value > y.Value)
first, and then the values
return 1;
are compared only if the
if (x.Value < y.Value)
suits match.
return -1;
return 0;
Instead of using if/else
}
if, we used a series of if
}
statements. This works
Deck deck1;
Deck deck2;
Random random = new Random();
public Form1() {
InitializeComponent();
ResetDeck(1);
ResetDeck(2);
RedrawDeck(1);
RedrawDeck(2);
}

because each if statement
only executes if the previous
one didn’t—otherwise the
previous one would have
returned.

The form’s constructor
needs to reset the two
decks, and then it draws
them.

private void ResetDeck(int deckNumber) {
if (deckNumber == 1) {
int numberOfCards = random.Next(1, 11);
deck1 = new Deck(new Card[] { });
for (int i = 0; i < numberOfCards; i++)
deck1.Add(new Card((Suits)random.Next(4),
(Values)random.Next(1, 14)));
deck1.Sort();
To reset deck #1, this meth
} else
to pick how many cards will od first uses random.Next()
deck2 = new Deck();
go into the deck, and then
}
creates a new em

You’ve already got the
RedrawDeck() method
from the instructions.

pty de
that many random cards.ckIt. It uses a for loop to add
deck. Resetting deck #2 is finishes off by sorting the
easy—just create a new
instance of Deck().

We’re not done yet—flip the page!
you are here 4   361

information overload

(continued)

Naming your controls makes it a lot easier to read
your code. If these were called button1_Click,
button2_Click, etc., you wouldn’t know which
button’s code you were looking at!

Here’s the rest of
code for the form. the

private void reset1_Click(object sender, EventArgs e) {
ResetDeck(1);
RedrawDeck(1);
}
private void reset2_Click(object sender, EventArgs e) {
ResetDeck(2);
RedrawDeck(2);
}

These buttons are
pretty simple—first
reset or shuffle the
deck, then redraw it.

private void shuffle1_Click(object sender, EventArgs e) {
deck1.Shuffle();
RedrawDeck(1);
}
private void shuffle2_Click(object sender, EventArgs e) {
deck2.Shuffle();
RedrawDeck(2);
}
private void moveToDeck1_Click(object sender, EventArgs e) {
if (listBox2.SelectedIndex >= 0)
if (deck2.Count > 0) {
deck1.Add(deck2.Deal(listBox2.SelectedIndex));
}
RedrawDeck(1);
RedrawDeck(2);
}

}

private void moveToDeck2_Click(object sender, EventArgs e) {You can use the
ListBox
if (listBox1.SelectedIndex >= 0)
control’s SelectedIndex property
if (deck1.Count > 0)
to figure out which card the
deck2.Add(deck1.Deal(listBox1.SelectedIndex)); user selected and
then move it
RedrawDeck(1);
from one deck to the other. (If
RedrawDeck(2);
it’s less than zero, no card was
}
selected, so the

362   Chapter 8

button does
nothing.) Once the card’s moved,
both decks need to be redrawn.

enums and collections

Use a dictionar y to store keys and value s
A list is like a big long page full of names. But what if you also want, for each name, an
address? Or for every car in the garage list, you want details about that car? You need a
dictionary. A dictionary lets you take a special value—the key—and associate that key
with a bunch of data—the value. And one more thing: a specific key can only appear
once in any dictionary.

This is the key. It’s
how you look up
definition in (youa
guessed it) a dictio
nary.

dic•tion•ar•y
A book that lists the words of a language in
alphabetical order and gives their meaning.

This is the value. It’s the data
associated with a particular key.

Here’s how you declare a Dictionary in C#:

Dictionary  kv = new Dictionary ();
These are like List. The  means
a type goes in there. So you can declare
one type for the key, and another type
for the value.

These represent types. The first
type in the angle brackets is always
the key, and the second is always
the data.

And here’s a Dictionary in action:
private void button1_Click(object sender, EventArgs e)
{
This dictionary has
Dictionary wordDefinition = keys,
and strings as
new Dictionary();
re

string values for
e value. It’s like
al dictionary: termth
, and definition. a

wordDefinition.Add (“Dictionary”, “A book that lists the words of a ”
The Add()
+ “language in alphabetical order and gives their meaning”);
method is how wordDefinition.Add (“Key”, “A thing that provides a means of gaining access to ”
you add keys
+ “our understanding something.”);
Add() takes a
and values to wordDefinition.Add (“Value”, “A magnitude, quantity, or number.”);
.
key, and then
ry
na
io
ct
the di
the value.
if (wordDefinition.ContainsKey(“Key”)){
MessageBox.Show(wordDefinition[“Key”]);
u if a key is in
yo
lls
te
()
ey
sK
in
Conta
}
huh?
dictionary. Handy,
e
th
y.
}
the value for a ke
t
ge
u
yo
w
t
ho
ge
s
e’
Her
e an array index
lik
of
nd
ki
s
ok
.
lo
It
key at this index
the value for the
you are here 4   363

map anything to anything

The Dictionar y Functionalit y Rundown
Dictionaries are a lot like lists. Both types are flexible in letting you work with lots of data types,
and also come with lots of built-in functionality. Here are the basic Dictionary methods:

± Add an item.

You can add an item to a dictionary by passing a key and a value to its Add() method.
Dictionary myDictionary = new Dictionary();
myDictionary.Add(“some key”, “some value”);

± Look up a value using its key.

The most important thing you’ll do with a dictionary is look up values—which makes
sense, because you stored those values in a dictionary so you could look them up using
their unique keys. For this Dictionary, you’ll look up values using a
string key, and it’ll return a string.

		

string lookupValue = myDictionary[“some key”];

± Remove an item.

Just like a List, you can remove an item from a dictionary using the Remove() method.
All you need to pass to the Remove method is the Key value to have both the key and the
value removed.
Keys are unique in a Dictionary; any

		

myDictionary.Remove(“some key”);

± Get a list of keys.

key appears
tly
once. Values can appear any number of times—twoexac
keys
can have the same value. That way, when you look up or
remove a key, the Dictionary knows what to remove.

You can get a list of all of the keys in a dictionary using its Keys property and loop
through it using a foreach loop. Here’s what that would look like:

		

foreach (string key in myDictionary.Keys) { ... };

± Count the pairs in the dictionary.

cular
Keys is a property of your dictionary object. This parti
s.
string
of
tion
collec
dictionary has string keys, so Keys is a

The Count property returns the number of key-value pairs that are in the dictionary:

		

int howMany = myDictionary.Count;

Your key and value can be dif ferent t ypes
Dictionaries are really versatile and can hold just about anything, from strings to numbers and even objects.
Here’s an example of a dictionary that’s storing an integer as a key and a duck object as a value.

It’s common to see a
		
that maps
dictionary
to objects when
integers 		
you’re assigning unique ID
numbers to objects.

364   Chapter 8

Dictionary duckDictionary = new Dictionary();
duckDictionary.Add(376, new Duck()
{ Kind = KindOfDuck.Mallard, Size = 15 });

enums and collections

Build a program that use s a Dictionar y
Here’s a quick program that any New York baseball fan will like. When an
important player retires, the team retires the player’s jersey number. Let’s
build a program that looks up who wore famous numbers and when those
numbers were retired. Here’s a class to keep track of a jersey number:

Do this!
Yogi Berra was #8
for one team and Cal
Ripken, Jr. was #8
for another. But in
a Dictionary only one
key can map to a single
value, so we’ll only
include numbers from
one team here. Can
you think of a way to
store retired numbers
for multiple teams?

class JerseyNumber {
public string Player { get; private set; }
public int YearRetired { get; private set; }

}

public JerseyNumber(string player, int numberRetired) {
Player = player;
YearRetired = numberRetired;
}

Here’s the form:

And here’s all of the code for the form:
public partial class Form1 : Form {
Dictionary retiredNumbers = new Dictionary() {
{3, new JerseyNumber(“Babe Ruth”, 1948)},
{4, new JerseyNumber(“Lou Gehrig”, 1939)},
Use a collection
{5, new JerseyNumber(“Joe DiMaggio”, 1952)},
initializer to populate
{7, new JerseyNumber(“Mickey Mantle”, 1969)},
{8, new JerseyNumber(“Yogi Berra”, 1972)},
your Dictionary with
{10, new JerseyNumber(“Phil Rizzuto”, 1985)},
JerseyNumber objects.
{23, new JerseyNumber(“Don Mattingly”, 1997)},
{42, new JerseyNumber(“Jackie Robinson”, 1993)},
{44, new JerseyNumber(“Reggie Jackson”, 1993)},
};
public Form1() {
InitializeComponent();

}

}

foreach (int key in retiredNumbers.Keys) {
number.Items.Add(key);
}

Add each key from
the dictionary to the
ComboBox’s Items
collection.

private void number_SelectedIndexChanged(object sender, EventArgs e) {
JerseyNumber jerseyNumber = retiredNumbers[(int)number.SelectedItem] as JerseyNumber;
nameLabel.Text = jerseyNumber.Player;
The ComboBox’s SelectedItem
yearLabel.Text = jerseyNumber.YearRetired.ToString();
property is an Object. Since the
}
Dictionary key is an int, we

Use the ComboBox’s SelectedIndexChanged event
to update the two labels on the form with the
values from the JerseyNumber object retrieved
from the Dictionary.

need
to cast it to an int value before
doing the lookup in the Dictionary.
you are here 4   365

go fish!

Build a game of Go Fish! that you can play against the computer.
This exercise is a little different....
There’s a good chance that you’re learning C# because you want a job as a professional developer. That’s
why we modeled this exercise after a professional assignment. When you’re working as a programmer on a
team, you don’t usually build a complete program from start to finish. Instead, you’ll build a piece of a bigger
program. So we’re going to give you a puzzle that’s got some of the pieces already filled in. The code for the
form is given to you in step #3. You just have to type it in—which may seem like a great head start, but it
means that your classes have to work with that code. And that can be a challenge!
1

Start with the spec
Every professional software project starts with a specification, and this one is no
exception. You’ll be building a game of the classic card game Go Fish! Different
people play the game by slightly different rules, so here’s a recap of the rules you’ll
be using:
≥≥ The game starts with a deck of 52 cards. Five cards are dealt to each
player. The pile of cards that’s left after everyone’s dealt a hand is called
the stock. Each player takes turns asking for a value (“Do you have any
sevens?”). Any other player holding cards with that value must hand them
over. If nobody has a card with that value, then the player must “go fish”
by taking a card from the stock.
≥≥ The goal of the game is to make books, where a book is the complete
set of all four cards that have the same value. The player with the most
books at the end of the game is the winner. As soon as a player collects
a book, he places it face-up on the table so all the other players can see
what books everyone else has.
≥≥ When placing a book on the table causes a player to run out of cards,
then he has to draw five more cards from the stock. If there are fewer
than five cards left in the stock, he takes all of them. The game is over
as soon as the stock is out of cards. The winner is then chosen based on
whoever has the most books.
≥≥ For this computer version of Go Fish, there are two computer players and
one human player. Every round starts with the human player selecting
one of the cards in his hand, which is displayed at all times. He does this
by choosing one of the cards and indicating that he will ask for a card.
Then the two computer players will ask for their cards. The results of
each round will be displayed. This will repeat until there’s a winner.
≥≥ The game will take care of all of the trading of cards and pulling out of
books automatically. Once there’s a winner, the game is over. The game
displays the name of the winner (or winners, in case of a tie). No other
action can be taken—the player will have to restart the program in order
to start a new game.

366   Chapter 8

If you don’t
know what
you’re building
before you start,
then how would
you know when
you’re done?
That’s why most
professional
software
projects
start with a
specification
that tells you
what you’re
going to build.

enums and collections

2

Build the form
Build the form for the Go Fish! game. It should have a ListBox control for the
player’s hand, two TextBox controls for the progress of the game, and a button to let
the player ask for a card. To play the game, the user will select one of the cards from
the hand and click the button to ask the computer players if they have that card.

This TextBox control should have its
Name property set to textName. Inuldthisbe
screenshot, it’s disabled, but it sho.
enabled when the program starts

These are
TextBox
controls named
textProgress
and textBooks.

Set the ReadOnly property
of the two TextBox controls
to True—that will make th
read-only text boxes, and em
Multiline property to true. set the

Set this button’s Na
property
to buttonStart. It’s me
di
sa
this screenshot, but it bled in
enabled. It’ll get disablestarts out
d once the
game is started.

The player’s
current hand is
displayed in a
ListBox control
called listHand.
You can set its
name using the
Name property.

Set this button’s Name property to buttonAsk, and set its Enabled
property to False. That will disable it, which means it can’t be
pressed. The form will enable it as soon as the game starts.
We’re not done yet—flip the page!
you are here 4   367

here’s the form code

(continued)
3

Here’s the code for the form
Enter it exactly like you see here. The rest of the code that you write will have to work with it.

public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
This
private Game game;

is the only class that the form
interacts with. It runs the whole game.

private void buttonStart_Click(object sender, EventArgs e) {
if (String.IsNullOrEmpty(textName.Text)){
The Enabled s
MessageBox.Show(“Please enter your name”, “Can’t start the game yet”);
property enable
return;
or disables a
}
control on the game = new Game(textName.Text, new List { “Joe”, “Bob” }, textProgress);
form.
buttonStart.Enabled = false;
textName.Enabled = false;
When you start a new game, it creates a new
buttonAsk.Enabled = true;
instance of the Game class, enables the “Ask”
UpdateForm();
button, disables the “Start Game” button,
}
and then redraws the

form.

private void UpdateForm() {
listHand.Items.Clear();
foreach (String cardName in game.GetPlayerCardNames())
listHand.Items.Add(cardName);
textBooks.Text = game.DescribeBooks();
textProgress.Text += game.DescribePlayerHands();
textProgress.SelectionStart = textProgress.Text.Length;
textProgress.ScrollToCaret();

This method
clears and
repopulates
the ListBox
that holds
the player’s
hand, and then
updates the }
text boxes.

}

Using SelectionStart and
ScrollToCaret() like this
scrolls the text box to the
end, so if there’s too much
text to display at once it
scrolls down to the bottom.
The SelectionStart line moves
the flashing text box cursor
to the end, and once it’s
moved, the ScrollToCaret()
method scrolls the text box
down to the cursor.

private void buttonAsk_Click(object sender, EventArgs e) {
textProgress.Text = “”;
if (listHand.SelectedIndex < 0) {
MessageBox.Show(“Please select a card”);
return;
}
if (game.PlayOneRound(listHand.SelectedIndex)) {
textProgress.Text += “The winner is... ” + game.GetWinnerName();
textBooks.Text = game.DescribeBooks();
buttonAsk.Enabled = false;
The player selects one of
} else
button to see if any of ththe cards and clicks the “Ask”
UpdateForm();
matches its value. The Ga e other players have a card that
me class plays a round using
}
PlayOn

368   Chapter 8

eRound() method.

the

enums and collections

4

You’ll need this code, too
You’ll need the code you wrote before for the Card class, the Suits and Values enums, the Deck
class, and the CardComparer_byValue class. But you’ll need to add a few more methods to the
Deck class…and you’ll need to understand them in order to use them.
public Card Peek(int cardNumber) {
return cards[cardNumber];
}
public Card Deal() {
return Deal(0);
}

The Peek() method lets you take a
peek at one of the cards in the deck
without dealing it.

a little easier
Someone overloaded Deal() to make itmet
ers, it deals
para
to read. If you don’t pass it any
.
a card off the top of the deck

public bool ContainsValue(Values value) {
foreach (Card card in cards)
if (card.Value == value)
return true;
return false;
}

The ContainsValue() method searches through
the entire deck for cards with a certain value,
and returns true if it finds any. Can you
guess how you’ll use this in the Go Fish game?

public Deck PullOutValues(Values value) {
Deck deckToReturn = new Deck(new Card[] { });
for (int i = cards.Count - 1; i >= 0; i--)
if (cards[i].Value == value)
deckToReturn.Add(Deal(i));
return deckToReturn;
}
public bool HasBook(Values value) {
int NumberOfCards = 0;
foreach (Card card in cards)
if (card.Value == value)
NumberOfCards++;
if (NumberOfCards == 4)
return true;
else
return false;
}
public void SortByValue() {
cards.Sort(new CardComparer_byValue());
}

You’ll use the PullOutValues()
method when you build the code to
get a book of cards from the deck.
It looks for any cards that match
a value, pulls them out of the deck,
and returns a new deck with those
cards in it.

The HasBook() method checks a
deck to see if it contains a book
of four cards of whatever value
was passed as the parameter. It
returns true if there’s a book in
the deck, false otherwise.
The SortByValue() me
deck using the Comparthod sorts the
er_byValue class.
Still not done—flip the page!
you are here 4   369

go get ’em tiger!

(continued)
5

Now comes the HARD part: Build the Player class
There’s an instance of the Player class for each of the three players in the
game. They get created by the buttonStart button’s event handler.

class Player
{
private string name;
public string Name { get { return name; } }
private Random random;
private Deck cards;
private TextBox textBoxOnForm;

Look closely at each of the com
ts—they tell
you what the methods are supposmen
ed
to
do. Your
job is to fill in the methods.

public Player(String name, Random random, TextBox textBoxOnForm) {
// The constructor for the Player class initializes four private fields, and then
// adds a line to the TextBox control on the form that says, “Joe has just
// joined the game” - but use the name in the private field, and don’t forget to
// add a line break at the end of every line you add to the TextBox.
}
public IEnumerable PullOutBooks() {

} // see the facing page for the code

public Values GetRandomValue() {
// This method gets a random value—but it has to be a value that’s in the deck!
}
public Deck DoYouHaveAny(Values value) {
// This is where an opponent asks if I have any cards of a certain value
// Use Deck.PullOutValues() to pull out the values. Add a line to the TextBox
// that says, “Joe has 3 sixes” - use the new Card.Plural() static method
}
public void AskForACard(List players, int myIndex, Deck stock) {
// Here’s an overloaded version of AskForACard() - choose a random value
// from the deck using GetRandomValue() and ask for it using AskForACard()
}

public void AskForACard(List players, int myIndex, Deck stock, Values value) {
// Ask the other players for a value. First add a line to the TextBox: “Joe asks
// if anyone has a Queen”. Then go through the list of players that was passed in
// as a parameter and ask each player if he has any of the value (using his
// DoYouHaveAny() method). He’ll pass you a deck of cards - add them to my deck.
// Keep track of how many cards were added. If there weren’t any, you’ll need
// to deal yourself a card from the stock (which was also passed as a parameter),
// and you’ll have to add a line to the TextBox: “Joe had to draw from the stock”
}
// Here’s a property and a few short methods that were already written for you
public int CardCount { get { return cards.Count; } }

public void TakeCard(Card card) { cards.Add(card); }

public IEnumerable GetCardNames() { return cards.GetCardNames(); }

public Card Peek(int cardNumber) { return cards.Peek(cardNumber); }

}

public void SortHand() { cards.SortByValue(); }

370   Chapter 8

enums and collections

That Peek() method we added to the Deck class will come
in handy. It lets the program look at one of the cards in
the deck by giving its index number, but unlike Deal() it
doesn’t remove the card.
public IEnumerable PullOutBooks() {
List books = new List();
for (int i = 1; i <= 13; i++) {
Values value = (Values)i;
int howMany = 0;
for (int card = 0; card < cards.Count; card++)
if (cards.Peek(card).Value == value)
howMany++;
if (howMany == 4) {
books.Add(value);
for (int card = cards.Count - 1; card >= 0; card--)
cards.Deal(card);
}
}
return books;
You’ll have to build TWO overloaded versions
}
AskFor

of the
ACard() method. The first one is used by the
opponents when they ask for cards—it’ll look through
their hands and find a card to ask for. The second
one is used when the player asks for the card. Both
of them ask EVERY other player (both computer and
human) for any cards that match the value.

6

You’ll need to add this method to the Card class
It’s a static method to take a value and return its plural—that way a ten will return
“Tens” but a six will return “Sixes” (with “es” on the end). Since it’s static, you call it
with the class name—Card.Plural()—and not from an instance.
public partial class Card {
public static string Plural(Values value) {
if (value == Values.Six)
return “Sixes”;
else
return value.ToString() + “s”;
}
}

We used a partial class to add this
static method to Card to make it
easy for you to see what’s going
on. But you don’t need to use a
partial class—if you want, you
can just add it straight into the
existing Card class.
Nearly there—keep flipping!
you are here 4   371

book ’em danno

(continued)
7

The rest of the job: Build the Game class
The form keeps one instance of Game. It manages the game play. Look
closely at how it’s used in the form.

class Game {
private List players;
private Dictionary books;
private Deck stock;
private TextBox textBoxOnForm;

The Player and Game classes both use a reference to
the multiline TextBox on the form to print messages
for the user to read. Make sure you add “using
System.Windows.Forms;” to the top of their files.

public Game(string playerName, IEnumerable opponentNames, TextBox textBoxOnForm) {
Random random = new Random();
Using IEnumerable in
this.textBoxOnForm = textBoxOnForm;
public class members is
players = new List();
a great way to make your
players.Add(new Player(playerName, random, textBoxOnForm));
classes more flexible, and
foreach (string player in opponentNames)
players.Add(new Player(player, random, textBoxOnForm)); that’s something you need
to think about when your
books = new Dictionary();
code
needs to be reused.
stock = new Deck();
It’s great for encapsulation, too. If
Now
someone
else can use
Deal();
you expose an IEnumerable instead
a string[]. List, or
players[0].SortHand();
of, say, a List, then you can’t
something else entirely to
}
instantiate the Game class.
accidentally write code that modifies it.
private void Deal() {
// This is where the game starts - this method’s only called at the beginning
// of the game. Shuffle the stock, deal five cards to each player, then use a
// foreach loop to call each player’s PullOutBooks() method.
}
public bool PlayOneRound(int selectedPlayerCard) {
// Play one round of the game. The parameter is the card the player selected
// from his hand - get its value. Then go through all of the players and call
// each one’s AskForACard() methods, starting with the human player (who’s
// at index zero in the Players list - make sure he asks for the selected
// card’s value). Then call PullOutBooks() - if it returns true, then the
// player ran out of cards and needs to draw a new hand. After all the players
// have gone, sort the human player’s hand (so it looks nice in the form).
// Then check the stock to see if it’s out of cards. If it is, reset the
// TextBox on the form to say, “The stock is out of cards. Game over!” and return
// true. Otherwise, the game isn’t over yet, so return false.
}

public bool PullOutBooks(Player player) {
// Pull out a player’s books. Return true if the player ran out of cards, otherwise
// return false. Each book is added to the Books dictionary. A player runs out of
// cards when he’s used all of his cards to make books—and he wins the game.
}
public string DescribeBooks() {
// Return a long string that describes everyone’s books by looking at the Books
// dictionary: “Joe has a book of sixes. (line break) Ed has a book of Aces.”
}

372   Chapter 8

enums and collections

Here’s a hint for writing the GetWinnerName() method: You’ll need to create a new Dictionary
the
number
of books he made during the game. First you’ll use a foreach loop to go through the books that the players made
build the dictionary. Then you’ll use another foreach loop to find the highest number of books associated with anyand
player. But there might be a tie—more than one player might have the most books! So you’ll need one
foreach
loop to look for all the players in winners that have the number of books that you found in the secondmore
loop
and build a
string that says who won.
public string GetWinnerName() {
// This method is called at the end of the game. It uses its own dictionary
// (Dictionary winners) to keep track of how many books each player
// ended up with in the books dictionary. First it uses a foreach loop
// on books.Keys -- foreach (Values value in books.Keys) -- to populate
// its winners dictionary with the number of books each player ended up with.
// Then it loops through that dictionary to find the largest number of books
// any winner has. And finally it makes one last pass through winners to come
// up with a list of winners in a string (“Joe and Ed”). If there’s one winner,
// it returns a string like this: “Ed with 3 books”. Otherwise it returns a
// string like this: “A tie between Joe and Bob with 2 books.”
}
// Here are a couple of short methods that were already written for you:
public IEnumerable GetPlayerCardNames() {
return players[0].GetCardNames();
}
public string DescribePlayerHands() {
string description = “”;
for (int i = 0; i < players.Count; i++) {
description += players[i].Name + “ has ” + players[i].CardCount;
if (players[i].CardCount == 1)
description += “ card.” + Environment.NewLine;
else
description += “ cards.” + Environment.NewLine;
}
description += “The stock has ” + stock.Count + “ cards left.”;
return description;
}

Go to the Watch
window and type
(int)’\r’ to cast the
character \r to a
number. It turns into
13. ‘\n’ turns into 10.
Every char turns into
its own unique number
called its Unicode
value. You’ll learn
more about that in
the next chapter.

Use Envrionment.NewLine to add line breaks

You’ve been using \n throughout the book to add
line breaks to message boxes. .NET also gives you
a convenient
constant for addling line breaks: Environment.New
Line. It always contains the constant value “\r\
n”. If you
actually look at the characters that make up a
Windows-formatted text file, at the end of ever
y line you’ll
see two characters: ‘\r’ and ‘\n’. Other operatin
g systems (like Unix) only use a ‘\n’ to indicate
the end of
each line. The MessageBox.Show() method is smar
t enough to automatically convert ‘\n’ characte
rs to line
breaks, but your code can be easier to read if
you use Environment.NewLine instead of escape
characters. Also
Environment.NewLine is what gets appended to
the end of each line when you use Console.Writ you are here ,4  
eLine().

373

exercise solution

Here are the filled-in methods in the Game class.
private void Deal() {
stock.Shuffle();
for (int i = 0; i < 5; i++)
foreach (Player player in players)
player.TakeCard(stock.Deal());
foreach (Player player in players)
PullOutBooks(player);
}

The Deal() method gets called when the
game first starts—it shuffles the deck and
then deals five cards to each player. Then
it pulls out any books that the players
happened to have been dealt.

public bool PlayOneRound(int selectedPlayerCard) {
Values cardToAskFor = players[0].Peek(selectedPlayerCard).Value;
for (int i = 0; i < players.Count; i++) {
if (i == 0)
players[0].AskForACard(players, 0, stock, cardToAskFor);
else
players[i].AskForACard(players, i, stock);
After the player or if (PullOutBooks(players[i])) {
opponent asks for a
textBoxOnForm.Text += players[i].Name
card, the game pulls
+ “ drew a new hand” + Environment.NewLine;
int card = 1;
out any books that he
while (card <= 5 && stock.Count > 0) {
As soon as the player clicks the “Ask
made. If a player’s out
players[i].TakeCard(stock.Deal());
for a card” button, the game calls
of books, he draws a
card++;
AskForACard() with that card. Then
new hand by dealing up
}
it calls AskForACard() for each
to 5 cards from the }
opponent.
stock.
players[0].SortHand();
if (stock.Count == 0) {
textBoxOnForm.Text =
“The stock is out of cards. Game over!” + Environment.NewLine;
return true;
After the round is played, the game sorts
}
player’s hand to make sure it’s displayed in the
}
the form. Then it checks to see if the gamorder on
return false;
e’s over.
If it is, PlayOneRound() returns true.
}
public bool PullOutBooks(Player player)
{
IEnumerable booksPulled = player.PullOutBooks();
foreach (Values value in booksPulled)
books.Add(value, player);
s to see
PullOutBooks() looks through a player’s card
if (player.CardCount == 0)
If he
return true;
if he’s got four cards with the same value.ry.
And if
return false;
does, they get added to his books dictionarns true
.
}
he’s got no cards left afterward, it retu

374   Chapter 8

enums and collections

The form needs to display a list of books,
so it uses DescribeTheBooks() to turn the
player’s books dictionary into words.
public string DescribeBooks() {
string whoHasWhichBooks = “”;
foreach (Values value in books.Keys)
whoHasWhichBooks += books[value].Name + “ has a book of ”
+ Card.Plural(value) + Environment.NewLine;
return whoHasWhichBooks;
}
public string GetWinnerName() {
Dictionary winners = new Dictionary();
foreach (Values value in books.Keys) {
string name = books[value].Name;
Once the last card’s been picked up, the
if (winners.ContainsKey(name))
winners[name]++;
game needs to figure out who won. That’s
else
what the GetWinnerName() does. And
winners.Add(name, 1);
it’ll use a dictionary called winners to
}
do it. Each player’s name is a key in the
int mostBooks = 0;
value is the number of books
foreach (string name in winners.Keys) dictionary; its
that player got during the game.
if (winners[name] > mostBooks)
mostBooks = winners[name];
bool tie = false;
Next the game looks through the dictionary
string winnerList = “”;
to
figure the number of books that the
foreach (string name in winners.Keys)
player
with the most books has. It puts that
if (winners[name] == mostBooks)
value in a variable called mostBooks.
{
if (!String.IsNullOrEmpty(winnerList))
{
winnerList += “ and ”;
tie = true;
Now that we know which player
}
has the most books, the method
winnerList += name;
can come up with a string that
}
winnerList += “ with ” + mostBooks + “ books”; lists the winner (or winners).
if (tie)
return “A tie between ” + winnerList;
else
return winnerList;
}

We’re not done yet—flip the page!
you are here 4   375

exercise solution

(continued)
Here are the filled-in methods in the Player class.

public Player(String name, Random random, TextBox textBoxOnForm) {
this.name = name;
Here’s the constructor for the Player class.
this.random = random;
It
sets its private fields and adds a line to
this.textBoxOnForm = textBoxOnForm;
the
progress text box saying who joined.
this.cards = new Deck( new Card[] {} );
textBoxOnForm.Text += name +
“ has just joined the game” + Environment.NewLine;
}
public Values GetRandomValue() {
Card randomCard = cards.Peek(random.Next(cards.Count));
return randomCard.Value;
The GetRandomValue()
}

method uses Peek() to
look at a random card in the player’s hand.

public Deck DoYouHaveAny(Values value) {
Deck cardsIHave = cards.PullOutValues(value);
textBoxOnForm.Text += Name + “ has ” + cardsIHave.Count + “ ”
+ Card.Plural(value) + Environment.NewLine;
return cardsIHave;
}

DoYouHaveAny() uses
the PullOutValues()
method to pull out and
return all cards that
match the parameter.

public void AskForACard(List players, int myIndex, Deck stock) {
Values randomValue = GetRandomValue();
There are two overloaded
AskForACard(players, myIndex, stock, randomValue);
AskForACard() methods.
}
This one is used by the
Bonus mini-exercise: Can you figure out a way to improve
opponents—it gets a
encapsulation and design in your Player class by replacing
random card from the
List with IEnumerable in these two
hand and calls the other
methods without changing the way the software works? Flip to
AskForACard().
Leftover #7 in the Appendix for a useful tool to help with that.
public void AskForACard(List players, int myIndex,
Deck stock, Values value) {
textBoxOnForm.Text += Name + “ asks if anyone has a ”
+ value + Environment.NewLine;
int totalCardsGiven = 0;
for (int i = 0; i < players.Count; i++) {
This AskForACard() method
if (i != myIndex) {
looks through every player
Player player = players[i];
(except for the one asking),
Deck CardsGiven = player.DoYouHaveAny(value);
totalCardsGiven += CardsGiven.Count;
calls its DoYouHaveAny()
while (CardsGiven.Count > 0)
method,
and adds any cards
cards.Add(CardsGiven.Deal());
handed
over
to the hand.
}
}
if (totalCardsGiven == 0) {
textBoxOnForm.Text += Name +
“ must draw from the stock.” + Environment.NewLine;
cards.Add(stock.Deal());
}
If no cards were handed over, the player has to
}
from the stock using its Deal() method.

draw

376   Chapter 8

enums and collections

And ye t MORE collection t ype s…
List and Dictionary objects are two of the built-in generic collections that are
part of the .NET Framework. Lists and dictionaries are very flexible—you can access any
of the data in them in any order. But sometimes you need to restrict how your program
works with the data because the thing that you’re representing inside your program works
like that in the real world. For situations like this, you’ll use a Queue or a Stack. Those
are the other two generic collections that are similar to lists, but they’re especially good at
making sure that your data is processed in a certain order.
Use a Queue when the first
object you store will be the first
one you’ll use, like:

Use a Stack when you always want
to use the object you stored most
recently, like:
≥≥ Furniture loaded into the back of a
moving truck

≥≥ Cars moving down a one-way street
≥≥ People standing in line

≥≥ A stack of books where you want to
read the most recently added one first

≥≥ Customers on hold for a customer
service support line

≥≥ People boarding or leaving a plane

≥≥ Anything else that’s handled on a
first-come, first-served basis

A queue is first-in first-out, which
means that the first object that
you put into the queue is the first
one you pull out of it to use.

r types of
There are otheo—
t these
collections, to atbu you’re
are the ones thcome in
most likely to
contact with.

≥≥ A pyramid of cheerleaders, where the
ones on top have to dismount first…
imagine the mess if the one on the
bottom walked away first!

object
The stack is first in, last out: the first that
one
last
the
is
k
stac
that goes into the
comes out of it.

Generic collections are an important part of
the .NET Frame work
They’re really useful—so much that the IDE automatically adds
this statement to the top of every class you add to your project:
using System.Collections.Generic;

Almost every large project that you’ll work on will include some
sort of generic collection, because your programs need to store
data. And when you’re dealing with groups of similar things in
the real world, they almost always naturally fall into a category
that corresponds pretty well to one of these kinds of collections.

You can, however, use foreach to
enumerate through a stack or queue,
because they implement IEnumerable!

A queue is like a
list that lets you put
objects on the end of
the list and use the
ones in the front. A
stack only lets you
access the last object
you put into it.
you are here 4   377

don’t you hate waiting in line?

A queue is FIFO—First In, First Out
A queue is a lot like a list, except that you can’t just add or remove items at any
index. To add an object to a queue, you enqueue it. That adds the object to the
end of the queue. You can dequeue the first object from the front of the queue.
When you do that, the object is removed from the queue, and the rest of the objects
in the queue move up a position.

Create a
new queue
of strings.

Queue myQueue = new Queue();
Here’s where we add four we
myQueue.Enqueue(“first in line”);
items to the queue. Wheneue,
myQueue.Enqueue(“second in line”);
pull them out of the qu e
myQueue.Enqueue(“third in line”);
they’ll come out in the sam
order they went in.
Peek() lets
myQueue.Enqueue(“last in line”);
you take
string takeALook = myQueue.Peek(); 1
a “look” at
The first Deque
string getFirst = myQueue.Dequeue(); 2 first item out ue() pulls the
the first
of th
item in the
the second one shiftse upqueue. Then
string getNext = myQueue.Dequeue(); 3
queue without
the first place—the next into
int
howMany
=
myQueue.Count;
removing it.
4
Dequeue() pulls that on call to
e out next.
myQueue.Clear();
MessageBox.Show(“Peek() returned: “ + takeALook + “\n”
The Clear()
+ “The first Dequeue() returned: “ + getFirst + “\n”
method
+ “The second Dequeue() returned: “ + getNext + “\n”
removes all
om
fr
s
object
+ “Count before Clear() was “ + howMany + “\n”
the queue.
+ “Count after Clear() is now “ + myQueue.Count);
5

The queue’s Count property returns
the number of items in the queue.

Objects in a
queue need to
wait their turn.
The first one in
the queue is the
first one to come
out of it.
378   Chapter 8

1
2
3
4
5

enums and collections

A stack is LIFO—Last In, First Out
A stack is really similar to a queue—with one big difference. You push each item
onto a stack, and when you want to take an item from the stack, you pop one off
of it. When you pop an item off of a stack, you end up with the most recent item
that you pushed onto it. It’s just like a stack of plates, magazines, or anything else—
you can drop something onto the top of the stack, but you need to take it off before
you can get to whatever’s underneath it.
just

Creating a stack is
like creating any other
generic collection.

When you push
an item onto a
stack, it pushes
the other items
back one notch
and sits on top.

Stack myStack = new Stack();
myStack.Push(“first in line”);
myStack.Push(“second in line”);
myStack.Push(“third in line”);
myStack.Push(“last in line”);
1 string takeALook = myStack.Peek();
When you pop an item
off
the stack, you get
2 string getFirst = myStack.Pop();
the most recent item
3 string getNext = myStack.Pop();
that was added.
4 int howMany = myStack.Count;
myStack.Clear();
MessageBox.Show(“Peek() returned: “ + takeALook + “\n”
+ “The first Pop() returned: “ + getFirst + “\n”
+ “The second Pop() returned: “ + getNext + “\n”
+ “Count before Clear() was “ + howMany + “\n”
+ “Count after Clear() is now “ + myStack.Count);

You can
also use
Environment.
NewLine
instead of \n
here, but we
wanted the
code to be
easier to read.

5

The last object you put
on a stack is the first
object that you pull
off of it.

1
2
3
4
5

you are here 4   379

flapjacks and lumberjacks
Wait a minute, something’s bugging me. You
haven’t shown me anything I can do with a stack
or a queue that I can’t do with a list—they just
save me a couple of lines of code. But I can’t get at
the items in the middle of a stack or a queue. I can
do that with a list pretty easily! So why would I
give that up just for a little convenience?

Let’s set up a stack with
four items—in this case, a
stack of strings.

Don’t worry—you don’t give up anything when you use a
queue or a stack.
It’s really easy to copy a Queue object to a List object. And it’s just as
easy to copy a List to a Queue, a Queue to a Stack…in fact, you can
create a List, Queue, or Stack from any other object that implements the
IEnumerable interface. All you have to do is use the overloaded constructor
that lets you pass the collection you want to copy from as a parameter. That
means you have the flexibility and convenience of representing your data with
the collection that best matches the way you need it to be used. (But remember,
you’re making a copy, which means you’re creating a whole new object and
adding it to the heap.)

Stack myStack = new Stack();
myStack.Push(“first in line”);
ck
It’s easy to convert that sta
myStack.Push(“second in line”);
ue
que
to a queue, then copy the e list
myStack.Push(“third in line”);
to a list, and then copy th
to another stack.
myStack.Push(“last in line”);
Queue myQueue = new Queue(myStack);
List myList = new List(myQueue);
Stack anotherStack = new Stack(myList);
MessageBox.Show(“myQueue has “ + myQueue.Count + “ items\n”
+ “myList has “ + myList.Count + “ items\n”
+ “anotherStack has “ + anotherStack.Count + “ items\n”);

All four items wenerew
copied into the
collections.
380   Chapter 8

…and you can always use
a foreach loop to access
all of the members in a
stack or a queue!

enums and collections

Write a program to help a cafeteria full of lumberjacks eat some flapjacks. Start with the Lumberjack
class, filling in the missing code. Then design the form, and add the button event handlers to it.
1

Here’s the Lumberjack class. Fill in the get accessor for FlapjackCount enum Flapjack {
Crispy,
and the TakeFlapjacks and EatFlapjacks methods.
Soggy,

class Lumberjack {
private string name;
}
public string Name { get { return name; } }
private Stack meal;
public Lumberjack(string name) {
this.name = name;
meal = new Stack();
}
public int FlapjackCount { get { // return the count } }
public void TakeFlapjacks(Flapjack Food, int HowMany) {
// Add some number of flapjacks to the Meal stack
}
public void EatFlapjacks() {
// Write this output to the console
}
}

2

Browned,
Banana

Build this form. It lets you enter the names of lumberjacks into a text box so they get in the breakfast
line. You can give the lumberjack at the front of the line a plate of flapjacks, and then tell him to move
on to eat them using the “Next lumberjack” button. We’ve given you the click event handler for the “Add
flapjacks” button. Use a queue called breakfastLine to keep track of the lumberjacks.

When the user clicks “Add Lumberjack”, add the name
in the name text box to the breakfastLine queue.

This
listbox
is called
line.

trols into the
When you drag these RadioButton con
s them and
link
lly
tica
group box, the form automa
m at a time.
the
of
one
only allows the user to check method to figure
Look at the addFlapjacks_Click
out what they should be named.

Notice how the Flapjack
enum uses uppercase letters
(“Soggy”), but the output has
lowercase letters (“soggy”)?
Here’s a hint to help you get
the output right. ToString()
returns a string object, and
one of its public members is
a method called ToLower()
that returns a lowercase
version of the string.

private void addFlapjacks_Click(...) {
Flapjack food;
if (crispy.Checked == true)
food = Flapjack.Crispy;
te the special
else if (soggy.Checked == true) No
“else if” syntax.
food = Flapjack.Soggy;
else if (browned.Checked == true)
food = Flapjack.Browned; Peek() returns a reference to
This button should dequeue the next lumberjack, else
first lumberjack in the
call his EatFlapjacks(), then redraw the list box.
food = Flapjack.Banana; the

You’ll need to add a RedrawList() method
to update the list box with the contents
of the queue. All three buttons will call it.
Here’s a hint: it uses a foreach loop.
}

queue.

Lumberjack currentLumberjack = breakfastLine.Peek();
currentLumberjack.TakeFlapjacks(food,
(int)howMany.Value);
RedrawList(); The NumericUpDown control is called

howMany, and the label is called nextInLine.

you are here 4   381

exercise solution

A

private Queue breakfastLine = new Queue();
private void addLumberjack_Click(object sender, EventArgs e) {
breakfastLine.Enqueue(new Lumberjack(name.Text));
name.Text = “”;
RedrawList();
}
We called the
private void RedrawList() {
between the twlisot box “line”, and the label
buttons “nextInL
int number = 1;
ine”.
line.Items.Clear();
The RedrawList()
foreach (Lumberjack lumberjack in breakfastLine) {
line.Items.Add(number + “. ” + lumberjack.Name);
method uses a
foreach loop to pull } number++;
the lumberjacks out if (breakfastLine.Count == 0) {
This if statement updates the
of their queue and
label with information about the
groupBox1.Enabled = false;
add each of them to
nextInLine.Text = “”;
first lumberjack in the queue.
}
else
{
the list box.
groupBox1.Enabled = true;
Lumberjack currentLumberjack = breakfastLine.Peek();
nextInLine.Text = currentLumberjack.Name + “ has ”
+ currentLumberjack.FlapjackCount + “ flapjacks”;
}
}
private void nextLumberjack_Click(object sender, EventArgs e) {
Lumberjack nextLumberjack = breakfastLine.Dequeue();
nextLumberjack.EatFlapjacks();
nextInLine.Text = “”;
RedrawList();
}
class Lumberjack {
private string name;
public string Name { get { return name; } }
private Stack meal;
public Lumberjack(string name) {
this.name = name;
meal = new Stack();
}

The TakeFlapjacks
method updates the
Meal stack.

The EatF
method uselapjacks
loop to prins a while
lumberjack’s t out the
meal.
}

382   Chapter 8

public int FlapjackCount { get { return meal.Count; } }
public void TakeFlapjacks(Flapjack food, int howMany) {
for (int i = 0; i < howMany; i++) {
meal.Push(food);
Here’s where the Flapjack enum is
}
}
made lowercase. Take a minute and

figure out what’s going on.

public void EatFlapjacks() {
Console.WriteLine(name + “’s eating flapjacks”);
while (meal.Count > 0) {
Console.WriteLine(name + “ ate a ”
+ meal.Pop().ToString().ToLower() + “ flapjack”);
}

}

meal.Pop() returns an enum, whose ToString() method is called to return a string
object, whose ToLower() method is called to return another string object.

enums and collections

Collectioncross
1

2

3

4

5
6

8

7

9

10

11

12

13

14
15
16
17

18

19

20

21

Across
Across
3. An instance
of a ______________ collection only works with
3. type
An instance of a ______________ collection only
one specific
works with one specific type.
6. A special6.kind
of loopkind
thatofworks
on IEnumerable
A special
loop that
only works on collections
9.
The
name
of
the
method
usea to
sendtoathe
string to
9. The name of the method you use toyou
send
string
the
output
output
10. How you remove something from a stack
10. How you
something
from
stack but more flexible
11.remove
An object
that's like
anaarray
13.
Two
methods
in
a
class
with
the same name but
11. An object that’s like an array but more flexible
different parameters are...
13. Two methods
in a class
with the
same
name but
different
15. A method
to figure
out
if a certain
object
is in a
parameterscollection
are ______________.
19.toAnfigure
easyout
wayif atocertain
keep track
15. A method
objectofiscategories
in a collection
20. All generic collections implement this interface
19. An easy21.way
to
keep
track
of
categories
How you remove something from a queue
20. All generic collections implement this interface
21. How you remove something from a queue

Down
1. Down
The generic collection that lets you map keys to values
1. The generic collection that lets you map keys to
2. values
This collection is first-in, first-out
This
collection
first-in,
first-out
4. 2.
The
built-in
class isthat
lets your
program write text to the
4. The built-in class that lets your program write text
output
to the output
5.5.A A
method
to to
findfind
outout
howhow
many
things
are in
collection
method
many
things
area in
a
7. collection
The only method in the IComparable interface
. The professional
only method projects
in the IComparable
interface
8.7Most
start with this
8. Most professional projects start with this
12.12.
AnAn
object
thatthat
implements
this this
interface
helpshelps
your list sort
object
implements
interface
list sort its contents
itsyour
contents
How
you
addsomething
somethingtoto
a queue
14.14.
How
you
add
a queue
16. This collection is first-in, last-out
16.17
This
collection
first-in, last-out
. How
you add is
something
to a stack
Thisyou
method
returns the
object to come off of
17.18.
How
add something
to anext
stack
a stack or queue
18. This method returns the next object to come off of a stack or
queue
you are here 4   383

crossword solution

Collectioncross solution
1
3

G

E

N

E

R

2

D
I

4

C

C
8

9

S

W R

I

P

T

E

P

C

O

E

L

A

F

R

I

P
O

V

E

O

18

N

U

P

M

E

R

R

N

S

Q

T

U

A

O

S

E

C

N

H

K

K

B

L

12

I

S

C
O

Q
U

R

E

L

T

O

A

7

C

U

U

O

N

E

M

T

A
A

D

E

D

R

M

E

P

T

A

H

P

C

E

C

E

L

14

16

P

11

L

15

17

F

E

O
13

A
I

N

Y

T

6

S

C

20

I

N

I

C
O

I
10

5

I

N

S

N

U

M

E

U

E

O

R
19

E

E

R

U
21

D

Across
3. An instance of a ______________ collection only
works with one specific type. [generic]
6. A special kind of loop that only works on collections
[foreach]
9. The name of the method you use to send a string to
the output [writeline]
10. How you remove something from a stack [pop]
384  
Chapter
11. An
object8that's like an array but more flexible
[list]
13. Two methods in a class with the same name but

E

Q

U

Down
1. The generic collection that lets you map keys to
values [dictionary]
2. This collection is first-in, first-out [queue]
4. The built-in class that lets your program write text
to the output [console]
5. A method to find out how many things are in a
collection [count]
7. The only method in the IComparable interface
[CompareTo]
8. Most professional projects start with this

Name:

Date:

C# Lab
The Quest
This lab gives you a spec that describes a program
for you to build, using the knowledge you’ve gained
over the last few chapters.
This project is bigger than the ones you’ve seen so
far. So read the whole thing before you get started,
and give yourself a little time. And don’t worry if
you get stuck—there’s nothing new in here, so you
can move on in the book and come back to the lab
later.
We’ve filled in a few design details for you, and
we’ve made sure you’ve got all the pieces you
need…and nothing else.
It’s up to you to finish the job. You can download
an executable for this lab from the website…but we
won’t give you the code for the answer.

C# Lab   385

The Quest
The spec: build an adventure game
Your job is to build an adventure game where a mighty adventurer
is on a quest to defeat level after level of deadly enemies. You’ll
build a turn-based system, which means the player makes
one move and then the enemies make one move. The player can
move or attack, and then each enemy gets a chance to move and
attack. The game keeps going until the player either defeats all the
enemies on all seven levels or dies.

rhead
The game window gives an ove
the
view of the dungeon where
player fights his enemies. The player can pick
up weapons and
potions along the way.

ws
Here’s the player’s inventory. Itup,shoand
what items the player’s picked t
draws a box around the item thaer
they’re currently using. The play uses
clicks on an item to equip it, and .
the Attack button to use the item

386   Head First Lab #1

The player and
enemies move around
in the dungeon.

The enemies get a bit
of an advantage—they
move every turn, and
after they move they’ll
attack the player if he’s
in range.

The player moves
using the four
Move buttons.

The game shows you the number of
hit points for the player and enemies.
When the player attacks an enemy,
the enemy’s hit points go down. Once
the hit points get down to zero, the
enemy or player dies.

These four buttons are
used to attack enemies
and drink potions.
(The player can use
any of the buttons to
drink a potion.)

The Quest

The player picks up we apons…
There are weapons and potions scattered around the
dungeon that the player can pick up and use to defeat his
enemies. All he has to do is move onto a weapon, and it
disappears from the floor and appears in his inventory.

it’s currently
A black box around a weapon meaknsdifferently—they have
equipped. Different weapons worack in one direction while
different ranges, some only att they cause different
others have a wider range, ands they hit.
levels of damage to the enemie

…and at tacks enemie s with them
Every level in the game has a weapon that the player can
pick up and use to defeat his enemies. Once the weapon’s
picked up, it should disappear from the game floor.

The bat is to the right of
the player, so he hits the
Right attack button.

Higher levels bring more enemies
There are three different kinds of enemies: a bat, a ghost, and
a ghoul. The first level has only a bat. The seventh level is the
last one, and it has all three enemies.

The bat flies
around somewhat
randomly. When it’s
near the player,
it causes a small
amount of damage.

The attack causes the
bat’s hit points to
drop, from 6 to 2 in
this case.

A ghoul moves quickly
toward the player, and
causes heavy damage
when it attacks.

The ghost moves slowly toward the
player. As soon as it’s close to the
player, it attacks and causes a medium
amount of damage.
you are here 4   387

The Quest
The design: building the form
The form gives the game its unique look. Use the form’s
BackgroundImage property to display the image of the dungeon
and the inventory, and a series of PictureBox controls to show
the player, weapons, and enemies in the dungeon. You’ll use a
TableLayoutPanel control to display the hit points for the player,
bat, ghost, and ghoul as well as the buttons for moving and attacking.

The dungeon itself is a static image,
displayed using the BackgroundImage
property of the form.

Each of these icons is a PictureBox.

Make sure the
BackgroundImageLayout
property is set to None.

ttons, and
Hit points, movementallbudisplayed in a
attack buttons are
TableLayoutPanel.

Download the background image and the graphics for the
weapons, enemies, and player from the Head First Labs
website: www.headfirstlabs.com/books/hfcsharp
388   Head First Lab #1

The Quest
Ever ything in the dungeon is a PictureBox
Players, weapons, and enemies should all be represented by icons. Add
nine PictureBox controls, and set their Visible properties to
False. Then, your game can move around the controls, and toggle
their Visible properties as needed.

You can set a PictureBox’s BackColor
property to Color.Transparent to let the
form’s background picture or color show
through any transparent pixels in the
picture.

Add nine PictureBox controls to the
dungeon. Use the Size property to
make each one 30x30. It doesn’t
matter where you place them—the
form will move them around. Use the
little black arrow that shows up when
you click on the PictureBox to set
each to one of the images from the
Head First Labs website.

After you’ve added the nine PictureBox con
right-click on the player’s icon and select trols,
to Front”, then send the three weapon icon“Bring
the back. That ensures player icons stay “abs to
ove”
any items that are picked up.

The inventor y contains PictureBox controls, too
You can represent the inventory of the player as five 50×50
PictureBox controls. Set the BackColor property of each to Color.
Transparent (if you use the Properties window to set the property, just
type it into the BackColor row). Since the picture files have a transparent
background, you’ll see the scroll and dungeon behind them:

Controls overlap each other in the , so
the form needs to know which ones IDE
in
front, and which are in back. That’sare
wha
the “Bring to Front” and “Send to Back”t
form designer commands do.

You’ll need five more
50x50 PictureBoxes
for the inventory.

Build your stats window
The hit points are in a TableLayoutPanel, just like the
attack and movement buttons. For the hit points, create two
columns in the panel, and drag the column divider to the left a
bit. Add four rows, each 25% height, and add in Label controls
to each of the eight cells:

2 columns, 4 rows…8
cells for your hit
point statistics.

When the player equips one of the weapons,
the form should set the BorderStyle of
that weapon icon to FixedSingle and the
rest of the icons’ BorderStyle to None.

Each cell ha
and you can supa Label in it,
values during t date those
he game.

you are here 4   389

The Quest
This is just the general overview. We’ll give
you a lot more details on how the player
and enemies move, how the enemy figures
out if it’s near the player, etc.

The architecture: using the objects

ec t

You’ll need several types of objects in your game: a Player
object, several subtypes of an Enemy object, and several sub-types
of a Weapon object. And you’ll also need one object to keep up
with everything that’s going on: the Game object.

The Game object handle s turns
When one of your form’s move buttons is clicked, the form
will call the Game object’s Move() method. That method
will let the player take a turn, and then let all the enemies
move. So it’s up to Game to handle the turn-based movement
portion of the game.

m y ob

390   Head First Lab #1

G a m ob j e
e

If any of the enemies
end up near the player
after they’ve moved,
they attack the player.

ec t

4. if (NearPlayer())
game.HitPlayer();

ct

t
j

ec

Ene

After the player moves,
Game tells each of the
enemies to Move().

Game’s Move() method
first calls the Player
j
object’s Move() method to Player ob
tell the player to move.

ec t

G a m ob j e
e

3. enemy.Move()
Near
Player

The Game object
keeps up with
players, weapons,
and a list of
enemies.

2. player.Move()

ct

rm o b j e

ct

Fo

e a p o n ob j

We left the parameters out of this diagram.
Each Move() method takes a direction, and
some of them take a Random object, too.

v
1. game.Mo e()

When the user clicks
one of the four move
buttons, the form calls
Game’s Move() method.

W

There’s only one weapon per level,
so the game just needs a Weapon
reference, not a List. The Player,
however, has a List to
hold the inventory.

For example, here’s how the move buttons work:

Move
Button
Clicked

L is t < Ene m
t

Game takes the input fr
the form and deals with om
the
objects in the game.

ec

The form never interacts
directly with the players,
weapons, or enemies.

y>

G a m ob j e
e

rm o b j e

ct

Fo

ct

Play r obj
e

Play r obj
e

The Quest
The form delegate s acti vit y to the Game object
Movement, attacking, and inventory all begin in the form. So clicking a
movement or attack button, or an item in inventory, triggers code in your
form. But it’s the Game object that controls the objects in the game. So
the form has to pass on anything that happens to the Game object, and
then the Game object takes it from there: Game.Move() calls the enemies’

Move() methods, which all
take a random reference.

(
Move
1.

Move
Button
Clicked

Direction.Right, ra
ndo
m);

Use a Direction enum for
the four button directions.

2. UpdateCharacters();

ct

rm o b j e

ct

How moving works

G a m ob j e
e

This UpdateCharacters() method is part of the
form. It reads the location of the player, enemies,
and any weapons currently in the dungeon and
moves the PictureBoxes to match them.

When the player hits an
enemy, it causes a random
amount of damage (up to
a maximum damage limit).

How attacking works

Attack
Button
Clicked

2. UpdateCharacters();

ct

rm o b j e

The UpdateCharacters() method
also checks the player’s inventory
and makes sure the correct icons are
displayed on the inventory scroll.

How the inventory scroll works

Inventory
Icon
Clicked

rm o b j e

ct

Fo

All the other weapons’
borders should be
turned off.

ct

Direction.Right, ra
ttack(
ndom)
1. A
;

Fo

Game handles updati
locations, so when ng
UpdateCharacters()
called, things are moveisd
to their new locations.

G a m ob j e
e

Attacking is like
movement…the form
calls Attack() on
Game, and Game
handles dealing with
the attack.

The inventory scroll displays all of
the icons for the items that the
player has picked up.

CheckPlayerInventory(“Bow”)) {
game.
if (
game.Equip(“Bow”);

inventoryBow.BorderStyle =
BorderStyle.FixedSingle;
inventorySword.BorderStyle =
BorderStyle.None;

ct

Fo

The Form object calls the
game’s Move(), and then calls
its own UpdateCharacters()
method to update the screen.

G a m ob j e
e

The BorderStyle property
highlights the active item in
the player’s inventory.
you are here 4   391

The Quest
Building the Game class
We’ve gotten you started with the Game class in the code below.
There’s a lot for you to do—so read through this code carefully, get
it into the IDE, and get ready to go to work:

You’ll need Rectangle and Point from
System.Drawing, so be sure to add this
to the top of your class.
class Game {
on are well
These are OK as public properties if Enemy and Weap
public List Enemies;
do
encapsulated…in other words, just make sure the form can’t
public Weapon WeaponInRoom;
anything inappropriate with them.
The game keeps a private Player object. The
form will only interact with this through
methods on Game, rather than directly.
private Player player;
using System.Drawing;

public Point PlayerLocation { get { return player.Location; } }
public int PlayerHitPoints { get { return player.HitPoints; } }
public List PlayerWeapons { get { return player.Weapons; } }

private int level = 0;
public int Level { get { return level; } }

The Rectangle object has Top, Bottom,
Left, and Right fields, and works
perfectly for the overall game area.

private Rectangle boundaries;
public Rectangle Boundaries { get { return boundaries; } }

Game starts out with a bounding box for
public Game(Rectangle boundaries) {
the
dungeon, and creates a new Player
this.boundaries = boundaries;
obje
ct
in the dungeon.
player = new Player(this,
new Point(boundaries.Left + 10, boundaries.Top + 70));
}
public void Move(Direction direction, Random random) {
player.Move(direction);
Movement is simple: move the player in the
foreach (Enemy enemy in Enemies)
direction the form gives us, and move each
enemy.Move(random);
enemy in a random direction.
}
public void Equip(string weaponName) {
These are all
player.Equip(weaponName);
great examples
}
of encapsulation....
public bool CheckPlayerInventory(string weaponName) {
Game doesn’t know
return player.Weapons.Contains(weaponName);
how Player handles
}
these actions, it just
public void HitPlayer(int maxDamage, Random random) {
passes on the needed
player.Hit(maxDamage, random);
information and lets
}
Player do the rest.

392   Head First Lab #1

The Quest

public void IncreasePlayerHealth(int health, Random random) {
player.IncreaseHealth(health, random);
Attack() is almost exactly like Move().
}
The player attacks, and the enemies all

get a turn to move.

public void Attack(Direction direction, Random random) {
player.Attack(direction, random);
foreach (Enemy enemy in Enemies)
GetRandomLocation() will come in handy in
enemy.Move(random);
the NewLevel() method, which will use it to
}
where to place enemies and weapons.

determine

private Point GetRandomLocation(Random random) {
return new Point(boundaries.Left +
random.Next(boundaries.Right / 10 - boundaries.Left / 10) * 10,
boundaries.Top +
random.Next(boundaries.Bottom / 10 - boundaries.Top / 10) * 10);
}

This is just a math trick to get a
random location within the rectangle
that represents the dungeon area.
We only added the case for
Level 1. It’s your job to add
cases for the other levels.

}

public void NewLevel(Random random) {
level++;
switch (level) {
case 1:
Enemies = new List();
Enemies.Add(new Bat(this, GetRandomLocation(random)));
WeaponInRoom = new Sword(this, GetRandomLocation(random));
break;
e inventory for one
}
’ve only got room indthpotion. So if the
We
}
potion and one re

blue
d potion, then the
player already has a arered potion to the level
game shouldn’t add for the blue potion).
(and the same goes

Finish the re st of the levels
It’s your job to finish the NewLevel() method. Here’s the
breakdown for each level:

Level
2
3
4
5
6
7
8

Enemies			
Ghost			
Ghoul			
Bat, Ghost		
Bat, Ghoul		
Ghost, Ghoul		
Bat, Ghost, Ghoul		
N/A			

is still
So if the blue potiontory from
en
in the player’s inv pears on
Level 2, nothing ap
this level.

Weapons
Blue potion
Bow
Bow, if not picked up on 3; otherwise, blue potion
Red potion
Mace
Mace, if not picked up on 6; otherwise, red potion
N/A - end the game with Application.Exit()

This only appears if
the red potion from
Level 5 has already
been used up.
you are here 4   393

The Quest
Finding common behavior: movement
You already know that duplicate code is bad, and duplicate code
usually shows up when two or more objects share the same behavior.
That’s the case in the dungeon game, too…both enemies and players
move.
Let’s create a Mover class, to abstract that common behavior into a
single place. Player and Enemy will inherit from Mover. And even
though weapons don’t move around, they inherit from Mover, too,
because they need some of its properties and methods. Mover has
a Move() method for moving around, and a read-only Location
property that the form can use to position a subclass of Mover.

Mover is abstract, so
can’t be instantiated.
You’ll only instantiate
Player and Enemy, which
inherit from it.

We added return values
and parameters to this
class diagram to make
it easier for you to see
what’s going on.
Nearby() takes a point,
and figures out if it’s
within a certain distance
away from the object.

Mover
(abstract)
Location: Point
Nearby(locationToCheck: Point,
distance: int): bool
Move(direction: Direction,
boundaries: Rectangle): Point

n as well
Move takes a directuniodaries, and
as the dungeon’s bo e end point of
calculates where thuld be.
that movement wo

Player and Enemy both
inherit from Mover.
Enemy
(abstract)
HitPoints: int

Player
Weapons: List
HitPoints: int
Attack(direction: Direction, random: Random)
Hit(maxDamage: int, random: Random)
Equip(weaponName: String)
Move(direction: Direction)

The Player class overrides
the Move() method.

Add a Direction enum

You can call Nearb
Move() on both Eney() and
and Player now. my

The Mover class, as well as several other classes, need
a Direction enum. Create this enum, and give it four
enumerated values: Up, Down, Left, and Right.

394   Head First Lab #1

Move(random: Random)
Hit(maxDamage: int,
random: Random)

Enemies don’t
have an Attack()
method because
their attacking is
built into Move().

Weapon
(abstract)

PickedUp
Location
PickUpWeapon()
DamageEnemy()

The Quest
The Mover class source code
Here’s the code for Mover:

Since protected
available to subclaprssoperties are only
can’t set the locaties, the form object
through the public on…only read it
get method we defi
ne.

abstract class Mover {
private const int MoveInterval = 10;
protected Point location;
public Point Location { get { return location; } }
protected Game game;
public Mover(Game game, Point location) {
this.game = game;
this.location = location;
}

}

ke in the Game
Instances of Mover ta
ation.
object and a current loc

public bool Nearby(Point locationToCheck, int distance) {
if (Math.Abs(location.X - locationToCheck.X) < distance &&
(Math.Abs(location.Y - locationToCheck.Y) < distance)) {
return true;
} else {
The Nearby method checks a Point against this object’s current
return false;
location. If they’re within distance of each other, then it
}
returns true; otherwise, it returns false.
}
public Point Move(Direction direction, Rectangle boundaries) {
Point newLocation = location;
The Move() method
switch (direction) {
tries to move one st
case Direction.Up:
if (newLocation.Y - MoveInterval >= boundaries.Top)
in a direction. If it ep
newLocation.Y -= MoveInterval;
can, it returns the
break;
new Point. If it hits a
case Direction.Down:
boundary, it returns
if (newLocation.Y + MoveInterval <= boundaries.Bottom) the
original Point.
newLocation.Y += MoveInterval;
break;
If the end location is
case Direction.Left:
if (newLocation.X - MoveInterval >= boundaries.Left)
outside the boundaries,
newLocation.X -= MoveInterval;
the new location
break;
stays the same as the
case Direction.Right:
starting point.
if (newLocation.X + MoveInterval <= boundaries.Right)
newLocation.X += MoveInterval;
break;
default: break;
}
return newLocation;
Finally, this new location is
}

returned (which might still be the
same as the starting location!).

you are here 4   395

The Quest
The Player class keeps track of the
Here’s a start on the Player class. Start with this code
in the IDE, and then get ready to add to it.

The Player and Enemy objects need to
player stay inside the dungeon, which means
they need to know the boundaries of the
playing area. Use the Contains() method
of the boundaries Rectangle to make sure
they don’t move out of bounds.
All of the properties
of Player are hidden
from direct access.

class Player : Mover {
private Weapon equippedWeapon;
private int hitPoints;
public int HitPoints { get { return hitPoints; } }

private List inventory = new List();
public List Weapons {
get {
List names = new List();
A Player can hold
foreach (Weapon weapon in inventory)
multiple weapons in
names.Add(weapon.Name);
inventory, but can only
return names;
equip one at a time.
}
Player
}

inherits
from Mover, so
this passes in
public Player(Game game, Point location);
the Game and
: base(game, location) {
The
playe
r’s
const
ructo
r
sets
location to that
hitPoints = 10;
its
hitPo
ints to 10 and then
base class.
}
calls the base class constructor.
When an enemy hits the player,
public void Hit(int maxDamage, Random random) {
it causes a random amount of
hitPoints -= random.Next(1, maxDamage);
damage. And when a potion
}
increases the player’s health, it
increases it by a random amount.

public void IncreaseHealth(int health, Random random) {
hitPoints += random.Next(1, health);
}

}

public void Equip(string weaponName) {
foreach (Weapon weapon in inventory) {
if (weapon.Name == weaponName)
equippedWeapon = weapon;
}
}

396   Head First Lab #1

The Equip() method tells the player to
equip one of his weapons. The Game
object calls this method when one of the
inventory icons is clicked.

ly have one Weapon
A Player object canaontime.
object equipped at

Even though potions help the player
rather than hurt the enemy, they’re
still considered weapons by the game.
That way the inventory can be a
List, and the game can
point to one with its WeaponInRoom
reference.

The Quest
Write the Move() me thod for the Player
Game calls the Player’s Move() method to tell a player to move
in a certain direction. Move() takes the direction to move as an
argument (using the Direction enum you should have already
added). Here’s the start of that method:

This happens when one of
the movement buttons on
the form is clicked.

public void Move(Direction direction) {
base.location = Move(direction, game.Boundaries);
if (!game.WeaponInRoom.PickedUp) {
// see if the weapon is nearby, and possibly pick it up
}
When the player
}
You’ve got to fill in the rest of this method. Check and see if the
weapon is near the player (within a single unit of distance). If
so, pick up the weapon and add it to the player’s inventory.
If the weapon is the only weapon the player has, go ahead and
equip it immediately. That way, the player can use it right away,
on the next turn.

Add an At tack() me thod, too
Next up is the Attack() method. This is called when one of the
form’s attack buttons is clicked, and carries with it a direction (again,
from the Direction enum). Here’s the method signature:

Move is in the Mover
base class.

picks up a weapon
needs to disappear from the dungeo, itn
and appear in the inventory.

The Weapon and form will handle
making the weapon’s PictureBox
invisible when the player picks it up…
that’s not the job of the Player class.

tack()
The weapons all have an At
tion enum
method that takes a Direc
yer’s
e
and a Random object. Thwhpla
weapon
ich
Attack() will figure outAttack().
is equipped and call its

public void Attack(Direction direction, Random random) {
// Your code goes here
}

If the weapon is a
potion, then Attack()
removes it from the
inventory after the
player drinks it.

If the player doesn’t have an equipped weapon, this method
won’t do anything. If the player does have an equipped weapon,
this should call the weapon’s Attack() method.
But potions are a special case. If a potion is used, remove it
from the player’s inventory, since it’s not available anymore.

Potions will implement an IPotion interface (more on that
in a minute), so you can use the “is” keyword to see if a
Weapon is an implementation of IPotion.
you are here 4   397

The Quest
Bats, ghosts, and ghouls inherit f rom the Enemy class
We’ll give you another useful abstract class: Enemy. Each
different sort of enemy has its own class that inherits from the
Enemy class. The different kinds of enemies move in different
ways, so the Enemy abstract class leaves the Move method
as an abstract method—the three enemy classes will need to
implement it differently, depending on how they move.

Enemy
(abstract)
HitPoints: int

abstract class Enemy : Mover {
Move(random: Random)
private const int NearPlayerDistance = 25;
Hit(maxDamage: int,
private int hitPoints;
random: Random)
public int HitPoints { get { return hitPoints; } }
public bool Dead { get {
if (hitPoints <= 0) return true; The form can use this read-only
property to see if the enemy should
else return false;
be visible in the game dungeon.
}
}
public Enemy(Game game, Point location, int hitPoints)
: base(game, location) { this.hitPoints = hitPoints; }

Each
subclass public
of Enemy
implements
public
this.

When the player attacks
an enemy, it calls the
enemy’s Hit() method, which
void Hit(int maxDamage, Random random) {
subtracts a random number
hitPoints -= random.Next(1, maxDamage);
from the hit points.
}
The Enemy class inherited the Nearby()
method from Mover, which it can use to
protected bool NearPlayer() {
figu
re out whether it’s near the player.
return (Nearby(game.PlayerLocation,

}

abstract void Move(Random random);

NearPlayerDistance));
}
protected Direction FindPlayerDirection(Point playerLocation) {
Direction directionToMove;
if (playerLocation.X > location.X + 10)
If you feed FindPlayerDirection()
directionToMove = Direction.Right;
the player’s location, it’ll use
else if (playerLocation.X < location.X - 10)
the base class’s location field to
directionToMove = Direction.Left;
figure out where the player is in
else if (playerLocation.Y < location.Y - 10)
relation to the enemy and return
directionToMove = Direction.Up;
a Direction enum that tells you in
else
which direction the enemy needs to
directionToMove = Direction.Down;
move in order to move toward the
return directionToMove;
player.
}

398   Head First Lab #1

The Quest
Write the dif ferent Enemy subclasse s
The three Enemy subclasses are pretty straightforward. Each enemy has a
different number of starting hit points, moves differently, and does a different
amount of damage when it attacks. You’ll need to have each one pass a different
startingHitPoints parameter to the Enemy base constructor, and you’ll have
to write different Move() methods for each subclass.
Here’s an example of how one of those classes might look:
class Bat : Enemy {
public Bat(Game game, Point location)
: base(game, location, 6)
{ }

You probably won’t need any constructor for
these; the base class handles everything.

}

The bat starts with 6 hit points, so it
passes 6 to the base class constructor.

public override void Move(Random random) {
// Your code will go here
}

Each of these subclasses the
Enemy base class, which in turn
subclasses Mover.
Bat

Move()

Ghost

Move()

Ghoul

Move()

The bat flies around
somewhat randomly, so
it uses Random to fly
in a random direction
half the time.

points,
Once an enemy has no more hity it.
But
pla
dis
the form will no longer
list
es
emi
En
e’s
it’ll still be in the gam
until the player finishes the level.

The bat starts with 6 hit points. It’ll keep moving toward the player
and attacking as long as it has one or more hit points. When it
moves, there’s a 50% chance that it’ll move toward the player, and a
50% chance that it’ll move in a random direction. After the bat moves,
it checks if it’s near the player—if it is, then it attacks the player with
up to 2 hit points of damage.

We’ll have to make
sure the form
sees if an enemy
should be visible
at every turn.

The ghost is harder to defeat than the bat, but like the bat, it will only
move and attack if its hit points are greater than zero. It starts with 8
hit points. When it moves, there’s a 1 in 3 chance that it’ll move toward
the player, and a 2 in 3 chance that it’ll stand still. If it’s near the player,
it attacks the player with up to 3 hit points of damage.

The ghoul is the toughest enemy. It starts with 10 hit points, and only
moves and attacks if its hit points are greater than zero. When it moves,
there’s a 2 in 3 chance that it’ll move toward the player, and a 1 in 3
chance that it’ll stand still. If it’s near the player, it attacks the player
with up to 4 hit points of damage.

The ghost
and ghoul use
Random to make
them move more
slowly than the
player.

you are here 4   399

The Quest
Weapon inherits from Mover,
each weapon inherits from Weapon
We need a base Weapon class, just like we had a base Enemy class.
And each weapon has a location, as well as a property indicating
whether or not it’s been picked up. Here’s the base Weapon class:

Weapon
(abstract)

Weapon inherits
from Mover
because it uses
its Nearby() and
Move() methods in
DamageEnemy().

abstract class Weapon : Mover {

protected Game game;
private bool pickedUp;
public bool PickedUp { get { return pickedUp; } }
private Point location;
public Point Location { get { return location; } }

PickedUp
Location
PickUpWeapon()
DamageEnemy()

A pickedUp weapon shouldn’t
be displayed anymore…the
form can use this get
accessor to figure that out.

Every weapon has a location
in the game dungeon.

public Weapon(Game game, Point location) {
this.game = game;
The constructor sets the game and location
this.location = location;
fields, and sets pickedUp to false (because
pickedUp = false;
it hasn’t been picked up yet).
}
public void PickUpWeapon() { pickedUp = true; }
public abstract string Name { get; }

Each weapon class needsertoty and an
implement a Name prop determines
Attack() method thatcks.
how that weapon atta

Each public abstract void Attack(Direction direction, Random random);
weapon’s
Name protected bool DamageEnemy(Direction direction, int radius, Each weapon has a
different range and
property
int damage, Random random) {
pattern of attack, so
returns Point target = game.PlayerLocation;
weapons implement
the
its name for (int distance = 0; distance < radius; distance++) {
Attack() method
the
(“Sword”,
foreach (Enemy enemy in game.Enemies) {
rently.
diffe
“Mace”,
if (Nearby(enemy.Location, target, radius)) {
“Bow”).
enemy.Hit(damage, random);
}

return true;

}
target = Move(direction, target, game.Boundaries);

}

}

}
return false;

The Nearby() method in the Mover class only takes two
parameters, a Point and an int, and it compares the Point to
the Mover field location. You’ll need to add an overloaded
Nearby() that’s almost identical, except that it takes three
parameters, two Points and a distance, which compares the
first Point to the second Point (instead of location).

400   Head First Lab #1

The DamageEnemy() method is called by
Attack(). It attempts to find an enemy in
a certain direction and radius. If it does, it
calls the enemy’s Hit() method and returns
true. If no enemy’s found, it returns false.

The Quest
Dif ferent we apons at tack in dif ferent ways
Each subclass of Weapon has its own name and attack logistic. Your job is to
implement these classes. Here’s the basic skeleton for a Weapon subclass:

the
Each subclass represents one, of
mace.
or
bow
,
rd
three weapons: a swo

class Sword : Weapon {

public Sword(Game game, Point location)
: base(game, location) { }
public override string Name { get { return

}

Each subclass relies on the base class
to do the initialization work.
basically hardcoding in
“Sword”; } } You’re
the name of each weapon.

public override void Attack(Direction direction, Random random) {
// Your code goes here
}
Th

The player can use the
weapons over and over—they
never get dropped or used up.

Sword

Name
Attack()

Bow

Name
Attack()

Mace

Name
Attack()

e Game object will pass on
the direction to attack in.

The sword is the first weapon the player picks up. It’s got a wide angle
of attack: if he attacks up, then it first tries to attack an enemy that’s in
that direction—if there’s no enemy there, it looks in the direction that’s
clockwise from the original attack and attacks any enemy there, and if
it still fails to hit then it attempts to attack an enemy counterclockwise
from the original direction of attack. It’s got a radius of 10, and causes
3 points of damage.
The bow has a very narrow angle of attack, but it’s got a very long
range—it’s got an attack radius of 30, but only causes 1 point of
damage. Unlike the sword, which attacks in three directions (because
the player swings it in a wide arc), when the player shoots the bow in a
direction, it only shoots in that one direction.

Think carefully
about this…what
is to the right
of the direction
left? What is to
the left of up?

The mace is the most powerful weapon in the dungeon. It doesn’t
matter in which direction the player attacks with it—since he swings it
in a full circle, it’ll attack any enemy within a radius of 20 and cause up
to 6 points of damage.

The different weapons will call DamageEnemy() in various ways. The
Mace attacks in all directions, so if the player’s attacking to the
right, it’ll call DamageEnemy(Direction.Right, 20, 6, random). If
that didn’t hit an enemy, it’ll attack Up. If there’s no enemy there,
it’ll try Left, then Down—that makes it swing in a full circle.
you are here 4   401

The Quest
Potions implement the IPotion interface
There are two potions, a blue potion and a red potion, which increase the
player’s health. They act just like weapons—the player picks them up in
the dungeon, equips them by clicking on the inventory, and uses them
by clicking one of the attack buttons. So it makes sense for them to
inherit from the abstract Weapon class.
But potions act a little differently, too, so you’ll need to add an IPotion
interface so they can have extra behavior: increasing the player’s health.
The IPotion interface is really simple. Potions only need to add one readonly property called Used that returns false if the player hasn’t used the
potion, and true if he has. The form will use it to determine whether or
not to display the potion in the inventory.
interface IPotion {
bool Used { get; }
}

IPotion makes potions
usable only once. It’s
also possible to find
out if a Weapon is a
potion with “if (weapon
is IPotion)” because of
this interface.

BluePotion

Name
Attack()

RedPotion

Name
Attack()

402   Head First Lab #1

The potions inherit from the Weapon class because
they’re used just like weapons—the player clicks on
the potion in the inventory scroll to equip it, and
then clicks any of the attack buttons to use it.

Weapon
(abstract)

PickedUp
Location
PickUpWeapon()
DamageEnemy()

RedPotion

IPotion
(interface)

Used

BluePotion

Name

Name

Attack()

Attack()

You should be able to
write these classes using
this class diagram and
the information below.

The BluePotion class’s Name property should return the string
“Blue Potion”. Its Attack() method will be called when the player
uses the blue potion—it should increase the player’s health by up to
5 hit points by calling the IncreasePlayerHealth() method.
After the player uses the potion, the potion’s Used() method
should return true.
cks up

a blue potion
If the player pi it, and then picks
on level 2, uses on level 4, the game
up another one ting two different
will end up creaances.
BluePotion inst

The RedPotion class is very similar to BluePotion, except that
its Name property returns the string “Red Potion”, and its Attack()
method increases the player’s health by up to 10 hit points.

The Quest
The form brings it all toge ther
There’s one instance of the Game object, and it lives as a private field of
your form. It’s created in the form’s Load event, and the various event
handlers in the form use the fields and methods on the Game object to
keep the game play going.
Everything begins with the form’s Load event handler, which passes the
Game a Rectangle that defines the boundaries of the dungeon play
area. Here’s some form code to get you going:

Using a Rectangle

You’ll find a lot of Rectangles any
time you work with forms. You
can create one by passing it X, Y,
Width, and Height values, or two
Points (for opposite corners). Once
you’ve got a rectangle instance, you
can also access its Left, Right,
Top, and Bottom, as well as its X,
Y, Width, and Height values.

private Game game;
private Random random = new Random();
private void Form1_Load(object sender,
EventArgs e) {
game = new Game(new Rectangle(78, 57, 420, 155));
game.NewLevel(random);
UpdateCharacters();
These are the boundaries of the
}
dungeon in the background image

you’ll download and add to the form.

Remember to
double-click on
each PictureBox
so the IDE adds
a separate event
handler method
for each of them.

The form has a separate event handler for each of these PictureBox’s Click events. When the
player clicks on the sword, it first checks to make sure the sword is in the player’s inventory using the
Game object’s CheckPlayerInventory() method. If the player’s holding the sword, the form
calls game.Equip() to equip it. It then sets each PictureBox’s BorderStyle property to
draw a box around the sword, and make sure none of the other icons has a box around it.
There’s an event handler for each of the four movement buttons.
They’re pretty simple. First the button calls game.Move() with
the appropriate Direction value, and then it calls the form’s
UpdateCharacters() method.

Make sure you change the buttons
back when the player equips the
sword, bow, or mace.

The four attack button event handlers are also really simple.
Each button calls game.Attack(), and then calls the form’s
UpdateCharacters() method. If the player equips a potion,
it’s still used the same way—by calling game.Attack()—but
potions have no direction. So make the Left, Right, and Down
buttons invisible when the player equips a potion, and change the
text on the Up button to say “Drink”.
you are here 4   403

The Quest
The form’s UpdateCharacters() me thod
moves the PictureBoxe s into position
The last piece of the puzzle is the form’s UpdateCharacters() method.
Once all the objects have moved and acted on each other, the form updates
everything…so weapons that been dropped have their PictureBoxes’
Visible properties set to false, enemies and players are drawn in their
new locations (and dead ones are made invisible), and inventory is updated.
Here’s what you need to do:
1

Update the player’s position and stats
The first thing you’ll do is update the player’s PictureBox location and the
label that shows his hit points. Then you’ll need a few variables to determine
whether you’ve shown each of the various enemies.
public void UpdateCharacters() {
Player.Location = game.PlayerLocation;
playerHitPoints.Text =
game.PlayerHitPoints.ToString();
bool showBat = false;
bool showGhost = false;
bool showGhoul = false;
int enemiesShown = 0;
// more code to go here...

2

The showBat variable will be set to true if
we made the bat’s PictureBox visible. Same
goes for showGhost and showGhoul.

Update each enemy’s location and hit points
Each enemy could be in a new location and have a different set of hit points. You need to
update each enemy after you’ve updated the player’s location:

foreach (Enemy enemy in game.Enemies) {
This goes right aftee.r
if (enemy is Bat) {
the code from abov
bat.Location = enemy.Location;
batHitPoints.Text = enemy.HitPoints.ToString(); This will affect the
visibility of the enemy
if (enemy.HitPoints > 0) {
PictureBox controls in
showBat = true;
just
a bit.
enemiesShown++;
}
You’ll need two more if statements like this
}
in your foreach loop—one for the ghost
// etc...
and one for the ghoul.

Once you’ve looped through all the enemies on the level, check the showBat variable. If
the bat was killed, then showBat will still be false, so make its PictureBox invisible
and clear its hit points label. Then do the same for showGhost and showGhoul.
404   Head First Lab #1

The Quest

3

Update the weapon PictureBoxes
Declare a weaponControl variable and use a big switch statement to set it equal to
the PictureBox that corresponds to the weapon in the room.
sword.Visible = false;

Make sure your controls’ names

to end
bow.Visible = false;
match these names. It’s easy ult
to
redPotion.Visible = false;
up with bugs that are diffic tch.
bluePotion.Visible = false;
track down if they don’t ma
mace.Visible = false;
Control weaponControl = null;
switch (game.WeaponInRoom.Name) { You’ll have more cases
for
case “Sword”:
each weapon type.
weaponControl = sword; break;

The rest of the cases should set the variable weaponControl to the correct control on
the form. After the switch, set weaponControl.Visible to true to display it.
4

Set the Visible property on each inventory icon PictureBox
Check the Game object’s CheckPlayerInventory() method to figure out whether
or not to display the various inventory icons.

5

Here’s the rest of the method
The rest of the method does three things. First it checks to see if the player’s already
picked up the weapon in the room, so it knows whether or not to display it. Then it
checks to see if the player died. And finally, it checks to see if the player’s defeated all of
the enemies. If he has, then the player advances to the next level.
weaponControl.Location = game.WeaponInRoom.Location;
if (game.WeaponInRoom.PickedUp) {
Every level has one weapon. If
weaponControl.Visible = false;
it’s been picked up, we need to
} else {
make its icon invisible.
weaponControl.Visible = true;
}
if (game.PlayerHitPoints <= 0) {
Application.Exit() immediately quits the program.
MessageBox.Show(“You died”);
It’s part of System.Windows.Forms, so you’ll need
Application.Exit();
the appropriate using statement if you want to
}
use it outside of a form.
if (enemiesShown < 1) {
MessageBox.Show(“You have defeated the enemies on this level”);
game.NewLevel(random);
If there are no more enemies on the
UpdateCharacters();
level, then the player’s defeated them
}

all and it’s time to go to the next level.

you are here 4   405

The Quest
The fun’s just beginning!
Seven levels, three enemies…that’s a pretty decent game. But you
can make it even better. Here are a few ideas to get you started.…

Make the enemies smarter
Can you figure out how to change the enemies’ Move() methods so that they’re harder to defeat?
Then see if you can change their constants to properties, and add a way to change them in the
game.
Add more levels
The game doesn’t have to end after seven levels. See if you can add more…can you figure out how
to make the game go on indefinitely? If the player does win, make a cool ending animation with
dancing ghosts and bats! And the game ends pretty abruptly if the player dies. Can you think of a
more user-friendly ending? Maybe you can let the user restart the game or retry his last level.
Add different kinds of enemies
You don’t need to limit the dangers to ghouls, ghosts, and bats. See if you can add more enemies to
the game.
Add more weapons
The player will definitely need more help defeating any new enemies you’ve added. Think of new
ways that the weapons can attack, or different things that potions can do. Take advantage of the
fact that Weapon is a subclass of Mover—make magic weapons the player has to chase around!
Add more graphics
You can go to www.headfirstlabs.com/books/hfcsharp/ to find more graphics files for additional
enemies, weapons, and other images to help spark your imagination.
Make it an action game
Here’s an interesting challenge. Can you figure out how to use the KeyDown event and Timer you
used in the Key Game in Chapter 4 to change this from a turn-based game into an action game?

This is your chance to show off! Did you come up with a cool new
version of the game? Join the Head First C# forum and claim your
bragging rights: www.headfirstlabs.com/books/hfcsharp/
406   Head First Lab #1

9 reading and writing files

Save the byte array, save the world
OK, go ahead with our shopping
list…chicken wire…tequila…grape
jelly…bandages…yes, dear, I am
writing this down.

Sometimes it pays to be a little persistent.
So far, all of your programs have been pretty short-lived. They fire up, run for
a while, and shut down. But that’s not always enough, especially when you’re
dealing with important information. You need to be able to save your work. In
this chapter, we’ll look at how to write data to a file, and then how to read that
information back in from a file. You’ll learn about the .NET stream classes,
and also take a look at the mysteries of hexadecimal and binary.

this is a new chapter   407

islands in the stream

.NET uses stre ams to re ad and write data

Whenever you
want to read
data from a
file or write
data to a file,
you’ll use a
Stream object.

A stream is the .NET Framework’s way of getting data in and out of
your program. Any time your program reads or writes a file, connects
to another computer over a network, or generally does anything
where it sends or receives bytes from one place to another, you’re
using streams.

Let’s say you have a simple program—a form
with an event handler that needs to read data
from a file. You’ll use a Stream object to do it.
input = stream.Read(...);

form

input contains data read
from the stream

St

rea

file

t

ain

ad from the

ec

M

s re
byte

m o bj

…and the stream wo
with the file directrks
ly.

You use a
Stream object…

And if your program needs to write data out
to the file, it can use another Stream object.
stream.Write(...);

output contains data to

s
byte written to

ain

form

408   Chapter 9

St

You can use a different
Stream object, but the
process is the same.

rea

ec

M

t

write to the stream

m o bj

the file

reading and writing files

Dif ferent stre ams re ad and write dif ferent things
Every stream is a subclass of the abstract Stream class, and there are a bunch
of built-in stream classes to do different things. We’ll be concentrating on reading
and writing regular files, but everything you learn in this chapter will just as easily
apply to compressed or encrypted files, or network streams that don’t use files at all.

Stream is an abstract
so you can’t instantiateclaitss,
on
its own.

Stream
Close()
Read()
Seek()
Write()

These are just some
of the methods in the
Stream class.

FileStream
Close()
Read()
Seek()
Write()

A FileStream
object lets you
read from and
write to files.

Each subclass adds
methods and properties
specific to that class’s
functionality.

MemoryStream

NetworkStream

Close()
Read()
Seek()
Write()

Close()
Read()
Seek()
Write()

A MemoryStream
object lets you read
from and write
data to chunks of
memory.

A NetworkStream
object lets you read
and write data to
other computers or
devices on a network.

GZipStream
Close()
Read()
Seek()
Write()

A GZipStream
object lets you
compress data so
that it takes up less
space and is easier to
download and store.

Things you can do with a stre am:
1

Write to the stream.
You can write your data to a stream through a stream’s Write()
method.

2

Read from the stream.
You can use the Read() method to get data from a file, or a network,
or memory, or just about anything else, using a stream.

3

Change your position within the stream.
Most streams support a Seek() method that lets you find a position
within the stream so you can read or insert data at a specific place.

Streams let you
read and write
data. Use the
right kind of
stream for the
data you’re
working with.
you are here 4   409

so much easier

A FileStre am re ads and write s byte s to a file
When your program needs to write a few lines of text
to a file, there are a lot of things that have to happen:

1

Make sure you add using System.
IO; to any program that uses streams.

Create a new FileStream object and tell it to write to the file.

ec

eS

t

Fil

tr

eam obj A FileStream
can only be

attached to one file at a

The FileStream attaches itself to a file.

69 117 114 101 107 97 33

Eureka!

Call the stream’s Write() method and pass it the byte array.
69 1

1 7 114

101 1
07 97 33

ec

eS

t

Fil

tr

e a m o bj

Close the stream so other programs can access the file.

Fil

tr

eS

410   Chapter 9

a
close a stream wisill be
Forgetting to rw
ile
f
ise, the
big deal. Othe her programs won’t
locked, and ot it until you close your
be able to use
stream.

t

5

e a m o bj

Streams write bytes to files, so you’ll need to convert the string that you
want to write to an array of bytes.

This is called encoding, and we’ll
talk more about it later on…
4

ec

eS

3

t

Fil

tr

ec

2

e a m o bj

time.

reading and writing files

How to write te xt to a file in 3 simple steps
C# comes with a convenient class called StreamWriter that does
all of those things in one easy step. All you have to do is create a new
StreamWriter object and give it a filename. It automatically creates a
FileStream and opens the file. Then you can use the StreamWriter’s
Write() and WriteLine() methods to write everything to the file you
want.

1

StreamWriter
creates and
manages a
FileStream
object for you
automatically.

Use the StreamWriter’s constructor to open or create a file
You can pass a filename to the StreamWriter() constructor. When you do, the writer automatically
opens the file. StreamWriter also has an overloaded constructor that takes a bool: true if you want
to add text to the end of an existing file (or append), or false if you want to delete the existing file and
create a new file with the same name.

t

Putting @ in front of the
filename tells C# to treat t
this as a literal string withou
escape characters like \t for
tab or \n for newline.

ec

je

tr

eS

am
2

b
riter o

Fil

Stre

W

ct

StreamWriter writer = new StreamWriter(@”C:\newfiles\toaster oven.txt”, true);

e a m o bj

Use the Write() and WriteLine() methods to write to the file
These methods work just like the ones in Console: Write() writes text, and WriteLine() writes
text and adds a line break to the end. If you include “{0}”, “{1}”, “{2}”, etc., inside the string you’re
writing, the methods include parameters in the strings being written: “{0}” is replaced with the first
parameter after the string being written, “{1}” is replaced with the second, etc.
writer.WriteLine(“The {0} is set to {1} degrees.”, appliance, temp);

ct

St

350 degree
s.

je

ct

je

b
riter o

le

am

3

to
The aster ov
en…

Fi

Stre

W

to
set
…is

rea m ob

Call the Close() method to release the file
If you leave the stream open and attached to a file, then it’ll keep the file locked open
and no other program will be able to use it. So make sure you always close your files!
writer.Close();
you are here 4   411

write it down

It’s probably not a
good idea to write to
your root folder, and
The Swindler launche s another diabolical plan
your OS might not even
let you do it. So pick
The citizens of Objectville have long lived in fear of the Swindler.
another directory you
Now he’s using a StreamWriter to implement another evil
want to write to.
plan. Let’s take a look at what’s going on. Create a new Console
The path starts with an @ sign so
Application and add this to the Main() method::
that the StreamWriter doesn’t
and
This line creates the StreamWriter object
inte
rpret the “\” as the start of
tells it where the file will be.
an escape sequence.
StreamWriter sw = new StreamWriter(@”C:\secret_plan.txt”);
sw.WriteLine(“How I’ll defeat Captain Amazing”);

WriteLine()
adds a new line
after writing.
Write() sends
just the text,
with no extra
line feeds at
the end.

sw.WriteLine(“Another genius secret plan by The Swindler”);
sw.Write(“I’ll create an army of clones and ”);
sw.WriteLine(“unleash them upon the citizens of Objectville.”);
string location = “the mall”;
for (int number = 0; number <= 6; number++){

Can you figure out what’s
going on with the location
variable in this code?

sw.WriteLine(“Clone #{0} attacks {1}”, number, location);
if (location == “the mall”) { location = “downtown”; }
else { location = “the mall”; }
}
sw.Close();

Close() frees up any connections to theter is
file and any resources the StreamWri if you
using. The text doesn’t get written
don’t close the stream.

This is what the above code produces.

StreamWriter is
in the System.IO
namespace, so
make sure you add
“using System.IO;”
to the top of your
program.
412   Chapter 9

You can use the {}
within the text to
pass in variables to the
string being written.
{0} is replaced by the
first parameter after
the string, {1} by the
second, and so on.

reading and writing files

StreamWriter Magnets

Suppose you have the code for button1_Click() shown
below. Your job is to use the magnets to build code for the Flobbo
class so that when the event handler is called, it produces the
output shown at the bottom of the page. Good luck!

);
sw.WriteLine(Zap
”;
ge
an
or
Zap = “red
;
ue
tr
return
}

private void button1_Click(object sender, EventArgs e) { sw.WriteLine(Zap);
sw.Close();
Flobbo f = new Flobbo(“blue yellow”);
return false;
StreamWriter sw = f.Snobbo();
f.Blobbo(f.Blobbo(f.Blobbo(sw), sw), sw);
}
public bool Blobbo
(bool Already, StreamWriter sw) {
reamWriter sw) {
public bool Blobbo(St
sw.WriteLine(Zap);
Zap = “green purple”;
return false;
}

return new
w.txt”);
StreamWriter(“maca

}

}

}

private string Zap;

public Flobbo(string Zap
) {
this.Zap = Zap;
}

class Flobbo {
if (Already) {
} else {
public StreamWriter Sno
bbo() {

Output:

you are here 4   413

read it in

StreamWriter Magnets Solution

Your job was to construct the Flobbo class from the magnets
to create the desired output.
private void button1_Click(object sender, EventArgs e) {
Flobbo f = new Flobbo(“blue yellow”);
StreamWriter sw = f.Snobbo();
f.Blobbo(f.Blobbo(f.Blobbo(sw), sw), sw);
}

Just a reminder: we picked
intentionally weird variable
names and methods in these
puzzles because if we used
really good names, the
puzzle would be too easy!
Don’t use names like this in
your code, ok?

class Flobbo {

private string Zap;
public Flobbo(string Zap) {
this.Zap = Zap;
}
public StreamWriter Snobbo() {

}

return new
StreamWriter(“macaw.txt”);

public bool Blobbo(StreamWriter sw) {

}

sw.WriteLine(Zap);
Zap = “green purple”;
return false;

The Blobbo() method
is overloaded—it’s got
two declarations with
different parameters.

public bool Blobbo
(bool Already, StreamWriter sw) {
if (Already) {
sw.WriteLine(Zap);
sw.Close();
return false;
} else {
sw.WriteLine(Zap);
Zap = “red orange”;
return true;

}

414   Chapter 9

}

}

e
Make sure you clos one
files when you’re d
with them.

Output:

reading and writing files

Re ading and writing using t wo objects
Let’s read Swindler’s secret plans with another stream, a StreamReader.
StreamReader works just like StreamWriter, except instead
of writing a file you give the reader the name of the file to read in its
constructor. The ReadLine() method returns a string that contains the
next line from the file. You can write a loop that reads lines from it until its
EndOfStream field is true—that’s when it runs out of lines to read:

StreamReader reader =

One quick note. We’re playing a little
fast and loose with the word “stream.” A
StreamReader (which inherits from
TextReader) is a class that reads
characters from streams. It’s not a stream
itself. When you pass a filename into its
constructor, it creates a stream for you, and
closes it when you call its Close() method.
It’s also got an overloaded constructor that
takes a Stream. See how that works?

new StreamReader(@“c:\secret_plan.txt”);

StreamWriter writer =

Pass the file you want
to read from into the or.
StreamReader’s construct

new StreamWriter(@“c:\emailToCaptainAmazing.txt”);

This program uses a StreamReader to read the
Swindler’s plan, and a StreamWriter to write a file
that will get emailed to Captain Amazing.

writer.WriteLine(“To: CaptainAmazing@objectville.net”);

writer.WriteLine(“From: Commissioner@objectiville.net”);

writer.WriteLine(“Subject: Can you save the day... again?”);
writer.WriteLine();

An empty WriteLine() method
writes a blank line.

writer.WriteLine(“We’ve discovered the Swindler’s plan:”);
while (!reader.EndOfStream) {

string lineFromThePlan = reader.ReadLine();

}

writer.WriteLine(“The plan -> ” + lineFromThePlan);

writer.WriteLine();

writer.WriteLine(“Can you help us?”);

the property
EndOfStream isif there’s no
that tells you ad in the file.
data left unre

This loop reads a line from
the reader and writes it
out to the writer.

writer.Close();

reader.Close();

Make sure to close every
stream that you open, even if
you’re just reading a file.
The StreamReader and StreamWriter
opened up their own streams when
you instantiated them. Calling their
Close() methods tells them to close
those streams.

you are here 4   415

don’t cross the streams

Data can go through more than one stre am
One big advantage to working with streams in .NET is that you can have your data
go through more than one stream on its way to its final destination. One of the many
types of streams that .NET ships with is the CryptoStream class. This lets you
encrypt your data before you do anything else with it:

Stream
Close()
Read()
Seek()
Write()

a
Using a normal FileStream, your dat
t.
tex
as
file
a
gets written directly to

CryptoStream
Close()
Read()
Seek()
Write()

Now your FileStre
the encrypted textam writes
to the file.

is
This CryptoStreamileStream,
connected to a Fle stream
and gives that fi crypted.
your text, but en

You write normal
text to a
CryptoStream.

ob

St

le

pt

tream

4ÿ Ö
*3yd

dfr5 6dì¢L
1═

Fi

Cry

oS

ject

n
4ÿ Ö
*3yd

CryptoStream inherits
from the abstract
Stream class, just
like the other stream
classes.

ndfr5 6dì¢L1
═

ct

rea m

ob

je

le

St

je

Fi

ct

C lo n e s a n d
I ’ ll cr
of
eate
y
an arm

rea m ob

You can CHAIN streams. One stream
can write to another stream, which
writes to another stream…often
ending with a network or file stream.
416   Chapter 9

reading and writing files

Pool Puzzle

Your job is to take code snippets from
the pool and place them into the
blank lines in the program. You
can use the same snippet more
than once, and you won’t need
to use all the snippets. Your goal
is to make the program produce
the output shown to the right.

class Pizza {

private ____________

class Pineapple {

public Pizza(__________

const ______ d = “delivery.txt”;
public _____

______

}

public static void Main() {

Pizza pz = new Pizza(new __________(d, true));
for (_____ w = 3; w >= 0; w--) {
Pizza i = new Pizza

(new ___________(d, false));

}

private ____________ reader;

public Party(____________ reader) {

Party p = new Party(new __________(d));
p.___________(o);

}

q._________(reader._________());

o.__________();

}

Note: Each snippet
from the pool can
be used more than
once!
HowMany
HowMuch
HowBig
HowSmall

int
long
string
enum
class

ReadLine
WriteLine

Stream
reader
writer
StreamReader
StreamWriter
Open
Close

__________.reader = reader;

public void HowMuch(__________ q) {

o.___________(“That’s all folks!”);

}

}

writer.__________();

class Party {

i.Idaho((Fargo)w);

}

______.writer = writer;

writer._________(f);

__________ o = new ____________(“order.txt”);
pz.________(Fargo.Flamingo);

_______) {

public void ______(______.Fargo f) {

{ North, South, East, West, Flamingo }

}

_______;

public
private
this
class
static

}

reader.__________();

for
while
foreach

=
>=
<=
!=
==
++
--

Fargo
Utah
Idaho
Dakota
Pineapple

you are here 4   417

a serious dialog

Pool Puzzle Solution
This enum (specifically
ToString() method) is ,useitsd
print a lot of the output to
.
class Pineapple {
const string d = “delivery.txt”;
public enum Fargo { North, South, East, West, Flamingo }
public static void Main() {
StreamWriter o = new StreamWriter(“order.txt”);
Pizza pz = new Pizza(new StreamWriter(d, true));
r
fo
t
in
po
y
tr
en
e
pz.Idaho(Fargo.Flamingo);
th
’s
Here
a
s
te
ea
cr
It
for (int w = 3; w >= 0; w--) {
m.
ra
og
pr
the
passes to
it
at
th
Pizza i = new Pizza(new StreamWriter(d, false));
er
rit
W
am
re
St
it loops
n
he
i.Idaho((Fargo)w);
T
.
ss
cla
y
rt
Pa
e
th
s,
er
mb
Party p = new Party(new StreamReader(d));
me
o
rg
through the Fa em to the
p.HowMuch(o);
th
passing each of od to print.
}
th
Pizza.Idaho() me
o.WriteLine(“That’s all folks!”);
o.Close();
}
}
ss keeps
class Pizza {
private StreamWriter writer;
public Pizza(StreamWriter writer) {
this.writer = writer;
}
public void Idaho(Pineapple.Fargo f) {
writer.WriteLine(f);
writer.Close();
}
}
class Party {
private StreamReader reader;
public Party(StreamReader reader) {
this.reader = reader;
}
public void HowMuch(StreamWriter q) {
q.WriteLine(reader.ReadLine());
reader.Close();
}
}

The Party class has a
StreamReader field, and
its HowMuch() method
reads a line from that
StreamReader and writes
it to a StreamWriter.

418   Chapter 9

a
The Pizza claer as a private
StreamWrit s Idaho() method
field, and ito enums to the
writes Fargheir ToString()
file using t hich WriteLine()
methods, w ically.
calls automat

reading and writing files

Use built-in objects to pop up standard dialog boxe s
When you’re working on a program that reads and writes files, there’s
a good chance that you’ll need to pop up a dialog box at some point to
prompt the user for a filename. That’s why .NET ships with objects to
pop up the standard Windows file dialog boxes.

This is the ialog
FolderBrowseD
dialog box.
.NET has dialog boxes built in,
like this OpenFileDialog for
selecting a file to open.

ShowDialog() pops up a dialog box
Displaying a dialog box is easy. Here’s all you
need to do:

We’ll walk you thro h
these steps in a minuugte
.

1

Create an instance of the dialog box object. You can do this in code
using new, or you can drag it out of the Toolbox and onto your form.

2

Set the dialog box object’s properties. A few useful ones include Title (which
sets the text in the title bar), InitialDirectory (which tells it which
directory to open first), and FileName (for Open and Save dialog boxes).

3

Call the object’s ShowDialog() method. That pops up the dialog box,
and doesn’t return until the user clicks the OK or Cancel button, or closes
the window.

4

The ShowDialog() method returns a DialogResult, which is an enum.
Some of its members are OK (which means the user clicked OK), Cancel, Yes,
and No (for Yes/No dialog boxes).

you are here 4   419

dialog boxes are objects too

Dialog boxe s are just another .NET control
You can add Windows standard file dialog boxes to your program by dragging them
to your form—just drag an OpenFileDialog control out of the Toolbox and drop
it onto your form. Instead of showing up as a visual control, you’ll see it appear in the
space below your form. That’s because it’s a component, which is a special kind of
non-visual Toolbox control that doesn’t appear directly on the form, but which you
can still use in your form’s code just like you use any other control.

“Non-visual” just means
it doesn’t appear on your
form when you drag it
out of the Toolbox.

When you drag a component out of the
Toolbox and onto your form, the IDE
displays it in the space underneath the
form editor.
The InitialDirectory property changes the folder
that’s first displayed when the dialog opens.

The Filter
property lets you
change the filters
openFileDialog1.InitialDirectory = @“c:\MyFolder\Default\”;
that show up on
the bottom of the
openFileDialog1.Filter = “Text Files (*.txt)|*.txt|”
dialog box, such as
wh
at types of files
+ “Comma-Delimited Files (*.csv)|*.csv|All Files (*.*)|*.*”;
to show.
openFileDialog1.FileName = “default_file.txt”;
box
ese properties tell the dialogthe
Th
openFileDialog1.CheckFileExists = true;
to display an error message if
h
user tries to open up a filedriorve.pat
openFileDialog1.CheckPathExists = false;
that doesn’t exist on the
DialogResult result = openFileDialog1.ShowDialog();

if (result == DialogResult.OK){
OpenSomeFile(openFileDialog1.FileName);
}

420   Chapter 9

Display the dialog box using its ShowDialog()
method, which returns a
DialogResult. That’s an enum that you can
use
user hit the OK button. It’ll be set to DialogRto check whether or not the
esult.OK if the user clicked OK,
and DialogResult.Cancel if he hit Cancel.

reading and writing files

Dialog boxe s are objects, too
An OpenFileDialog object shows the standard Windows “Open” window,
and the SaveFileDialog shows the “Save” window. You can display
them by creating a new instance, setting the properties on the object, and
calling its ShowDialog() method. The ShowDialog() method returns
a DialogResult enum (because some dialog boxes have more than two
When
buttons or results, so a simple bool wouldn’t be enough).
saveFileDialog1 = new SaveFileDialog();

you drag a save dialog object out
of the Toolbox and onto your form, the
IDE just adds a line like this to your
form’s InitializeComponent() method.

saveFileDialog1.InitialDirectory = @“c:\MyFolder\Default\”;
saveFileDialog1.Filter = “Text Files (*.txt)|*.txt|”

+ “Comma-Delimited Files (*.csv)|*.csv|All Files (*.*)|*.*”;
DialogResult result = saveFileDialog1.ShowDialog();
if (result == DialogResult.OK){
SaveTheFile(saveFileDialog1.FileName);
}

The Filter property isn’t
hard to figure out. Just
compare what’s between the |
characters in the string with
what shows up in the window.

FileName
The ShowDialog() anacdtly the same
properties work ex ialog object.
as on the OpenFileD
The SaveFileDialog
object pops up the
standard Windows
“Save as…” dialog box.

The Title property lets
you change this text.

The ShowDialog()
method pops up
the dialog box and
opens the folder
specified in the
InitialDirectory
property.

When the user choo
file, its full path is sesasvea
in the FileName propertyd
.

Change the “Save as
type” list using the
Filter property.
The DialogResult
returned by the od
ShowDialog() metht
lets you figure ou
which button the
user clicked.

you are here 4   421

directory assistance

Use the built-in File and Director y classe s
to work with file s and directorie s
Like StreamWriter, the File class creates streams that let you work with files behind
the scenes. You can use its methods to do most common actions without having to create
the FileStreams first. Directory objects let you work with whole directories full of
files.

Things you can do with a File:
1

Find out if the file exists
You can check to see if a file exists using the
Exists() method. It’ll return true if it does
and false if it doesn’t.

2

Read from and write to the file
You can use the OpenRead() method to get data
from a file, or the Create() or OpenWrite()
method to write to the file.

3

Append text to the file
The AppendAllText() method lets you append
text to an already-created file. It even creates the file
if it’s not there when the method runs.

4

Get information about the file
The GetLastAccessTime() and
GetLastWriteTime() methods return the
date and time when the file was last accessed
and modified.

FileInfo works just like File

If you’re going to be doing a lot of work with
a file, you might want to create an instance
the FileInfo class instead of using the File of
class’s
static methods.
The FileInfo class does just about everyth
ing the
File class does except you have to instantiate
it to use it. You can create a new instance
of
FileInfo and access its Exists() method or
its
OpenRead() method in just the same way.
The only difference is that the File class
is faster for a small number of actions, and
FileInfo is better suited for big jobs.

Things you can do with a Director y:
1

Create a new directory
Create a directory using the CreateDirectory() method. All
you have to do is supply the path; this method does the rest.

2

Get a list of the files in a directory
You can create an array of files in a directory using the
GetFiles() method; just tell the method which directory you
want to know about and it will do the rest.

3

Delete a directory
Deleting a directory is really simple too. Just use the Delete() method.

422   Chapter 9

so
File is a static class, th
s
me
it’s just a set of thod
wi
that let you work ject
files. FileInfo is an ob and
that you instantiate, same as
its methods are the le.
the ones you see on Fi

reading and writing files

Q:

I still don’t get that {0} and {1} thing that was part of the

StreamWriter.

A:

When you’re printing strings to a file, you’ll often find yourself in
the position of having to print the contents of a bunch of variables. For
example, you might have to write something like this:

writer.WriteLine(“My name is ” + name +
“and my age is ” + age);
It gets really tedious and somewhat error-prone to have to keep using +
to combine strings. It’s easier to take advantage of {0} and {1}:

writer.WriteLine(
“My name is {0} and my age is {1}”,
name, age);
It’s a lot easier to read that code, especially when many variables are
included in the same line.

Q:

Why did you put an @ in front of the string that contained the
filename?

A:

When you add a string literal to your program, the compiler
converts escape sequences like \n and \r to special characters.
That makes it difficult to type filenames, which have a lot of backslash
characters in them. If you put @ in front of a string, it tells C# not to
interpret escape sequences. It also tells C# to include line breaks in
your string, so you can hit Enter halfway through the string and it’ll
include that as a line break in the output:

string twoLine = @"this is a string
that spans two lines.";

Q:
A:\r

And what do \n and \t mean again?

Those are escape sequences. \n is a line feed and \t is a
tab.
is a return character, or half of a Windows return—in Windows
text files, lines have to end with \r\n (like we talked about when we
introduced Environment.NewLine from Chapter 8). If you want
to use an actual backslash in your string and not have C# interpret it as the
beginning of an escape sequence, just do a double backslash: \\.

Q:

What was that in the beginning about converting a string to a
byte array? How would that even work?

A:

You’ve probably heard many times that files on a disk are
represented as bits and bytes. What that means is that when you write
a file to a disk, the operating system treats it as one long sequence
of bytes. The StreamReader and StreamWriter are
converting from bytes to characters for you—that’s called encoding and
decoding. Remember from Chapter 4 how a byte variable can store
any number between 0 and 255? Every file on your hard drive is one
long sequence of numbers between 0 and 255. It’s up to the programs
that read and write those files to interpret those bytes as meaningful
data. When you open a file in Notepad, it converts each individual byte
to a character—for example, E is 69 and a is 97 (but this depends on
the encoding…you’ll learn more about encodings in just a minute). And
when you type text into Notepad and save it, Notepad converts each of
the characters back into a byte and saves it to disk. And if you want to
write a string to a stream, you’ll need to do the same.

Q:
A:

If I’m just using a StreamWriter to write to a file, why
do I really care if it’s creating a FileStream for me?

If you’re only reading or writing lines to or from a text file in order,
then all you need are StreamReader and StreamWriter.
But as soon as you need to do anything more complex than that,
you’ll need to start working with other streams. If you ever need to
write data like numbers, arrays, collections, or objects to a file, a
StreamWriter just won’t do. But don’t worry, we’ll go into a lot
more detail about how that will work in just a minute.

Q:
A:

What if I want to create my own dialog boxes? Can I do that?

Yes, you definitely can. You can add a new form to your
project and design it to look exactly how you want. Then you
can create a new instance of it with new (just like you created
an OpenFileDialog object). Then you can call its
ShowDialog() method, and it’ll work just like any other dialog
box. We’ll talk a lot more about adding other forms to your program in
Chapter 13.

Q:
A:

Why do I need to worry about closing streams after I’m done
with them?

Have you ever had a word processor tell you it couldn’t open a file
because it was “busy”? When one program uses a file, Windows locks
it and prevents other programs from using it. And it’ll do that for your
program when it opens a file. If you don’t call the Close() method,
then it’s possible for your program to keep a file locked open until it
ends.
you are here 4   423

do it yourself notepad

.NET has two built-in classes with a bunch of static methods for working
with files and folders. The File class gives you methods to work with
files, and the Directory class lets you work with directories. Write
down what you think each of these lines of code does.
Code
if (!Directory.Exists(@“c:\SYP”)) {
Directory.CreateDirectory(@“c:\SYP”);
}
if (Directory.Exists(@“c:\SYP\Bonk”)) {
Directory.Delete(@“c:\SYP\Bonk”);
}

Directory.CreateDirectory(@“c:\SYP\Bonk”);
Directory.SetCreationTime(@“c:\SYP\Bonk”,
new DateTime(1976, 09, 25));

string[] files = Directory.GetFiles(@“c:\windows\”,
“*.log”, SearchOption.AllDirectories);
File.WriteAllText(@“c:\SYP\Bonk\weirdo.txt”,
@”This is the first line
and this is the second line
and this is the last line”);
File.Encrypt(@“c:\SYP\Bonk\weirdo.txt”);

See if you can guess what this one
does—you haven’t seen it yet.

File.Copy(@“c:\SYP\Bonk\weirdo.txt”,
@“c:\SYP\copy.txt”);
DateTime myTime =
Directory.GetCreationTime(@“c:\SYP\Bonk”);
File.SetLastWriteTime(@“c:\SYP\copy.txt”, myTime);

File.Delete(@“c:\SYP\Bonk\weirdo.txt”);

424   Chapter 9

What the code does

reading and writing files

Use file dialogs to open and save file s
(all with just a fe w line s of code)
You can build a program that opens a text file. It’ll let you make
changes to the file and save your changes, with very little code,
all using standard .NET controls. Here’s how:

Do this

Here’s a trick to make your TextBox fill up
the form. Drag a TableLayoutPanel from
the Containers toolbox onto the form, set
its Dock property to Fill, and use its Rows
and Columns property editors to give it two
rows and one column. Drag the TextBox into
the top cell. Then drag a FlowLayoutPanel
out of the Toolbox into the bottom cell, set
its Dock to Fill, set its FlowDirection
property to RightToLeft, and drag the two
buttons onto it. Set the size of the top row in the
TableLayoutPanel to 100%, and resize the
bottom row so that the two buttons just fit. Now
your editor will resize smoothly!

1

Build a simple form.
All you need is a TextBox and two Buttons. Drop the
OpenFileDialog and SaveFileDialog controls onto
the form, too. Double-click on the buttons to create their event
handlers and add a private string field called name to
the form. Don’t forget to put a using statement up top for
System.IO.

2

Hook the Open button up to the openFileDialog.
The Open button shows an OpenFileDialog and then uses File.
ReadAllText() to read the file into the text box:

This is a TextBox
with Multiline set
to true.

private void open_Click(object sender, EventArgs e) {
if (openFileDialog1.ShowDialog() == DialogResult.OK) {
name = openFileDialog1.FileName;
textBox1.Clear();
textBox1.Text = File.ReadAllText(name); Clicki
ng Open shows the
}
Op
enF
ileDialog control.
}

3

Now, hook up the Save button.
The Save button uses the File.WriteAllText() method to save the file:
private void save_Click(object sender, EventArgs e) {
if (saveFileDialog1.ShowDialog() == DialogResult.OK) {
name = saveFileDialog1.FileName;
File.WriteAllText(name, textBox1.Text);
}
}

4

Play with the other properties of the dialog boxes.
Use the Title property of the saveFileDialog to change the
text in the title bar.

±
±

Set the initialFolder property to have the OpenFileDialog
start in a specified directory.

±

Filter the OpenFileDialog so it will only show text files using the
Filter property.

The ReadAllText() and
WriteAllText() methods are
part of the File class. That’s
coming up on the next page.
We’ll look at them in more
detail in just a few pages.

If you don’t add a filter, then
the drop-down lists at the bottom
of the open and save dialog boxes
will be empty. Try using this filter:
“Text Files (*.txt)|*.txt”.

you are here 4   425

dispose in the proper receptacle

.NET has two built-in classes with a bunch of static methods for working
with files and folders. The File class gives you methods to work with
files, and the Directory class lets you work with directories. Your job
was to write down what each bit of code did.
Code

What the code does

if (!Directory.Exists(@”c:\SYP”)) {
Directory.CreateDirectory(@”c:\SYP”);
}

Check if the C:\SYP folder exists. If it
doesn’t, create it.

if (Directory.Exists(@”c:\SYP\Bonk”)) {
Directory.Delete(@”c:\SYP\Bonk”);
}

Check if the C:\SYP\Bonk folder exists. If
it does, delete it.

Directory.CreateDirectory(@”c:\SYP\Bonk”);

Create the directory C:\SYP\Bonk.

Directory.SetCreationTime(@”c:\SYP\Bonk”,
new DateTime(1976, 09, 25));

Set the creation time for the C:\SYP\Bonk
folder to September 25, 1976.

string[] files = Directory.GetFiles(@”c:\windows\”,
“*.log”, SearchOption.AllDirectories);

Get a list of all files in C:\Windows that
match the *.log pattern, including all
matching files in any subdirectory.

File.WriteAllText(@”c:\SYP\Bonk\weirdo.txt”,
@”This is the first line
and this is the second line
and this is the last line”);

Create a file called “weirdo.txt” (if it
doesn‘t already exist) in the C:\SYP\Bonk
folder and write three lines of text to it.

File.Encrypt(@”c:\SYP\Bonk\weirdo.txt”);

Take advantage of built-in Windows
encryption to encrypt the file “weirdo.txt”
using the logged-in account’s credentials.

File.Copy(@”c:\SYP\Bonk\weirdo.txt”,
@”c:\SYP\copy.txt”);

Copy the C:\SYP\Bonk\weirdo.txt file to
C:\SYP\Copy.txt.

DateTime myTime =
Directory.GetCreationTime(@”c:\SYP\Bonk”);

Declare the myTime variable and set it equal
to the creation time of the C:\SYP\Bonk
folder.

File.SetLastWriteTime(@”c:\SYP\copy.txt”, myTime);

Alter the last write time of the copy.txt
file in C:\SYP\ so it’s equal to whatever
time is stored in the myTime variable.

File.Delete(@”c:\SYP\Bonk\weirdo.txt”);

Delete the C:\SYP\Bonk\weirdo.txt file.

This is an alternative to using
a CryptoStream.

426   Chapter 9

reading and writing files

IDisposable make s sure your objects are disposed of properly
A lot of .NET classes implement a particularly useful interface called
IDisposable. It has only one member: a method called Dispose().
Whenever a class implements IDisposable, it’s telling you that there
are important things that it needs to do in order to shut itself down, usually
because it’s allocated resources that it won’t give back until you tell it to.
The Dispose() method is how you tell the object to release those resources.
You can use the “Go To Definition” feature in the IDE to show you the
official C# definition of IDisposable. Go to your project and type
“IDisposable” anywhere inside a class. Then right-click on it and select “Go
To Definition” from the menu. It’ll open a new tab with code in it. Expand all
of the code and this is what you’ll see:

namespace System

{

// Summary:

//

You’ll learn
more about
“Go To
Definition”
later on.

Declare an
object in a using
block and that
object’s Dispose()
method is called
automatically.

A lot of classes allocate important resources, like
memory, files, and other objects. That means they
take them over, and don’t give them back until
you tell them you’re done with those resources.

Defines a method to release allocated resources.

public interface IDisposable
{

// Summary:
//

Performs application-defined tasks

//

resetting unmanaged resources.

//

}

}

associated with freeing, releasing, or

void Dispose();

Any class that implements IDisposable will immediately
release any resources that it took over as soon as you
call its Dispose() method. It’s almost always the last
thing you do before you’re done with the object.

Go To Definition

There’s a handy feature in the IDE
definition for any variable, object, orthat lets you automatically jump to the
select “Go To Definition”, and the IDEmethod. Just right-click on it and
code that defines it. You can also pre will automatically jump right to the
ss F12 instead of using the menu.

al-lo-cate, verb.

to distribute resources
or duties for a particular
purpose. The programming
team was irritated at their project
manager because he allocated
all of the conference rooms for a
useless management seminar.
you are here 4   427

that’s a lot of vet appointments

Avoid file system errors with using statements
We’ve been telling you all chapter that you need to close your streams. That’s
because some of the most common bugs that programmers run across when they
deal with files are caused when streams aren’t closed properly. Luckily, C# gives
you a great tool to make sure that never happens to you: IDisposable and
the Dispose() method. When you wrap your stream code in a using
statement, it automatically closes your streams for you. All you need to do is
declare your stream reference with a using statement, followed by a block
of code (inside curly brackets) that uses that reference. When you do that, the
using statement automatically calls the stream’s Dispose() method
as soon as it finishes running the block of code. Here’s how it works:

s
A using statement is alwdeayclaration…
t
jec
followed by an ob

These “using” statements are
different from the ones at
the top of your code.

…and then a block of code
within curly braces.

using (StreamWriter sw = new StreamWriter(”secret_plan.txt”)) {
sw.WriteLine(“How I’ll defeat Captain Amazing”);
sw.WriteLine(“Another genius secret plan”);
sw.WriteLine(“by The Swindler”);
}

When the using statement ends,
the Dispose() method of the
object being used is run.

Every stream has a Dispose()
method that closes the stream. So
if you declare your stream in a using
statement, it will always close itself!

d
ct being used is poiningte
In this case, the obje
us
declared in the
to by sw—which wae sDispose() method of the
statement—so th n…which closes the stream.
Stream class is ru

Use multiple using statements for multiple objects
You can pile using statements on top of each other—you don’t need extra sets of curly
brackets or indents.
using (StreamReader reader = new StreamReader(“secret_plan.txt”))
using (StreamWriter writer = new StreamReader(“email.txt”))
{
// statements that use reader and writer
}

) on the
You don’t need to call Close(
statement
streams now, because the usily.ng
will close them automatical

428   Chapter 9

These statements
can use the object
created in the
using statement
above like any
normal object.

Any time you
use a stream,
you should
ALWAYS
declare it
inside a using
statement. That
makes sure it’s
always closed!

reading and writing files

Trouble at work
Meet Brian. He likes his job as a C# developer, but he loves taking
the occasional day off. His boss hates when people take vacation
days, so Brian’s got to come up with a good excuse.
That’s the ninth vet
appointment you’ve had
since March, son. If I find out
you’re lying to me, you’d better
start looking for a new job!

Sorry I’ve gotta leave
early, boss. My cat’s
got a vet appointment.

You can help Brian out by building a program
to manage his e xcuse s
Use what you know about reading and writing files to build an
excuse manager that Brian can use to keep track of which excuses
he’s used recently and how well they went over with the boss.

Sometimes Brian’s too
lazy to think up an
excuse. Let’s add a
button to load up a
random excuse from his
excuse folder.

Brian wants to keep
all of his excuses in
one place, so let’s let
him select a folder to
store all of them.
ve
Sa
an
se
cu
ex

The folder contains one text
file for each excuse. When
Brian clicks the Save button,
the current excuse is saved out
to the folder. The Open button
lets him open a saved excuse.

you are here 4   429

brian needs excuses

Build the excuse manager so Brian can manage his excuses at work.
1

2

Excuse

Description: string
Results: string
LastUsed: DateTime
ExcusePath: string

Build the form
This form has a few special features:
OpenFile(string)
≥≥ When the form’s first loaded, only the Folder button should be enabled—
Save(string)
disable the other three buttons until the user selects a folder.
≥≥ When the form opens or saves an excuse, it displays the file date for the excuse file using
a Label control with AutoSize set to False and BorderStyle set to Fixed3D.
≥≥ After an excuse is saved, the form pops up an “Excuse Written” message box.
≥≥ The Folder button brings up a folder browser dialog box. If the user selects a folder,
it enables the Save, Open, and Random Excuse buttons.
When you drag
≥≥ The form knows when there are unsaved changes. When there are no unsaved
a
text box to a
changes, the text on the form’s title bar is “Excuse Manager”. But when the user
form and doublehas changed any of the three fields, the form adds an asterisk (*) to the title bar.
click on it, you
The asterisk goes away when the data is saved or a new excuse is opened.
cre
ate a Changed
≥≥ The form will need to keep track of the current folder and whether or not the
event handler for
current excuse has been saved. You can figure out when the excuse hasn’t been
that field.
saved by using the Changed event handlers for the three input controls.

Create an Excuse class and store an instance of it in the form
Now add a CurrentExcuse field to the form to hold the current excuse. You’ll need three overloaded
constructors: one for when the form’s first loaded, one for opening up a file, and one for a random excuse.
Add methods OpenFile() to open an excuse (for the constructors to use), and Save() to save the excuse.
Then add this UpdateForm() method to update the controls (it’ll give you some hints about the class):

This parameter indicates wheth
private void UpdateForm(bool changed) {
if (!changed) {
or not the form has changed. er
this.description.Text = currentExcuse.Description; You’ll need a
field in your
Remember, the ! this.results.Text = currentExcuse.Results;
keep track of this status. form to
means NOT—so this.lastUsed.Value = currentExcuse.LastUsed;
this checks if if (!String.IsNullOrEmpty(currentExcuse.ExcusePath))
= File.GetLastWriteTime(currentExcuse.ExcusePath).ToString();
the excuse path FileDate.Text
builds
this.Text
=
“Excuse
Manager”;
is NOT null or }
Double-click on the input controls so the tIDE
lers for
hand
even
The
you.
empty.
Changed event handlers for
else
use
Exc
the
ge
chan
t
firs
this.Text = “Excuse Manager*”;
the three input controls will
up to
it’s
then
e)—
(tru
orm
this.formChanged = changed;
instance and then call UpdateF
.
form
}
your
to change the fields on

you

And make sure you initialize the excuse’s LastUsed value in the form’s constructor:

public Form1() {
InitializeComponent();
currentExcuse.LastUsed = lastUsed.Value;
}

3

Make the Folder button open a folder browser
When the user clicks on the Folder button, the form should pop up a “Browse for Folder” dialog
box. The form will need to store the folder in a field so that the other dialog boxes can use it.
When the form first loads, the Save, Open, and Random Excuse buttons are disabled, but if
the user selects a folder then the Folder button enables them.

430   Chapter 9

reading and writing files

4

Make the Save button save the current excuse to a file
Clicking the Save button should bring up the Save As dialog box.
≥≥ Each excuse is saved to a separate text file. The first line of the file is the excuse, the second is the
result, and the third is the date last used (using the DateTimePicker’s ToString() method).
The Excuse class should have a Save() method to save an excuse out to a specified file.
≥≥ When the Save As dialog box is opened, its folder should be set to the folder that the user
selected using the Folder button, and the filename should be set to the excuse plus a “.txt”
extension.
≥≥ The dialog box should have two filters: Text Files (*.txt) and All Files (*.*).
≥≥ If the user tries to save the current excuse but has left either the excuse or the result blank, the
form should pop up a warning dialog box:

tion icon by
You can display this ExclassamageBox.Show()
using the overloaded Me to specify a
method that allows you ter.
MessageBoxIcon parame
5

Make the Open button open a saved excuse
Clicking the Open button should bring up the Open dialog box.
≥≥ When the Open dialog box is opened, its folder should be set to the folder that the user
selected using the Folder button.
≥≥ Add an Open() method to the Excuse class to open an excuse from a given file.

≥≥ Use Convert.ToDateTime() to load the saved date into the DateTimePicker control.

≥≥ If the user tries to open a saved excuse but the current excuse hasn’t been saved, it pops up this
dialog box:

Show a Yes/No dialog box by using
the overloaded MessageBox.Show()
method that lets you specify the
MessageBoxButtons.YesNo parameter. If
the user clicks “No”, then Show() returns
DialogResult.No.

6

Finally, make the Random Excuse button load a random excuse
When the user clicks the Random Excuse button, it looks in the excuse folder, chooses one of the
excuses at random, and opens it.
≥≥ The form will need to save a Random object in a field and pass it to one of the overloaded
constructors of the Excuse object.
≥≥ If the current excuse hasn’t been saved, the button should pop up the same warning dialog
box as the Open button.
you are here 4   431

exercise solution

Build the excuse manager so Brian can manage his excuses at work.

private Excuse currentExcuse = new Excuse();
private string selectedFolder = “”;
private bool formChanged = false;
Random random = new Random();

The form uses fields to store the current Excuse
object to the selected folder and remember whether
or not the current excuse has changed, and to keep a
Random object for the Random Excuse button.

private void folder_Click(object sender, EventArgs e) {
folderBrowserDialog1.SelectedPath = selectedFolder;
ed a folder, e
ct
le
se
er
us
e
h
t
DialogResult result = folderBrowserDialog1.ShowDialog();
If
he folder namhree
t
s
ve
sa
if (result == DialogResult.OK) {
rm
fo
e
th
s the other t
le
selectedFolder = folderBrowserDialog1.SelectedPath;
ab
en
en
h
t
d
an
save.Enabled = true;
buttons.
open.Enabled = true;
randomExcuse.Enabled = true;
The two vertical bars mean OR—this is true if
}
description is empty OR results is empty.
}
private void save_Click(object sender, EventArgs e) {
if (String.IsNullOrEmpty(description.Text) || String.IsNullOrEmpty(results.Text)) {
MessageBox.Show(“Please specify an excuse and a result”,
“Unable to save”, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
Here’s where the filters are
}
set
for the Save As dialog.
saveFileDialog1.InitialDirectory = selectedFolder;
saveFileDialog1.Filter = “Text files (*.txt)|*.txt|All files (*.*)|*.*”;
saveFileDialog1.FileName = description.Text + “.txt”;
DialogResult result = saveFileDialog1.ShowDialog();
This will cause two rows to show up
if (result == DialogResult.OK) {
in the “Files of Type” drop-d
currentExcuse.Save(saveFileDialog1.FileName);
at
UpdateForm(false);
the bottom of the Save dialogown
box
:
MessageBox.Show(“Excuse written”);
one for Text Files (*.txt), and one
}
for
All Files (*.*).
}
private void open_Click(object sender, EventArgs e) {
if (CheckChanged()) {
openFileDialog1.InitialDirectory = selectedFolder;
openFileDialog1.Filter = “Text files (*.txt)|*.txt|All files (*.*)|*.*”;
openFileDialog1.FileName = description.Text + “.txt”;
DialogResult result = openFileDialog1.ShowDialog();
Use the DialogResult enum
if (result == DialogResult.OK) {
currentExcuse = new Excuse(openFileDialog1.FileName); returned by the Open and Save
UpdateForm(false);
dialog boxes to make sure you only
}
open or save if the user clicked
}
“OK”, and not “Cancel”.
}
private void randomExcuse_Click(object sender, EventArgs e) {
if (CheckChanged()) {
currentExcuse = new Excuse(random, selectedFolder);
UpdateForm(false);
}
}

432   Chapter 9

reading and writing files

private bool CheckChanged() {
if (formChanged) {
DialogResult result = MessageBox.Show(
“The current excuse has not been saved. Continue?”,
“Warning”, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (result == DialogResult.No)
return false;
}
MessageBox.Show() also returns a
Here are the three
return true;
DialogResult enum that we can check.
}
Changed event handlers
private void description_TextChanged(object sender, EventArgs e) {
currentExcuse.Description = description.Text;
UpdateForm(true);
}
private void results_TextChanged(object sender, EventArgs e) {
currentExcuse.Results = results.Text;
UpdateForm(true);
}
private void lastUsed_ValueChanged(object sender, EventArgs e) {
currentExcuse.LastUsed = lastUsed.Value;
UpdateForm(true);
Passing true to UpdateForm() tells it
}
to just mark the form as changed, but

for the three input
fields on the form. If any
of them are triggered,
that means the excuse
has changed, so first
we update the Excuse
instance and then we
call UpdateForm(), add
the asterisk to the
form’s title bar, and set
Changed to true.

not update the input controls.
class Excuse {
public string Description { get; set; }
public string Results { get; set; }
public DateTime LastUsed { get; set; }
public string ExcusePath { get; set; } The Random Excuse
bu
public Excuse() {
read all of the text filtteson uses Directory.GetFiles() to
ExcusePath = “”;
array, and then chooses a in the selected folder into an
random array index to op
}
en.
public Excuse(string excusePath) {
OpenFile(excusePath);
}
We made sure to use a using
public Excuse(Random random, string folder) {
statement every time we
string[] fileNames = Directory.GetFiles(folder, “*.txt”);
opened a stream. That way
OpenFile(fileNames[random.Next(fileNames.Length)]);
our files will always be closed.
}
private void OpenFile(string excusePath) {
this.ExcusePath = excusePath;
using (StreamReader reader = new StreamReader(excusePath)) {
Description = reader.ReadLine();
Results = reader.ReadLine();
LastUsed = Convert.ToDateTime(reader.ReadLine());
Here’s where the using
}
statement comes in. We
}
r
declared the StreamWrt,iteso
public void Save(string fileName) {
using (StreamWriter writer = new StreamWriter(fileName))
inside a using statemencalled
{
its Close() method is
writer.WriteLine(Description);
for us automatically!
writer.WriteLine(Results);
writer.WriteLine(LastUsed);
}
}
Did you call LastUsed.ToString()? Remember, WriteLine() calls it automatically!
}
you are here 4   433

i’m the decider

Writing file s usually involve s
making a lot of decisions
You’ll write lots of programs that take a single input, maybe from a
file, and have to decide what to do based on that input. Here’s code
that uses one long if statement—it’s pretty typical. It checks the
part variable and prints different lines to the file based on which
enum it uses. There are lots of choices, so lots of else ifs:
enum BodyPart {
Head,
Shoulders,
Knees,
Toes
}

Here’s an enum—we’ll want to compare
a variable against each of the four
members and write a different line to the
StreamWriter depending on which one it
matches. We’ll also write something different
if none of them match.

private void WritePartInfo(BodyPart part, StreamWriter writer) {
if (part == BodyPart.Head)
writer.WriteLine(“the head is hairy”);
else if (part == BodyPart.Shoulders)
writer.WriteLine(“the shoulders are broad”);
If we use a series of if/else
else if (part == BodyPart.Knees)
statements, then we end
writer.WriteLine(“the knees are knobby”);
up writing this “if (part
else if (part == BodyPart.Toes)
==[option])” over and over.
writer.WriteLine(“the toes are teeny”);
We’ve got a final else in
case
else
we didn’t find a matc
h.
writer.WriteLine(“some unknown part is unknown”);
}

What sort of things can go wrong when you write code
that has this many if/else statements? Think about typos
and bugs caused by brackets, a single equals sign, etc.

434   Chapter 9

reading and writing files

Use a switch statement to
choose the right option
Comparing one variable against a bunch of different values is
a really common pattern that you’ll see over and over again.
It’s especially common when you’re reading and writing
files. It’s so common, in fact, that C# has a special kind of
statement designed specifically for this situation.

There’s nothing about a switch
statement that’s specifically
related to files. It’s just a useful
C# tool that we can use here.

A switch statement lets you compare one variable against
many values in a way that’s compact and easy to read. Here’s
a switch statement that does exactly the same thing as the
series of if/else statements on the opposite page:
enum BodyPart
{
Head,
Shoulders,
Knees,
Toes,
}

A switch statement
compares ONE
variable against
MULTIPLE
possible values.

You’ll start with the switch
keyword followed by the variable
that’s going to be compared against
a bunch of different possible values.

private void WritePartInfo(BodyPart part, StreamWriter writer)
{
The body of the switch
switch (part) {
statement is a series
Every case ends case BodyPart.Head:
of
cases that compare
writer.WriteLine(“the head is hairy”);
with “break;” so
wha
tever follows the
break;
C# knows where
swit
ch keyword against
one case ends and case BodyPart.Shoulders:
a
par
ticular value.
writer.WriteLine(“the shoulders are broad”);
the next begins.
break;
case BodyPart.Knees:
You can also end a
writer.WriteLine(“the knees are knobby”);
case with “return”
break;
Each of these cases consists
– the program will case BodyPart.Toes:
of the case keyword
compile as long as
writer.WriteLine(“the toes are teeny”);
by the value
followed
there’s no way for
break;
and a colon.
compare
to
one case to “fall default:
is a series of
that
After
through” to the
writer.WriteLine(“some unknown part is unknown”); statements followed by
next one.
break;
“break;”. Those statements
}
will be executed if the case
Switch statements can end
}
matches the comparison value.

with a “default:” block that
gets executed if none of the
other cases are matched.

you are here 4   435

asleep at the switch

Use a switch statement to le t your deck of
cards re ad f rom a file or write itself out to one The switch
Writing a card out to a file is straightforward—just make a loop that writes the name
of each card out to a file. Here’s a method you can add to the Deck object that does
exactly that:
public void WriteCards(string filename) {
using (StreamWriter writer = new StreamWriter(filename)) {
for (int i = 0; i < cards.Count; i++) {
writer.WriteLine(cards[i].Name);
}
}
}

But what about reading the file in? It’s not quite so simple. That’s where the switch
statement can come in handy.

The switch statement starts wit
value to compare against. This swih a
statement is called from a methodtch
that has a suit stored in a string
.

statement lets
you test one
value against a
bunch of cases
and execute
different
statements
depending on
which one it
matches.

Suits suit;
switch (suitString) (
case “Spades”:
		
suit = Suits.Spades;
		
break;
Each of these case lines compares
case “Clubs”:
some value against the value in
		
suit = Suits.Clubs;
the switch line. If they match,
		
break;
it executes all of the following
statements until it hits a break.
case “Hearts”:
		
suit = Suits.Hearts;
		
break;
case “Diamonds”:
The default line comes at the end.
		
suit = Suits.Diamonds;
If none of the cases match, the
state
ments after the default get
		
break;
executed instead.
default:
		
MessageBox.Show(suitString + “ isn’t a valid suit!”);
}
436   Chapter 9

reading and writing files

Add an overloaded Deck() constructor that
re ads a deck of cards in f rom a file
You can use a switch statement to build a new constructor for the Deck
class that you wrote in the last chapter. This constructor reads in a file and
checks each line for a card. Any valid card gets added to the deck.
There’s a method that you can find on every string that’ll come in handy:
Split(). It lets you split the string into an array of substrings by passing it
a char[] array of separator characters that it’ll use to split the string up.

This line tells C# to split the nextCard
string using a space as a separator
character. That splits the string “Six
of Diamonds” into the array {“Six”, “of”,
“Diamonds”}.

public Deck(string filename) {
cards = new List();
StreamReader reader = new StreamReader(filename);
while (!reader.EndOfStream) {
bool invalidCard = false;
string nextCard = reader.ReadLine();
string[] cardParts = nextCard.Split(new char[] { ‘ ’ });
Values value = Values.Ace;
switch (cardParts[0]) {
case “Ace”: value = Values.Ace; break;
case “Two”: value = Values.Two; break;
case “Three”: value = Values.Three; break;
case “Four”: value = Values.Four; break;
case “Five”: value = Values.Five; break;
case “Six”: value = Values.Six; break;
case “Seven”: value = Values.Seven; break;
case “Eight”: value = Values.Eight; break;
case “Nine”: value = Values.Nine; break;
case “Ten”: value = Values.Ten; break;
case “Jack”: value = Values.Jack; break;
case “Queen”: value = Values.Queen; break;
case “King”: value = Values.King; break;
default: invalidCard = true; break;
}

}

}

Suits suit = Suits.Clubs;
switch (cardParts[2]) {
case “Spades”: suit = Suits.Spades; break;
case “Clubs”: suit = Suits.Clubs; break;
case “Hearts”: suit = Suits.Hearts; break;
case “Diamonds”: suit = Suits.Diamonds; break;
default: invalidCard = true; break;
}
if (!invalidCard) {
cards.Add(new Card(suit, value));
}

This switch statement
checks the first word
in the line to see if it
matches a value. If it
does, the right value
is assigned to the
value variable.

We do the same thing for
the third word in the line,
except we convert this
one to a suit.

you are here 4   437

p.s. i’ll find my frog

All that code just to read in one simple card?
That’s way too much work! What if my object has a
whole bunch of fields and values? Are you telling me I
need to write a switch statement for each of them?

There’s an easier way to store your objects in
files. It’s called serialization.
Instead of painstakingly writing out each field and value to
a file line by line, you can save your object the easy way by
serializing it out to a stream. Serializing an object is like
flattening it out so you can slip it into a file. And on the
other end, you can deserialize it, which is like taking it out
of the file and inflating it again.

438   Chapter 9

Ok, just to come clean here: There’s also a method called
Enum.Parse() — you’ll learn about it in Chapter 14 —
that will convert the string “Spades” to the enum value
Suits.Spades. But serialization still makes a lot more
sense here. You’ll find out more about that shortly....

reading and writing files

What happens to an object when it’s serialized?
It seems like something mysterious has to happen to an object in order to copy
it off of the heap and put it into a file, but it’s actually pretty straightforward.

1

Object on the heap

When you create an instance of an
object, it has a state. Everything
that an object “knows” is what makes
one instance of a class different from
another instance of the same class.

byte
has two eight.
t
c
e
j
b
o
This width and h
fields,

Object serialized

When C# serializes an object, it saves
the complete state of the object, so
that an identical instance (object) can be
brought back to life on the heap later.

1
0010010

1
10
10
01
00
0
1
0
00
01

Width

2

Height

0
0100011

file.dat

The instance variable va
for width and height arlues
saved to the file “file.d e
along with a little more at”,
info that the CLR ed
s
to restore the objectnelat
(like the type of the ob er
and each of its fields). ject

Object on the heap again

3

And later on…
Later—maybe days later, and in a
different program—you can go back to
the file and deserialize it. That pulls
the original class back out of the file
and restores it exactly as it was, with
all of its fields and values intact.
you are here 4   439

save the cheerleader

But what e xactly IS an object’s
state? What needs to be saved?
We already know that an object stores its state in its fields. So when an
object is serialized, every one of those fields needs to be saved to the file.
Serialization starts to get interesting when you have more complicated objects. 37
and 70 are bytes—those are value types, so they can just be written out to a file
as-is. But what if an object has an instance variable that’s an object reference? What
about an object that has five instance variables that are object references? What if
those object instance variables themselves have instance variables?
Think about it for a minute. What part of an object is potentially unique? Imagine
what needs to be restored in order to get an object that’s identical to the one that
was saved. Somehow everything on the heap has to be written to the file.

What has to happen for this Car object to be saved so
that it gets restored back to its original state? Let’s say
the car has three passengers and a 3-liter engine and
all-weather radial tires…aren’t those things all part of the
Car object’s state? What should happen to them?

object

Li st

o references s a h t c e j b The Car o ine object, an array to an Eng jects, and a List<> e of Tire ob er objects. Those ar of Passeng s state, too—what part of it them? happens to enger s Each of the passenger objects has its own references to other objects. Do those need to be saved, too? reading and writing files When an object is serialized, all of the objects it refers to ge t serialized, too… Some people call this whole group of connected objects a “graph.” …and all of the objects they refer to, and all of the objects those other objects refer to, and so on and so on. But don’t worry—it may sound complicated, but it all happens automatically. C# starts with the object you want to serialize and looks through its fields for other objects. Then it does the same for each of them. Every single object gets written out to the file, along with all the information C# needs to reconstitute it all when the object gets deserialized. to serialize When you ask C# , it looks for the Kennel objects a reference any field that ha . to another object ID ob Co Breed.Beagle 4 years old 32 pounds 14” tall Dog nnel object c t “Spike” Li st< Dog> objec t Each of the two Dog objects has references to a DoggyID object and a Collar object. They’ll need to get serialized along with each Dog. ggy Co Breed.Mutt 6 years old 18 pounds 11” tall Dog objec ID ob llar obje c t Do ct One of the fields of the Kennel object is this List that contains two Dog objects, so C# will need to serialize them, too. objec obje je Ke llar t ggy je Do ct “Fido” t r are the end DoggyID and Colladon’t have of the line—they other objects. references to any you are here 4   441 serialized for your protection Serialization le ts you re ad or write a whole object all at once You’re not just limited to reading and writing lines of text to your files. You can use serialization to let your programs copy entire objects to files and read them back in…all in just a few lines of code! There’s a tiny amount of prep work you need to do—add one [Serializable] line to the top of the class to serialize—but once you do that, everything’s ready to write. You’ll need a Binar yFormat ter object If you want to serialize an object—any object—the first thing you do is create an instance of BinaryFormatter. It’s really straightforward to do—and all it takes is one line of code (and an extra using line at the top of the class file). It’s quick to copy an object out to a file or read it in from one. You can serialize or deserialize it. using System.Runtime.Serialization.Formatters.Binary; ... BinaryFormatter formatter = new BinaryFormatter(); The File.Create() method creates a new Now just cre ate a stre am and re ad or write your objects open an exi file. You can sting one using File. Use the Serialize() method from the BinaryFormatter object to write any OpenWrite(). object out to a stream. using (Stream output = File.Create(filenameString)) { formatter.Serialize(output, objectToSerialize); } The Serialize() method takes an object and writes it out to a stream. That’s a whole lot easier And once you’ve got an object serialized out to a file, use the BinaryFormatter than building a method to write it object’s Deserialize() method to read it back in. The method returns a yourself! reference, so you need to cast the output so that it matches the type of the reference out variable you’re copying it to. using (Stream input = File.OpenRead(filenameString)) { SomeObj obj = (SomeObj)formatter.Deserialize(input); } When you use Deserialize() to read an object back from a stream, don’t forget to cast the return value to match the type of object you’re reading. 442   Chapter 9 reading and writing files If you want your class to be serializable, mark it with the [Serializable] at tribute An attribute is a special tag that you can add to the top of any C# class. It’s how C# stores metadata about your code, or information about how the code should be used or treated. When you add [Serializable] to the top of a class just above the class declaration, you’re telling C# that your class is safe for serialization. And you only use it with classes that include fields that are either value types (like an int, decimal, or enum) or other serializable classes. If you don’t add the attribute to the class you want to serialize, or if you include a field with a type that isn’t serializable, then your program will have an error when you try to run it. See for yourself… 1 Do this Create a class and serialize it Remember the Guy class from Chapter 3? Let’s serialize Joe so we can keep a file that knows how much money he’s got in his pocket even after you close your program. [Serializable] class Guy You need to add this attribute to the top of any class in order to serialize it. Here’s code to serialize it to a file called Guy_file.dat—add a “Save Joe” button and a “Load Joe” button to the form: using System.IO; using System.Runtime.Serialization.Formatters.Binary; ... private void saveJoe_Click(object sender, EventArgs e) { using (Stream output = File.Create(“Guy_File.dat”)) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(output, joe); } } private void loadJoe_Click(object sender, EventArgs e) { using (Stream input = File.OpenRead(“Guy_File.dat”)) { BinaryFormatter formatter = new BinaryFormatter(); joe = (Guy)formatter.Deserialize(input); } UpdateForm(); } 2 You’ll need these two using lines. The first one is for the file and stream methods, and the second is for serialization. Run the program and play around with it If Joe had two hundred dollars saved up from his transactions with Bob during your time running the program, it would be a pain to lose all that money just because you needed to exit. Now your program can save Joe out to a file and restore him whenever you want. you are here 4   443 i like milk on my serial Le t’s serialize and de serialize a deck of cards Take a deck of cards and write it out to a file. C# makes serializing objects really easy. All you need to do is create a stream and write out your objects. Do this 1 Create a new project and add the Deck and Card classes Right-click on the project in the Solution Explorer and choose “Add/Existing Item”, and add the Card and Deck classes (and the Suits and Values enums and CardComparer_bySuit and CardComparer_byValue interfaces) you used in Go Fish! in Chapter 8. You’ll also need to add the two card comparer classes, since Deck uses them. The IDE will copy the files into the new project—make sure you change the namespace line at the top of each class file to match your new project’s namespace. 2 Mark the classes serializable Add the [Serializable] attribute to both classes you added to the project. 3 Add a couple of useful methods to the form The RandomDeck method creates a random deck of cards, and the DealCards method deals all of the cards and prints them to the console. Random random = new Random(); private Deck RandomDeck(int number) { Deck myDeck = new Deck(new Card[] { }); for (int i = 0; i < number; i++) { myDeck.Add(new Card( (Suits)random.Next(4), (Values)random.Next(1, 14))); } return myDeck; } If you don’t do this, C# won’t let you serialize the classes to a file. This creates an empty deck and then adds some random cards to it usinge the Card class from th last chapter. private void DealCards(Deck deckToDeal, string title) { Console.WriteLine(title); The DealCards() while (deckToDeal.Count > 0) method deals each of { th e cards off of the Card nextCard = deckToDeal.Deal(0); deck and prints it to Console.WriteLine(nextCard.Name); } the console. Console.WriteLine(“------------------”); } 444   Chapter 9 4 reading and writing files OK, prep work’s done.. now serialize that deck Start by adding buttons to serialize a random deck to a file and read it back. Check the console output to make sure the deck you wrote out is the same as the deck you read. ject The BinaryFormatter ob with takes any object marked e—in the Serializable attribut and this case a Deck object— using writes it out to a stream its Serialize() method. private void button1_Click(object sender, EventArgs e) { Deck deckToWrite = RandomDeck(5); using (Stream output = File.Create(“Deck1.dat”)) { BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(output, deckToWrite); } DealCards(deckToWrite, “What I just wrote to the file”); } The BinaryFormatter’s private void button2_Click(object sender, EventArgs e) { Deserialize() method returns using (Stream input = File.OpenRead(“Deck1.dat”)) { an Object, which is just the BinaryFormatter bf = new BinaryFormatter(); gene ral type that every C# Deck deckFromFile = (Deck)bf.Deserialize(input); DealCards(deckFromFile, “What I read from the file”);object inherits from—which is } why we need to cast it to a } Deck object. 5 Now serialize a bunch of decks to the same file Once you open a stream, you can write as much as you want to it. You can serialize as many objects as you need into the same file. So now add two more buttons to write out a random number of decks to the file. Check the output to make sure everything looks good. private void button3_Click(object sender, EventArgs e) { Notice how the line that using (Stream output = File.Create(“Deck2.dat”)) { reads a single deck from BinaryFormatter bf = new BinaryFormatter(); the file uses (Deck) to cast for (int i = 1; i <= 5; i++) { Deck deckToWrite = RandomDeck(random.Next(1,10)); the e output of Deserialize() You can serializ bf.Serialize(output, deckToWrite); r to a Deck. That’s because te af one object DealCards(deckToWrite, “Deck #” + i + “ written”); Deseria lize() returns an another to the } object, but doesn’t necessarily . am same stre } know what type of object. } private void button4_Click(object sender, EventArgs e) { using (Stream input = File.OpenRead(“Deck2.dat”)) { As long as you cast the BinaryFormatter bf = new BinaryFormatter(); objects you read off the for (int i = 1; i <= 5; i++) { stream to the right type, Deck deckToRead = (Deck)bf.Deserialize(input); DealCards(deckToRead, “Deck #” + i + “ read”); there’s no limit to the number of objects you can } } serialize. } 6 Take a look at the file you wrote Open up Deck1.dat in Notepad (File.Create() created it in the bin\ Debug folder under your project folder). It may not be something you’d read on the beach, but it’s got all the information to restore your whole deck of cards. you are here 4   445 builds character Wait a minute. I’m not sure I like all this writing objects out to some weird file that looks like garbage when I open it up. When I wrote the deck of cards as strings, I could open up the output in Notepad and see everything in it. Isn’t C# supposed to make it easy for me to understand everything I’m doing? When you serialize objects out to a file, they’re written in a binary format. But that doesn’t mean it’s indecipherable—just compact. That’s why you can recognize the strings when you open up a file with serialized objects in it: that’s the most compact way C# can write strings to a file—as strings. But writing out a number as a string would be really wasteful. Any int can be stored in four bytes. So it would be odd if C# stored, say, the number 49,369,144 as an 8-character string that you could read—10 characters if you include commas. That would be a waste of space! .NET uses Unicode to encode a char or string into bytes. Luckily, Windows has a useful little tool to help us figure out how Unicode works. Open up the Character Map (it’s in the Start menu under Accessories / System Tools, or do Start/Run and type “charmap.exe”). Behind the Scenes When you look at all the letters and symbols that are used in languages all around the world, you realize just how many different things need to be written to a file just to store text. That’s why .NET encodes all of its strings and characters in a format called Unicode. Encoding just means taking the logical data (like the letter H) and turning it into bytes (the number 72). It needs to do that because letters, numbers, enums, and other data all end up in bytes on disk or in memory. And that’s why Character Map is useful—it shows you how letters are encoded into numbers. Select the Arial font and scroll down until you reach the Hebrew letters. Find the letter Shin and click on it. As soon as you click on the letter, its Unicode number shows up in the status bar. The Hebrew letter Shin is number 05E9. That’s a hexadecimal number—“hex” for short. You can convert it to decimal using the Windows calculator: open it up, put it in Scientific mode, click the “Hex” radio button, enter “05E9”, and then click “Dec”—it’s 1,513. 446   Chapter 9 Unicode is an industry standard developed by a non-profit group called the Unicode Consortium, and it works across programs and different computer platforms. Take a minute and look at their website: http://unicode.org/ reading and writing files .NET uses Unicode to store characters and te xt The two C# types for storing text and characters—string and char—keep their data in memory as Unicode. When that data’s written out as bytes to a file, each of those Unicode numbers is written out to the file. So start a new project and drag three buttons onto a form, and we’ll use the File.WriteAllBytes() and ReadAllBytes() methods to get a sense of exactly how Unicode data is written out to a file. 1 Do this! Write a normal string out to a file and read it back Use the same WriteAllText() method that you used in the text editor to have the first button write the string “Eureka!” out to a file called “eureka.txt”. Then create a new byte array called eurekaBytes, read the file into it, and then print out all of the bytes read: File.WriteAllText(“eureka.txt”, “Eureka!”); byte[] eurekaBytes = File.ReadAllBytes(“eureka.txt”); foreach (byte b in eurekaBytes) Console.Write(“{0} ”, b); Console.WriteLine(); The ReadAllBytes() method returns a reference to a new array of bytes that contains all of the bytes that were read in from the file. You’ll see these bytes written to the output: 69 117 114 101 107 97 33. Now open up the file in the Simple Text Editor that you wrote earlier in the chapter. It says “Eureka!” 2 Make the second button display the bytes as hex numbers It’s not just Character Map that shows numbers in hex. Almost anything you read that has to do with encoding data will show that data in hex, so it’s useful to know how to work with it. Make the code for the second button’s event handler in your program identical to the first one, except change the Console.Write() line so it looks like this instead: Hex uses the numbers 0 through 9 and Console.Write(“{0:x2} ”, b); letters A through F to represent numbers in base 16, so 6B is equal to 107. That tells Write() to print parameter 0 (the first one after the string to print) as a two-character hex code. So it writes the same seven bytes in hex instead of decimal: 45 75 72 65 6b 61 21 3 Make the third button write out Hebrew letters Go back to Character Map and double-click on the Shin character (or click the Select button). It’ll add it to the “Characters to copy” box. Then do the same for the rest of the letters in “Shalom”: Lamed (U+05DC), Vav (U+05D5), and Final Mem (U+05DD). Now add the code for the third button’s event handler. It’ll look exactly like button 2, except for one change. Click the “Copy” button in Character Map, and then paste the letters over “Eureka!” and add the Encoding.Unicode parameter, so it looks like this: File.WriteAllText(“eureka.txt”, “‫”שלום‬, Encoding.Unicode); Did you notice that the IDE pasted the letters in backward? That’s because it knows that Hebrew is read right-to-left, so any time it encounters Hebrew Unicode letters, it displays them right-to-left. Put your cursor in the middle of the letters—the left and right arrow keys reversed! That makes it a lot easier if you need to type in Hebrew. Now run the code, and look closely at the output: ff fe e9 05 dc 05 d5 05 dd 05. The first two characters are “FF FE”, which is the Unicode way of saying that we’re going to have a string of two-byte characters. The rest of the bytes are the Hebrew letters—but they’re reversed, so U+05E9 appears as e9 05. Now open the file up in your Simple Text Editor—it looks right! you are here 4   447 take a byte out of crime C# can use byte arrays to move data around Since all your data ends up encoded as bytes, it makes sense to think of a file as one big byte array. And you already know how to read and write byte arrays. te a byte array, Here’s the code to cr, eaand read data open an input streamh 6 of the array. into bytes 0 throug byte[] greeting; Hello!! greeting = File.ReadAllBytes(filename); 7 byte variables 72 101 for This is a static methodthe es Arrays that revers We’re order of the bytes. that the just using it to show the byte changes you make to t to the array get written ou file exactly. s the When the program wrfiitele, the a byte array out to der too. text is in reverse or 108 108 111 33 These numbers ar the Unicode numbee for the charactersrs in “Hello!!” Array.Reverse(greeting); File.WriteAllBytes(filename, greeting); 7 byte variables 33 33 111 108 108 101 72 !!olleH Now the bytes are in reverse order. 448   Chapter 9 33 Reversing the bytes in “Hello!!” only works because each of those characters is one byte long. Can you figure out why this won’t work for ‫?שלום‬ reading and writing files Use a Binar yWriter to write binar y data StreamWriter also encodes your data. It just specializes in text and text encoding. You could encode all of your strings, chars, ints, and floats into byte arrays before writing them out to files, but that would get pretty tedious. That’s why .NET gives you a very useful class called BinaryWriter that automatically encodes your data and writes it to a file. All you need to do is create a FileStream and pass it into the BinaryWriter’s constructor. Then you can call its methods to write out your data. So add another button to your program, and we’ll show you how to use BinaryWriter(). 1 Start by creating a Console Application and setting up some data to write to a file. int intValue = 48769414; string stringValue = “Hello!”; byte[] byteArray = { 47, 129, 0, 116 }; float floatValue = 491.695F; char charValue = ‘E’; 2 Do this! If you use File.Create(), it’ll start file—if there’s one there already, it’ll blow aitnew awa start a brand new one. There’s also the y and OpenWrite() method, which opens the exisFile. and starts overwriting it from the beginniting one ng. To use a BinaryWriter, first you need to open a new stream with File.Create(): using (FileStream output = File.Create(“binarydata.dat”)) using (BinaryWriter writer = new BinaryWriter(output)) { 3 Now just call its Write() method. Each time you do, it adds new bytes onto the end of the file that contain an encoded version of whatever data you passed it as a parameter. writer.Write(intValue); writer.Write(stringValue); writer.Write(byteArray); writer.Write(floatValue); } 4 writer.Write(charValue); Each Write() statement encodes one value into bytes, and then sends those bytes to the FileStream object. You can pass it any value type, and it’ll encode it automatically. The FileStream writes the bytes to the end of the file. Now use the same code you used before to read in the file you just wrote. byte[] dataWritten = File.ReadAllBytes(“binarydata.dat”); foreach (byte b in dataWritten) Console.Write(“{0:x2} “, b); Console.WriteLine(“ - {0} bytes”, dataWritten.Length); Console.ReadKey(); Here’s a hint: Strings can be different lengths, so the string has to start with a number to tell .NET how long it is. Also, you can look up the string and char Unicode values using Character Map. Write down the output in the blanks below. Can you figure out what bytes correspond to each of the five Write() statements? Mark each group of bytes with the name of the variable. __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ - ___ bytes you are here 4   449 an amalgam of data float and int values take up 4 bytes when you write them to a file. If you’d used long or double, then they’d take up 8 bytes each. 86 6c 6c 74 __ f6 __ d8 f5 __ 29 __ e8 __ 02 __ 06 __ 48 __ 65 __ __ __ 6f __ 21 __ 2f __ 81 __ 00 __ __ __ 43 __ 45 __ - 20 ___ bytes intValue stringValue byteArray charValue The first byte in the string is 6—that’s the length of the string. You can use Character Map to look up each of the characters in “Hello!”—it starts with U+0048 and ends with U+0021. If you use the Windows calculator to convert these bytes from hex to decimal, you can see that these are the numbers in byteArray. char holds a Unicode character, and ‘E’ only takes one byte—it’s encoded as U+0045. Use Binar yRe ader to re ad the data back in Don’t take our word for it. Replace the line that reads the float with a call to ReadInt32(). (You’ll need to change the type of floatRead to int.) Then you can see for yourself what it reads from the file. The BinaryReader class works just like BinaryWriter. You create a stream, attach the BinaryReader object to it, and then call its methods. But the reader doesn’t know what data’s in the file! And it has no way of knowing. Your float value of 491.695F was encoded as d8 f5 43 45. But those same bytes are a perfectly valid int—1,140,185,334. So you’ll need to tell the BinaryReader exactly what types to read from the file. Add one more button to your form, and have it read the data you just wrote. 1 Start out by setting up the FileStream and BinaryReader objects: using (FileStream input = File.OpenRead(“binarydata.dat”)) using (BinaryReader reader = new BinaryReader(input)) { 2 You tell BinaryReader what type of data to read by calling its different methods. int intRead = reader.ReadInt32(); string stringRead = reader.ReadString(); byte[] byteArrayRead = reader.ReadBytes(4); float floatRead = reader.ReadSingle(); char charRead = reader.ReadChar(); 3 Each value type has its own met in BinaryReader() that returns thehod data in the correct type. Most don’t nee any parameters, but ReadBytes() takd one parameter that tells BinaryReaderes how many bytes to read. You tell BinaryReader what type of data to read by calling its different methods. Console.Write(“int: {0} string: {1} bytes: ”, intRead, stringRead); foreach (byte b in byteArrayRead) Console.Write(“{0} ”, b); Console.Write(“ float: {0} char: {1} ”, floatRead, charRead); } Console.ReadKey(); Here’s the output that gets printed to the console: int: 48769414 450   Chapter 9 string: Hello! bytes: 47 129 0 116 float: 491.695 char: E reading and writing files You can re ad and write serialized file s manually, too Serialized files don’t look so pretty when you open them up in Notepad. You’ll find all the files you write in your project’s bin\Debug folder—let’s take a minute and get more acquainted with the inner workings of a serialized file. 1 Do this! Serialize two Card objects to different files Use the serialization code you’ve already written to serialize the Three of Clubs to three-c.dat and Six of Hearts to six-h.dat. Check to make sure that both files were written out and are now in a folder, and that they both have the same file size. Then open one of them in Notepad: There are some words in the file, but it’s mostly unreadable. 2 Write a loop to compare the two binary files We used the ReadByte() method to read the next byte from a stream—it returns an int that contains the value of that byte. We also used the stream’s Length field to make sure we read the whole file. byte[] firstFile = File.ReadAllBytes(“three-c.dat”); byte[] secondFile = File.ReadAllBytes(“six-h.dat”); for (int i = 0; i < firstFile.Length; i++) if (firstFile[i] != secondFile[i]) Console.WriteLine(“Byte #{0}: {1} versus {2}”, i, firstFile[i], secondFile[i]); The two files are read into two different byte arrays, so they can be compared byte by byte. Since the same class was serialized to two different files, they’ll be almost identical…but let’s see just HOW identical they are. This loop examines the first byte from each of the files and compares them, then the second byte, then the third, etc. When it finds a difference, it writes a line to the console. When you write to a file, you don’t always start from a clean slate! Be careful if you use File.OpenWrite(). It doesn’t delete the file—it just starts overwriting the data starting at the beginning. That’s why we’ve been using File.Create()—it creates a new file. We’re not done yet—flip the page! you are here 4   451 celebrate our differences Find where the file s dif fer, and use that information to alter them The loop you just wrote pinpoints exactly where the two serialized Card files differ. Since the only difference between the two objects were their Suit and Value fields, then that should be the only difference in their files, too. So if we find the bytes that hold the suit and value, we should be able to change them to make a new card with whatever suit and value we want! 3 You can also serialize your objects to XML. Flip to leftover #9 in the appendix to learn more about it. Take a look at the console output to see how the two files differ The console should show that two bytes differ: Byte #322: 1 versus 3 Byte #382: 3 versus 6 That should make a lot of sense! Go back to the Suits enum from the last chapter, and you’ll find the value for Clubs is 1 and the value for Hearts is 3, so that’s the first difference. And the second difference—six versus three—is pretty obviously the card’s value. You might see different byte numbers, which isn’t surprising: you might be using a different namespace, which would change the length of the file. Remember how the namespace was included as part of the serialized file? If your namespace is diff then the byte numbers will be different, too. erent, 4 If you found different byte numbers in step #3, substitute them in here. Hmm, if byte #322 in the serialized file represents the suit, then we should be able to change the suit of the card by reading that file in, changing that one byte, and writing it out again. (Remember, your own serialized file might store the suit at a different location.) Write code to manually create a new file that contains the King of Spades We’ll take one of the arrays that we read, alter it to contain a new card, and write it back out. firstFile[322] = (byte)Suits.Spades; firstFile[382] = (byte)Values.King; File.Delete(“king-s.dat”); File.WriteAllBytes(“king-s.dat”, firstFile); Now deserialize the card from king-s.dat and see if it’s the King of Spades! 452   Chapter 9 Now that you know which bytes contain the suit and value, you can change just those bytes in the array before it gets written out to king-s.dat. reading and writing files Working with binar y file s can be trick y What do you do if you have a file and you aren’t quite sure what’s inside it? You don’t know what application created it, and you need to know something about it—but when you open it in Notepad, it looks like a bunch of garbage. What if you’ve exhausted all your other options, and really need to just look inside? Looking at that picture, it’s pretty clear that Notepad just isn’t the right tool. Here’s the serialized card, opened up in Notepad. That’s not going to be useful at all. You can make out a few things—like the enum names (“Suit” and “Value”), and the name of the namespace we used (“Serialize_a_ deck_of_cards”). But that’s not all that helpful. There’s another option—it’s a format called a “hex dump,” and it’s a pretty standard way to look at binary data. It’s definitely more informative than looking at the file in Notepad. Hexadecimal—or “hex”—is a convenient way to display bytes in a file. Every byte takes 2 characters to display in hex, so you can see a lot of data in a really small space, and a format that makes it easy to spot patterns. Also, it’s useful to display binary data in rows that are 8, 16, or 32 bytes long because most binary data tends to break down in chunks of 4, 8, 16, or 32…like all the types in C#. For example, an int takes up 4 bytes, and is 4 bytes long when serialized on disk. Here’s what that same file looks like as a hex dump, using one of any number of free hex dump programs available for Windows: You can immediately see the numeric value of each byte in the file. The number at the beginning of each line is the offset (or distance into the file) of the first byte in the line. You still get to see the original text, but the garbage characters are replaced with dots. you are here 4   453 69 73 6e 27 74 20 74 68 69 73 20 66 75 6e 3f 0a Use file stre ams to build a he x dumper A hex dump is a hexadecimal view of the contents of a file, and it’s a really common way for programmers to take a deep look at a file’s internal structure. Most operating systems ship with a built-in hex dump utility. Unfortunately, Windows doesn’t. So let’s build one! How to make a he x dump Start with some familiar text: We the People of the United States, in Order to form a more perfect Union... Here’s what a hex dump of that text would look like: Again, you can immediately see the numeric value of each byte in the file. 0000: 0010: 0020: 0030: 0040: 57 20 65 66 65 65 74 73 6f 63 20 68 2c 72 74 74 65 20 6d 20 68 20 69 20 55 65 55 6e 61 6e 20 6e 20 20 69 50 69 4f 6d 6f ------ 65 74 72 6f 6e We’ll add the number at the beginning of each line by using the offset of the first byte in the line. 6f 65 64 72 2e 70 64 65 65 2e 6c 20 72 20 2e 65 53 20 70 20 74 74 65 6f 61 6f 72 66 74 20 66 We the People of the United Stat es, in Order to form a more perf ect Union... Each of those numbers—57, 65, 6F—is the value of one byte in the file. The reason some of the “numbers” have letter values is that they’re hexadecimal (or hex). That’s just another way of writing a number. Instead of using ten digits from 0 to 9, it uses sixteen digits from 0 to 9 plus the letters A through F. And we’ll need to replace the garbage characters with periods. Each line in our hex dump represents sixteen characters in the input that was used to generate it. In our dump, the first four characters are the offset in the file—the first line starts at character 0, the next at character 16 (or hex 10), then character 32 (hex 20), etc. (Other hex dumps look slightly different, but this one will do for us.) Working with he x You can put hex numbers directly into your program—just add the characters 0x (a zero followed by an x) in front of the number: int j = 0x20; MessageBox.Show(“The value is ” + j); When you use the + operator to concatenate a number into a string, it gets converted to decimal. You can use the static String. Format() method to convert your number to a hex-formatted string instead: string h = String.Format(“{0:x2}”, j); 454   Chapter 9 String.Format() uses parameters just like Console.WriteLine(), so you don’t need to learn anything new to use it. reading and writing files Stre amRe ader and Stre amWriter will do just fine (for now) Our hex dumper will write its dump out to a file, and since it’s just writing text a StreamWriter will do just fine. But we can also take advantage of the ReadBlock() method in StreamReader. It reads a block of characers into a char array—you specify the number of characters you want to read, and it’ll either read that many characters or, if there are fewer than that many left in the file, it’ll read the rest of the file. Since we’re displaying 16 characters per line, we’ll read blocks of 16 characters. So add one more button to your program—add this hex dumper to it. Change the first two lines so that they point to real files on your hard drive. Start with a serialized Card file. Then see if you can modify it to use the Open and Save As dialog boxes. The reason the method’s called “ReadBlock()” is that when you call it, it “blocks” (which means it keeps executing and doesn’t return to your program) until it’s either read all the characters you asked for or run out of data to read. using (StreamReader reader = new StreamReader(@”c:\files\inputFile.txt”)) using (StreamWriter writer = new StreamWriter(@”c:\files\outputFile.txt”, false)) { A StreamReader’s EndOfStream property returns false if there are characters still left to read in the file. int position = 0; while (!reader.EndOfStream) { char[] buffer = new char[16]; This ReadBlock() call reads up to 16 characters into a char array. int charactersRead = reader.ReadBlock(buffer, 0, 16); writer.Write(“{0}: ”, String.Format(“{0:x4}”, position)); position += charactersRead; for (int i = 0; i < 16; i++) { This loop goes through the characters and prints each of them to a line in the output. if (i < charactersRead) { string hex = String.Format(“{0:x2}”, (byte)buffer[i]); } writer.Write(hex + “ ”); else writer.Write(“ ”); th a value under Some characters wiwe ’ll replace all 32 don’t print, so riod. of them with a pe if (i == 7) { writer.Write(“-- ”); } } The static String.Format method converts numbers to strings. “{0:x4}” tells Format() to print the second parameter—in this case, position—as a 4-character hex number. You can convert a char[] array to a string by passing it to the overloaded constructor for string. if (buffer[i] < 32 || buffer[i] > 250) { buffer[i] = ‘.’; } string bufferContents = new string(buffer); } } writer.WriteLine(“ ” + bufferContents.Substring(0, charactersRead)); rns a piece of the string. Every string has a Substring method that retuad characters starting In this case, it returns the first charactersRe top the loop to see at the beginning (position 0). (Look back at themethodofreturns the number where charactersRead is set—the ReadBlock() of characters that it read into the array.) you are here 4   455 build hexdump right Use Stre am.Re ad() to re ad byte s f rom a stre am Do this The hex dumper works just fine for text files. But there’s a problem. Try using File. WriteAllBytes() to write an array of bytes with values over 127 to a file and then run it through your dumper. Uh oh—they’re all read in as “fd”! That’s because StreamReader is built to read text files, which only contain bytes with values under 128. So let’s do this right—by reading the bytes directly from the stream using the Stream.Read() method. And as a bonus, we’ll build it just like a real hex dump utility: we’ll make it take a filename as a command-line argument. Create a new Console Application and call it hexdumper. The code for the program is on the facing page. Here’s what it will look like when you run the program: If you run hexdumper without any arguments, it returns an error message and exits with an error code. It also exits with an error if you pass it the name of a file that doesn’t exist. If you pass it a valid filename, it’ll write a hex dump of the contents of the file to the console. Normally we use Console. WriteLine() to print to the console. But we’ll use Console.Error. WriteLine() to print error messages so they don’t get redirected if we use > or >> to redirect the output. Using command-line arguments Every time you create a new Console method that has this declaration: statApplication project, Visual Studio creates a Program class with an entry arguments, the args parameter will con ic void Main(string[] args). If you run your program with command-line point any Windows Forms Application project tain those arguments. And it’s not just for Console Applications, eith er: open up ’s Program.cs file, and you’ll see the same thing. You’ll want to pass command-line arg program in the IDE’s debugger, chooseuments when you’re debugging your program. To pass arguments when you run “Properties…” from the Project men u and enter them on the Debug tab your . 456   Chapter 9 Command-line arguments will be passed using the args parameter. If args.Length is not equal to 1, then either zero or more than one argument was passed on the command line. Notice how we’re using Console. Error.WriteLine() here. reading and writing files This Exit() method quits the static void Main(string[] args) program. If you pass it an int, it { return that error code (which will if (args.Length != 1) is useful when writing command { scripts and batch files). Console.Error.WriteLine(“usage: hexdmper file-to-dump”); System.Environment.Exit(1); } Let’s make sure that a if (!File.Exists(args[0])) valid file was passed. If { it doens’t exist, print a Console.Error.WriteLine(“File does not exist: {0}”, args[0]); different error message System.Environment.Exit(2); and return a different We don’t need a } exit code. StreamReader because using (Stream input = File.OpenRead(args[0])) we’re reading bytes { directly from the stream. Use the Stream.Read() method int position = 0; to read bytes directly into byte[] buffer = new byte[16]; a buffer. Notice how this while (position < input.Length) time the buffer is a byte { array. That makes sense—we’re int charactersRead = input.Read(buffer, 0, buffer.Length); reading bytes, not characters if (charactersRead > 0) from a text file. { Console.Write("{0}: ", String.Format("{0:x4}", position)); position += charactersRead; This part of the program is exactly the same, except the buffer contains bytes and not characters (but String.Format() does the right thing in either case). for (int i = 0; i < 16; i++) { if (i < charactersRead) { string hex = String.Format("{0:x2}", (byte)buffer[i]); Console.Write(hex + " "); } else Console.Write(" "); if (i == 7) Console.Write("-- "); } } } } if (buffer[i] < 32 || buffer[i] > 250) { buffer[i] = (byte)'.'; } } string bufferContents = Encoding.UTF8.GetString(buffer); Console.WriteLine(" " + bufferContents.Substring(0, charactersRead)); This is an easy way to convert a byte array to a string. It’s part of Encoding.UTF8 (or another Unicode encoding, or ASCII, or another encoding) because different encodings can map the same byte array to different strings. you are here 4   457 no dumb questions Q: Why didn’t I have to use the Close() method to close the file after I used File.ReadAllText() and File.WriteAllText()? A: The File class has several very useful static methods that automatically open up a file, read or write data, and then close it automatically. In addition to the ReadAllText() and WriteAllText() methods, there are ReadAllBytes() and WriteAllBytes(), which work with byte arrays, and ReadAllLines() and WriteAllLines(), which read and write string arrays, where each string in the array is a separate line in the file. All of these methods automatically open and close the streams, so you can do your whole file operation in a single statement. Q: If the FileStream has methods for reading and writing, why do I ever need to use StreamReader and StreamWriter? A: The FileStream class is really useful for reading and writing bytes to binary files. Its methods for reading and writing operate with bytes and byte arrays. But a lot of programs work exclusively with text files— like the first version of the Excuse Generator, which only wrote strings out to files. That’s where the StreamReader and StreamWriter come in really handy. They have methods that are built specifically for reading and writing lines of text. Without them, if you wanted to read a line of text in from a file, you’d have to first read a byte array and then write a loop to search through that array for a linebreak—so it’s easy to see how they make your life easier. 458   Chapter 9 Q: When should I use File, and when should I use FileInfo? A: File The main difference between the and FileInfo classes is that the methods in File are static, so you don’t need to create an instance of them. On the other hand, FileInfo requires that you instantiate it with a filename. In some cases, that would be more cumbersome, like if you only need to perform a single file operation (like just deleting or moving one file). On the other hand, if you need to do many file operations to the same file, then it’s more efficient to use FileInfo, because you only need to pass it the filename once. You should decide which one to use based on the particular situation you encounter. In other words, if you’re doing one file operation, use File. If you’re doing a lot of file operations in a row, use FileInfo. Q: Back up a minute. Why was “Eureka!” written out with one byte per character, but when I wrote out the Hebrew letters they took up two bytes? And what was that “FF FE” thing at the beginning of the bytes? A: What you’re seeing is the difference between two closely related Unicode encodings. Plain English letters, numbers, normal punctuation marks, and some standard characters (like curly brackets, ampersands, and other things you see on your keyboard) all have very low Unicode numbers—between 0 and 127. (If you’ve used ASCII before, they’re the same as the ASCII characters.) If a file only contains those Unicode characters with low numbers, it just prints out their bytes. Things get a little more complicated when you add higher-numbered Unicode characters into the mix. One byte can only hold a number between 0 and 255. But two bytes in a row can store numbers between 0 and 65,536—which, in hex, is FFFF. The file needs to be able to tell whatever program opens it up that it’s going to contain these higher-numbered characters. So it puts a special reserved byte sequence at the beginning of the file: “FF FE”. That’s called the “byte order mark.” As soon as a program sees that, it knows that all of the characters are encoded with two bytes each. (So an E is encoded as 00 45—with leading zeroes.) Q: A: Why is it called a byte order mark? Remember how your bytes were reversed? Shin’s Unicode value of U+05E9 was written to the file as E9 05. That’s called “little endian.” Go back to the code that wrote out those bytes and change the third parameter to WriteAllText(): Encoding.BigEndianUnicode. That tells it to write the data out in “big endian,” which doesn’t flip the bytes around.You’ll see the bytes come out as “05 E9” this time. You’ll also see a different byte order mark: “FE FF”. And your Simple Text Editor is smart enough to read both of them! If you’re writing a string that only has Unicode characters with low numbers, it writes one byte per character. But if it’s got high-numbered characters, they’ll be written using two or more bytes each. by default. You The encoding is called UTF-8, which .NET usesencod ing by passing rent can tell File.WriteAllText() to use a diffe t Unicode abou more it a different Encoding value. You can learn encodings at http://unicode.org. reading and writing files Change Brian’s Excuse Manager so it uses binary files with serialized Excuse objects instead of text files. 1 Make the Excuse class serializable Mark the Excuse class with the [Serializable] attribute to make it serializable. Also, you’ll need to add the using line: using System.Runtime.Serialization.Formatters.Binary; 2 Change the Excuse.Save() method to serialize the excuse When the Save() method writes a file out to the folder, instead of using StreamWriter to write the file out, have it open a file and serialize itself out. You’ll need to figure out how the current class can deserialize itself. 3 Change the Excuse.OpenFile() method to deserialize an excuse You’ll need to create a temporary Excuse object to deserialize from the file, and then copy its fields into the current class. 4 Now just change the form so it uses a new file extension There’s just one very small change you need to make to the form. Since we’re no longer working with text files, we shouldn’t use the .txt extension anymore. Change the dialog boxes, default filenames, and directory search code so that they work with *.excuse files instead. Hint: What keyword can you use inside of a class that returns a reference to itself? Wow, that was really easy! All the code for saving and opening excuses was inside the Excuse class. I just had to change the class—I barely had to touch the form at all. It’s like the form doesn’t even care how the class saves its data. It just passes in the filename and knows everything will get saved properly. That’s right! Your code was very easy to change because the class was well encapsulated. When you’ve got a class that hides its internal operations from the rest of the program and only exposes the behavior that needs to be exposed, it’s called a well-encapsulated class. In the Excuse Manager program, the form doesn’t have any information about how excuses are saved to files. It just passes a filename into the excuse class, and the class takes care of the rest. That makes it very easy to make big changes to how your class works with files. The better you encapsulate your classes, the easier they are to alter later on. Remember how encapsulation was one of the four core OOP principles? Here’s an example of how using those principles makes your programs better. you are here 4   459 exercise solution Change Brian’s Excuse Manager so it uses binary files with serialized Excuse objects instead of text files. You only need to change these three statements in the form: two in the Save button’s Click event, and one in the Open button’s—they just change the dialogs to use the .excuse extension, and set the default save filename. private void save_Click(object sender, EventArgs e) { // existing code saveFileDialog1.Filter = “Excuse files (*.excuse)|*.excuse|All files (*.*)|*.*”; saveFileDialog1.FileName = description.Text + “.excuse”; // existing code d } Standard savexan do es private void open_Click(object sender, EventArgs e) { open dialog bo . // existing code the trick here openFileDialog1.Filter = “Excuse files (*.excuse)|*.excuse|All files (*.*)|*.*”; // existing code } Here’s the entire Excuse class. [Serializable] The only change to the form class Excuse { is to have it change the file public string Description { get; set; } ext ension it passes to the public string Results { get; set; } Exc use class. public DateTime LastUsed { get; set; } public string ExcusePath { get; set; } public Excuse() { ExcusePath = “”; } public Excuse(string excusePath) { OpenFile(excusePath); } public Excuse(Random random, string folder) { string[] fileNames = Directory.GetFiles(folder, “*.excuse”); OpenFile(fileNames[random.Next(fileNames.Length)]); } The constructor for loading private void OpenFile(string excusePath) { random excuses needs to look this.ExcusePath = excusePath; for the “.excuse” extension BinaryFormatter formatter = new BinaryFormatter(); Excuse tempExcuse; instead of “*.txt” files. using (Stream input = File.OpenRead(excusePath)) { tempExcuse = (Excuse)formatter.Deserialize(input); } Description = tempExcuse.Description; Results = tempExcuse.Results; LastUsed = tempExcuse.LastUsed; } public void Save(string fileName) { BinaryFormatter formatter = new BinaryFormatter(); using (Stream output = File.OpenWrite(fileName)) { formatter.Serialize(output, this); We pass in “this” } because we want this } class to be serialized. } 460   Chapter 9 reading and writing files Filecross 1 2 3 4 5 6 8 7 9 10 11 12 13 14 15 16 17 18 19 Across 6. The method in the File class that checks whether or not a Across specific file is on the drive 6. The method in the File class that checks whether or a specific file is the drive 9. This statement not indicates the end of on a case inside a switch statement Down 1.Down This class has a method that writes a type to a file This static class method has a method writes anythat value typean array backward Array class turns 2.1. The in the that to a file 3.2.The gets run whenever 9. This statement indicates the end of a case inside a The event statichandler methodthat in the Array class that someone turns an modifies the data in backwards an input control FileStream inherits from 10. The abstract class thatstatement switch array 10. The abstract The event handler that gets run whenever 4.3. This class has many static methods that let someone you manipulate folders 11. A non-visual control that lets youclass pop that up theFileStream standard inherits Windowsfrom 11. A nonvisual control that lets you pop up the modifies the data in an input control “Save As” dialog box 5. Using this OOP principle makes it a lot easier to maintain your code standard Windows "Save As" dialog box 4. This class has many static methods that let you How you write numbers in base-16 15. How you write 15. numbers in base-16 7.manipulate If you don’tfolders use this attribute to indicate that a class can be written to 16. If you don't call this method, your stream could be Using this OOP principle makes it a lotan easier a5.stream, BinaryFormatter will generate errorto 16. If you don’t calllocked this method, your stream could be locked open so open so other methods or programs can't open it maintain your code other methods or programs can’t open itmethod that reads data into a 8.7. This method to reads an object 17. The StreamReader If youBinaryFormatter don't use this attribute indicate that afrom classa stream char[] arraymethod that reads data into a char[] can be written to a stream, BinaryFormatter will 17. The StreamReader 12. \n and \r are examples of this kind of sequence 18. An encoding system that assigns a uniue number to generate an error array each character 8. This method an object in from 13. ThisBinaryFormatter class lets you perform all reads the operations the File class for stream file 18. An encoding system that assigns a unique number to each character aa specific 12. \n and \r are examples of this kind of sequence 19. Use this statement to indicate which statements should be executed 14. This method sends text to a stream followed by a line break when the value being tested in a switch statement does not match any of the cases you are here 4   461 exercise solution Filecross solution 1 2 B 5 I 8 E E D N N V E A C E A M R Y P S R W 11 I R U 10 S T E A R E S I T A I E T Z A V R 9 F B I R L F 15 H O E 12 E A E A D X L T 7 S E R G C I E T A I A L C O G L R I Y Z I A 14 W A L P R B E X A D E C O I M A L L T 16 N B S N D K I E C L O S F R E D R I N 17 6 S I E E 4 C H 13 L L 3 R E E L C K 18 U N I C O D E F A U L N 19 D 462   Chapter 9 E T Across Down 6. The method in the File class that checks whether or not a specific file is on the drive [exists] 9. This statement indicates the end of a case inside a switch statement [break] 10. The abstract class that FileStream inherits from [stream] 11. A nonvisual control that lets you pop up the standard Windows "Save As" dialog box [savefiledialog] 15. How you write numbers in base-16 [hexadecimal] 16. If you don't call this method, your stream could be locked open so other methods or programs can't open it [close] 17. The StreamReader method that reads data into a char[] array [readblock] 1. This class has a method that writes any value type to a file [binarywriter] 2. The static method in the Array class that turns an array backwards [reverse] 3. The event handler that gets run whenever someone modifies the data in an input control [changed] 4. This class has many static methods that let you manipulate folders [directory] 5. Using this OOP principle makes it a lot easier to maintain your code [encapsulation] 7. If you don't use this attribute to indicate that a class can be written to a stream, BinaryFormatter will generate an error [serializable] 8. This BinaryFormatter method reads an object from a stream [deserialize] 10 exception handling Putting out fires gets old Good thing I wrote code to handle my HangoverException. Programmers aren’t meant to be firefighters. You’ve worked your tail off, waded through technical manuals and a few engaging Head First books, and you’ve reached the pinnacle of your profession: master programmer. But you’re still getting panicked phone calls in the middle of the night from work because your program crashes, or doesn’t behave like it’s supposed to. Nothing pulls you out of the programming groove like having to fix a strange bug…but with exception handling, you can write code to deal with problems that come up. Better yet, you can even react to those problems, and keep things running. this is a new chapter   463 mo’ programs mo’ problems Brian needs his e xcuse s to be mobile Brian recently got reassigned to the international division. Now he flies all over the world. But he still needs to keep track of his excuses, so he installed the program you built on his laptop and takes it with him everywhere. Work’s boring today. I want to go scuba diving. Time to fire up the Excuse Generator. Brian’s got the excuse Generator running on his laptop. Same ol’ Brian… always looking for an excuse to get out of work. But the program isn’t working! Brian clicks the “Random Excuse” button, and gets a pretty nasty looking error. Something about not finding his excuses. What gives? An unhandled exception…must have been a problem we didn’t account for. 464   Chapter 10 exception handling Here’s another example of some broken code. There are five different exceptions that this code throws, and the error messages are shown on the right. It’s your job to match the line of code that has a problem with the exception that line generates. Read the exception messages for a good hint. public static void BeeProcessor() { object myBee = new HoneyBee(36.5, “Zippo”); float howMuchHoney = (float)myBee; HoneyBee anotherBee = new HoneyBee(12.5, “Buzzy”); l Calling double.Parse(“32”) awil urn parse a string and ret double value, like 32. double beeName = double.Parse(anotherBee.MyName); double totalHoney = 36.5 + 12.5; string beesWeCanFeed = “”; for (int i = 1; i < (int) totalHoney; i++) { } beesWeCanFeed += i.ToString(); 1 float f = float.Parse(beesWeCanFeed); int drones = 4; 2 int queens = 0; int dronesPerQueen = drones / queens; anotherBee = null; 3 if (dronesPerQueen < 10) { } } anotherBee.DoMyJob(); When you have a reference that doesn’t point to any object, it gets a special value called null. Setting a reference to null tells C# it doesn’t point to anything. 4 5 you are here 4   465 breaking the rules Your job was to match the line of code that has a problem with the exception that line generates. object myBee = new HoneyBee(36.5, “Zippo”); float howMuchHoney = (float)myBee; at—but there’s no way C# lets you cast myBee to a flo to a float value. When your to convert a HoneyBee objecthas no idea how to actually do code actually runs, the CLR alidCastException. that cast, so it throws an Inv HoneyBee anotherBee = new HoneyBee(12.5, “Buzzy”); double beeName = double.Parse(anotherBee.MyName); double totalHoney = 36.5 + 12.5; string beesWeCanFeed = “”; for (int i = 1; i < (int) totalHoney; i++) { } beesWeCanFeed += i.ToString(); The Parse() method wants you to give it a string in a certain format. “Buzzy” isn’t a string it knows how to convert to a number. That’s why it throws a FormatException. called The for loop will create a string ber with over num a ns tai con beesWeCanFeed that a float can hold 60 digits in it. There’s no way to cram it into a a number that big, and trying xcepti on. float will throw an OverflowE float f = float.Parse(beesWeCanFeed); You’d never actually get all these exceptions in a row—the program would throw the first exception and then stop. You’d only get to the second exception if you fixed the first. 466   Chapter 10 exception handling int drones = 4; int queens = 0; int dronesPerQueen = drones / queens; It’s really easy to throw a DivideByZeroException. Just divide any number by zero. tion. Even if you Dividing any integer by zero always throws this kind of excep ing the value to check by just it t don’t know the value of queens, you can preven s. drone make sure it’s not zero before you divide it into anotherBee = null; if (dronesPerQueen < 10) { } anotherBee.DoMyJob(); Setting the anotherBee reference variable equal to null tells C# that it doesn’t point to anything. So instead of pointing to an object, it points to nothing. Throwing a NullReferenceException is C#’s way of telling you that there’s no object whose DoMyJob() method can be called. That DivideByZero error didn’t have to happen. You can see just by looking at the code that there’s something wrong. The same goes for the other exceptions. These problems were preventable—and the more you know about exceptions, the better you’ll be at keeping your code from crashing. you are here 4   467 mmm fudge When your program throws an e xception, .NET generate s an Exception object. You’ve been looking at .NET’s way of telling you something went wrong in your program: an exception. In .NET, when an exception occurs, an object is created to represent the problem. It’s called, no surprise here, Exception. For example, suppose you have an array with four items. Then, you try and access the sixteenth item (index 15, since we’re zero-based here): This code is int[] anArray = {3, 4, 1, 11}; obviously going to cause problems. epti j ec xc E As soon as your program runs into an exception, it generates an object with all the data it has about it. t int aValue = anArray[15]; on ob a person or thing that is excluded from a general statement or does not follow a rule. While Jim usually hates peanut butter, he made an exception for Ken’s peanut butter fudge. You can see this detail by clicking on the View Detail link in the unhandled exception window. has a The exception object what’s message that tells yoallu of the wrong and a list of to the calls that were madeding up to the system’s memory lea e exception. event that caused th .NET goes to the trouble of creating an object because it wants to give you all the information about what caused the exception. You may have code to fix, or you may just need to make some changes to how you handle a particular situation in your program. In this case, an IndexOutOfRangeException indicates you have a bug: you’re trying to access an index in the array that’s out of range. You’ve also got information about exactly where in the code the problem occurred, making it easy to track down (even if you’ve got thousands of lines of code). 468   Chapter 10 ex-cep-tion, noun. exception handling Q: A: Why are there so many kinds of exceptions? There are all sorts of ways that you can write code that C# simply doesn’t know how to deal with. It would be difficult to troubleshoot your problems if your program simply gave a generic error message (“A problem occurred at line 37”). It’s a lot easier to track down and fix problems in your code when you know specifically what kind of error occurred. Q: A: So what is an exception, really? It’s an object that .NET creates when there’s a problem. You can specifically generate exceptions in your code, too (more about that in a minute). Q: A: Wait, what? It’s an object? Yes, an exception is an object. The properties in the object tell you information about the exception. For example, it’s got a Message property that has a useful string like “Specified cast was invalid” or “Value was either too large or too small for a Single”, which is what it used to generate the exception window. The reason that .NET generates it is to give you as much information as it can about exactly what was going on when it executed the statement that threw the exception. Q: OK, I still don’t get it. Sorry. Why are there so many different kinds of exceptions, again? A: Because there are so many ways that your code can act in unexpected ways. There are a lot of situations that will cause your code to simply crash. It would be really hard to troubleshoot the problems if you didn’t know why the crash happened. By throwing different kinds of exceptions under different circumstances, .NET is giving you a lot of really valuable information to help you track down and correct the problem. Q: So exceptions are there to help me, not just cause a pain in my butt? A: Yes! Exceptions are all about helping you expect the unexpected. A lot of people get frustrated when they see code throw an exception. But if you think about an exception as .NET’s way of helping you track down and debug your program, it really helps out when you’re trying to track down what’s causing the code to bomb out. Q: So when my code throws an exception, it’s not necessarily because I did something wrong? A: Exactly. Sometimes your data’s different than you expected it to be—like you’ve got a method that’s dealing with an array that’s a lot longer or shorter than you anticipated when you first wrote it. And don’t forget that human beings are using your program, and they almost always act in an unpredictable way. Exceptions are .NET’s way to help you handle those unexpected situations so that your code still runs smoothly and doesn’t simply crash or give a cryptic, useless error message. Q: Once I knew what I was looking for, it was pretty clear that the code on the previous page was going to crash. Are all exceptions easy to spot? A: No. Unfortunately, there will be times when your code will have problems, and it’ll be really hard to figure out what’s causing them just by looking at it. That’s why the IDE gives you a really useful tool called the debugger. It lets you pause your program and execute it statement by statement, inspecting the value of each individual variable and field as you go. That makes it a lot easier for you to figure out where your code is acting in a way that’s different from how you expect it to act. That’s when you have the best chance of finding and fixing the exceptions— or, even better, preventing them in the first place. Exceptions are all about helping you find and fix situations where your code behaves in ways you didn’t expect. you are here 4   469 nobody expects the … Brian’s code did some thing une xpected When Brian wrote his excuse manager, he never expected the user to try to pull a random excuse out of an empty directory. 1 The problem happened when Brian pointed his Excuse Manager program at an empty folder on his laptop and clicked the Random button. Let’s take a look at it and see if we can figure out what went wrong. Here’s the unhandled exception window that popped up when he ran the program outside the IDE: 2 OK, that’s a good starting point. It’s telling us that the index was outside the bounds of the array, right? So let’s look for an array in the code for the Random Excuse button’s event handler: private void randomExcuse_Click(object sender, EventArgs e) { if (CheckChanged()) { currentExcuse = new Excuse(random, selectedFolder); UpdateForm(false); } } 3 Hmm, no arrays in there. But it creates a new Excuse object using one of the overloaded constructors. Maybe there’s an array in the constructor code: public Excuse(Random random, string Folder) { string[] fileNames = Directory.GetFiles(Folder, “*.excuse”); OpenFile(fileNames[random.Next(fileNames.Length)]); Bingo! There’s } the array. yin We must be tr g to use an index that’s past the end of the array. 470   Chapter 10 exception handling 4 It turns out that Directory.GetFiles() returns an empty array when you point it at a directory with no files in it. Hey, we can test for that! All we need to do is add a check to make sure the directory’s not empty before we open a file, and the nasty unhandled exception window will be replaced with an informative message box. private void randomExcuse_Click(object sender, EventArgs e) { string[] fileNames = Directory.GetFiles(selectedFolder,”*.excuse”); if (fileNames.Length == 0) { MessageBox.Show(“Please specify a folder with excuse files in it”, “No excuse files found”); By checking for excuse } else { in the folder before files if (CheckChanged() == true) { the Excuse create we CurrentExcuse = new Excuse(random, Folder); can prevent we object, UpdateForm(false); from being exception the } up a pop thrown—and } too. box, message helpful } Oh, I get it. Exceptions aren’t always bad. Sometimes they identify bugs, but a lot of the time they’re just telling me that something happened that was different from what I expected. That’s right. Exceptions are a really useful tool that you can use to find places where your code acts in ways you don’t expect. A lot of programmers get frustrated the first time they see an exception. But exceptions are really useful, and you can use them to your advantage. When you see an exception, it’s giving you a lot of clues to help you figure out when your code is reacting to a situation that you didn’t anticipate. And that’s good for you: it lets you know about a new scenario that your program has to handle, and it gives you an opportunity to do something about it. you are here 4   471 the exception family tree All e xception objects inherit f rom Exception .NET has lots of different exceptions it may need to report. Since many of these have a lot of similar features, inheritance comes into play. .NET defines a base class, called Exception, that all specific exceptions types inherit from. The Exception class has a couple of useful members. The Message property stores an easy-to-read message about what went wrong. And StackTrace tells you what code was being executed when the exception occurred, and what led up to the exception. (There are others, too, but we’ll use those first.) ToString() generates a summary of all of the information in the exception’s fields and returns it in a string. IndexOutOfRange Exception Message StackTrace GetBaseException() ToString() Message StackTrace GetBaseException() ToString() FormatException OverflowException Message StackTrace Message StackTrace GetBaseException() ToString() GetBaseException() ToString() It’s really useful that .NET gives us so many types of exceptions, because each different exception is thrown in a different situation. You can learn a lot about the sing unexpected action that’s cau at the exception just by looking which one was thrown. 472   Chapter 10 Exceptio any othern ccan be extended lik your own ex lass. So you can wr e Message an ception classes, andite properties d any other Except use and method ion s. Exception DivideByZero Exception Message StackTrace GetBaseException() ToString() exception handling The debugger helps you track down and prevent e xceptions in your code Before you can add exception handling to your program, you need to know which statements in your program are throwing the exception. That’s where the debugger that’s built into the IDE can be really helpful. You’ve been using the debugger throughout the book, but now let’s take a few minutes and really dig into it. When you run the debugger, the IDE pops up a toolbar with some really useful buttons. Take a minute and hover your mouse cursor over each of them to see what it does: Step over: execute the next statement. If it’s a method, Stop: end the program and execute it as a single statement. exit the debugger. The Debug toolbar only shows up when you’re debugging your program in the IDE. So you’ll have to run a program in order to hover over the toolbar icons. Toggle hexadecimal display on and off. Locals: show the values of all of the local variables currently in memory. Continue: run until the next breakpoint is hit or the program ends. Step out: run the rest of the Show the next statement that’s Step into: execute the next statements in the current method, going to run. statement. If it’s a method, execute and break when it’s done. the first statement in the method. Put your IDE into Expert mode to e xpand the Debug toolbar When you first start using Visual Studio 2010 Express, it’s set to Basic Settings mode, which is great for getting started. But now that you’ve been using it for a while, let’s change it. Choose Tools >> Settings >> Expert Settings from the menu (it may take the IDE a minute to adjust its settings). Now take another look at the debug toolbar. You’ll see that it added two new buttons (the other editions already have them turned on): Restart stops the program and starts it up again. Break all causes the program to stop in its tracks as if it hit a breakpoint. Toggle he xadecimal mode on and of f Press the Hex button to turn hexadecimal mode on, then hover over any field or variable. Then press it again to turn off hexadecimal mode. The IDE automatically converts values to hex for you—and you learned last chapter how valuable that can be. Here’s the same value displayed in hex mode on the left and decimal mode on the right. you are here 4   473 you don’t know where that watch has been Use the IDE’s debugger to ferre t out e xactly what went wrong in the Excuse Manager Let’s use the debugger to take a closer look at the problem that we ran into in the Excuse Manager. You’ve probably been using the debugger a lot over the last few chapters, but we’ll go through it step by step anyway—to make sure we don’t leave out any details. 1 Debug this Add a breakpoint to the Random button’s event handler You’ve got a starting point—the exception happens when the Random Excuse button is clicked after an empty folder is selected. So open up the code for the button, click anywhere in the first line of the method (Debug >> Toggle Breakpoint or F9), and then run the program. Select an empty folder and click the Random button to make your program break at the breakpoint: Hover over the fileNames.Length property to show the hovering expression window, then click the pushpin to pin it so it doesn’t disappear. 2 Step through the event handler and into the Excuse constructor Use the Step Into command (using either the toolbar or the F11 key) to move through the application line by line. Since you selected an empty folder, you should see the program execute the MessageBox.Show() and then exit the event handler. Now select a folder with excuses in it and click the Random button again, then keep stepping into the code. (Make sure you’re using Step Into, not Step Over—although you might want to step over the CheckChanged() method.) When it gets to the line that creates the new Excuse object, it’ll jump straight into the constructor. Step past the first line so it sets the fileNames variable. Then hover over the variable to see its value, too. 474   Chapter 10 exception handling 3 Use the Watch window to reproduce the problem You’ve already seen how powerful the Watch window is. Now we’ll use it to reproduce the exception. Right-click on fileNames and choose Expression: ‘fileNames’ >> Add Watch to add a watch to the Watch window. Then click on the empty line below fileNames and enter the expression random.Next(fileNames.Length) to tell the debugger to add a watch for it. Here’s what the Watch window should look like for a folder with three excuses (so fileNames has length 3). We’ll use the Watch window to reproduce the problem that caused the exception. We’ll start by adding the fileNames array. 4 Set fileNames equal to an empty string array The Watch window has another very useful feature—it lets you change the value of variables and fields that it’s displaying. It even lets you execute methods and create new objects—and when you do, it displays its re-evaluate icon ( ) that you can click to tell it to execute that line again, because sometimes running the same method twice will generate different results (like with Random). Double-click on the value for fileNames—you’ll see the text {string[3]} highlighted. Replace it with new string[0]. You should immediately see two things. First, you’ll see the expand icon next to the fileNames variable disappear, because now it’s empty. And second, the random.Next() line will become gray with a re-evaluate icon ( ). Click the icon to execute the method again, which should return 0. We know the problem happened with an empty fileNames array, so we’ll use the Watch window to change its value to an empty string array. 5 This icon tells the Watch window to re-evaluate the Next() method. Reproduce the problem that threw Brian’s original exception Here’s where debugging gets really interesting. Add one more line to the debugger—the statement that actually threw the exception: fileNames[random.Next(fileNames.Length)]. As soon as you type it in, the Watch window evaluates it…and that throws the exception. It tells you that it found the exception by displaying an exclamation point, and displays the text of the exception in the Value column. This exclamation point is the Watch window’s way of telling you it found an exception. When you get an exception, you can go back and reproduce it in the debugger. That’s another way that more descriptive exception messages can help you fix your code. you are here 4   475 make a break for it Q: How come Brian’s unhandled exception window looked different from the one in the IDE? A: Because when you run a program inside the IDE, you’re running it in the debugger, which breaks the program (as if you’d pressed the Break All button or inserted a breakpoint) as soon as it intercepts an exception, and displays it in a useful window. That lets you inspect the Exception object and your program’s fields and variables so you can track down the problem. When Brian ran his program, he wasn’t running it from inside the IDE. He’d published his program and installed it, just like you did back in Chapter 1 with the Contact List program. You can run your program outside the IDE any time without publishing it—just build your program, which causes Visual Studio to create an executable file. Look inside your project’s folder for the bin/ folder—one of its subdirectories should have the exe file for your application. If you run that, any exceptions that it throws will be unhandled and show the same window that Brian saw. Q: So that’s it? When an exception happens outside the IDE, my program just stops and there’s nothing I can do about it? A: Well, your program does stop when there’s an unhandled exception. But that doesn’t mean that all of your exceptions have to be unhandled! We’ll talk a lot more about how you can handle exceptions in your code. There’s no reason your users ever have to see an unhandled exception. 476   Chapter 10 Q: How do I know where to put a breakpoint? A: That’s a really good question, and there’s no one right answer. When your code throws an exception, it’s always a good idea to start with the statement that threw it. But usually, the problem actually happened earlier in the program, and the exception is just fallout from it. For example, the statement that throws a divide by zero error could be dividing values that were generated 10 statements earlier but just haven’t been used yet. So there’s no one good answer to where you should put a breakpoint, because every situation is different. But as long as you’ve got a good idea how your code works, you should be able to figure out a good starting point. Q: Can I run any method in the Watch window? A: Yes. Any statement that’s valid in your program will work inside the Watch window, even things that make absolutely no sense to run inside a Watch window. Here’s an example. Bring up a program, start it running, break it, and then add this to the Watch window: System.Threading. Thread.Sleep(2000). (Remember, that method causes your program to delay for two seconds.)There’s no reason you’d ever do that in real life, but it’s interesting to see what happens: you’ll get an hourglass for two seconds while the method evaluates. Then, since Sleep() has no return value, the Watch window will display the value, “Expression has been evaluated and has no value” to let you know that it didn’t return anything. But it did evaluate it. Not only that, but it displays IntelliSense pop ups to help you type code into the window. That’s useful because it’ll tell you what methods are available to an object when your program is running. Q: Wait, so isn’t it possible for me to run something in the Watch window that’ll change the way my program runs? A: Yes! Not permanently, but it can definitely affect your program’s output. But even better, just hovering over fields inside the debugger can cause your program to change its behavior, because hovering over a property executes its get accessor. If you have a property that has a get accessor that executes a method, then hovering over that property will cause that method to execute. And if that method sets a value in your program, then that value will stay set if you run the program again. And that can cause some pretty unpredictable results inside the debugger. Programmers have a name for results that seem to be unpredictable and random: they’re called heisenbugs (which is a joke that makes sense to physicists and cats in boxes). When you run your program inside the IDE, an unhandled exception will cause it to break as if it had run into a breakpoint. exception handling Uh oh—the code’s still got problems… Brian was happily using his Excuse Manager when he remembered that he had a folder full of excuses that he made when he first built the program—but he forgot that he made that folder before he added serialization to the program. Let’s see what happens.... No, not again! 1 You can re-create Brian’s problem—just create your own text-based Excuse file using Notepad. The first line should be the description, the second should be the results, and the third should be the last used date (“10/4/2007 12:08:13 PM”). 2 Pop open the Excuse Manager and open up the excuse. It throws an exception! But this time, click on the Details button so we can take a closer look at what it says. Pay attention to the call stack—that’s what it’s called when a method is called by another method, which is called by another method, etc. The program threw a SerializationException. Can we figure out what line threw it from the exception details? ************** Exception Text ************** System.Runtime.Serialization.SerializationException: End of Stream encountered before parsing was completed. at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run() It looks like there was a problem with the BinaryFormatter—which makes sense, because it was trying to deserialize a text file. You can learn a lot from the call stack, which tells you which methods were running. You can see that the Excuse class’s OpenFile() method was being called from its constructor (“.ctor”), which was called from the “Random Excuse” button’s click event handler. 3 at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHa ndler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream) at Chapter10.Excuse.OpenFile(String ExcusePath) in C:\Documents and Settings\Administrator\ My Documents\Visual Studio 2005\Projects\Chapter10\Chapter10\Excuse.cs:line 40 at Chapter10.Excuse..ctor(Random random, String Folder) in C:\Documents and Settings\ Administrator\My Documents\Visual Studio 2005\Projects\Chapter10\Chapter10\Excuse.cs:line 30 at Chapter10.Form1.randomExcuse_Click(Object sender, EventArgs e) in C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\Projects\Chapter10\Chapter10\Form1. cs:line 146 So the Details button in the unhandled exception window tells you a lot about what caused this problem. Can you think of anything you can do about it? you are here 4   477 users are unpredictable Wait a second. Of course the program’s gonna crash—I gave it a bad file. Users screw up all the time. You can’t expect me to do anything about that, right? Actually, there is something you can do about it. Yes, it’s true that users screw up all the time. That’s a fact of life. But that doesn’t mean you can’t do anything about it. There’s a name for programs that deal with bad data, malformed input, and other unexpected situations gracefully: they’re called robust programs. And C# gives you some really powerful exception handling tools to help you make your programs more robust. Because while you can’t control what your users do, you can make sure that your program doesn’t crash when they do it. ro-bust, adj. sturdy in construction; able to withstand or overcome adverse conditions. After the Tacoma Narrows Bridge disaster, the civil engineering team looked for a more robust design for the bridge that would replace it. BinaryFormatter will throw an exception if there’s anything at all wrong with a serialized file. It’s easy to get the Excuse Manager to throw a SerializationException—just feed it any file that’s not a serialized Excuse object. When you try to deserialize an object from a file, BinaryFormatter expects the file to contain a serialized object that matches the class that it’s trying to read. If the file contains anything else, anything at all, then the Deserialize() method will throw a SerializationException. 478   Chapter 10 exception handling Handle e xceptions with tr y and catch In C#, you can basically say, “Try this code, and if an exception occurs, catch it with this other bit of code.” The part of the code you’re trying is the try block, and the part where you deal with exceptions is called the catch block. In the catch block, you can do things like print a friendly error message instead of letting your program come to a screeching halt: private void randomExcuse_Click(object sender, EventArgs e) { // ... code you added a few pages ago goes here ... try { This is the try block. You start exception handling with try. In this case, we’ll put the existing code in it. } if (CheckChanged() == true) { currentExcuse = new Excuse(random, selectedFolder); } UpdateForm(false); The catch keyword means that the block immediately following it contains an exception handler. catch (SerializationException) { Put the code that mi t throw an exception inside thgh e tr y If no exception happens, it’ block. run exactly as usual, and thll get statements in the catch bloe be ignored. But if a state ck will in the try block throws anment exception, the rest of th e try block won’t get executed . When an exception is thrown, the MessageBox.Show( program immediately jumps to the catch “Your excuse file was invalid.”, statement and starts executing “Unable to open a random excuse”); the catch block. } } This is the simplest kind of exception handling: stop the program, write out the exception message, and keep running. If throwing an exception makes your code automatically jump to the catch block, what happens to the objects and data you were working with before the exception happened? you are here 4   479 risky business What happens when a me thod you want to call is risky? Users are unpredictable. They feed all sorts of weird data into your program, and click on things in ways you never expected. And that’s just fine, because you can handle unexpected input with good exception handling. our meth to y od ser gives i np au ut 1 Let’s say your user is using your code, and gives it some input that it didn’t expect. public class Data { public void Process(Input i) { if (i.IsBad()) { explode(); } } } ˙∆å˚ß∂ıÏÔ˚œ∑ˆ øƒ¥∂∫√˚Ω∆¬˙√˚ ÔÒÎ˙˚∆¬åߥ∂ÒÅ ∆˚åƒ˙ß∂∆˙å∆˚ß ƒå∂ß˙˚ƒ∆˚å∂ß∂ ´˙®£√•√∂¨∂¬∆ƒ ƒ˜å∂√˚祃´∂ˆ´ ∂å˚∆ƒ´∫®˚´¨√∂ some input a class you wrote user 2 That method does something risky, something that might not work at runtime. “Runtime” just means “while your program is running.” Some people refer to exceptions as “runtime errors.” public class Data { public void Process(Input i) { if (i.IsBad()) { explode(); } } } a class you wrote I wonder what happens if I click here… 3 You need to know that the method you’re calling is risky. If you can come up with a way to do a less risky thing that avoids throwing the exception, that’s the best possible outcome! But some risks just can’t be avoided, and that’s when you want to do this. My Process() method will blow up if it gets bad input data! public class Data { public void Process(Input i) { if (i.IsBad()) { explode(); } } } a class you wrote user Wow, this program’s really stable! ur program’s more rob w yo ust! no 4 You then write code that can handle the failure if it does happen. You need to be prepared, just in case. public class Data { public void Process(Input i) { try { if (i.IsBad()) { explode(); } catch { HandleIt(); } } } user 480   Chapter 10 public void Process(Input i) { if (i.IsBad()) { explode(); } } your class, now with exception handling exception handling Q: A: So when do I use try and catch? Any time you’re writing risky code, or code that could throw an exception. The trick is figuring out which code is risky, and which code is safer. You’ve already seen that code that uses input provided by a user can be risky. Users give you incorrect files, words instead of numbers, and names instead of dates, and they pretty much click everywhere you could possibly imagine. A good program will take all that input and work in a calm, predictable way. It might not give the users a result they can use, but it will let them know that it found the problem and hopefully suggest a solution. Q: How can a program suggest a solution to a problem it doesn’t even know about in advance? A: catch That’s what the catch block is for. A block is only executed when code in the try block throws an exception. It’s your chance to make sure the user knows that something went wrong, and to let the user know that it’s a situation that might be corrected. If the Excuse Manager simply crashes when there’s bad input, that’s not particularly useful. But if it tries to read the input and displays garbage in the form, that’s also not useful—in fact, some people might say that it’s worse. But if you have the program display an error message telling the user that it couldn’t read the file, then the user has an idea of what went wrong, and information that he can use to fix the problem. add watches for a few variables, the Watch window updates their values every time you step into, out of, or over code. That lets you monitor exactly what happens to them after every statement, which can be really useful when you’re trying to track down a problem. So the debugger should really only be used to troubleshoot exceptions then? The Watch window also lets you type in any statement you want, and it’ll evaluate it. If the statement updates any of the fields and variables in your program, then it does that, too. That lets you change values while your program is running, which can be another really useful tool for reproducing exceptions and other bugs. Q: A: No. As you’ve already seen many times throughout the book, the debugger’s a really useful tool that you can use to examine any code you’ve written. Sometimes it’s useful to step through your code and check the values of certain fields and variables—like when you’ve got a really complex method, and you want to make sure it’s working properly. But as you may have guessed from the name “debugger,” its most common use is to track down and remove bugs. Sometimes those bugs are exceptions that get thrown. But a lot of the time, you’ll be using the debugger to try to find other kinds of problems, like code that gives a result that you don’t expect. Q: I’m not sure I totally got what you did with the Watch window. A: When you’re debugging a program, you usually want to pay attention to how a few variables and fields change. That’s where the Watch window comes in. If you Any changes you make in the Watch window just affect the data in memory, and only last as long as the program is running. Restart your program, and values that you changed will be undone. The catch block is only executed when code in the try block throws an exception. It gives you a chance to make sure your user has the information to fix the problem. you are here 4   481 go with the flow Use the debugger to follow the tr y/catch flow An important part of exception handling is that when a statement in your try block throws an exception, the rest of the code in the block gets short-circuited. The program’s execution immediately jumps to the first line in the catch block. But don’t take our word for it.... 1 Debug this Make sure that you’ve incorporated all of the code from this chapter into the Random Excuse button’s Click event handler in your Excuse Manager. Place a breakpoint on the first line in the event handler. Then run your program in the IDE. Click the Folder button and specify a folder with a single excuse file in it—and make sure it’s not a valid excuse file (but still has the “.excuse” extension). Press the Random Excuse button. The debugger should break the program at the breakpoint you placed earlier. Press the Step Over button (or F10) six times to get to the statement that calls the Excuse constructor. Here’s what your debugger screen should look like: Here’s the breakpoint we placed earlier on the first line of the event handler. Step over the statements until your yellow “next statement” bar shows that the next statement to get executed will create the new Excuse object. 2 Use the Step Over (F10) command in the debugger so it doesn’t step into the CheckChanged() method. Use Step Into (F11) to step into the new statement. The debugger will jump to the Excuse constructor, and position its yellow “next statement” bar over the declaration line in the code. Keep hitting Step Into (F11) to step into the OpenFile() method. Watch what happens when you hit the Deserialize() line. As soon as you step into the new statement that creates the Excuse object, the debugger jumps to the constructor code. 482   Chapter 10 exception handling 3 Keep stepping through the code. As soon as the debugger executes the Deserialize() statement, the exception is thrown and the program short-circuits right past the call to UpdateForm() and jumps straight to the catch block. The debugger will highlight the catch statement with its yellow “next statement” block, but it shows the rest of the block in gray to show you that it’s about to execute the whole thing. 4 Start the program again by pressing the Continue button (or F5). It’ll begin running the program again, starting with whatever’s highlighted by the yellow “next statement” block—in this case, the catch block. Here’s a career tip: a lot of C# programming job interviews include a question about how you deal with exceptions in a constructor. Be careful with exceptions in a constructor! You’ve noticed by now that a constructor doesn’t have a return value, not even void. That’s because a constructor doesn’t actually return anything. Its only purpose is to initialize an object—which is a problem for exception handling inside the constructor. When an exception is thrown inside the constructor, then the statement that tried to instantiate the class won’t end up with an instance of the object. That’s why you had to move the try/catch block to the button’s event handler. That way, if there’s an exception in the constructor, the code won’t expect CurrentExcuse to contain a valid Excuse object. you are here 4   483 clean up after yourself If you have code that ALWAYS should run, use a finally block When your program throws an exception, a couple of things can happen. If the exception isn’t handled, your program will stop processing and crash. If the exception is handled, your code jumps to the catch block. But what about the rest of the code in your try block? What if you were closing a stream, or cleaning up important resources? That code needs to run, even if an exception occurs, or you’re going to make a mess of your program’s state. That’s where the finally block comes in really handy. It comes after the try and catch blocks. The finally block always runs, whether or not an exception was thrown. Here’s how you’d use it to finish the event handling in the Random Excuse button: private void randomExcuse_Click(object sender, EventArgs e) { string[] fileNames = Directory.GetFiles(selectedFolder, “*.excuse”); if (fileNames.Length == 0) { MessageBox.Show(“Please specify a folder with excuse files in it”, “No excuse files found”); } else { try { if (CheckChanged() == true) { currentExcuse = new Excuse(random, selectedFolder); } exception, we If the Excuse constructor throws an rent } Excuse. have no way of knowing what’s in Cur catch (SerializationException) { use was Exc of The finally block makes But you do know that no instance a new Excuse currentExcuse = new Excuse(); sure that UpdateForm() created. So the catch block creates currentExcuse.Description = “”; gets run whether or not an object and clears out all its fields. exception was thrown. So currentExcuse.Results = “”; if the Excuse constructor currentExcuse.LastUsed = DateTime.Now; successfully read an excuse, MessageBox.Show( it’ll call UpdateForm(), “Your excuse file was invalid.”, but it’ll also call it if the “Unable to open a random excuse”); constructor threw an exception and cleared out } the excuse. finally { SerializationException is in the System.Runtime. UpdateForm(false); Serialization namespace, so you’ll need to add using System.Runtime.Serialization; } to the top of your form’s file. } } Always catch specific exceptions like SerializationException. You typically follow a catch statement with a specific kind of exception telling it what to catch. It’s valid C# code to just have “catch (Exception)” and you can even leave the exception type out and just use catch. When you do that, it catches all exceptions, no matter what type of exception is thrown. But it’s a really bad practice to have a catch-all exception handler like that. Your code should always catch as specific an exception as possible. 484   Chapter 10 exception handling Now debug this 1 Update the Random Excuse button’s event handler with the code on the facing page. Then place a breakpoint on the first line in the method and debug the program. 2 Run the program normally, and make sure that the Random Excuse button works when you set the program’s folder to one with a bunch of normal excuse files in it. The debugger should break at the breakpoint you set: When the “next statement” bar and the breakpoint are on the same line, the IDE shows you the yellow arrow placed over the big red dot in the margin. 3 Step through the rest of the Random Excuse button’s event handler and make sure it runs the way you expect it to. It should finish the try block, skip over the catch block (because no exceptions were thrown), and then execute the finally block. 4 Now set the program’s folder so that it’s pointed to the folder with one malformed excuse file in it and click the Random Excuse button. It should start executing the try block, and then jump to the catch block when it throws the exception. After it finishes all of the statements in the catch block, it’ll execute the finally block. you are here 4   485 exceptions lead to instability Q: Back up a second. So every time my program runs into an exception, it’s going to stop whatever it’s doing unless I specifically write code to catch it. How is that a good thing? A: One of the best things about exceptions is that they make it really obvious when you run into problems. Imagine how easy it could be in a complex application for you to lose track of all of the objects your program was working with. Exceptions call attention to your problems and help you root out their causes so that you always know that your program is doing what it’s supposed to do. Any time an exception occurs in your program, something you expected to happen didn’t. Maybe an object reference wasn’t pointing where you thought it was, or it was possible for a user to supply a value you hadn’t considered, or a file you thought you’d be working with suddenly isn’t available. If something like that happened and you didn’t know it, it’s likely that the output of your program would be wrong, and the behavior from that point on would be pretty different from you expected when you wrote the program. Now imagine that you had no idea the error had occurred and your users started calling you up with incorrect data and telling you that your program was unstable. That’s why it’s a good thing that exceptions disrupt everything your program is doing. They force you to deal with the problem while it’s easy to find and fix. Q: OK, so now what’s a handled exception and what’s an unhandled exception? A: Whenever your program throws an exception, the runtime environment will 486   Chapter 10 search through your code looking for a catch block that handles it. If you’ve written one, the catch block will execute Q: What happens when you have a catch that doesn’t specify a particular exception? and do whatever you specified for that particular exception. Since you wrote a catch block to deal with that error up front, that exception is considered handled. If the runtime can’t find a catch block to match the exception, it stops everything your program is doing and raises an error. That’s an unhandled exception. A: catch try Q: catch But isn’t it easier to use a catch-all exception? Isn’t it safer to write code that always catches every exception? Good question. Because certain exceptions might require different actions to keep your program moving. An exception that happens when you divide by zero might have a catch block where you go back and set some number values to save some of the data you’ve been working with. A null reference exception might require that you create new instances of an object if you’re going to recover. Q: A: You should always do your best to avoid catching Exception, and instead catch specific exceptions. You know that old saying about how an ounce of prevention is better than a pound of cure? That’s especially true in exception handling. Depending on catch-all exceptions is usually just a way to make up for bad programming. For example, you’re much better off using File.Exists() to check for a file before you try to open it than catching a FileNotFoundException. While some exceptions are unavoidable, you’ll find that a surprising number of them never have to be thrown in the first place. It’s sometimes really useful to leave exceptions unhandled. Real-life programs have complex logic, and it’s often difficult to recover correctly when something goes wrong, especially when a problem occurs very far down in the program. By only handling specific exceptions, avoiding catch-all exception handlers, and letting those exceptions bubble up to get caught on a top level, you end up with much more robust code. A block like that will catch any kind of exception the block can throw. If a block with no specified exception will catch anything, why would I ever want to specify? A: Q: Does all error handling happen in a try/catch/finally sequence? A: No. You can mix it up a bit. You could have multiple catch blocks if you wanted to deal with lots of different kinds of errors. You could also have no catch block at all. It’s legal to have a try/finally block. That wouldn’t handle any exceptions, but it would make sure that the code in the finally block ran even if you got stopped halfway through the try block. But we’ll talk a lot more about that in a minute.... An unhandled exception means your program will run unpredictably. That’s why the program stops whenever it runs into one. Pool Puzzle Your job is to take code snippets from the pool and place them into the blank lines in the program. You can use the same snippet more than once, and you won’t need to use all the snippets. Your goal is to make the program produce the output. Output: G’day Mate! using System.IO; public static void Main() { Kangaroo joey = new Kangaroo(); int koala = joey.Wombat( joey.Wombat(joey.Wombat(1))); try { Console.WriteLine((15 / koala) + “ eggs per pound”); } catch (___________________) { Console.WriteLine(“G’Day Mate!”); } } Note: Each snippet from the pool can be used more than once! exception handling class Kangaroo { ___________ fs; int croc; int dingo = 0; } public int Wombat(int wallaby) { _______ __; try { if (________ > 0) { __ = _____.OpenWrite(“wobbiegong”); croc = 0; } else if (________ < 0) { croc = 3; } else { ___ = _____.OpenRead(“wobbiegong”); croc = 1; } } catch (IOException) { croc = -3; } catch { croc = 4; } finally { if (______ > 2) { croc ___ dingo; } } ________ ______; } return Exception IOException NullPointerException DivideByZeroException InvalidCastException OutOfMemoryException ef i fs int j FileInfo File Directory Stream FileStream ++ -= += == != dingo wallaby koala croc platypus The pool puzzles are getting harder, and the names are getting more obscure to give you fewer hints. You’ll really need to work through the problem! Remember, the puzzles are optional, so don’t worry if you need to move on and come back to this one…but if you really want to get this stuff into your brain, these puzzles will do the trick! you are here 4   487 one object’s trash is another’s treasure Pool Puzzle Solution The clue that this is a FileStream is that it has an OpenRead() method and throws an IOException. Joey.Wombat() is called three times, and the third time it returns zero. That causes the WriteLine() to throw a DivideByZeroException. public static void Main() { Kangaroo joey = new Kangaroo(); int koala = joey.Wombat(joey.Wombat(joey.Wombat(1))); try { Console.WriteLine((15 / koala) + “ eggs per pound”); } catch (DivideByZeroException) { Console.WriteLine(“G’Day Mate!”); } } class Kangaroo { FileStream fs; int croc; int dingo = 0; This catch block only catches exceptions where the code divides by zero. public int Wombat(int wallaby) { dingo ++; try { if (wallaby > 0) { This code opens a file called “wobbiego ng” fs = File.OpenWrite(“wobbiegong”); and keeps it open the first time it’s croc = 0; called. Later on, it opens the file aga in. } else if (wallaby < 0) { But it never closed the file, whi croc = 3; it to throw an IOException. ch causes } else { fs = File.OpenRead(“wobbiegong”); croc = 1; } } catch (IOException) { croc = -3; e } You already know that you always hav catchRemember, you should avoid h wit e don ’re you catch { to close files when all exceptions in your code. But you them. If you don’t, the file will be it do we croc = 4; should also avoid other things locked open, and if you try to open } to make puzzles more interesting, like again it’ll throw an IOException. using obfuscated variable names. finally { if (dingo > 2) { croc -= dingo; } } return croc; } } 488   Chapter 10 exception handling Use the Exception object to ge t information about the problem We’ve been saying all along that .NET generates an Exception object when an exception is thrown. When you write your catch block, you have access to that object. Here’s how it works: 1 An object is humming along, doing its thing, when it encounters something unexpected and throws an exception. Uh oh—what the heck happened? An ob 2 ject Luckily, its try/catch block caught the exception. Inside the catch block, it gave the exception a name: ex. try { DoSomethingRisky(); } catch (RiskyThingException ex) { When you specify a type of exception in the catch block, if you provide a variable name, then your code can use it to access the Exception object. string message = ex.Message; MessageBox.Show(message, “I took too many risks!”); } The exception object stays around until the catch block is done. Then the ex reference disappears, and it’s eventually garbage-collected. ssage = ex.Message; string me xc E An ob ject t EX epti j ec 3 on ob you are here 4   489 playing catch Use more than one catch block to handle multiple t ype s of e xceptions You know that you can catch a specific type of exception…but what if you write code where more than one problem can occur? In these cases, you may want to write code that handles each different type of exception. That’s where using more than one catch block comes in. Here’s an example from the code in the beehive nectar processing plant. You can see how it catches several kinds of exceptions. In some cases it uses properties in the Exception object. It’s pretty common to use the Message property, which usually contains a description of the exception that was thrown. You can also call throw; to rethrow the message, so it can be handled further up the call stack. You can also call the exception’s ToString() method to get a lot of the pertinent data into your MessageBox. public void ProcessNectar(NectarVat vat, Bee worker, HiveLog log) { try { NectarUnit[] units = worker.EmptyVat(vat); for (int count = 0; count < worker.UnitsExpected, count++) { stream hiveLogFile = log.OpenLogFile(); worker.AddLogEntry(hiveLogFile); y’re Sometimes you When you have several catch blocks, the } If you won’t use the Exception object, cks for it t want to bubble examined in order. In this code, firs Logche there’s no need to declare it. eption. Exc Hive } an exception up a VatEmptyException and then a ption. to the method catch (VatEmptyException) { The last catch block catches IOExce erent file that called That’s the base class for several diffxception and vat.Emptied = true; this one by exceptions, including FileNotFoundE } using throw; to EndOfStreamException. rethrow the catch (HiveLogException ex) { exception. throw; variable ex, which } This catch block assigns the exception to theption object. Exce it can use to get information from the catch (IOException ex) { worker.AlertQueen(“An unspecified file error happened: ” It’s fine for two + “Message: ” + ex.Message + “\r\n” blocks to use the + “Stack trace: ” + ex.StackTrace + “\r\n” same name (“ex”) for the Exception. + “Data: ” + ex.Data + “\r\n”); This statement uses three properties in } Message, which has the message you’d northe Exception object: finally { window in the IDE (“Attempted to divi mally see in the exception which gives you a summary of the call stade by zero”); StackTrace, vat.Seal(); sometimes contains pertinent data that’s ck; and Data, which worker.FinishedJob(); associated with the exception. } } 490   Chapter 10 exception handling Of course, one method in a single class can throw a method that’s caught by another method in the same class. One class throws an exception, another class catches the exception When you’re building a class, you don’t always know how it’s going to be used. Sometimes other people will end up using your objects in a way that causes problems—and sometimes you do it yourself ! That’s where exceptions come in. The whole point behind throwing an exception is to see what might go wrong, so you can put in place some sort of contingency plan. You don’t usually see a method that throws an exception and then catches it. An exception is usually thrown in one method and then caught in a totally different one—usually in a different object. This BeeProfile object’s constructor expects the filename for a profile data file that it’ll open using File.Open(). If there’s a problem opening the file, the program bombs out. Instead of this… Without good exception handling, one exception can halt the entire program. Here’s how it would work in a program that manages bee profiles for a queen bee. stream = File.Open(profile); Pr e o f i l e obj Notice how the BeeProfile obj intercepts the exception, logs itectusin WriteLogEntry() method, and then g its it again so it’s passed along to the throws hive. try { stream = File.Open(profile); } catch (FileNotFoundException ex) { WriteLogEntry(“unable to find ” + profile + “: ” + ex.Message(); throw; } …we can do this. The BeeProfile object can intercept the exception and add a log entry. Then it can turn around and throw the exception back to the hive, which catches it and recovers gracefully. of.dat”) Profile(“pr w Bee e n try { prof = new BeeProfile(“prof.dat”); } catch (FileNotFoundException) { Hive.RecreateBeeProfile(“prof.dat”); } Pr e v object Be Hi e e ct v object Be Hi e The BeeProfile object tried to read a file but it wasn’t there, so File.Open() threw an exception. The hive didn’t catch it, so it went unhandled. ct of.dat”) Profile(“pr w Bee e n o f i l e obj e Now when the hive tries to createita an new BeeProfile object by passing Profile invalid filename, it can trust Beeit to to log the error and then alerteption. the problem by throwing an exc and The hive can catch the exceptionthis case, take some corrective action—in recreating the bee profile. you are here 4   491 your very own exception Bees need an OutOfHoney e xception Exception Your classes can throw their own exceptions. For example, if you get a null parameter in a method that was expecting a value, it’s pretty common to throw the same exception a .NET method would: throw new ArgumentException(); Your methods can throw this exception if they get invalid or unexpected values in their parameters. But sometimes you want your program to throw an exception because of a special condition that could happen when it runs. The bees we created in the hive, for example, consume honey at a different rate depending on their weight. If there’s no honey left to consume, it makes sense to have the hive throw an exception. You can create a custom exception to deal with that specific error condition just by creating your own class that inherits from Exception and then throwing the exception whenever you encounter a specific error. class OutOfHoneyException : System.Exception { } Message StackTrace GetBaseException() ToString() your Exception Message StackTrace GetBaseException() ToString() public OutOfHoneyException(string message) : base(message) { } class HoneyDeliverySystem { ... public void FeedHoneyToEggs() { if (honeyLevel == 0) { You need to create a class for your exception and make sure that it inherits from System. Exception. Notice how we’re overloading the constructor so we can pass an exception message. throw new OutOfHoneyException(“The hive is out of honey.”); } else { foreach (Egg egg in Eggs) { ... } public partial class Form1 : Form { ... If there’s honey in the hive, the exception will never get thrown and this code will run. w This throws ahene t instance of ct. exception obje private void consumeHoney_Click(object sender, EventArgs e) { HoneyDeliverySystem delivery = new HoneyDeliverySystem(); try { } delivery.FeedHoneyToEggs() catch (OutOfHoneyException ex){ You can catch a custom exception by name just like any other exception and do whatever you , need to do to handle it. MessageBox.Show(ex.Message, “Warning: Resetting Hive”); } } } Hive.Reset(); 492   Chapter 10 In this case, if the hive is out of honey none of the bees can work, so the simulator can’t continue. The only way to keep the program working once the hive runs out of honey is to reset it, and we can do that by putting the code to reset it in the catch block. exception handling Exception Magnets public static void Main() { Console.Write(“when it “); ExTestDrive.Zero(“yes”); Console.Write(“ it “); ExTestDrive.Zero(“no”); Console.WriteLine(“.”); } class MyException : Exception { } Arrange the magnets so the application writes the output to the console. output: when it thaws it throws. } } } if (t == “yes”) { Console.Write(“a”); Console.Write(“o”); Console.Write(“t”); Console.Write(“w”); try { Console.Write(“s”); } catch (MyException) { throw new MyException(); } finally { doRisky(test); ”); Console.Write(“r } } class ExTestDrive { public static void Zero(string test) { static void DoRisky(String t) { Console.Write(“h”); you are here 4   493 a little review Exception Magnets Solution public static void Main() { Console.Write(“when it “); ExTestDrive.Zero(“yes”); Console.Write(“ it “); ExTestDrive.Zero(“no”); Console.WriteLine(“.”); } Arrange the magnets so the application writes the output to the console. output: when it thaws it throws. class MyException : Exception { } This line defines a custom exception called MyException, which gets caught in a catch block in the code. class ExTestDrive { public static void Zero(string test) { try { Console.Write(“t”); doRisky(test); Console.Write(“o”); } catch (MyException) { The Zero() method either prints “thaws” or “throws”, depending on whether it was passed “yes” or something else as its test parameter. Console.Write(“a”); } finally { } Console.Write(“w”); Console.Write(“s”); } The finally block makes sure that the method always prints “w”. And the “s” is printed outside the exception handler, so it always prints, too. static void DoRisky(String t) { Console.Write(“h”); if (t == “yes”) { This line only gets executed if doRisky() doesn’t throw the exception. throw new MyException(); } } 494   Chapter 10 } Console.Write(“r”); The doRisky() method on throws an exception if it’ly passed the string “yes”. s exception handling ¢¢ ¢¢ ¢¢ ¢¢ Any statement can throw an exception if something fails at runtime. try { catch // // } catch catch catch Use a try/catch block to handle exceptions. Unhandled exceptions will cause your program to stop execution and pop up an error window. Any exception in the block of code after the try statement will cause the program’s execution to immediately jump to the first statement in the block of code after catch. The Exception object gives you information about the exception that was caught. If you specify an Exception variable in your catch statement, that variable will contain information about any exception thrown in the try block: try { // statements that might // throw exceptions } catch (IOException ex) { // if an exception is thrown, // ex has information about it } ¢¢ Each try can have more than one catch: ¢¢ ... } (NullReferenceException ex) { these statements will run if a NullReferenceException is thrown (OverflowException ex) { ... } (FileNotFoundException) { ... } (ArgumentException) { ... } Your code can throw an exception using throw: ¢¢ throw new Exception(“Exception message”); ¢¢ ¢¢ Your code can also rethrow an exception using throw; but this only works inside of a catch block. Rethrowing an exception preserves the call stack. You can create a custom exception by inheriting from the Exception base class. class CustomException : Exception; ¢¢ There are many different kinds of exceptions that you can catch. Each has its own object that inherits from Exception. Really try to avoid just catching Exception—catch specific exceptions instead. Most of the time, you only need to throw exceptions that are built into .NET, like ArgumentException. The reason you use different kinds of exceptions is so that you can give more information to your users. Popping up a window with the text “An unknown error has occurred” is not nearly as useful as an error message that says “The excuse folder is empty. Please select a different folder if you want to read excuses.” An e asy way to avoid a lot of problems: using gi ves you tr y and finally for f ree You already know that using is an easy way to make sure that your files always get closed. But what you didn’t know is that it’s really just a C# shortcut for try and finally! using (YourClass c = new YourClass() ) { // code } Remember, when you declare a reference in a “using” statement, its Dispose() method is automatically called at the end of the block. YourClass c = new YourClass(); try { // code is like this } finally { } c.Dispose(); When you use a using statement, you’re taking advantage of finally to make sure its Dispose() method is always called. you are here 4   495 an ounce of prevention Exception avoidance: implement IDisposable to do your own cle anup Streams are great, because they already have code written to close themselves when the object is disposed of. But what if you have your own custom object, and it always needs to do something when it’s disposed of ? Wouldn’t it be great if you could write your own code that got run if your object was used in a using statement? C# lets you do just that with the IDisposable interface. Implement IDisposable, and write your cleanup code in the Dispose() method, like this: IDisposable is a really effective way to avoid common exceptions and problems. Make sure you use using statements any time you’re working with any class that implements it. You can only use a class in a “using” statement if it implements IDisposable; otherwise, your program won’t compile. Your object must implement IDisposable if you want to use your object within a using statement. class Nectar : IDisposable { private double amount; private BeeHive hive; private Stream hiveLog; public Nectar(double amount, BeeHive hive, Stream hiveLog) { this.amount = amount; The IDisposable interface only has one member: the this.hive = hive; Dispose() method. Whatever you put in this method will this.hiveLog = hiveLog; get executed at the end of the using statement…or } whenever Dispose() is called manually. public void Dispose() { This Dispose