首页资源分类其它科学普及 > Head First C#(英文版)

Head First C#(英文版)

已有 460501个资源

下载专区


TI最新应用解决方案

工业电子 汽车电子 个人消费电子

上传者其他资源

文档信息举报收藏

标    签: c

分    享:

文档简介

Head First C#(英文版)

文档预览

More free ebooks : http://fast-file.blogspot.com 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 “Head First C# is a great book for hobbyist programmers. It provides examples and guidance on a majority of the things [those] programmers are likely to encounter writing applications in C#.” —Peter Ritchie, Microsoft MVP (2006-2007), Visual Developer, C# “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 “Head First C# is perfect blend of unique and interesting ways covering most of the concepts of programming. Fun excercises, bullet points, and even comic strips are some of the catchy and awesome works that this book has. The game-based labs are something that you really don’t want to miss. [This book is] a great work... the novice as [well as the] well-experienced will love this book. GREAT JOB!” —Aayam Singh, .NET professional “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 More free ebooks : http://fast-file.blogspot.com 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 dog-eared, 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 More free ebooks : http://fast-file.blogspot.com 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 ‘Buehler… Buehler… Buehler…’ 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 More free ebooks : http://fast-file.blogspot.com Other related books from O’Reilly Programming C# 3.0 C# 3.0 in a Nutshell C# 3.0 Cookbook™ C# 3.0 Design Patterns 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 (2008) Head First Programming (2008) Head First Ruby on Rails (2008) Head First PHP & MySQL (2008) More free ebooks : http://fast-file.blogspot.com Head First C# 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 More free ebooks : http://fast-file.blogspot.com Head First C# by Andrew Stellman and Jennifer Greene Copyright © 2008 O’Reilly Media, Inc. 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 (safari.oreilly.com). For more information, contact our corporate/institutional sales department: (800) 998-9938 or corporate@oreilly.com. Series Creators: Series Editor: Design Editor: Cover Designers: Production Editor: Proofreader: Indexer: Page Viewers: Kathy Sierra, Bert Bates Brett D. McLaughlin Louise Barr Louise Barr, Steve Fehler Sanders Kleinfeld Colleen Gorman Julie Hawks Quentin the whippet and Tequila the pomeranian Printing History: November 2007: First 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. TM This book uses RepKover™,  a durable and flexible lay-flat binding. ISBN: 978-0-596-51482-2 [M] [9/08] More free ebooks : http://fast-file.blogspot.com 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. More free ebooks : http://fast-file.blogspot.com 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 … because we know you’re going to have a great time learning C#. This photo (and Gowanus Canal) the photo of the by Nisha Sondhe 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. Jennifer Greene studied philosophy in 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 college but, like everyone else in the field, couldn’t find a job doing it. Luckily, she’s a great software tester, so she started out doing it at an online service, and that’s the first time she really got a good sense of what project management was. cello and jazz bass guitar. He and Jenny first She moved to New York in 1998 to test software worked together at that same financial software at a financial software company. She managed company, where he was managing a team of a team of testers at a really cool startup that programmers. He’s had the privilege of working did artificial intelligence and natural language with some pretty amazing programmers over the processing. years, and likes to think that he’s learned a few things from them. Since then, she’s traveled all over the world to work with different software teams and build all kinds of When he’s not writing books, Andrew keeps cool projects. himself busy writing useless (but fun) software, playing music (but video games even more), studying taiji and aikido, having a girlfriend named Lisa, and owning a pomeranian. She loves traveling, watching Bollywood movies, reading the occasional comic book, waiting for her Xbox to be repaired, drinking carloads of carbonated beverages, and owning a whippet. JTf2sbeci0ohrnioeesn0tknyys5t,mfi.asotentTuthdsnhedsieyAnteynudd1ddp9oruyS9ebait8nwleig.lslohlhThmteaehdavoreenbfitrib&hcseiefpdGeieirnerrasekftbeeixuinnrbipgelsodotoasCinutkbogr,onecoAssokuoipnnlftpfitnlVeiinwreitgeeadhtnriecnneSeaoH2asmfen0atadvn0wdedwta3Frrsm.eiittreWosiePntthbrgieuosnneaijglerbdsticoethouaseft, MyrHe’ssreooaaeafflnldyattngwwonFetaaemirrarbeeetsunteeitslnndoP,ggfiMnwiitnngaeewPseesa,rorprsifieunn,tbgapw2lirrtsa0cohorhjeg0eeidetc7toet.brhcyetfwrsoOrrsai’tiRnnidecniegllythiney project managers. Check out their blog, Building Better Software: http://www.stellman-greene.com viii More free ebooks : http://fast-file.blogspot.com 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 43 3 Objects Get Oriented: Making code make sense 85 4 Types and References: It’s 10:00. Do you know where your data is? 123 C# Lab 1: A Day at the Races 163 5 Encapsulation: Keep your privates… private 173 6 Inheritance: Your object’s family tree 205 7 Interfaces and abstract classes: Making classes keep their promises 251 8 Enums and collections: Storing lots of data 309 C# Lab 2: The Quest 363 9 Reading and writing files: Save the byte array, save the world 385 10 Exception handling: Putting Out Fires Gets Old 439 11 Events and delegates: What Your Code Does When You’re Not Looking 483 12 Review and preview: Knowledge, Power, and Building Cool Stuff 515 13 Controls and graphics: Make it pretty 563 14 Captain Amazing: The Death of the Object 621 15 LINQ: Get control of your data 653 C# Lab 3: Invaders 681 i Leftovers: The top 5 things we wanted to include in this book 703 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? We know what you’re thinking Metacognition Bend your brain into submission What you need for this book Read me The technical review team Acknowledgments xxx xxxi xxxiii xxxv xxxvi xxxii xxxiv xxxv ix More free ebooks : http://fast-file.blogspot.com 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 for a button, and which one was for its label. Sound appealing? Turn the page, and let’s get programming. 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 Here’s what you’re going to build 6 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 You can already run your application 16 We need a database to store our information 18 Creating the table for the Contact List 20 The blanks on contact card are columns in our People table 22 Finish building the table 25 Diagram your data so your application can access it 26 Insert your card data into the database 28 Connect your form to your database objects with a data source 30 Add database-driven controls to your form 32 Good apps are intuitive to use 34 How to turn YOUR application into EVERYONE’S application 37 Give your users the application 38 You’re NOT done: test your installation 39 You built a complete data-driven application 40  More free ebooks : http://fast-file.blogspot.com 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… 44 …the IDE does this 45 Where programs come from 46 The IDE helps you code 48 When you change things in the IDE, you’re also changing your code 50 Anatomy of a program 52 Your program knows where to start 54 You can change your program’s entry point 56 Two classes can be in the same namespace 61 Your programs use variables to work with data 62 C# uses familiar math symbols 64 Loops perform an action over and over again 65 Time to start coding 66 if/else statements make decisions 67 Set up conditions and see if they’re true 68 xi More free ebooks : http://fast-file.blogspot.com 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. new Navigator() new Navigator() new Navigator() 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 simple application 89 Mike gets an idea 90 Mike can use objects to solve his problem 91 You use a class to build an object 92 When you create a new object from a class, it’s called an instance of that class 93 A better solution… brought to you by objects! 94 An instance uses fields to keep track of things 98 Let’s create some instances! 99 Thanks for the memory 100 What’s on your program’s mind 101 You can use class and method names to make your code intuitive 102 Give your classes a natural structure 104 Class diagrams help you organize your classes so they make sense 106 Build a class to work with some guys 110 Create a project for your guys 111 Build a form to interact with the guys 112 There’s an even easier way to initialize objects 115 A few ideas for designing intuitive classes 116 xii More free ebooks : http://fast-file.blogspot.com table of contents types and references 4 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, how to work with data in your program, and even figure out a few dirty secrets about objects (psstt… objects are data, too). Lucky Lucky fido The variable’s type determines what kind of data it can store 124 A variable is like a data to-go cup 126 10 pounds of data in a 5 pound bag 127 Even when a number is the right size, you can’t just assign it to any variable 128 When you cast a value that’s too big, C# will adjust it automatically 129 C# does some casting automatically 130 When you call a method, the variables must match the types of the parameters 131 Combining = with an operator 136 Objects use variables, too 137 Refer to your objects with reference variables 138 References are like labels for your object 139 If there aren’t any more references, your object gets garbage collected 140 Multiple references and their side effects 142 Two references means TWO ways to change an object’s data 147 A special case: arrays 148 Arrays can contain a bunch of reference variables, too 149 Welcome to Sloppy Joe’s Budget House o’ Discount Sandwiches! 150 Objects use references to talk to each other 152 Where no object has gone before 153 fido xiii More free ebooks : http://fast-file.blogspot.com 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. The Spec: Build a Racetrack Simulator 164 The Finished Product 172 xiv More free ebooks : http://fast-file.blogspot.com 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 properties. 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 174 What does the estimator do? 175 Kathleen’s Test Drive 180 Each option should be calculated individually 182 It’s easy to accidentally misuse your objects 184 Encapsulation means keeping some of the data in a class private 185 Use encapsulation to control access to your class’s methods and fields 186 But is the realName field REALLY protected? 187 Private fields and methods can only be accessed from inside the class 188 A few ideas for encapsulating classes 191 Encapsulation keeps your data pristine 192 Properties make encapsulation easier 193 Build an application to test the Farmer class 194 Use automatic properties to finish the class 195 What if we want to change the feed multiplier? 196 Use a constructor to initialize private fields 197 xv More free ebooks : http://fast-file.blogspot.com 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 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 206 We need a BirthdayParty class 207 One more thing... can you add a $100 fee for parties over 12? 213 When your classes use inheritance, you only need to write your code once 214 Build up your class model by starting general and getting more specific 215 How would you design a zoo simulator? 216 Use inheritance to avoid duplicate code in subclasses 217 Different animals make different noises 218 Think about how to group the animals 219 Create the class hierarchy 220 Every subclass extends its base class 221 Use a colon to inherit from a base class 222 We know that inheritance adds the base class fields, properties, and methods to the subclass... 225 A subclass can override methods to change or replace methods it inherited 226 Any place where you can use a base class, you can use one of its subclasses instead 227 A subclass can access its base class using the base keyword 232 When a base class has a constructor, your subclass needs one too 233 Now you’re ready to finish the job for Kathleen! 234 Build a beehive management system 239 First you’ll build the basic system 240 Use inheritance to extend the bee management system 245 xvi More free ebooks : http://fast-file.blogspot.com 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 252 We can use inheritance to create classes for different types of bees 253 An interface tells a class that it must implement certain methods and properties 254 Use the interface keyword to define an interface 255 Get a little practice using interfaces 256 Now you can create an instance of NectarStinger that does both jobs 257 Classes that implement interfaces have to include ALL of the interface’s methods 258 You can’t instantiate an interface, but you can reference an interface 260 Interface references work just like object references 261 You can find out if a class implements a certain interface with “is” 262 Interfaces can inherit from other interfaces 263 The RoboBee 4000 can do a worker bee’s job without using valuable honey 264 is tells you what an object implements, as tells the compiler how to treat your object 265 A CoffeeMaker is also an Appliance 266 Upcasting works with both objects and interfaces 267 Downcasting lets you turn your appliance back into a coffee maker 268 Upcasting and downcasting work with interfaces, too 269 There’s more than just public and private 273 Access modifiers change scope 274 Some classes should never be instantiated 277 An abstract class is like a cross between a class and an interface 278 Like we said, some classes should never be instantiated 280 An abstract method doesn’t have a body 281 Polymorphism means that one object can take many different forms 289 xvii More free ebooks : http://fast-file.blogspot.com 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. Strings don’t always work for storing categories of data 310 Enums let you enumerate a set of valid values 311 Enums let you represent numbers with names 312 We could use an array to create a deck of cards... 315 Arrays are hard to work with 316 Lists make it easy to store collections of... anything 317 Lists are more flexible than arrays 318 Lists shrink and grow dynamically 321 List objects can store any type 322 Collection initializers work just like object initializers 326 Let’s create a list of Ducks 327 Lists are easy, but SORTING can be tricky 328 Two ways to sort your ducks 329 Use IComparer to tell your List how to sort 330 Create an instance of your comparer object 331 IComparer can do complex comparisons 332 Use a dictionary to store keys and values 335 The Dictionary Functionality Rundown 336 Your key and value can be different types, too 337 You can build your own overloaded methods 343 poof! And yet MORE collection types... 355 A queue is FIFO — First In, First Out 356 A stack is LIFO — Last In, First Out 357 xviii More free ebooks : http://fast-file.blogspot.com 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 364 The fun’s just beginning! 484 xix More free ebooks : http://fast-file.blogspot.com 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. C# uses streams to read and write data 386 Different streams read and write different things 387 A FileStream writes bytes to a file 388 Reading and writing takes two objects 393 Data can go through more than one stream 394 Use built-in objects to pop up standard dialog boxes 397 Dialog boxes are objects, too 399 Use the built-in File and Directory classes to work with files and directories 400 Use File Dialogs to open and save files 403 IDisposable makes sure your objects are disposed properly 405 Avoid file system errors with using statements 406 Writing files usually involves making a lot of decisions 412 Use a switch statement to choose the right option 413 Add an overloaded Deck() constructor that reads a deck of cards in from a file 415 What happens to an object when it’s serialized? 417 But what exactly IS an object’s state? What needs to be saved? 418 When an object is serialized, all of the objects it refers to get serialized too... 419 Serialization lets you read or write a whole object all at once 420 If you want your class to be serializable, mark it with the [Serializable] attribute 421 69 117 114 101 107 97 33 .NET converts text to Unicode automatically 425 C# can use byte arrays to move data around 426 Use a BinaryWriter to write binary data 427 You can read and write serialized files manually, too 429 StreamReader and StreamWriter will do just fine 433 xx More free ebooks : http://fast-file.blogspot.com 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 pages 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 440 When your program throws an exception, .NET generates an Exception object. 444 Brian’s code did something unexpected 446 All exception objects inherit from Exception 448 The debugger helps you track down and prevent exceptions in your code 449 Use the IDE’s debugger to ferret out exactly what went wrong in the excuse manager 450 Uh-oh—the code’s still got problems... 453 Handle exceptions with try and catch 455 What happens when a method you want to call is risky? 456 Use the debugger to follow the try/catch flow 458 If you have code that ALWAYS should run, use a finally block 460 Use the Exception object to get information about the problem 465 Use more than one catch block to handle multiple types of exceptions 466 One class throws an exception, another class catches the exception 467 Bees need an OutOfHoney exception 468 An easy way to avoid a lot of problems: using gives you try and finally for free 471 Exception avoidance: implement IDisposable to do your own clean up 472 The worst catch block EVER: comments 474 Temporary solutions are okay (temporarily) 475 A few simple ideas for exception handling 476 Brian finally gets his vacation... 481 xxi More free ebooks : http://fast-file.blogspot.com 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’ve got too many objects responding to the same event. And that’s when callbacks will come in handy. Ever wish your objects could think for themselves? 484 But how does an object KNOW to respond? 484 When an EVENT occurs... objects listen 485 One object raises its event, others listen for it... 486 Then, the other objects handle the event 487 Connecting the dots 488 The IDE creates event handlers for you automatically 492 The forms you’ve been building all use events 498 Connecting event senders with event receivers 500 A delegate STANDS IN for an actual method 501 Delegates in action 502 Any object can subscribe to a public event... 505 Use a callback instead of an event to hook up exactly one object to a delegate 507 Callbacks use delegates, but NOT events 508 xxii More free ebooks : http://fast-file.blogspot.com 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 learn about some new odds and ends: timers and dealing with collections using LINQ (to name a couple). We’re also going to build phase I of a really complex application, and 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 cool software. You’ve come a long way, baby 516 We’ve also become beekeepers 517 The beehive simulator architecture 518 Building the beehive simulator 519 Life and death of a flower 523 Now we need a Bee class 524 Filling out the Hive class 532 The hive’s Go() method 533 We’re ready for the World 534 We’re building a turn-based system 535 Giving the bees behavior 542 The main form tells the world to Go() 544 We can use World to get statistics 545 Timers fire events over and over again 546 The timer’s using a delegate behind the scenes 547 Let’s work with groups of bees 554 A collection collects... DATA 555 LINQ makes working with data in collections and databases easy 557 xxiii More free ebooks : http://fast-file.blogspot.com 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 on 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. You’ve been using controls all along to interact with your programs 564 Form controls are just objects 565 Add a renderer to your architecture 568 Controls are well-suited for visual display elements 570 Build your first animated control 573 Your controls need to dispose their controls, too! 577 A UserControl is an easy way to build a control 578 Add the hive and field forms to the project 582 Build the Renderer 583 Let’s take a closer look at those performance issues 590 You resized your Bitmaps using a Graphics object 592 Your image resources are stored in Bitmap objects 593 Use System.Drawing to TAKE CONTROL of graphics yourself 594 A 30-second tour of GDI+ graphics 595 Use graphics to draw a picture on a form 596 Graphics can fix our transparency problem... 601 Use the Paint event to make your graphics stick 602 A closer look at how forms and controls repaint themselves 605 Double buffering makes animation look a lot smoother 608 Double buffering is built into forms and controls 609 Use a Graphics object and an event handler for printing 614 PrintDocument works with the print dialog and print preview window objects 615 xxiv More free ebooks : http://fast-file.blogspot.com table of contents 14 CAPTAIN AMAZING THE DEATH OF THE OBJECT Captain Amazing, Objectville’s most amazing object pursues his arch-nemesis... 622 Your last chance to DO something... your object’s finalizer 628 When EXACTLY does a finalizer run? 629 Dispose() works with using, finalizers work with garbage collection 630 Finalizers can’t depend on stability 632 Make an object serialize itself in its Dispose() 633 Meanwhile, on the streets of Objectville... 636 A struct looks like an object... 637 ..but isn’t on the heap 637 Values get copied, references get assigned 638 Structs are value types; objects are reference types 639 The stack vs. the heap: more on memory 641 Captain Amazing... not so much 645 Extension methods add new behavior to EXISTING classes 646 Extending a fundamental type: string 648 xxv More free ebooks : http://fast-file.blogspot.com table of contents LINQ 15 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. An easy project... 654 ...but the data’s all over the place 655 LINQ can pull data from multiple sources 656 .NET collections are already set up for LINQ 657 LINQ makes queries easy 658 LINQ is simple, but your queries don’t have to be 659 LINQ is versatile 662 LINQ can combine your results into groups 667 Combine Jimmy’s values into groups 668 Use join to combine two collections into one query 671 Jimmy saved a bunch of dough 672 Connect LINQ to a SQL database 674 Use a join query to connect Starbuzz and Objectville 678 xxvi More free ebooks : http://fast-file.blogspot.com 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 682 And yet there’s more to do... 701 More free ebooks : http://fast-file.blogspot.com xxvii table of contents leftovers i The top 5 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. #1 LINQ to XML 704 #2 Refactoring 706 #3 Some of our favorite Toolbox components 708 #4 Console Applications 710 #5 Windows Presentation Foundation 712 Did you know that C# and the .NET Framework can... 714 xxviii More free ebooks : http://fast-file.blogspot.com how to use this book Intro I can’t believe they put that in a C# programming book! “ISnotwhihsyseDcItDiont,hweye pauntswtehratthien baurCn#ingpqruoegsrtaimonm:ing book?” xxix More free ebooks : http://fast-file.blogspot.com 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. f[oNrotaenyfornoemwimtahrkaectrinegd:itthciasrbdo.]ok is xxx   intro More free ebooks : http://fast-file.blogspot.com 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 THIS bisraiminpotrhtinaknst. 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 YTosaHuvrIiSnbgir.sani’nt twhoirntksh the most. 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.” Great. Only 700 more dull, dry, boring pages. you are here 4   xxxi More free ebooks : http://fast-file.blogspot.com how to use this book We think of a “Head First” reader as a learner. Syllaeootauewrsdnhtoianrnteg’dstteofaoaekrrsegcsiehttatiaintlok.cetIotmtg’osonlnrieteoiavttrehanasbsncooiutemetnxepcttuehos,innhngiaen?upgrFaofiagbrcesio.tt,slWoyigneoytuko, nhayoanowvduerewthdoheuagactedattu.tiiBrto,nnatsasheyleopdnusomyrncabhtkrhoaeelionsguoyrne, . Some of the Head First learning principles: Mmatwsrtakaohknoeleevsrebflideeotprastrvrstonotwibuismnldiuegtiomeahmrslsi)o.nu.rnIIecmtohlaaaanrtmlgseonoedothsermteeaoaarrertkepfheftafeesahgcrctteehomi,vinanegotngrer(deusanpmmltpe. tahoeormrine8ceo9usrr%nsatdbwhimeleeilrylpstbtrhraeoeanlvnaudetpwaembotteolorend,t.trswaPinaitcuhloereetnarcetsat,hhlllaiaekannendloydnto dtDsGaaihctesroGkciIoeaixemdtnicnsecneita’evutrtcgttnlcseolltyta—ui’laaohtsytbtskefifsoeianfeoeosttl,agetnhrnmylhmayxeesdodsneo,aytauabidatunwroklrrierndnvsutatteaanodehhaeeirkndelnteeonrtnfegeeeepuatprtUoeedrpsc.ong,—aurn,Thtaspodudhrreeeonstoeeitstnrlstynmi-ilhranecngptpafsctaasureohgarrteaoi,loolyroggitnmactmn,rvrniueoeopiieeoofpensdekptilwoklraseatnhd,yisenicncm.iindvtsknnureuW-idegeneeopgsp”ronostohnieerrqtoesmterwis’,xriuoecausnessopauehlsndosg4ere.cs,a’tdn,0dtworathaist,ii%eghofneootlctheearlendnnuoeeabacv.cslpncannpitAeede,ntuvglptltna.utsyeytreYieondpereaor.o,oindsr?iunbnIefrnuasnooegeayptdr.irndi.econaobbWUtt-tpyptnhoircyhosveaoeaaaormeei’iittssltvnunrrci,cotoseesrg-whyaptrllsvhay.ooeesiaonYeltlueauynelarhogaardsphtananur,dltsraaatueeirll,o.ndattieinnubthbnznAgdetetnrelvegihneaxtorlrocueeedeimptnhntlissaaveho“asstdgtsIewcsan,loyrleettndbieei:eotl.ryfrlnaoaoduatlllgth.eelwthyeLhae.esriwcnI,nanoagrmnnnrsettiutnechtcegnoahnttaltemsanpsaroteroeunrwkeodet,uihqtetoiussou,icbfgkuhlty, if it’s not. kyhysnouoeouruaspwTorcsrtomaoi‑sswruoleeevmrc,teeahchenbauintcorphtghiuohuiintinszse.gizgtliYlyatreos,hr,tgufeaolueetrmrnalie“ye,Irm’o“snmdwteaesihmbmopoaomebontuneretstedhrt.aehetwWeni.bn.hct.oe?gheo”ynnnen, aoiavycniwenotadsrdluykethbtnfhmehioosaeeodnwdl tfysotietoohgeehmnol.lasiaWunteel”gtyecthBo’hoorioueninfnbrg“ttkeIaa.fsrRnblNokiutisoiml.nli,ehtYgyw!aeo”retneutdom’hgr,rearieoonetmnrtemcioreooeeetrnmmamitnslabeigblzlisekeekdriwernyowghoehseunan’tt. xxxii   intro More free ebooks : http://fast-file.blogspot.com 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. 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. the intro I wonder how I can trick my brain into remembering this stuff... 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 More free ebooks : http://fast-file.blogspot.com how to use this book Here’s what WE did: When you define a class, you define its methods, just like defines the layout of a blueprint the house. 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, mamYnaoadkukeeycoaaaunnnyycuansnenuummoubbnseeeerrobonolueffepcohrlbaoijnusestscettsto,so. 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 More free ebooks : http://fast-file.blogspot.com the intro Here ’s w hat Y OU 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 oCnutyotuhrisreofurtfiogarenrydaotusotrai.cnkditwhat doesn’t. Try new things. 1 Slow down. The more you understand, the less you have to memorize. 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. 6 Talk about it. Out loud. 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. 2 Do the exercises. Write your own notes. 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 Read the “There are No Dumb Questions” That means all of them. They’re not optional sidebars—they’re part of the core content! Don’t skip them. 4 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. 7 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. 8 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. 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 More free ebooks : http://fast-file.blogspot.com how to use this book What you need for this book: We wrote this book using Visual C# 2008 Express Edition, which uses C# 3.0 and .NET Framework 3.5. 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 2008 Standard, Professional, or Team System 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 2008 EXPRESS EDITION � It’s easy enough to download and install Visual C# 2008 Express Edition. Here’s the link to the Visual Studio 2008 Express Edition download page: http://www.microsoft.com/express/download/ Make sure that you check all of the options when you install it. 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. at Microsoft has The C# team added some pretty cool features to the language. when we We’ll give you warnings talk about any of these topics. But definitely 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# 2008 Express Edition. Make sure you do a complete installation. That should install everything that you need: the IDE (which you’ll learn about), SQL Server Express Edition, and .NET Framework 3.5. � Once you’ve got it installed, you’ll have a new Start menu option: Microsoft Visual C# 2008 Express Edition. Click on it to bring up the IDE, and you’re all set. xxxvi   intro More free ebooks : http://fast-file.blogspot.com 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. Wmtoeakuuensedteoarusgltohatncodof.ncdepiatgsraemassietro † ciaAgent mi5Agent 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. “YSohuarshpeonuldyoduro pAeLncLil”ofacttihveities 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. asaEAbkrixoceptuetirrtvechiltaieesliealmeyrs(niirmfminuapngyronokrCiunet#’gdraen.swthsi!oeterDh)iootulnosh’gteo 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. Itywfohoueyno’datucotnlsii’ekvteeitlttiykhheieesstPeowopeiotsilttioyPhneualzrol,.zgialcen,dlyoogifuo, 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 More free ebooks : http://fast-file.blogspot.com the review team The technical review team Lisa Kellner Joe Albahari Jay Hilyard Daniel Kinnaer Not pictured (but just as awesome): Wayne Bradney, Dave Murdoch, and Bridgette Julie Landers Aayam Singh Theodore Casser Andy Parker Peter Ritchie Bill Mietelski Technical Reviewers: When we wrote this book, it had a bunch of mistakes, issues, problems, typos, and terrible arithmetic errors. Okay, 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 Joe Albahari for the enormous amount of technical guidance. He really set us straight on a few really important things, and if it weren’t for him you’d be learning incorrect stuff. We also want to thank Lisa Kellner—this is our third 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 Jay Hilyard and Daniel Kinnaer for catching and fixing a whole lot of our mistakes, and Aayam Singh for actually going through and doing every one of these exercises before we fixed them and corrected their problems. Aayam, you’re really dedicated. Thanks! And special thanks to our favorite readers, David Briggs and Jaime Moreno, for going above and beyond the call of duty by finding and reporting many errors that we didn’t catch in the first printing, and to Jon Skeet for going through the whole book carefully and helping us fix a bunch of errors. xxxviii   intro More free ebooks : http://fast-file.blogspot.com Krishna Pala Giuseppe Turitto Acknowledgments Our editor: We want to thank our editor, Brett McLaughlin, for editing this book. He 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! Brett McLaughlin the intro 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. First of all, the Head First team rocks—Laurie Petrycki, Catherine Nolan, Sanders Kleinfeld (the most super production editor ever!), Caitrin McCullough, Keith McNamara, and Brittany Smith. Special thanks to Colleen Gorman for her sharp proofread, Ron Bilodeau for volunteering his time and preflighting expertise, and Adam Witwer 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, Isabel Kunkle, 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 More free ebooks : http://fast-file.blogspot.com safari books online Safari® Books Online When you see a Safari® icon on the cover of your favorite technology book that means the book is available online through the O’Reilly Network Safari Bookshelf. Safari offers a solution that’s better than e-books. It’s a virtual library that lets you easily search thousands of top tech books, cut and paste code samples, download chapters, and find quick answers when you need the most accurate, current information. Try it for free at http://safari.oreilly.com. xl   intro More free ebooks : http://fast-file.blogspot.com 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 for a button, and which one was for its label. Sound appealing? Turn the page, and let’s get programming. this is a new chapter    More free ebooks : http://fast-file.blogspot.com c# makes it easy Why you should learn 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 automates for you... The IDE—or Visual Studio Integrated Development Environment—is an important part of working in C#. It’s a program that helps you edit your code, manage your files, and publish your projects. Every time you want to get started writing a program, or just putting a button on a form, your program needs private { void InitializeComponent() /tt/hhiiss..Sbuustpteonnd1La=yonuetw()S;ystem.Windows.Forms.Button(); a whole bunch of repetitive code. // // button1 uuunsssaiiimnnnegggspSSSayyycsssettteeeAmmm_;..NCWeoiwln_ldPeorcwotsgi.roFanomsr.mGse;neric; { static class Program { ///[s{///St///TaAtyMiiie>aoooninnntn...r(ESRy)neuatnpbC(oloniemenVpwtiastFfuiooabrrllmSe1ttT(hye)elx)et;asRp(ep)nl;diecraitnigoDne.fault(false); } ///ttttttt///hhhhhhhiiiiiiiFssssssso.......rbbbbbbbmuuuuuuu1ttttttttttttttooooooonnnnnnn1111111.......CUTTSNLlseaiaoiexbzmccVtIeeakints=d==i+ueo=a“xn“nlbebnSu=wu=etttwyt0Stnlo;yoeSensnwyB1t1sa”e”Stc;m;yek.smCDt.oreElamvow.eriDnnrt=gaH.watSinrinduzglee.e;(Pr7o(5it,nhti2(s31.)0b;5u,tt5o6n)1;_Click); ttttttthhhhhhhiiiiiiisssssss.......RTNCCAAeeaoluusxmnittuteteoomrnSSe==otccLlSaaa““sillyFF.zeeoooAeMDurrdoitmmd=dm(11(eef””tnna;;he=sliwissSoe.Syn)byss;usttte=temom.nn.We1Diw)rn;adSwoyiwsnstg.e.FmSo.irDzmresa(.w2Ai9un2tg,o.SS2ci6az7le)eF;M(o8dFe,.F1o6nFt);; } } } What you get with Visual Studio and C#… cmaIotoubrltudetakvttieoassnukaeaollnlteetlaenhmfitseoinrmctmoesd.setAaojdsutdmsthinuegcthfoaocdrfomredawew. With a language like C#, tuned for Windows programming, and the Visual Studio IDE, you can focus on what your program is supposed to do immediately: tTloaohkkeeisnrgelessauspltptliiimscaeattibooentwttrheiatrte. jects Form Ob .NETsoFlruatmioenwsork CIstDmt#erEodusiatcohntuadpusvrrectoeosghpdrertaeehVm-atimbtshuuianaihtlglta’snStdtpaluasekdrstti.ohoef Data access    Chapter 1 More free ebooks : http://fast-file.blogspot.com C# and the Visual Studio IDE make lots of things easy When you use C# and Visual Studio, you get all of these great features, without having to do any extra work. Together, they let you: get productive with c# 1  Build an application, FAST. Creating programs in C# is a snap. The language is powerful and easy to learn, and the Visual Studio IDE does a lot of work for you automatically. You can leave mundane coding tasks to the IDE and focus on what your code should accomplish. 2  Design a great looking user interface. The Form Designer in the Visual Studio IDE is one of the easiest design tools to use out there. It does so much for you that you’ll find that making stunning user interfaces is one of the most satisfying parts of developing a C# application. You can build full-featured professional programs without having to spend hours writing a graphical user interface entirely from scratch. 3  Create and interact with databases. The IDE includes a simple interface for building databases, and integrates seamlessly with SQL Server Express, as well as several other popular database systems. 4  Focus on solving your REAL problems. The IDE does a lot for you, but you are still in control of what you build with C#. The IDE just lets you focus on your program, your work (or fun!), and your customers. But the IDE handles all the grunt work, such as: ≥ Keeping track of all of your projects ≥ Making it easy to edit your project’s code ≥ Keeping track of your project’s graphics, audio, icons, and other resources ≥ Managing and interacting with databases All this means you’ll have all the time you would’ve spent doing this routine programming to put into building killer programs. Ywohua’trewgeoimngeatnonseexet.exactly More free ebooks : http://fast-file.blogspot.com you are here 4   the boss needs your help Help the CEO go paperless The Objectville Paper Company just hired a new CEO. He loves hiking, coffee, and nature... and he’s decided that to help save forests. He wants to become a paperless executive, starting with his contacts. He’s heading to Aspen to go ski for the weekend, and expects a new address book program by the time he gets back. Otherwise… well… it won’t be just the old CEO who’s looking for a job. Name: Laverne Smith Company: XYZ Industries Telephone: (212)555-8129 Email: Laverne.Smith@XyZindustriescom Client: Y es Last call: 05/26/07 YtCooEug’Ode’tsbletathptitseorpdafqtiunaidcokna. two atyhe    Chapter 1 More free ebooks : http://fast-file.blogspot.com Get to know your users’ needs before you start building your program Before we can start writing the address book application—or any application—we need to take a minute and think about who’s going to be using it, and what they need from the application. 1  The CEO needs to be able to run his address book program at work and on his laptop too. He’ll need an installer to make sure that all of the right files get onto each machine. get productive with c# TapnrhoeignrCstaEmaOlleorwnaihsnitsasdmteuossktbt.eopabalnedtloaprtuonp,hisso Windows installer 2  The Objectville Paper company sales team wants to access his address book, too. They can use his data to build mailing lists and get client leads for more paper sales. The CEO figures a database would be the best way that everyone in the company to see his data, and then he can just keep up with one copy of all his contacts. Wmedteaiaonahskntfaeyeloaly.rssrbeHamoawalanseaodveestryinikltcoegikoenntnpa,gcsoymoewwtnvotheaitftnelalhhcttCaatdhthcsEaecoOtiVeundsagissaabhautnatatadshle.heCser#e’s SQL Database More free ebooks : http://fast-file.blogspot.com you are here 4   here’s your goal Here’s what you’re going to build You’re going to need an application with a graphical user interface, objects to talk to a database, the database itself, and an installer. It sounds like a lot of work, but you’ll build all of this over the next few pages. Here’s the structure of the program we’re going to create: Ybouun’lclhboefbuviilsduianlgcaonWtrinodlsowons form it. with a ttsThheeahpteadraaiantpttapeebliracdasaacettt.iasonlwahiytaehsr a SELECT command .NET Visual Objects .NET Database Objects INSERT command UPDATE command DELETE command urce object ws.Form object objects pter object System.Windo data entry BindingSo TableAda igator object object bject t object PictureBox ToolBar o Erofeanopcrrthmehsoeewfneat’tdlslhdaecrsreecesosaontbbteoj.reoocklts    Chapter 1 BindingNav Ddaitaagbraasme saotWpurperu’llciltctaanutberileeoednsi,so,kabnajodnewdicatgwmsrhoatarmote.tttaohlekledttoaotuarbase More free ebooks : http://fast-file.blogspot.com DataSe get productive with c# Ta hSeQdLatSaerisvearllEstxoprreedssindaatatbaabslee. in Data Storage Table suDpBpodritaogbrajemcts SQL Database Here’s Visual Stthueddioatwaibllasheeliptsueslfc,rewahticeh and maintain. Once the program’s it’ll be packaged up built, into a Windows installer. Deployment Package Database .exe Program file pttrpjhoTduooesgienihntnrpetsaauntmrssaeaeat.enllmlddehsaeistcnnoltdicwk ill Windows installer More free ebooks : http://fast-file.blogspot.com you are here 4   let’s get started What you do in Visual Studio… Go ahead and start up Visual Studio, if you haven’t already. Skip over the start page and select New Project from the File menu. Name your project “Contacts” and click OK. What Visual Studio does for you… As soon as you save the project, the IDE creates a Form1.cs, Form1. Designer.cs, and Program.cs file when you create a new project. It adds these to the Solution Explorer window, and by default, puts those files in My Documents\Visual Studio 2008\Projects\Contacts\. This file contains the C# code that defines the behavior of the form. Tttdhhhiiaesstphplasartyossagtrrtthahsemeucfapoondrdem. Things may look a bit different in your IDE. This is what the “New Project” window looks like in Visual Studio 2008 Express Edition. If you’re using the Professional or Team Foundation edition, it might be a bit different. But don’t worry, everything still works exactly the same. Make sure that you save your project as soon as you create it by selecting “Save All” from the File menu—that’ll save all of the project files out to the folder. If you select “Save”, it just saves the one you’re working on. laTdivneehdfseiinhtceeossrdeote.bhjteehcfattosrm C# Form1.cs    Chapter 1 C# C# Program.cs Visual Studio creates all three of these files automatically. Form1.Designer.cs More free ebooks : http://fast-file.blogspot.com get productive with c# ctTuhhrairtsentatopolpyllbydaortionhgwashinabtutthyteoouIn’DrseE. Below is what your screen probably looks like right now. You should be able to figure out what most of these windows and files are based on what you already know. 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. If your IDE doesn’t look exactly like this picure, you can select “Reset Window Layout” from the Window menu. We’ve blown up this window below so you have more room. You can also bring up these windows by selecting Solution Explorer, Properties, or Error List from the View menu. More free ebooks : http://fast-file.blogspot.com you are here 4   know your ide ctTuhhrairtsentatopolpyllbydaortionhgwashinabtutthyteoouIn’DrseE. 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 is the toolbox. It has a bunch of visual controls that you can drag onto your form. Tdwhehibesungbgotithntegor. emItaprsaehnoeewrisrsoyfroosurin your code. SnffoTeoliwurlhetesypioorFtnuoohjraEwemtcxht1ept.cnlahosperyapeoIenruDad. raEPdinrdcoretegdharteatemhd.ecs This window shows all of the ptrhoepecrotnitersoolsfon your form. EfYxiolepuslocurasenirngsiwntitthcheheSbIoDelutEtw.ieoenn 10   Chapter 1 More free ebooks : http://fast-file.blogspot.com 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 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: First of all, you must be using Visual Studio 2008—in 2005, this doesn’t happen. When you first create a new project in Visual Studio 2008, 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 2008\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. 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 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). 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 your screen will 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 still up to you. you are here 4   11 More free ebooks : http://fast-file.blogspot.com 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. DpErevosepirgeynrettriie.mcsseoinysogtuehtmetafiknoegrmac,hcathnhagenegdceobdtyeo a control’s in Form1. the IDE. C# Form1.Designer.cs 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. 12   Chapter 1 More free ebooks : http://fast-file.blogspot.com You are Here .NET Visual Objects .NET Database Objects get productive with c# Data Storage Deployment Package 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: “YtPSjloitihurptituzhseortteepoeclIeapeaDtmpresnhrytbrEoeotliasaetrptlitcsseeeo”ooksrctatowsouaocmyesfircn.temmredTaosotatonswnkhhhwyeeeeisin control. Then click the can Select import “RaCelhsooocuoarslecreIemdsoaiauglreoc”ge.tbooxbrsiongyouup Cballaiccckoknotanrrortlo’hswisptrliootptaelcrecteisess. pswuitzCtihlehleioncooPhfisiatecnt.tg“hueZeretopBooicomtmx”uarftseorcahytmohtueahte 3  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. Hazjenuordsotem’tsrshitgethhoPeti.gcOetPtuCrtehBloeogxsoi,ze More free ebooks : http://fast-file.blogspot.com you are here 4   13 conserving c#’s natural resources Visual Studio, behind the scenes 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 graphic 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. TChoinstiamcatgeLiisstnaopwplaicraetsioonur. ce of the “tihTDSstGoitothowodriusFhCiobtnaoowltgtertrsi-mthl”lll-e,cih1nd.le2aciklciinsss)nSkdpktoitltiaoolnosunyegttels.oeFitxeocwoepnttraohtmnE“ehfd1Ixem.iPrplieaetllisoocgs:tgrxe(eouFis,fr”rocterlfiaBhitmcnra’ok1dsotx.mDno,cyonelaotitscnuhtikdgeahinmleoretdpnerhraoa.eorctrdprsthIy-oDeeawddenEpxo.dnlwpuTaeFsanxdhnotidadlcritesomettdndo1f.)(crni.oleoeersdxxte. C# C# Form1.Designer.cs HVceirrseueaatal erSdettuedahrieoliferil.es Form1.cs C# Program.cs C# Form1.resx 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. WII(sDtgthroEecarnopecnhdyrtieocadausita,nitsevmdaiadp)loetlraohots,ifsseaoducftdiihatlieetoheefradeonimsrdwoauiytogroethcu,he.Fsetorhrem1. 14   Chapter 1 More free ebooks : http://fast-file.blogspot.com 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 { public Form1() { 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(); } private void pictureBox1_Click(object sender, EventArgs e) TgwPohhioicesdtnmuirsdeoetemBaheoooaxdnbeconouacntmltiecwrkohgslei.vonensittyhoriuusnas: { 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. bTbooyxxpewtoiilnlpbtoehpiutspiltiwnleeitdho“ftAhcbeooduttee.”x.Itt ycoauuspersoavidmee.ssTahgee OoibFdcfnyooiclniecesneogomyldenoe“ecuSn,tt’uavhis.nevaegeGvteIe“ADytSipltElae”ivdnuetrs”oetiinnoghfgluetbrlatahohrrehmaleybolt!iirnStheaeovef Q: What’s a method? Q: What does that \n thing do? A: A method is just a named block of code. We’ll talk a lot more about methods in Chapter 2. A: 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:”. More free ebooks : http://fast-file.blogspot.com you are here 4   15 run the app (already!) You can already 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: . cdbAoiulddltnett’tohtnrohseamewvaeookrfteko—tthwhaeenrsmdieteywooaurnyk. Clicking on the OthPeCAlbogooutbrbionxgsyuopu just coded. Where are my files? When you run your program, Visual Studio copies all of your files to My Documents\Visual Studio 2008\Projects\Contacts\ Contacts\bin\debug. You can even hop over to that directory and run your program by doubleclicking on the .exe file the IDE creates. C# turns your program into a file that you can run, called an executable. You’ll find it in here, in the debug folder. C# C# C# Program.cs C# Form1. C# Contacts.csproj bin Designer.cs Form1.cs Form1.resx Properties This isn’t a mistake; there folder has the actual C# are two levels code files. of folders. The inner Q: In my IDE, the green arrow is marked as “Debug”. Is that a problem? A: 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: I don’t see the Stop Debugging button on my toolbar. What gives? A: The Stop Debugging button only 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. 16   Chapter 1 More free ebooks : http://fast-file.blogspot.com 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. .NET Visual Objects .NET Database Objects get productive with c# SQL Database Data Storage Deployment Package aHlreerae’dsywdhoante…we’ve …owbibnuitjteohcuwtrteshdetsatotdilailanbtntaaeeserewda.ec’stlol mpeut hiwtTtcaoeovh’yneritensehtaesec,ntdtoseditaipnnatgctraiesaebobaawaudasrbeseyoe.fdu,fotoosrnorm’t Socainonrniedttwaihteapiilusnntdgesttaeoitdenuapgrtinosndeotaxfmototeac:itbuas. se, 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. More free ebooks : http://fast-file.blogspot.com 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. bsMteofapokpreeedsyuodrueebcyuoognugt’viniengue. 1  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.mdf. This new file is our database. SQL ContactDB.mdf Pick the right icon for the version you’re using. Choose SQL Database if you’re using Visual Studio Express 2005 and ServiceBased Database if you’re using 2008. 2  Click on the Add button in the Add New Item window. 3  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. 4  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.mdf in the Solution Explorer and look at the left side of your screen. The Toolbox has changed to a Database Explorer. TDohEFhRnyaahexollEtvyoiuppeawSA’rwrbQSbeDeaotsaQLsroMscnekLkoidsEnitcostSitofioseftnaurlhytrlveoiehesdue.r. If you’re not using the Express edition, you’ll see “Server Explorer” instead of “Database Explorer”. The Visual Studio 2008 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. 18   Chapter 1 More free ebooks : http://fast-file.blogspot.com get productive with c# The IDE created a database .NET Visual Objects .NET Database Objects Data Storage Deployment Package 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. You are Here Ytroaoubwrlse,dwalitkitaeh’sincsotalourmsepndrseaiandnsdaheet. Tables chdAooadwtSeaQi,ttLa’osndhdstaetrlhpuaacbsytaoiusnurefeaosdcrtcmoaeransetsdsioitSyno.QuaLrbout ProScteodreudres DaStaQbLase Stored procedures are statements that let you work with your data easily. 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. SQL 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 ContactDB.mdf any time. The IDE generates SQL statements and stored procedures for you automatically to let your program access the data in the database. [note from marketing: Can we get a plug for Head First SQL in here?] 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. More free ebooks : http://fast-file.blogspot.com you are here 4   19 data storage made easy Creating 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 Add New Table. This will open up a window where you can define the columns in the table you just created. Q: What’s a column again? A: 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 dropdown box. Be sure to uncheck the Allow Nulls checkbox. 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. This your is the Primary database look Key button. A primary up records quickly. key helps Q: What’s that Int from Data Type mean? A: 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. Focus on the basic steps, and we’ll spend a lot more time on databases in the later chapters of the book. And if you’re dying to know more right away, you can always pick up Head First SQL to read along with this book. 20   Chapter 1 More free ebooks : http://fast-file.blogspot.com .NET Visual Objects .NET Database Objects get productive with c# Data Storage Deployment Package 3  Tell the database to auto-generate 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. In the properties below your table, scroll down to Identity Specification, click the + button, and select Yes next to the (Is Identity) property. Tttohhiesdedwfainitndaeoiwytouiwsrilwlthasatbtoleryeao. nuduse You are Here It’s important that you leave this unchecked. Since the primary key is the main program way your will locate records, it always needs to have a value. Ytseoolued’clletsniYegenedsatfterooCmcolincttkhaecotndIDrtohpaedsoryiwgonhutrnecrxoetcluomtrond and IsIdentity Identifier. More free ebooks : http://fast-file.blogspot.com rwafCeTiuhticoeteholnonsidrstomedvauawtecptiirhtsldilacIaaaDtamtdlnlaedtyeskhewede. you are here 4   21 let’s table this discussion The blanks on 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. Name: Laverne Smith Company: XYZ Industries Telephone: (212)555-8129 Email: Laverne.Smith@XyZindustries.com Client: Y es Last call: 05/26/07 oahFfdeordrtrnheeaeasmscl,haeis,ftpceostrhmsiemop’nsea,naswyhn,eeOpwwhPaoaCnnsteccanltilueolmnesdtbt,.eorar,nedemddaaaitltae, People tsEhhaeocuplhdeobmplalaenpkttaoobnlaet.hceolucmarndin 22   Chapter 1 What kinds of problems could result from having multiple rows stored for the same person? More free ebooks : http://fast-file.blogspot.com 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 Last Call Name ContactID Client? Data Type int bit nvarchar(50) datetime Description This type stores a date and time A Boolean true/false type A string of letters, numbers and other characters with a maximum length of 50 A whole number More free ebooks : http://fast-file.blogspot.com 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 Last Call Name ContactID Client? Data Type int bit nvarchar(50) datetime Description This type stores a date and time A Boolean true/false type A string of letters, numbers and other characters with a maximum length of 50 A whole number 24   Chapter 1 More free ebooks : http://fast-file.blogspot.com Finish building the table 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: .NET Visual Objects .NET Database Objects get productive with c# Data Storage Deployment Package You are Here Bit fields hold True or False values and can be represented as a checkbox. IAfchlolayolvuowemunaNunumvlcaluhslsu,etect.khe bliheSnetafovbomeclraeemnsrockatmat.arieiondnms,ciomsslosuiignmwhgntes’ll Click on the Save button on the toolbar to save your new table. You’ll be asked for a name. Call it “People” and click OK. People Wtigtaei’vb’sveleeniotbatesaeutnnnhtotefialf“lktPiciehnioiagspl lasentb”aeomptuetat.bhtlaeht,isbyuotu dwTahhtiicashbcagrsoeeea. steins athPeeoCpolenttaacbtlDe,B ContactDB More free ebooks : http://fast-file.blogspot.com you are here 4   25 map it out Diagram your data The Visual Studio IDE is built to work with databases, and it comes with a lot of built-in tools that help you when you’re handling a lot of data. One of the most powerful tools you have is the database diagram, which you can use to view and edit complex relationships between the tables in your database. So let’s go ahead and build a database diagram for your database. In very rare cases, a few people sometimes have problems getting the SQL database to work. If you run into any trouble, don’t worry—go to the Head First C# forum at http:// www.headfirstlabs.com/ for help troubleshooting the problem. 1  Create a new database diagram. Go to the Database Explorer window and right-click on the Database Diagrams node. Select Add New Diagram. 2  Let the IDE generate access code. Before you tell the IDE about your specific table, it needs to create some basic stored procedures for interacting with your database. Just click Yes here, and let the IDE go to work. Remember, these options are all under ContactDB, so they all apply to that specific database. 3  Select the tables you want to work with. Select the People table from the window that pops up, and click Add. Now the IDE is ready to generate code specific to your table. TsttthdhooeaarttieInDadtabEelaplrosracewocrctyeeyoadowutuueirrtcserhcsesoeatdvtheeeerda.l 26   Chapter 1 etwWnaittbhrlheeynmwoyuniollltutisphhhliaoesvwwetaiudnbpdaletoaswas,b.aeanascehs More free ebooks : http://fast-file.blogspot.com .NET Visual Objects .NET Database Objects get productive with c# Data Storage Deployment Package 4  Name your diagram PeopleDiagram. Select File>Save Diagram. You’ll be asked to name your new database diagram. Call it PeopleDiagram, and you’re all set. Tsvohehforewyydnosauihmtreaprtbleeaabsvrelieesp.udraieallsgyer.naItmta’tsisiaon If you had any other tables in the database you wanted diagrammed, they would appear here, too. You are Here ISFftiluyedo>uiSo’rae2ve0usA0inl5lg,inVsseitsleeucaatdl . TdIyhtoaoiftsumaritbashprajerksueismscttdoahlerauesymipgCnkincseotyyniunotrauaetn’cvdhtoeefIlDjitusttsafthsbeileodelf.dofneaa.sll A database diagram describes your tables to the Visual Studio IDE. The IDE will read your database and build a database diagram for you automatically. More free ebooks : http://fast-file.blogspot.com you are here 4   27 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. Your job from all into the sisixtoofenttheersetchaerddasta People table. 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. TiTnyypheteasht“eo’TsrCrhunlioeoew”nitnoSfrQcoo“.LlFumasltnsoe. r”es Name: Liz Nelson Company: JTP TECemlleieapnihlt:o: LnY ieze:Ns(e4l1s9o)5n5@L5aJ-sT2tP5c.O7a8Rllg: 03/04/06 Name: Lloyd Jones Company: Black Box inc. Telephone: (718)555-5638 Email: LJones@Xblackboxinc.com Client: Y es Last call: 05/26/07 Name: Lucinda Ericson Company: Ericson Events Telephone: (212)555-9523 Email: Lucy@EricsonEvents.info Client: N o Last call: 05/17/07 28   Chapter 1 More free ebooks : http://fast-file.blogspot.com Name: Matt Franks Company: XYZ Industries Telephone: (212)555-8125 Email: Matt.Franks@XyZindustries.com Client: Y es Last call: 05/26/07 get productive with c# Name: Sarah Kalter Company: Kalter, Riddle, and Stoft Telephone: (614)555-5641 Email: Sarah@KRS.org Client: n o Last call: 12/10/05 Objectville Paper Company is in the United States, so the CEO writes dates so that 05/26/07 means May 26, 2007. If your machine is set to a different location, you may need to enter dates differently; you might need to use 26/05/07 instead. Name: Laverne Smith Company: XYZ Industries Telephone: (212)555-8129 Email: Laverne.Smith@XyZindustries.com Client: Y es Last call: 05/26/07 3 Once you’ve entered all six records, select Save All from the File menu again. That should save the records to the database. “TSejuvahsevtaretys’tAsahvldlie”nisfgtfteiehnlrleseynfottuihlreefrayIoDpompuEl’ric“etSaotawivosoearn”vk.,einwghiocnh. Q: So what happened to the data after I entered it? Where did it go? A: 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 Express file, ContactDB.mdf. 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. Q: Okay, 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.mdf file is copied and stored along with the executable. When your application needs to access data, it reads and writes to ContactDB.mdf, in the program’s output directory. IcTdDaahnEtisaugbsfeaeinlseeietr,iasawtnaietdcdhtyuftoaouhlrlreyypcaorouodS.geQrLatmhe SQL ContactDB.mdf More free ebooks : http://fast-file.blogspot.com you are here 4   29 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. tYdooatugaentegerbdiadctkaontdcolotsyheoeubrdoitfahogrrtmahm.e 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. fTicnorhtreeemartdaiaancnttgdaiowynsiosolluubrhrecatdenwadyteloeeaunba’arlyelsoetu.hre 30   Chapter 1 More free ebooks : http://fast-file.blogspot.com .NET Visual Objects .NET Database Objects get productive with c# Data Storage Deployment Package You are Here 3  Configure your new data source. Now you need to setup your data source to use the ContactDB database. Here’s what to do: ≥ Select Database and click the Next button. ≥ Click Next in the “Choose your Data Connection” screen. ≥ Make sure the Save the connection checkbox is checked in the “Save the Connection” screen that follows and click Next. CtTnhoehewnetsPdaeecaostttpDaleepBssotudacrbaoctlneenaebiwncaittstehhy. eour ≥ In the “Choose Your Objects” screen, click the Table checkbox. ≥ In the Dataset Name field, make sure it says “ContactDBDataSet” and click Finish. NsCooouwnrtcyaeoctutroDfiBnotrdemartacacatbnawsueist.ehtthheedata XML ContactDBDataSet.xsd SQL Here’s your existing form. C# ContactDBDataSet. Designer.cs Tgsoehunerescreeaftyielodeus bjauyrsetthwseehtadutap’ts. a ContactDB.mdf This file is your database. More free ebooks : http://fast-file.blogspot.com you are here 4   31 bind it all together Add database-driven 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. 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 setup for your application. ibIntatcetkroaotckotacwrleiittahttlieonugwrfodorrakmt, abousbttjoenrcoatwgset.whea’rte If you don’t see this tab, select “Show Data Sources” from the Data menu. tyTsoaohubuilrseccsoewusoil.nrddWdohewaa’vtveeashbomoanwoslyersse.gyooftuoraolndleifyosfeuetrruedpn,tatbaut You can also look for, and click on, the Data Sources tab along the bottom of your Database Explorer window. 2  Select the People table. Under the ContactDBDataSet, you should see the People table and all of the columns in it. Click the plus sign 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. CttselopilcrlyektoauhtdrehshifsIeDoeartErm-rotlriwokaetaahddneddarticatnhdhcoaioovnnsidetournDaoelle.cltaoarnigltsertools 32   Chapter 1 syAhoolulwocfruepatthheeerdec.oshluomulnds More free ebooks : http://fast-file.blogspot.com .NET Visual Objects .NET Database Objects get productive with c# Data Storage Deployment Package You are Here 3  Create controls that bind to the People table. Drag and drop the People table onto your form. 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 data IDE set the created to itanhntederPCaecootnptlweaicttthaDbBle database. WtocfthnohohetnereotnPertetyaoaohoclpbeuhwlleefdac.ostorrlaacumgbmrgl,eeneaadtined This form otbojeycoturcoPnenoepcltesttahbele. This adapter allows your controls to interact with SQL commands that the IDE and data source generated for you. ttconTooaoynhvlonbeigueaarbcrttintocsdraotibnnhltgeer.ols More free ebooks : http://fast-file.blogspot.com you are here 4   33 make it pretty Good programs are intuitive 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. Name: Laverne Smith Company: XYZ Industries Obeurmfoorreminwtouuitldive if it looked a lot like the Telephone: (212)555-8129 Email: Laverne.Smith@XyZindustriescom Client: Y es Last call: 05/26/07 contact card. 1 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. Byuatlopilrhnuuoeeeourdnnetlridnhtat.eehgosTefchwhfioeeeionlllylprdt’mssrryheouooalpsuws. 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. 34   Chapter 1 More free ebooks : http://fast-file.blogspot.com You are Here .NET Visual Objects .NET Database Objects get productive with c# Data Storage Deployment Package 3 Make the application look professional. You can change the name of the form by clicking on any 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 Co. - 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. twTtohhfoheanfet’tctromehcnaeahtsxaroMinonmglasieyxz, oiitsmnuohgiewzityaepo’nloulbtsruliotttfoitoookonrtnsmwuierosinfrd. TsSthyhohooeleuuulPrtdlroiIoowDbnpeeeErErr.txirgipiehglsohtrtwebirpen,ladoniownewof yTcoohunertrTfoeolxrsmtt’sphretoihpteeleardtbyinagr. on 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. More free ebooks : http://fast-file.blogspot.com you are here 4   35 okay, one last thing… Test drive Okay, 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). 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. ctCaolnicstmkooptvhetehoXen ptbroooxgtrhianemtnehsxoetycoosturenpe.r Building your Tltdeihnhtiefrtsfoyeheuoregucehodnpnttaattghrreaeoeblcsaosred. s program overwrites the data in your database. Wone’tllhsipseinndtmheorneexttime 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. 36   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. More free ebooks : http://fast-file.blogspot.com 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 Build menu. get productive with c# .NET Visual Objects .NET Database Objects Data Storage Deployment Package You are Here isaclncBoonroscutdeptaiaailhledtallasimentcystagoohcaanutehnfrShyiinfegepemiutrl.sreouaoPsapgcltuurhtbetiaioonxliminoesey.nhcofcuujiotlurueasltdble 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. More free ebooks : http://fast-file.blogspot.com you are here 4   37 share the love Give 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. Tsiunhpsitspaoislrletwrinhgaerrfeeilsaetlslorfoeofdr.tthhee Tetphvoreisorbgyfertialihenmicntlguiesdltlieshndasttthwaelhnleeeindends.ttsahleler ttTuhhsheeeiirrspsricswooighmlrlopawiunmtsyteooarnusllr! 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! 38   Chapter 1 TSyoohuuenrcdeas’snljijkueestttoohfnefebtmoososrteihsetphlseilnoagpseetsdo,. Good job! do before though… More free ebooks : http://fast-file.blogspot.com You’re NOT done: test your installation 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. btYaeerotxruwtocweafesnniealurndsedectototrhhdseews.itch get productive with c# .NET Visual Objects .NET Database Objects Data Storage Deployment Package You are Here gdNeetolewstaeyvoerudecctoaorndtash,dedan,ddcahttaahnbegayes’,ell.and Go ahead…make Ysitoomus’eovecthdhaeisnpgltoeiysm.eed, they’ll stick. TEST EVERYTHING! Test your program, test your deployment, test the data in your application. More free ebooks : http://fast-file.blogspot.com wgdCpaTieinaatlotlhtirnhtseatttiabyhiasnloaoeiclsxyfsurttereDaer.tlfneplBhTetcirel.dooeehmr,rgedaderywlfdas’orhmneyiagc.orhue you are here 4   39 super fast! You built a complete data-driven application 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. .NET Visual Objects .NET Database Objects Data Storage Deployment Package From this Name: Lloyd Jones Company: Black Box inc. Telephone: (718)555-5638 Email: LJones@Xblackboxinc.com Client: Y es Last call: 05/26/07 to this in no time flat. The power of Visual C# is that you can quickly get up and running, and then focus on your what your program’s supposed to do… not lots of windows, buttons, and SQL access code. 40   Chapter 1 More free ebooks : http://fast-file.blogspot.com 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 3 4 5 6 9 7 8 10 11 12 13 14 15 16 17 18 Across 1. When you do this from inside the IDE, it's called "debugging". 3. The ______ explorer is where you edit the contents of your SQL tables and bind them to your program. 5. The "About" box in the DCoanilytaSctcoLoispt pwraosgroanme wofatsheosne.of these 6. You build one of these so you can deploy your program to another computer. 9. An image, sound, icon or file that's attached to your project in a way that your objects can access easily. 11. Before you can run your program, the IDE does this to create the executable and move files to the output directory. 14. The database ____________ gives the IDE information about your database so it can generate SQL statements automatically. 16. The ___________ explorer in the IDE is where you'll find the files in your project. 17. Drag one of these objects onto your form to display an Down 2. What's happening when code is turned into an executable. 4. A SQL database can use many of these to store its data. 7. What you change to alter the appearance or behavior of objects on your form. 8. What you're doing to your program when you run it from inside the IDE. 10. Every row in a database contains several of these, and all of them can have different data types. 12. Before you start building any application, always think about the users and their ________. 13. You drag objects out of this and onto your form. 15. When you double-clicked on a visual control, the IDE created this for you and you added code to it. image. 18. A stored ___________ is a way for a SQL database to save queries and statements that you can reuse later. you are here 4   41 More free ebooks : http://fast-file.blogspot.com crossword solution CSharpcross Solution 1E X E 2C U T E 3D A 4T A B A S E O A 5M E S S A G E B O X P L 6I N S T A L L E R L 7P 8D 9 R E S O U R 10C E R E O O B 11B U I L D P U 12N U 13T E G E M O R G E 14D I A G R A 1M5 N O T I 16S O L U T I O N S E B E G 17P I C T U R E B O X S H X O 18P R O C E D U R E Across Down 1. When you do this from inside the IDE, it's called "debugging". 2. What's happening when code is turned into an executable. [EXECUTE] [COMPILE] 3. The ______ explorer is where you edit the contents of your 4. A SQL database can use many of these to store its data. SQL tables and bind them to your program. [DATABASE] [TABLE] 5. The "About" box in the Daily Scoop was one of these. 7. What you change to alter the appearance or behavior of [MESSAGEBOX] objects on your form. [PROPERTIES] 6. You build one of these so you can deploy your program to 8. What you're doing to your program when you run it from another computer. [INSTALLER] inside the IDE. [DEBUGGING] 9. An image, sound, icon or file that's attached to your project in 10. Every row in a database contains several of these, and all of 42   a1C1wh. aBayepftohteraetryy1oouurcoabnjeructnsycoaunr access easily. [RESOURCE] program, the IDE does this to them can have different data types. [COLUMNS] 12. Before you start building any application, always think about create the executable and movMe ofilrees tofrteheeoeutbpuotodikrescto:ry.http:/t/hfeausste-rfsilaen.dbthloeigr _s_p__o_t_._c_o. m[NEEDS] [BUILD] 13. You drag objects 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   43 More free ebooks : http://fast-file.blogspot.com 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 new Windows Application solution There are several kinds of applications the IDE lets you build, but we’ll be concentrating on Windows applications for now. Those are programs that have visual elements, like forms and buttons. Make sure you project—that and add it to ytaoelwullrasyntsehwcereIpDartoEejetacotW.cirnedaotwesaFnoermmpstAypfpolircmation 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. All of these tasks have to do with standard actions, and boilerplate code. Those are the things the IDE is great for helping with. 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. tacTaouhthrudoeenomakPlailtroytofibcepeaaycrlsolythyda.ieewnIsatdinyw.wiFtnooodurloemdwd1ti.tiDankeatesihsgapeneelIcorDit.fcEiscloinsger 44   Chapter 2 More free ebooks : http://fast-file.blogspot.com …the IDE does 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. it’s all just code ccTarohepnaetrtseaeedinefasfinltiednhseeddairbstepaelsacmiycrpelcaaaottfdeeoedrtmtfho.ratom WindowsApplication1 Form1.cs .csproj Form1.Designer.cs Program.cs Properties 2 ... 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) { Form1.Designer.cs } TtwohheahtaIDntdoElepkuantobwiunstsithdooenwicttl—ioctka.hdaBdtu’atsnyitoeumdrpotjeoysbn.m’tetkhnoodw FgToehrtimss1ac.cdosdd. eed to Form1.cs 3 ... the IDE opens the Form1.Designer.cs file and updates a line of code. The IDE went into this file… partial class Form1 { ... ... this.Text = “Objectville Paper Company contact list”; } …and updated this line of code. More free ebooks : http://fast-file.blogspot.com Form1.Designer.cs you are here 4   45 great, the “talk” Where programs come from 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. Every 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. There’s no reason you couldn’t build your programs in Notepad, but it’d be a lot more time-consuming. 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. 46   Chapter 2 More free ebooks : http://fast-file.blogspot.com it’s all just code Build the program to create an executable 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. Yaniyomtoboof’uoowusrur.dtetauIouhntantten’b’orshitnoemeegu,rantCeatyoanLiouicltdgulRayrhlatlyhmspta.arokuyvYoceoekgshounrutcora’golaiwmolgr.whleeftoaorrrrny More free ebooks : http://fast-file.blogspot.com you are here 4   47 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. It’s got two views: a Solution Explorer view (which shows you the files in your project) and a Class View (which shows you how your code logically breaks down into classes). The Solution Explorer shows you how the different files in the solution folder. You’ll learn more about classes in a minute. Here’s the form’s ≥ 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. resource file that you added the Objectville Paper Company logo to. 48   Chapter 2 Wittohaevtniewtyhotue’hrseeamfwoeorrtmki’imsnegc—oodonen.ae form, you can for the form have two designer, tabs for and one More free ebooks : http://fast-file.blogspot.com 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: ToTEImffhnheatetyrteoheIruoaDcldalktEysneyyclpkboeanentlolgoSeaw,dmtsrieteEetltalhqshletauottlahedliecsmM,tnIesaRDesmaseSEsvfehaeseogtr.rweoeBi.nffocPiexylrlEoehuisqtas’ursaeitnlthst,hefyraopTenriaendbygoSoauhr.olowt. If you select Show and type (, the IDE’s IntelliSense will show you information about how you can complete the line: TatMmdrhhieeesiastpst2shlmaaoy1ygedoeadudBni(fislcofifkaxftene’ehrsreawceSntaanthlytltoswwthbteahuroyetestons or icons). The IDE also has shortcuts called snippets that let you type an abbreviation to tell 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: ≥ The Error List helps you troubleshoot compiler errors If you haven’t already discovered how easy it is to make typos in a C# program, you’ll find out very soon! Luckily, the IDE gives you a great tool for WttdirwothohuieeelnrclsnsuoI.sDnmihysIEofopybiwuo,luenutuisoryls,hdtoepetu, ryhSifeootetrigunrarrrwsroatyotprmonrstu’Dotrhiingniensrrpbiguatrdunmohegi,get.graiInanfgmd 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: Double-click on an error, and the IDE will jump to the problem in the code: The IDE will show a red underscore where it finds you’re missing a semicolon. More free ebooks : http://fast-file.blogspot.com you are here 4   49 let’s dig in When you change things in the IDE, you’re also changing your code 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 Application project, and see for yourself. Wattnohhdeednfomo,oylaoslotnuwdoseuapetlooiannogtf“.DotWuohete’tllwehtxhiseaa!l”tml,pytplooeouplwoeoeoxpkaeshcnftootlwyrheywtoohIuDa.gteEt Do this! 1 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? 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”; DnfSduooiimzrfnefb’tteelhrriwneesenoListrnroatyycrhoaeiautfrnaiotcntlihotheadtenesldee… this.pictureBox1.Size = new System.Drawing.Size(100, 50); this.pictureBox1.TabIndex = 1; this.pictureBox1.TabStop = false; 50   Chapter 2 More free ebooks : http://fast-file.blogspot.com 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: it’s all just code Most comments only start with two slashes (//). But the IDE sometimes adds these three-slash comments. 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? Yftmeto[ofosduhaDrohieksmrotedeemuosteoloridtnagr,dt’nbhteahs]erhsnel”uahiodcgnbacwthnevhotateelaunrhehfnpgd—etelgenoiietpp“msicFhrsn.omaleooivJvcgetreeckdrumhrhsaiet1toaamt.htncncoesegoledtyseh. e 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 projects’ code. More free ebooks : http://fast-file.blogspot.com you are here 4   51 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. Apprrcoolggarrsaasmmcso(nactlatanhinohsuagavhepsjieoucmstee of your very small one class). tYaAlihroveeeucrlmaionsnmasseidedshteeayhusooapudo’csvnoleeafaslaoswsl.rtraaAeymtasneoddhmryaemevsnmeeetteestnht—o.ohdloiksdes. sdEeepvfeairrnyaetteaimfnearmoymeosuptamhceaek.NefoEarTniteFwsroapmrtohegwartoarmikt,scylcoaousdsees.is Namespace Class Method 1 statement statement Method 2 statement statement Let’s take a closer look at your code Open up the code from your Contact 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 System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; FotyFTCtfohror#huiapsartemmshpoteepeeafowrwruocoteuogslrsvairrckeeiskaursnmnaleycalasgllramctiosonh.elsfidsaencoptesetnas.sehfctEaoeifhsla.sreepiecel.eehcc.TaNliwatofhEsinilesctleTyehus.teNtseieenElllalTsll using System.Windows.Forms; You’ll see slightly different using lines if you’re using Visual Studio 2005. 52   Chapter 2 More free ebooks : http://fast-file.blogspot.com it’s all just code 2 C# programs are organized into classes 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. namespace Contacts { pknWaaehiymrewenoospfryadoccueuartcflayotllrehbderitatyccookapuelrtloesfpdrisyoCogpouranrartmtaccoCotdfosenbttfyhaileceat.dCsEd,oivntnethgraeyctttIhDhseiEnnngaacmmirneeessaispdptaeaeccdeiet. as public partial class Form1 : Form { TftoohrlidsmiistanatdoctlcahrseseaTctaoelolelabdonxFewocromWn1ti.nrdIotolswcosonnFtoitar.imnTss haAellpIpoDlficEatthcireoencaotpderdeojetitcotwd. hreanw the you 3 Classes contain methods that perform actions When a class needs to do something, it uses a method. A method takes an input, performs Look for the some action, and sometimes produces an output. The way you pass input into a method is by matching pairs using parameters. Methods can behave differently depending on what input they’re given. of brackets. Some methods produce output. When they do, it’s called a return value. If you see the Every { is keyword void in front of a method, that means it doesn’t return anything. eventually paired up with a }. Some pairs can be public Form1() { This line calls a method named InitializeComponent(), which the IDE also created for you. inside others. InitializeComponent(); } 4 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. This gets is a method called when ctahleleduseprictcluircekBs ooxn1_thCelicpkic(t)utrehabtox. This method has sender and e. two parameters called private void pictureBox1_Click(object sender, EventArgs e) { MessageBox.Show(“Contact List 1.0”, “About”); } } } This is a statement. You already know what it does—it pops up a little message box window. YwisohuiincrshisdtiesatpteahmretenSotyfstctaelmhlee.WdMitnedhseoswaSgshe.FoBowor(xm) scmlnaeastsmh,eowsdph,aicche. Yminoeuttrhheostdma.teTessmhaeegneftibrposatxs,soeandnedtwwtaohseapassertcarominnedgteoornfsettweoaxstthateosStdrhiionswpgl(a)tyo display in its title bar. you are here 4   53 More free ebooks : http://fast-file.blogspot.com 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 double- TsahEtnhaavdavreettri’tysow’nshCheoa#ewelnwnapitytyrorsouykgncrrpoauaowlnimlnesdtitcw.amMhneeartoienhn(olty)do., click 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 find it in Program.cs. chapter. You’ll Your Code Up Close 1 using System; using System.Linq; using System.Collections.Generic; using System.Windows.Forms; 2 namespace Contacts { 3 static class Program { TCmhooenrtenaaicnmtesas.pfWaeecw’ellpftaoagrlekas.lalbtohuits cnoadmeesipsaces Lines that begin with you can add anywhere C# to ignore them. slashes are comments, you want. The slashes which tell /// /// The main entry point for the application. /// [STAThread] iEtvestrayrttismheeryeo,u artunthyeouerntprryogproaimnt, . 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 method is lcinaelleodftehveerdyeccllaarssatoiron. dkRniegomwienmtwobheatrth, eytohcuios’driees.ljoBuosukttinabgesafttoa.rretiynogupdoion,tyofuo’rll you to need to 54   Chapter 2 More free ebooks : http://fast-file.blogspot.com 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. YnafoabeumaortuetusprpreCaosc#getrsahamlrnikosduewg.thNilholEiusuTtsoe’stnhemoetoarhbseeoyroaoknbu.dulielmta-ornrine 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. piNnraodmgirefasfpmearsceeansrtelenpt’rtoygaorlusaomussine, the same as long as the same name those namespace. This particular class is called Program. The IDE created it and added the code that starts the program and brings up the Contacts form. Ycolaussceasninhaavesimngulletinpalemespace. 4 This code has one method, and it contains three 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. TttbeheucalthlnnCyioco#nauellywwM,ohnaiac’ithnp(rno)oengmeerdeaitsmthotochdade,noaehtnnadthvareytyompnuooorciwnea.tn”... Every C# program must have exactly one method 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. 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. More free ebooks : http://fast-file.blogspot.com you are here 4   55 classy things You can change your program’s entry 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. Do this! 1 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? Wwmthhreeiitntnhkeoydtdohuonawactnhmahewna,hgpaaepntdednhetwadhph.epyenyeodu Right-click on the 2 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 project in Properties and select “Add” and “Class…” file AnotherClass.cs. The IDE will add a class to your program called AnotherClass. Here’s the file the IDE added: using System; using System.Linq; using System.Collections.Generic; Tlinheessewfeoruerasdtdaenddatrodtuhse ifnileg. using System.Text; namespace Contacts { TtthhhaeistWctlianhsdesoIiwDssEinAaptdphldeicesadatmiwoehneCpnornyotojeuacctft.isrsntamcreesaptaceed class AnotherClass { } } The class IbDaEsedauotnomtahteicfaillleynnaamme.ed the 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: MitnStnoahhemteosashwedaMes(dgp)eeSasBticyssehsoat,eaxgeweummiBhsse.iioWnctaxghhincoclidlisdalnaosewwsstshshi.tn.yaFhtsoyat’rtosemupplsiahv#raetsd3.of class AnotherClass { public static void Main() { MessageBox.Show(“Pow!”); } } 56   Chapter 2 More free ebooks : http://fast-file.blogspot.com it’s all just code Now run it! So what happened? Instead of popping up the Contacts application, your program now shows this MessageBox. 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. Httoiwnotch:fayinloeguseottnowlydoohlainivtee.s in 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 System; using System.Linq; using System.Text; using System.Windows.Forms; Cloin#tehsecrtlaonssaaemdsdehspamaveectethsohdessef“ruosming” namespace SomeNamespace { class MyClass { public static void DoSomething() { MessageBox.Show(“This is a message”); } } } More free ebooks : http://fast-file.blogspot.com you are here 4   57 get some answers Q: What’s with all the curly brackets? A: 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? 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? 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(). Q: 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: 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. 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 System; using System.Linq; using System.Text; using System.Windows.Forms; Cloin#tehsecrtlaonssaaemdsdehspamaveecteths.ohdessef“ruosming” namespace SomeNamespace { class MyClass { All of the code lives in classes, needs a so the program class here. Tmdhoeietsshiossdoamienmteththinhego.dprM. oEegvtreahrmoyds are used to statements group together. public static void DoSomething() { } } } MessageBox.Show(“This is a message”); TWiwtmhihienspesdonsiopaswisgtae’uwsspitinetasaxhitdeleciaetmuttoelfneetdi.,t. 58   Chapter 2 More free ebooks : http://fast-file.blogspot.com 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 partial class Form1 { private void InitializeComponent() {... } } Set properties for a label Nothing—it’s a comment that the programmer added to explain the code to anyone who’s reading it 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:”; /// /// Bring up the picture of Rover when /// the button is clicked /// partial class Form1 { ... t...his.MaximizeBox = false; } A special kind of comment that the IDE uses to explain what an entire block of code does Change the background color of the Form1 window A block of code that executes whenever a program opens up a Form1 window More free ebooks : http://fast-file.blogspot.com you are here 4   59 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 partial class Form1 { private void InitializeComponent() {... } } Set properties for a label Nothing—it’s a comment that the programmer added to explain the code to anyone who’s reading it 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:”; /// /// Bring up the picture of Rover when /// the button is clicked /// partial class Form1 { ... t...his.MaximizeBox = false; } A special kind of comment that the IDE uses to explain what an entire block of code does Change the background color of the Form1 window A block of code that executes whenever a program opens up a Form1 window 60   Chapter 2 More free ebooks : http://fast-file.blogspot.com it’s all just code Two classes can be in the same namespace 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. Wictalhcamecsensesaisanniscttlseahvsemesrepiytrsoho“goptrduhasbem.lricc”an MoreClasses.cs namespace PetFiler2 { public class Fish { public void Swim() { // statements } } public partial class Cat { public void Purr() { // statements } } } SomeClasses.cs namespace PetFiler2 { public class Dog { public void Bark() { // statements go here } } public partial class Cat { public void Meow() { // more 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. More free ebooks : http://fast-file.blogspot.com you are here 4   61 your mileage may vary Your programs use variables 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 variables 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. These are th e variable types. oTfhetsheesaerevatrhiaebnleasm. es int maxWeight; string message; bool boxChecked; vtCaor#ilaimbulisetesswcthahanethvdoalardti.aabltehetsyepe TLndhaiekemsseceersminbteaethmhatetohsdemasrvaaaeknredfiaosbcrellneaYs’ssesOeuaUssn,a.dgusee. Variables vary 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. 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. 62   Chapter 2 More free ebooks : http://fast-file.blogspot.com it’s all just code You have to assign values 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 IDE 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. 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. A few useful types 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. 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. yvdctoOaiaoursnnaicayddebcoevhlucayeralnoanaturvgn’aaevegre.iiientaSai.tbtoslisoeaitg,lahntvseeashrdilageut’neasinvwnvgaaohllueauene More free ebooks : http://fast-file.blogspot.com you are here 4   63 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. int number = 15; number = number + 10; number = 36 * 15; 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. number = 12 - (42 / 7); number += 10; number *= 3; number = 71 / 3; This operator is a little different. += amcnuedrarneasndttdlayk10eeqtuthaoel ittvoa. lSu6ei,nacoedfdnniunumgmb1eb0retirso it sets its value to 16. int count = 0; 71 it divided can only bsyto3reisw2ho3l.e66n6u6m6b6e.rSs,inscoe number is an it gets rounded integer, to 23. This MessageBox will pop up a box that says “hello again hello” count ++; count --; Yabbonyyud’aslul-dbdu-tsienrogapicneottrnianeatgotloroonstetcfhofoemrroveamcilonuuietnh,,taasinnnoddgy,it.-a+n-edn+ddwseinhcucreprenememyqeoenuunattlsdstococotozhuueenrn+ott.+ string result = “hello”; result += “ again ” + result; When you use the + operator with a string, it just puts TI(ftIhoterh’sa“ask”dinndisdoinagconhfsaterlmriakipncettgsaye.r)zsst.erriong. MessageBox.Show(result); result = “the value is: ” result = “”; + count; two strings together. It’ll automatically convert numbers to strings for you. A bool stores true or false. The ! operator means NOT. It flips true to false, and vice versa. bool yesNo = false; bool anotherBool = true; yesNo = !anotherBool; Don’t worry about memorizing these operators now. You’ll get to know them because you’ll see ’em over and over again. 64   Chapter 2 More free ebooks : http://fast-file.blogspot.com it’s all just code Loops perform an action over and over again 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!). Tblooohuooatpltei’uafssneasitsbaasrighetopesuaosltdritmtkopeooeffrptiwglaouhnorytep.inAg. while (x > 5) { x = x - 3; } In a while loop, all of the the statements inside curly brackets get executed as long as the condition in the parentheses is true. 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 snippet to write simple for loops You’ll be typing for loops in a 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. If you change the variable to something else, the snippet automatically changes the other two occurrences of it. vycitnaPsohuorruadmienajessbugbestemelteertpr.laelmoetbnfniogngttetttohdihhmgetbeteoysotle.atwntYhghnhotiasueuhtml.ceocbuvToaeerpnrhrsoerorurnsa More free ebooks : http://fast-file.blogspot.com you are here 4   65 ready, set, code! 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. 2Tpwmrihitogpighhsrrtowaagmiwrlblaaslmanttntehk1llr”t—footouhygnreohamuomI’DulaeltnEbidttethasobenoumcibelredonetoitanhkrtg.iyenagpaowliinknheetowl.“eYCplorhouoatjpeotcfetr Build this form Add statements to show a message Get started by double-clicking on the first button. Then add these 6 statements to the button1_Click() method. Look closely at the code, and the output it produces. Syntax 101 ± Each statement must end in a semicolon. x = x + 1; ± A single-line comment begins with two forward slashes. // this line is ignored ± Most white space doesn’t matter. x = 3; is the same as x = 3; ± Variables are declared with a name and a type (there are plenty of types that you’ll learn about in chapter 4). int weight; // weight is an integer ± Classes and methods must be defined within a pair of curly braces. public void go() { // amazing code here } xpaoiatnfirssittnvathateleveugaleselrtsritaa,Cotba#el3enm.d. etTnththahetese“rittiens’stst” 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; lnfiScMTneiyaleehealsdltetaetsretdhehm,t’itPsosanhInac.haedoamMbdtveiuoeteasipl’tptsac.ah-agcumileosni,tvienecsgsfaolarSismtnosymhestecmthaebelmleer;d MessageBox.Show(“name is “ + name + “\nx is “ + x + “\nd is “ + d); } The \n is an escape sequence to add a line break to the message box. 66   Chapter 2 More free ebooks : http://fast-file.blogspot.com 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 equal sign (=) operator, which you use to set a value. if (someValue == 24) Esctvoaenrrdtyitsiifwonitsathlattaeesmte. nt { MessageBox.Show(“The value was 24.”); } Atwlwoaytshiunsges two are equal equal signs to to each check other. if if (someValue == 24) Ttethhxeeeestccsutuitsaretltydermbuoerenna.lytckiifentstsidhiees ipItfpsffOtrtter/iehthsraotetteetshglhttsereiesesyrsmateswmcaescetstttotionrsaneentreutodxmda,seefiei,eigtbmtcsnhtieebueotthttetrnnsfewx.aetaocesbelsrkceetwauenthtrtaweeterse.shdee.n { // You can have as many statements // as you want inside the brackets MessageBox.Show(“The value was 24.”); } else { MessageBox.Show(“The value wasn’t 24.”); } Don’t confuse the two equal sign operators! You use one equal sign (=) to set a variable’s value, but two equal signs (==) to compare two variables. You won’t believe how many bugs in programs—even ones made by experienced programmers!—were 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. More free ebooks : http://fast-file.blogspot.com you are here 4   67 the things you can do Set 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 < are called conditional operators. When you use them to test two variables or values, it’s called performing a conditional tests. ≥ 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). Set 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. DYsytuMesooheliuuaeenbkcgudcctegaootinnsdhmugteerseht“enwisoSsuty—ph.tooiopltiuepthbsteDbuthtyoIeeDtpbcoupElynogrosgowouiignrnnorggnapt”’tmtrhhfoe’slegrertortwaomumoinynlntobdbiuhanoeergwef,.d,ooritre private void button2_Click(object sender, EventArgs e) { First we set ctmcuhoapaelk5claeek.dvTiitafxhreeiiaatqnnb’usdlwaele equal to 10. int x = 5; if (x == 10) { MessageBox.Show(“x must be 10”); } else { MessageBox.Show(“x isn’t 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 More free ebooks : http://fast-file.blogspot.com it’s all just code Add another conditional test The third button makes this output. Now make a change to two lines of code so that it pops up both message boxes. Tsiteheicsihfleinciekts’sctheoeqcumkasal ksteooms3euVr, eaalnundeamtteohen is “Joe”. private void button3_Click(object sender, EventArgs e) { int someValue = 4; String name = “Bobbo Jr.”; if ((someValue == 3) && (name.Equals(“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; while (count < 10) { count = count + 1; } Ttfiisshhiveereeuxtsnteeehccsbteuoetn.fldeoIotdorppesaoanrstyhlthysoeuoi“lffcfdoottdrkhheeeaeesbptflloeooocsrnntkg,sgtioasaaisnnttdgier”muit.seehT.nleethsbesilsottchekastn TIvttahhliuajsuetss’tletltoabssetsuhipugesnetsidnhtaeienlgoeiotrp.. } for (int i = 0; i < 5; i++) { count = count - 1; } MessageBox.Show(“The answer is ” + count); TdaTlisothdothoie’dassipsstsireessiousomxnnwmeceehceanimeuttltltromheseedieniisn.dt,gthS.iitahteoItheneewleoilttvyioclehelporairdsayfaadetctctdoatebirsurml1e,oae,aclatllkiynotlt.dhti.ehe 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! More free ebooks : http://fast-file.blogspot.com 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 first one in the 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); 70   Chapter 2 More about conditional tests You can do simple conditional tests using a comparison operator. Here’s by checking the value how you compare two of a variable numbers, 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. More free ebooks : http://fast-file.blogspot.com Wait up! There’s a flaw in your logic. What happens to my loop if I write a conditional test that never becomes false? it’s all just code 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 ! Stohmiseatnimiensfiynoituecalollop. Loop #1 int count = 5; while (count > 0) { count = count * 3; count = count * -1; } Loop #2 int i = 0; while (i == 0) { count = count * 3; count = count * -1; } 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 #3 int j = 2; for (int i = 1; i < 100; i = i * 2) { j = j - i; while (j < 25) { j = j + 5; } } Loop #4 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; } eizHtxeieenrrctoau:.ttqoTerdhst.i“naqkr=tasbqoouu*tt equal when 2” is to the ibrRteueengmrisanetntmoihnbregearcot,ofnatdthfihteoeiroebnnloaldoolcpotkfe,aslatwtnhadaeytstbthlohecek. Can you think of a reason that you’d want to write a loop that never stops running? More free ebooks : http://fast-file.blogspot.com 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 x is greater than 3 result = result + x; // add x to the result variable x = x - 1; // subtract 1 from the value of x } for (int z = 1; z < 3; z = z + 1) { T3t,hheiitsn’slaonosopeclroounnngdserttwimleiceses—wtifthiahrnszt3s,wesittohttozhe2sel.otOoptnocset1o,itpasn.hdits // start the loop by 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 } // 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 #5 This loop executes 8 times. Loop #2 This loop runs forever Loop #4 Another infinite loop After iteration #1, q equals 2. Then it equals 0, then 4, then 0, 8, 0, 16, 0, and the loop stops when it hits 32. Take the time to really figure this one out. It might help to paste the code into the IDE and add messageboxes that pop up the values of p and q. 72   Chapter 2 More free ebooks : http://fast-file.blogspot.com it’s all just code Q: Is every piece of code always in a class? A: 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 you’re not allowed 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 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: I still don’t get why I need this partial class stuff. A: 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: 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. Drag a button on a form, change properties. Then try to undo it. What happens? Well, for simple things what you’ll see is 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. 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.  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. More free ebooks : http://fast-file.blogspot.com 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 rear- range the code snippets to make a working C# program that produc- es 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! The “” is an empty string—it means Result has no characters in it yet. if (x == 1) { Result x=x- = Result 1; + “d”; string Result = “”; Tofhfistmhaegfnertidgdeid…n’t fall } if (x == 2) { Result = Result + “b c”; } if (x > 2) { Result = Result + “a”; } int x = 3; x = x - 1; Result = Result + “-”; while (x > 0) { Output: MessageBox.Show(Result); Answers on page 82. 74   Chapter 2 More free ebooks : http://fast-file.blogspot.com We’ll give We’ll give don’t be ayyfooruuaitadhletotoanposefweekerxaeitnrctaihsecesoaulnipksleewetorfh—ispitat’ghsernso.outIgfhcoyhuoetuattgihenteg!bstouockk. , it’s all just code Ytenaaohcmurh’oilnluoggbnheteohucaitrsedtoaitnfheifinseg“rb2eoanoFtlkou,tnnaanomwdfiet.yahWopupief’lli-lcreaenctlesoieeomdnmsteondgive statements” based on the and the text in the title chapter number 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!) More free ebooks : http://fast-file.blogspot.com you are here 4   75 ooh, pretty! Let’s build something flashy! 1 Here’s the form to build Httlohiwnoaotpt:fovIofrarrhyilaaoobvoulepeds’osentcoehlnaaldrtyeecvbaaloaltirvdahartiuiniaossbenidletoehuintteshsivieddaeerloiaatobphfl’eeso,rlcoyulooorpuoly.’pll—berfitaochrkeer(itndst.ecScloa=rief0ity;o…iun)h—eaavtcehhen 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(); TdTmtohhohneeuiessfoeblotiencrhfelmeiocrtrkdeestol,hliesteisntntgdc’htse.eaiTrtlpserrdnywoergiteatrdawhaksmiitntthgostoeoosldfeuso,tt,eobvltpieekhcneyiatsousrusl.eirenferlioteao’ssnphdwmtashoietemeiienfnngogtruamwnrh,tilaicylthtaehhncakdepplfdoeooonrps. is Later on in the book, you’ll learn about a better way to let your programs do more than one thing at a time! But for now, use Application.DoEvents() to make sure your form stays responsive while it’s in a loop. Color me impressed! .NclteoEbvthlTyoaesrlussyChepoael,oiusckaliemfaogyaBrrbiken.luueegnFencyrthaovohnuaormrdleufAeeoRr,pwnerganudenbmd,dc(bebo)feaulortinrsbm:eslieutdautesahrivlnoesagddolu,e. 3 Make it slower Slow down the flashing by adding this line after the Application.DoEvents() line: System.Threading.Thread.Sleep(3); TdtShehyilesasy.stNtieanEtmTte.hmleTiebnhlrotraorepiny.as, eIdtarn’itsdsnagaitp’3asnraimtnmielotlsifhspeeaccoen. d 76   Chapter 2 More free ebooks : http://fast-file.blogspot.com 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!) “noiWnenssehit,deenewde”oanncleooatolllhpo.ieotrp is a Uh-oh! The program doesn’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 in an if statement or tempting to test for You can leave off the include the boolean. a boolean value like Visible a loop, sometimes it’s (Visible == true). “== true”—it’s enough to pi“iftosorAHin’forltiNelbnsrtcltDcbueoo:eimt”ngmT.ed.AestIhitttNeei’insDsoit&snhha&tttaolrhnhwotudaepeteyyets’ostArhtuasNiotrtsrtDdotsuoro,reglitevnemeothgtencehtala.eynhsrAesbiiscfnuiondnnttcdohhe When you’re working with a form or control, Visible is true as long as the form or control you set is it being displayed. If to false, it makes the form or control disappear. Can you figure out what’s causing that delay? Can you fix it so the program ends immediately when you close the window? More free ebooks : http://fast-file.blogspot.com you are here 4   77 exercise solution Time to get some practice using if/else statements. Can you build this program? using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; Here’s the entire Form1.cs file If/Else Statements!” exercise. for the “Fun with If we show you a lot of code in a file like this, we’ll draw a grey box behind the part that you should add. using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Fun_with_If_Else Here’s the code for the form. We named our solution “Fun with If Else”, so the IDE made the namespace Fun_with_If_Else. If you gave your solution a different name, it’ll have a different namespace. { public partial class Form1 : Form { public Form1() { InitializeComponent(); } eTbwbvuuhhetteertntyooIDynnto.1iEm_uTCedahdloeticudhmkbee(ldee)tb-tuhtcthooltdiecyokmongeu’eesdrttcshofloniorcdruktmnechdae.lled The outer if statement checks the checkbox to see if it’s been checked. Check! private void button1_Click(object sender, EventArgs e) { if (checkBox1.Checked == true) { if (label1.BackColor == Color.Red) { label1.BackColor = Color.Blue; } else { The inner if statement checks the label’s color. If the label is currently red, it executes a statement to turn it blue. 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 More free ebooks : http://fast-file.blogspot.com it’s all just code Let’s build something flashy! yboiSnofuoutmtttdheoheotneui1msb_looleleCgus-itlciwcicolekiinnc(,wk)tjeomhudnsee’ttttFhhtsleohahdosebhwuybttTihyttaohsotuinntttghihnhapeetrtoeIhcDjnehetEacfintrogeareidsmcddo.ienddAdeetlslwhigihsneenr. Wrbderohtaeeucsnrnkn’ettthbceeoafnrIoDerteEhaebtaohsduaetdmeceeduxrltiltnyrheaibslrsikmapecaekctteehht,oi.ssdoS,totoitmhseiaastdviiedms eespdpsearwacfneee’—cleltxblpytuutrtvaaCtli#dhe. private void button1_Click(object sender, EventArgs e) { while (Visible) { The outer loop keeps running as for (int c = 0; c < 254 && Visible; c++) { long as the form is visible. As soon this.BackColor = Color.FromArgb(c, 255 - c, c); as it’s closed, Visible is false, and the while will stop looping. We used “&& } Application.DoEvents(); System.Threading.Thread.Sleep(3); ssTcoeohcltoeohnrfesdyircfsylotocrolfeklooosromnpelooroowetpavhyem.r, asaeknsedsttthehhmee Visible” instead of “&& Visible for (int c = 254; c >= 0 && Visible; c--) { == true”. It’s this.BackColor = Color.FromArgb(c, 255 - c, c); just like saying “if it’s visible” instead of “if it’s true that it’s visible”—they mean the same } thing. } Application.DoEvents(); System.Threading.Thread.Sleep(3); Can you figure out what’s causing that WueVasaesiicsnisfhgboiloxoetnfe.hdeTatsht&haheV&teifsowieobpxraleteyrlroattaotuhpordesrnesalltoalofsoyoapmlbsceyaehnk.edecsk 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! More free ebooks : http://fast-file.blogspot.com 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 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. Note: each snippet from the pool can only be used once! Poem = Poem + “ ”; Poem = Poem + “a “; Poem = Poem + “n“; Poem = Poem + “an“; 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); using System; using System.Windows.Forms; namespace Chapter_2 { class Chapter2PoolPuzzle { public static void Main() { int x = 0; String Poem = “”; while ( __________ ) { _____________________________ if ( x < 1 ) { ___________________________ } _____________________________ if ( __________ ) { ____________________________ ___________ } if ( x == 1 ) { ____________________________ } if ( ___________ ) { ____________________________ } ____________ } __________________ } } } Poem = Poem + “noys “; Poem = Poem + “oise “; Poem = Poem + “ oyster “; Poem = Poem + “annoys”; Poem = Poem + “noise”; 80   Chapter 2 Answers on page 83. More free ebooks : http://fast-file.blogspot.com 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 6 8 9 5 7 10 11 12 13 14 15 16 Across 3. You giAvecrinofossrmation to a method using these 4. button341...YTboueutxttgoianvn1e.dTiencxfhtoeramcnkdaBtciohoxenc3kt.oNBoaaxmm3.Neetaahmroeed aeursxeianemgxtaphmleepssleeosfof 8. Every8s.tEavteermyesnttateenmdesnwt ietnhdosnweitohf othnesoef these 10. The n11a01m.. CTeohnoetfnaeainvmesermyofeCteh#voepdrsryoCg#rapmro’sgreanmt'sryenptorinytpoint 11. Conta1i2ns. Ymouerthsotadtsements live here 12. Your 1s4ta. tAemkienndtosflivvaerihaebrleethat's either true or false 14. A kind1st5oa.frAtvasprieacbialel mtheatht’sodetithhaetrtterlulseyoorurfaplsroegram where to 15. A spe1c6ia. lTmhisetkhinoddothf acltatsesllsspyaonus rmpurlotigprlae mfilewshere to start 16. This kind of class spans multiple files Down 1D. Tohwenoutput of a method is its _________ value 212...STShyyessttoeeummtp..WWutiinnodfdoaowwmsse.F.tFohroomrdmsisissiitassna_en_x_ae_mx_ap_lm_e_po_flevoanolefueoofne of ththeessee 556...AAAttbinilnoyyckppioieefccceeooodfef aaisppsruroorgrgroaruamnmdtehtdhaatbytddoeosessomsoemt hei nthging 67.. AThbelokcinkdooffctoesdtetihsastutrerlolsuandloeodp wbyhen to end 79..TYhoeu ckainndcaolfl t_e_s_t_t_h_a_t_t_e.lSlshoawlo()otpo wpohpeunptao seimndple 9W1.3Yi.noTduhoewckasinnddicaaolofllgv_ba_or_xia_b_l_e _th_a_t.Schonotwa(i)nstoapwohpoulepnaumsbimerple Windows dialog box 13. The kind of variable that contains a whole number More free ebooks : http://fast-file.blogspot.com 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 = “”; int x = 3; while (x > 0) { Tofhfistmhaegfnertidgdeid…n’t fall Tlcohoonepd,fitxiriositsnaetlqitmuaeelsttthowri3ollusgbohe the this true. if (x > 2) { Result = Result + “a”; } x = x - 1; Result = Result + “-”; if (x == 2) { Result = Result + “b c”; } if (x == 1) { Result = Result x = x - 1; + “d”; } stTeehqchruoioasnuldsgtthtoaittm2ehemetethlnohetorpofm,uirgaashknt.edst1ixmtehe Output: MessageBox.Show(Result); 82   Chapter 2 More free ebooks : http://fast-file.blogspot.com 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. using System; using System.Windows.Forms; namespace Chapter_2 { class Chapter2PoolPuzzle { public static void Main() { int x = 0; String Poem = “”; while ( x < 4 ) { Poem = Poem + “a”; if ( x < 1 ) { Poem = Poem + “ ”; } Poem = Poem + “n”; 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 correction 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. More free ebooks : http://fast-file.blogspot.com you are here 4   83 crossword solution Csharpcross Solution 1R 2N 3P A R A M E T E R S A T M 4P R O P E R T I E 5S U 6B E T R 7C R 8 S E 9M I C O L O N 1M0 A I N O A P E 11C L A S S T N 1M2 E T H O D K C S E E A 13I M I 14B O O L E A N T T G N N I S 15E N T R Y P O I N T O B E N O G X E A 16P A R T I A L R Across Down 3. You give information to a method using these 1. The output of a method is its _________ value [p arame te rs] [re t u r n] 4. button1.Text and checkBox3.Name are examples of 2. System.Windows.Forms is an example of one of [prope rt ie s] these [namespace] 8. Every statement ends with one of these [semicolon] 5. A tiny piece of a program that does something 10. The name of every C# program's entry point [statement] [main] 6. A block of code is surrounded by [brackets] 11. Contains methods [class] 7. The kind of test that tells a loop when to end 12. Your statements live here [method] [conditional] 14. A kind of variable that's either true or false 9. You can call _________.Show() to pop up a simple [b o o le an] Windows dialog box [MessageBox] 84  1st5a.CrAths[apepenctteiraryl 2mpoeitnhto]d that tells your program where to 13. The kind of variable that contains a whole number [integer] 16. This kind of class spans mMulotirpele frileees [epbarotoiakl]s : http://fast-file.blogspot.com 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 More free ebooks : http://fast-file.blogspot.com 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 then csoemtseshiuspdweistthinaatrioonu,te. 2 Good thing he had his radio on. There’s a huge traffic jam that’ll make him late! Misntifkroeeremgteatthseionnneewaebdosuttoaavoid. 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 Mike comes up with a new route to get to his interview on time. Now he can come with a new route the interview. up to No problem. If I take Route 28 instead, I’ll still be on time! 86   Chapter 3 More free ebooks : http://fast-file.blogspot.com 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. HitmnehereMtehn’iskoaedma’ssedopioanrngotrgtharoemapm,bo.aofntItdtaostmchhlo.aewsss SetDestination(“Fifth Ave & Penn Ave”); string route; route = GetRoute(); HGadeeisrrtteeRrc’sitonuitgothnetes(h)oMautmitkepcetouhtnsohtdfoau—rinlodsimtt’fsthohelleow. Navigator SetDestination() ModifyRouteToAvoid() ModifyRouteToInclude() GetRoute() GetTimeToDestination() TotalDistance() The navigation system sets a destination and comes up with a route “Take 31St Street Bridge to Liberty Avenue to Bloomfield” Tsntehrweeeintnafviotigramnteaietodinosnstyaostbaoevumotidgae. ts ModifyRouteToAvoid(“Liberty Ave”); Nroouwteittcoanthceomdeestupinawtiitohn.a new string route; route = GetRoute(); “Take Route 28 to the Highland Park Bridge to Washington Blvd” tsGtheratetRetoduoMteesi(nk)’etgwiivnaecnsltusadetnoetwhaevrooidut. e Mike’s navigation system solves the street navigation problem the same way he does More free ebooks : http://fast-file.blogspot.com you are here 4   87 set methods and modify routes Mike’s Navigator class has methods to set and modify routes 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. public class Navigator() { Mwwnoahikuvoliedgwacatmhseoastkaeehirmnsoekeunittnshgeeodattbohnorsauoomtumgehehsootwanehcatitoty. public void SetDestination(string destinationName) { ... }; public void ModifyRouteToAvoid(string streetName) { ... }; public string GetRoute() { ... }; } tsTsththraaiittnsegmimsveeatanrhntiseacbtraleheltleitnumrghnaetttthhyweopidGlel edoctofoRenstotnuha’ttienem(rt)eehttmeuherdotndihr.aoenIcdtytticomhaniennsa.gun.Wssehtiehtnattitot’sshevetoida, Some methods have a return value string route; route = GetRoute(); 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. Htructtheesahhetraleecsetuu’rrsvtlhneaahaasttleusneuaertanetnbwxhriaoaseectnmtkpartpuaterlt.resenoaumTlmotttehfenyhetatpeaneemdr—stmetsotieautthttpsoeoehasdmsosdent 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); M3vaeartniahdbold5ess. Bctaounttthyaeokmue.cvaanluaelssolikpeass 88   Chapter 3 More free ebooks : http://fast-file.blogspot.com objects: get oriented! Use what you’ve learned to build a simple application 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 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 file 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) { TdveaheqricusilaaaslbrtletaesotaeaanmndfeinensmteatlpSsttyirting string. } } string finalString = “”; This line of code adds the for (int count = 1; count <= numberOfTimes; count++) { finalString = finalString + thingToSay + “\n”; } tlcihnoeenbtfreiennatakslSootnfrtinotghtivnhagerTieoanSbdaley.ofanidt a to MessageBox.Show(finalString); return finalString.Length; 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. ThcaahlsicsuailsaptcreaoslpleetrdhteaylepcnragloltpehedrotLfye—nagetsvtehrr.iynWgsh,te\rninnigt counts as one character. 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 MessageBox 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. “SHeetllot!”heusdinegfaiutlstTteexxttporfoptehrteyT.extBox to 3 Add this form to your project. Then double-click on the button and have it run this code that calls BlahBlahBlah() and assigns its return value to an integer called len: 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 message box. this VTppcraroholonuipspteeerirrspottrla.yyoSpNtteeoourtmt11iye0,trsi,tticoaMsUn3Mdpin.Diaimtxouswimmnum you are here 4   89 More free ebooks : http://fast-file.blogspot.com introducing objects Mike gets an idea The interview went great! But the traffic jam this morning got Mike thinking about how he could improve his navigator. It’d be great if I could compare a few routes and figure out which is fastest... He could create three different 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. Navigator SetDestination() ModifyRouteToAvoid() ModifyRouteToInclude() GetRoute() GetTimeToDestination() TotalDistance() Navigator2 SetDestination() ModifyRouteToAvoid() ModifyRouteToInclude() GetRoute() GetTimeToDestination() TotalDistance() Tatitlhhl’siasotafbniottxehadeisosymeaswetcaatlhyaosatdsosgdlisianaengeacreeac.vmlea.rsysIt,thalininsdtgs Navigator3 SetDestination() ModifyRouteToAvoid() ModifyRouteToInclude() GetRoute() GetTimeToDestination() TotalDistance() 90   Chapter 3 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. More free ebooks : http://fast-file.blogspot.com objects: get oriented! 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. TianNhlliaMsoviifisgkaettt’shhoeerprNmoobaegjvtreihagcomatdt.oscIrattnhclilausatstsess.a Navigator SetDestination() ModifyRouteToAvoid() ModifyRouteToInclude() GetRoute() GetTimeToDestination() TotalDistance() new Navigator() new Navigator() new Navigator() navigator1 Navigator o navigator2 Navigator o bject bject All you need to create an object is the new keyword and the name of a class. navigator3 Navigator o bject Mike needed to compare atthroeneced,ifsfoerheentuserdoutes atthrteheeNsaavmigeattoimreo.bjects 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. More free ebooks : http://fast-file.blogspot.com you are here 4   91 for instance… 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 its methods, just a class, you define like a blueprint defines the layout of the house. ct ct ct mYamnoaadukkeecyaoaanunnyyucsannenuummounbbseeeerrbolnooueffepcohrlbaoinjsutesscetttso,os. An object gets its methods from 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 public method in your class becomes part of the object. House 38 Pine Street House obje GiveShelter() AppreciateInValue() GrowLawn() MailDelivered() ClogDrainPipes() AccruePropertyTaxes() NeedRepairs() 26A Elm Lane House obje 115 Maple Drive House obje 92   Chapter 3 More free ebooks : http://fast-file.blogspot.com When you create a new object from 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. objects: get oriented! seYtxoaeutcreumptreenostgar. anmew House 115MapleDrive = new House(); Agocfofltatsetsarhn:ienNiHnmosotweuamsnieotcr’esy. 115 Maple Drive House obje ct Check it out for yourself! Do this! 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. in-stance, noun. an example or one occurrence of something. The IDE search-andreplace feature finds every instance of a word and changes it to another. More free ebooks : http://fast-file.blogspot.com you are here 4   93 objects improve your code A better 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. fywGUoohUsuraemItrmsadtIynkeoatesunie’dgrarnsefefafbroco.urerim,ldGwiinnrhgaictpwhhhheiicesanl 1 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. 2 He created a Navigator object and set its destination. navigator1 3.5 miles The navigator1 object is an iNnsatvaignacteorofcltahsse. bject Navigator SetDestination() Navigator o ModifyRouteToAvoid() ModifyRouteToInclude() GetRoute() String destination = textBox1.Text; GetTimeToDestination() TotalDistance() 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. TMMmhpoeaoedrtdSiahiffemoytydeRDRtsooeeauurslttt.leietnTTaaootkAIienovconali(ud)ds,(te)r(i)anngdas a 4 The third Navigator object is called navigator3. Mike set its destination, and then called its ModifyRouteToInclude() method. Any time you bject bject bject navigator1 3.5 miles Navigator o navigator2 3.8 miles Navigator o navigator3 4.2 miles Navigator o 5 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! create a new object from a class, it’s called creating an instance of that class. 94   Chapter 3 More free ebooks : http://fast-file.blogspot.com 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; tdtWhheeesetgticaneoavxdetteiobyMnoouxiaekansed.hwesrtaordteeestttaonratgm.eeHtsetrfehr’esom Navigator navigator1 = new Navigator(); navigator1.SetDestination(destination); int distance1 = navigator1.TotalDistance(); Anaannvddighgaeetrtoer’tshotbehjdeecistcto,adsneectet.oitscrdeeastteintatheion, 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. The one. built-in C# Mike used it Mtoatfhi.nMdint(h)emsehtorhtodestcodmisptaarnecsettwoo numbers and returns the destination. the smallest int shortestDistance = Math.Min(distance1, Math.Min(distance2, distance3)); More free ebooks : http://fast-file.blogspot.com you are here 4   95 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(); sctsWetrhtereeeagietctateosvdentreaohymuetotoeufes,,giareaashttlnoedntaNgdhgaeevwstitdigtaaethrtshttoeti.rnhdHaeotiebscirtjoeoean’dcnsteca,ent.do 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 = new Navigator() navigator2. SetDestination(destination); navigator2. 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(); The one. built-in C# Mike used it Mtoatfhi.nMdint(h)emsehtorhtodestcodmisptaarnecsettwoo numbers and returns the destination. the smallest int shortestDistance = Math.Min(distance1, Math.Min(distance2, distance3)); 96   Chapter 3 More free ebooks : http://fast-file.blogspot.com Hold it! 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? objects: get oriented! 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: So how does an instance keep track of data? A: Turn the page and find out! More free ebooks : http://fast-file.blogspot.com you are here 4   97 an object’s state of affairs An instance uses 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. lgTspaieertmtcoeihplrainenrriotctnoat.ylola.ylaA,l itftphi’resaoltdspee—atrbttliuiytnttgislweavee’lrly This is where a class diagram shows the fields. Every instance of the class uses them to keep track of its state. Field1 Field2 Field3 Class Method1() Method2() Method3() Add this separate from the line to the fields 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 Every instance its destination of Navigator knows and its route. SetDestination() ModifyRouteToAvoid() ModifyRouteToInclude() GetRoute() GetTimeToDestination() TotalDistance() ailWtebtshouaryttoouuatthesNae, ttaavnraidgoadutgteoesetrt. inoinabftjoeiorcnmt,admtoiooednsifisy An object’s behavior is defined by its methods, and it uses fields to keep track of its state. 98   Chapter 3 More free ebooks : http://fast-file.blogspot.com Let’s create some instances! 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. Clown Name Height TalkAboutYourself() ookWrfehyteywhnooeuryrdmouceilntawhsaesoin,tdtdhdeotrneo’cttlcahrureesaaetctilteoahnsise.nsdstteaacntlaciercsation objects: get oriented! “rivRteoetimmdure”enaminnbasenftryr,hovawnatthlueieton.fdyoaouemssnee’ttehod, public class Clown { public String Name; public int Height; public void TalkAboutYourself() { MessageBox.Show(“My name is ” + Name + “ and I’m ” + Height + “ inches tall.”); } } tRoopeemtreaamtkoebrewrah,natdtheemveu*rlt=’sipoolypneitrtahtbeoylrewfthtealltosefvCet#rh’se 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.” More free ebooks : http://fast-file.blogspot.com you are here 4   99 a heaping helping of objects Thanks for the memory 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 project picture starts. of the heap Notice that before the it’s empty. Let’s take a closer look at what happened here Clown oneClown = new Clown(); oneClown.Name = “Boffo”; oneClown.Height = 14; Write down the contents of each message box that will be displayed after the statement next to it is executed. ocEblaajsceshctboyafnrdtehsefersilevliinnnggewiatsctuhpautnwekmitoehfnttmsheecmrooebarjtyeecostn’asntdhiaentsath.eaanpcefoofr the Clown that oneClown.TalkAboutYourself(); “My name is __B_o_f_f_o_ and I’m ___1_4__ inches tall.” Clown anotherClown = new Clown(); anotherClown.Name = “Biff”; anotherClown.Height = 16; anotherClown.TalkAboutYourself(); “My name is _B__if_f___ and I’m ___16___ inches tall.” Clown clown3 = new Clown(); clown3.Name = anotherClown.Name; clown3.Height = oneClown.Height - 3; clown3.TalkAboutYourself(); “My name is _B_i_f_f___ and I’m __1_1___ inches tall.” anotherClown.Height *= 2; anotherClown.TalkAboutYourself(); “My name is _B_i_f_f___ and I’m __3_2___ inches tall.” When your program creates a new object, it gets added to the heap. 100   Chapter 3 More free ebooks : http://fast-file.blogspot.com What’s on your program’s mind objects: get oriented! This object is an instance of the Clown class. t #1 Here’s how your program creates a new instance of the Clown class: Clown myInstance = new Clown(); 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: 1 CoolnnoeewCCnllooowwnnne..CNHlaeomiwegnh=t=“=nBeo1wf4f;Col”o;wn()Ti;fshiecelrdfesiartsaterdeo, bsaejnetdc.tits oneClown.TalkAboutYourself(); “Boffo” 14 Clown objec “Boffo” 14 “Biff” Clown objec t #2 16 Clown objec t #1 t #2 t #1 2 Clown anotherClown = new Clown(); anotherClown.Name = “Biff”; These statements create the second object and fill it anotherClown.Height = 16; with data. anotherClown.TalkAboutYourself(); 3 Clown clown3 = new Clown(); clown3.Name = anotherClown.Name; “Biff” 11 Clown objec t #3 “Boffo” 14 Clown objec “Biff” 16 clown3.Height = oneClown.Height - 3; clown3.TalkAboutYTocrhueerantsteedhleaftn(hdi)rpd;opCullaotwend.object is Clown objec 4 anotherClown.Height *= 2; anotherClown.TalkAboutYourself(); There’s no new command, which these statements don’t create a means new object. They’re just modifying one that’s already in memory. “Boffo” “Biff” 16 Clown objec t #3 14 Clown objec “Biff” 32 Clown objec t #2 t #1 More free ebooks : http://fast-file.blogspot.com you are here 4   101 making methods make sense You can use class and method names to make your code intuitive 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. int t = m.chkTemp(); “obj”, “ics”, and “m” if (t > 160) { Tintheegcehrk…Tebmutp()whmaetthdoodesriettudron?s an are terrible names! We have no idea what they do. And what’s that T class for? T tb = new T(); tb.clsTrpV(2); ics.Fill(); ics.Vent(); m.airsyschk(); } TmheethcolsdTrhpaVs (o)ne parameter, but we dito’ns’tsupkpnooswedwhtaotbe. 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. HyWafoociteuniwarghlrsleuta,edarcth,aseooeolwdtlnoyeshec.uopeotuceSidsacopftenirsfhiiuogtiilapscgou’tpsarorwoteakursrimpeoeoiutamdnupttsteoomettrnnowahy!fnehofdIouaunooplatlr?alottgwoheeisd. General Electronics Type 5 Candy Bar Maker Specification Manual Taisuhtteooomnohauotegt,daatsntyedsmtethmpee.rsIayftsutterhememtmeumustsptbepreaectruhfreoecrkemexdcteehveeedrysca31n6md0iy°nCuis,teotshlaebytciaoannndy cooling system (CICS) vent procedure. • Close the trip throttle valve on turbine #2 • Fill the isolation cooling system with a solid stream of water • Vent the water • Verify that there is no evidence of air in the system 102   Chapter 3 More free ebooks : http://fast-file.blogspot.com 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. TmheethIosNd’osugreattTuronoHtoytp(e) public boolean IsNougatTooHot() { int temp = Maker.CheckNougatTemperature(); if (temp > 160) { return true; } else { Btmhyeetnhcaoomddine“gCishteahcekloNctlaousesgaas“iteMTreatmkoepreu”rnadatneudrrsett”ah,ned. return false; } } Twhhiischmmetehaonds’sitrreettuurrnnts yapetrisuebooorlean, 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): rtAehtevuormidnetrahenotyduvradnlouteeysnapt’etmalel.ans public void DoCICSVentProcedure() { Turbine turbineController = new Turbine(); turbineController.CloseTripValve(2); IsolationCoolingSystem.Fill(); IsolationCoolingSystem.Vent(); Maker.CheckAirSystem(); } 5 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! More free ebooks : http://fast-file.blogspot.com you are here 4   103 classes au naturale Give your classes 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…). Use class diagrams to plan out your classes Acfloacrslsadessessodiguinatignorganmypoauisprearc.osdiImte’psBleaEwrFaeOyalRltyEovydaolruuaawbstleyaortutorol writing it. tWbphoarexrittdaesitatogfthrehatemnha.bemoTctehltaeoosnfms .wattNrhieotawecglelayaasoncsuchaect!manetthsheeoedtaoliplnootffhethe ClassName Method() Method() M... ethod() Let’s build a class diagram Take another look at the if statement in #5 on the last 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? public class CandyController { public void DoMaintenanceTests() { ... if (IsNougatTooHot() == true) { DoCICSVentProcedure(); } ... } public void DoCICSVentProcedure() ... public boolean IsNougatTooHot() ... } CandyController DoMaintenanceTests() DoCICSVentProcedure() IsNougatTooHot() 104   Chapter 3 More free ebooks : http://fast-file.blogspot.com 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 gfWooeersfthihleliresedo?nine.tWhihsactlamssetnhaomde Fill() OaFannimeldleoitnifthsiottdoshtecchalceallrlsaessdmsneeaFstmihlhelo(a)dd.. npTcarlhamesevesrioeaiunnswdtaphsamegoeenct.eohFdooiedtll.hoiennrtithse More free ebooks : http://fast-file.blogspot.com you are here 4   105 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() 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. Dishwasher CleanDishes() AddDetergent() SetWaterTemperature() t Turbine CloseTripValve() 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. You could figure out that Maker is a class because it appears in front of a dot in Maker.CheckAirSystem(). IsolationCoolingSystem Maker Fill() Vent() CheckNougatTemperature() CheckAirSystem() 106   Chapter 3 More free ebooks : http://fast-file.blogspot.com v Class23 CandyBarWeight() PrintWrapper() GenerateReport() Go() 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. This class is part of the candy manufacturing system from earlier. DeliveryGuy AddAPizza() PizzaDelivered() TotalCash() ReturnTime() DeliveryGirl AddAPizza() PizzaDelivered() TotalCash() ReturnTime() These two classes are part of a system that a pizza parlor uses to track the pizzas that are out for delivery. CashRegister MakeSale() NoSale() PumpGas() Refund() TotalCashInRegister() GetTransactionList() AddCash() RemoveCash() The CashRegister class is part of a program that’s used by an automated convenience store checkout system. More free ebooks : http://fast-file.blogspot.com you are here 4   107 create a class Here’s how we corrected the classes. They’re 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 descriptive—we chose MakeTheCandy(), but it could be anything. CandyMaker CandyBarWeight() PrintWrapper() GenerateReport() MakeTheCandy() 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 them with a single class that adds a field for gender.. DeliveryPerson Gender AddAPizza() PizzaDelivered() TotalCash() ReturnTime() WadwseehslyuiavmdeterdhdyeerdtgeuhtyewhsreeeraeGnwdeatnswgdoiarerlcrsleafsaseissepoeladnsrftabotoerectlaytru,hasaeecnmkwd.beotthhat’s 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. CashRegister MakeSale() NoSale() Refund() TotalCashInRegister() GetTransactionList() AddCash() RemoveCash() 108   Chapter 3 More free ebooks : http://fast-file.blogspot.com objects: get oriented! public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { String result = “”; Echo e1 = new Echo(); _________________________ int x = 0; while ( ___________ ) { result = result + e1.hello() + “\n”; __________________________ if ( ____________ ) { e2.count = e2.count + 1; } if ( ____________ ) { e2.count = e2.count + e1.count; } x = x + 1; } MessageBox.Show(result + “Count: ” + e2.count); } public class ____________ { public int _________ = 0; public string ___________ { return “helloooo...”; } } } 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. Output Bonus Question! 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. Note: Each snippet from the pool can be used more than once! x y e2 e1 = e1 + 1; count 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( ); x == 3 x == 4 Answers on page 120. More free ebooks : http://fast-file.blogspot.com you are here 4   109 working class guys Build a class to work with some guys Joe and Bob lend each other money all the time. Let’s build a class to keep track of them. 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). Tticsctnahhoorshfaeodteettnaaenetnhcarteceersehdawetsapt.ahtthlsHeliteeovegaeforefttoketiohesr’nssrmemlmtriwektuhnihewsinetsaostas loaded. Guy object Guy object #1 #2 Guy Name Cash GiveCash() ReceiveCash() 2 We’ll set each Guy object’s cash and name The two objects represent different guys, so each one has its own name and a different amount of cash in his pocket. #1 #1 #2 #1 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. “Joe” 100 Guy object “Bob” 50 Guy object 3 We’ll give cash to the guys and take cash from them We’ll use each guy’s GiveCash() method to give cash to a guy, and we’ll use his ReceiveCash() method to take cash back from him. TRheecefivoerCmascha(l)lsmtehtehoodbj.ect’s “Joe” joe.ReceiveCash(25); 100 When you take an instance of Guy and call its ReceiveCash() method, you pass the amount of cash to take as a parameter. So calling joe. ReceiveCash(25) takes 25 bucks from Joe. “Joe” 75 Guy object 110   Chapter 3 The method returns the number of bucks that were taken. Guy object More free ebooks : http://fast-file.blogspot.com objects: get oriented! Create 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 Do this! 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: public class Guy { public string Name; public int Cash; The Guy class has two fields. a string, and it’ll contain the And the Cash field is an int, track of how many bucks are The Name field is guy’s name (“Joe”). which will keep in his pocket. TcgauhlyelehGdoivwaemCmoausuchhn()tcamtsehhtahttoodygoihvuae’lslyuoosnuee. parameter to tell the public int GiveCash(int amount) { The Guy makes sure that you’re asking him for a positive amount of cash, otherwise he’d add to his cash instead of taking away from it. } if (amount <= Cash && amount > 0) { Cash -= amount; return amount; } else { MessageBox.Show( Hwdreehoteeutsus,rhenhessreainthteaiakfhseasststihateetnoeorumuetgtehnuotrfcnathsvohias—lcupheiofe.cckkheet and “I don’t have enough cash to give you ” + amount, Name + “ says...”); return 0; } thIfee’llltl hymoeaugksueoyGwdivioteehCsnaa’sthm(h)easvrseaetgeeunrobnuogx0h,. cash, he’ll and then public if int ReceiveCash(int (amount > 0) { Cash += amount; return amount; amount) { TtasauhmhnreedoeuGRtntiethhvceeaeanCtisvaaeasadChmd(apo)ssauhrnmi(tat)emttimeshoteogethdrrhi.es,oaIdccttha’eswesrhcop.ktraskhsssatenojduzmsateanrkloiek, e } else { MessageBox.Show(amount + “ isn’t an amount I’ll take”, Name + “ says...”); return 0; } } If the amount was positive, then the saRhdeodcweesidv.eaCIfmaseihsts(a)wgmaesebtzohexordoanroderttnuheregnnastrtivehete,uratnmhseou0gnu.ty } fabhBolraleravbeccyakaotlearuhtneefcwheuhwadlers,wnoatintyhgomheunayItutDomcyuEhbrpieenwcrgtu—ilrhclmlelyoaasulbkaitnersogtamscbucakrrlteoeaitsccistank.hlgelIyattbt.’irsnWeadevcheaekenrsenytyt.tttohopheeeynm’irneg you are here 4   111 More free ebooks : http://fast-file.blogspot.com 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. Build this! 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 variable 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 “joesCash” and “bobsCash” instead of “label1” and “label2”. fwtltbNaoheohbar’ebelemmilsrlCleaabtTadbtoasedenhhxlske,teauCattnapmndosrtdpeehohtr.ptelhnaeYmheobroea.dteutlibehtcojsooatietanttsloohClmeneaaesv,he, Tobhjiescbtu’sttRoencewivilelCcaaslhl (t)hme eJtoheod, Jspuoabestsifrnragocmtitint1g0hethabesantckahsevhaarimtiaogbuilnvete. s, and to This button will call the Bob object’s GiveCash() method, passing it 5 as the amount, and adding the cash it receives from Joe to the bank variable. 2 Add variables to your form Your form will need to keep track of the two guys, so you’ll need a variable for each of them. Call them joe and bob. Then add a variable 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 public partial class Form1 : Form { keep track of Guy joe; Joe and Bob, Guy bob; you declare their variables int bank = 100; using Guy. public Form1() { InitializeComponent(); } fgmTdtrahouhovweceemhnbattamdmohnoeoekapnuneenGgdnytoudeyrtiosnehfogcuebepcoijfvaenaoescnrdhthdmosi.wn 112   Chapter 3 More free ebooks : http://fast-file.blogspot.com 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 variable. 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 into the form right underneath where you added the bank variable: This new method is simple. public void UpdateForm() { It just updates the three CGaNrauoesythiuocpfbedijeeahlctodtwessd.’tNuhseainmlgaebtaehlnsed} joesCash.Text = joe.Name + “ has $” + joe.Cash; bobsCash.Text = bob.Name + “ has $” + bob.Cash; bankCash.Text = “The bank has $” + bank; labels by setting their Text properties. You’ll have each button call it to keep the labels up to date. 4 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 { JioWfbohjetee”hcnetb’tusbthaRtenoekuncs,eheitarvsehcCeelainfcsookhusr(gm)thhmcmeeaotl“lnhsGeoytidv.he—e$bJ1u0otetoonly 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); UpdateForm(); } Tdwinohheetasthn“eeR’tveebcrnaeenBiekvd,eobb$te5ogciavfceuhrsseoecmbkiatcB’hlkolo.bwj”usmtbuucathdtdoins IGfivBeCobas’sh(o)utwiollfremtounreny,zero. 5 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 a special 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 Form() { InitializeComponent(); // Initialize joe and bob here! } tAchrdeedairtteNhteamhleienetaswndoofoCbcajosedhcetfshieealrdneds.tsoet More free ebooks : http://fast-file.blogspot.com you are here 4   113 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() Hictnerwsretoeaa’tnsseecwstehtoiethfrseeGfowuibeeyjle.dscsTet.th, eaupnfditrhtstehelfininreesxtt public Form1() { InitializeComponent(); bob = new Guy(); bob.Name = “Bob”; bob.Cash = 100; Make sure you call UpdateForm() so the labels look right when the form first pops up. } joe = new Guy(); joe.Name = “Joe”; joe.Cash = 50; UpdateForm(); Then we do the same for the second instance of the Guy class. 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: Okay, so then why not get rid of the “Guy bob;” line at the top of the form? A: Then the bob variable 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 can access it from any other method inside the form or class. Mpbraaockjkeectstournietowyion—uwaseaf’vlelewctophmaeeges. Q: What happens if I don’t leave off that first “Guy”? A: 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. 114   Chapter 3 More free ebooks : http://fast-file.blogspot.com objects: get oriented! There’s an even easier 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; Object initializers only work with C# 3.0. If you’re running Visual Studio 2005, then this won’t work. Definitely consider downloading Visual Studio 2008 Express Edition—it’s free, and you can install it alongside your existing VS2005 installation. 2 Delete the second two lines, and the semicolon after “Guy()” and add a right curly bracket. joe = new Guy() { 3 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() { Object 4 Press tab to tell it to add the Cash field. Then set it equal to 50. joe = new Guy() { Cash = 50 intializers save you time and make 5 Type in a comma. As soon as you do, the other field shows up. joe = new Guy() { Cash = 50, your code more compact and easier to 5 Finish the object initializer. Now you’ve saved yourself two lines of code! read... and the joe = new Guy() { Cash = 50, Name = “Joe” }; Ttohrhiiignsignnaealwsly.tdhIetec’sltahrjuarsteteiosnlhinoderosteeosrfeaxcnoaddcteelyaysotiuehrewtrsooatmreeead. IDE helps you write them. More free ebooks : http://fast-file.blogspot.com you are here 4   115 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. bject myInst bestRoute obj Object Navigator 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 Name Duration ClosedRoad StreetName ReasonItsClosed FindDetour() CalculateDelay() Detour Name Duration ReasonItsClosed FindDetour() CalculateDelay() 116   Chapter 3 More free ebooks : http://fast-file.blogspot.com objects: get oriented! Add buttons to the “Fun with Joe and Bob” program to make the guys give each other cash. 1 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. 2 Add two more buttons to your form TIittfhh,aeyatnodutddhaeileltreetIbaDeadEctykhacetdlioocdlkedyedodbubrutethffteooorrnbem3u,,_taatCnnodldnic,ukrjs(eue)nsttammhedeetehlnietoetd.we method it adds now. 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. TygrwjoiohoviueniwesGds1boihi0nvuwoetutsblttThduoooecnBuknPsostaerbmeto.ltoelpsheiBerJttoo“ibe(eN,stsaoome)” TigtihvbeisotbbGubtiuvtceoksnTs ottJoeolleJs.oBe.obNatmo e 3 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 five bucks to Joe. Make sure the form updates itself after the cash changes hands. More free ebooks : http://fast-file.blogspot.com you are here 4   117 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(); aBtHnhoederbehtgiwaesrtonesaintimnshteitea.inaoclbiezjseecdotfwintitihtheia1Gl0izu0eyrcsbluafcsoksr.s bob = new Guy() { Cash = 100, Name = “Bob” }; joe = new Guy() { Cash = 50, Name = “Joe” }; UpdateForm(); } public void UpdateForm() { joesCash.Text = joe.Name + “ has $” + joe.Cash; bobsCash.Text = bob.Name + “ has $” + bob.Cash; bankCash.Text = “The bank has $” + bank; To make Joe give cash to Bob, we call Joe’s } GiveCash() method and send its results into private void button1_Click(object sender, EventArgs e) { Bob’s ReceiveCash() if (bank >= 10) { method. bank -= joe.ReceiveCash(10); UpdateForm(); } else { MessageBox.Show(“The bank is out of money.”); } } Take a close look at ahroewbtehinegGcuayllemde.tThohdes results returned private void button2_Click(object sender, EventArgs e) { by GiveCash() are The trick here is thinking through who’s giving the } bank += bob.GiveCash(5); UpdateForm(); pumped right into ReceiveCash() as its parameter. cash and who’s receiving it. 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(); } } 118   Chapter 3 More free ebooks : http://fast-file.blogspot.com 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 15 Across Across DoDwonwn 2. If a method’s return2ant.yyIfptaheimnisge.t_h_o_d'_s _re,tiutrdnoteyspne ’its r_e_t_u_r_n, iat ndoyethsnin'tgre. turn 1. T1fr.hoTimshisfaofrroamrnmgcecooynnotutrrosoelltll.eettsstthheeusuesrecrhocohsoeoasneumabneur mber from a range 7. An object’s fields 7. An obje de9f.iAnegoitosd ct's fields define its _______ _m_e_th_o_d____________ makes it cle ar what the you3. sIte'st.a great idea to create a class before you start writing code ________ on paper method does. 9. A good method ___1_0_. _W_h_e_re_ombjeacktes sliviet clear what the method does. 11. What you use to build an object 13. What you use to pass information into a method 3. I45t..’sTWhaehsagetrdeaenaftionbiedjewecathuatstoeascntroeobakjeetecetpadtorcealscaksosf_w_h_a_t_it_k_n_owons paper before you6.sAtnarotbwjecrtit'sinmgecthooddes define its ________ 7. Don't use this keyword in your class declaration if 10. Where objects live1145.. The statement you use to create an object A special kind of field that's used by the form 4. Wyohu awtaannt toobbjeeacbtleutsoecsretoatekeinesptatnrcaecskofoiftwhat it knows 8. An object is an ______________ of a class controls 11. What you use to build an object 5. T12h.eTsheisdsetafitneemewnht atetllasna mobetjehcotd dtooiemsmediately exit, and specifies the value that should be passed back to 13. What you use to pass information into a method 6. Athne sotbajteecmte’sntmtehathtocdalsledd ethfienmeeittsho_d_. ______ 14. The statement you use to create an object 7. Don’t use this keyword in your class declaration if you want to be able to create instances of it 15. A special kind of field that’s used by the form controls 8. An object is an ______________ of a class 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. More free ebooks : http://fast-file.blogspot.com you are here 4   119 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(); _E_c_h_o_e_2__=__n_e_w_E__ch_o_(_)_;______ int x = 0; while ( ___x__<__4____ ) { And here’s the bonus answer! Echo e2 = e1; result = result + e1.hello() + “\n”; __e1_.c_o_u_n_t_=__e_1_.c_o_un_t__+__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); } public class __E_c_h_o_______ { public int __c_o_un_t____ = 0; public string ___h_el_lo_(_)____ { return “helloooo...”; } } } 120   Chapter 3 More free ebooks : http://fast-file.blogspot.com objects: get oriented! Objectcross Solution 1N U M 2V O I 3D 4F 5M 6B E I I E 7S T A T E R 8I 9N A M E T T H I N G L 10H E A P A 11C L A S S R D O T V U T A 12R D I I P 13P A R A M E T E R S C O D N T R O C W 14N E W U 15P R O P E R T Y N N Across 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 [p arame te rs] 14. The statement you use to create an object [new] 15. A special kind of field that's used by the form controls [property] Down 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 [f ie ld] 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] More free ebooks : http://fast-file.blogspot.com you are here 4   121 More free ebooks : http://fast-file.blogspot.com 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, how to work with data in your program, and even figure out a few dirty secrets about objects (psstt… objects are data, too). this is a new chapter   123 More free ebooks : http://fast-file.blogspot.com not my type The variable’s type determines what kind of data it can store There are fifteen 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 float are the most common types. Ahawvehoaledneucmimbaelrpdoionets.n’t ≥ 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 “”). ≥ ≥ 1f3btpsoi05lrog3e,7ono80tita4(lsfyoii8tcgris,asni41cmnia1aftfi0npoBcf,llai0oselgnot.0ouowtT0lrref,eeehia0gsdnea0.unb0T“rvyy,esahis1ld3ge.u,n87eTe1i4c—z0fhi3ie3cam8,riat0totn’5rhaseta9silenn)f,i—ingtgg1hueu4maemr.lsr4oeebls3toao”e8knrnrs5psugf7awrteaho,retsamaoimrtnirtdyd±efooaa1n0aunn..ll50ydscs0a×thc0hneoa0e1.sms40tp7o3p−rer74olc5ie4critsa1aoifoten5en±wy5do3e,nafr.blu4lstumihh×gteabniv1teni’ef0rsuic3saam8eacswvntbleutaientarfrhigl:gleyuuparess.p“na“polfuflaopwmllciopoaneboaatysetsts.”eri”ndhngoaiusftsmposobtdhiaehnoerectr“,it”fmsw—aiafxhmaloeiscerdh On the other end of the range, 10-45 means that you can store any number as small as 10-45 (or a decimal point followed by 45 zeroes followed by 1)… but, you guessed it, as long as it only has 7 or fewer significant figures. More types for whole numbers The “u” in uint stands for “unsigned”, which means it can’t be negative (so there’s no minus sign). 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: A lot of times, if ≥ byte can store any whole number between 0 and 255. you’re using these types it’s because ≥ sbyte can store any whole number from -128 to 127. you’re solving a ≥ short can store any whole number from -32,768 to 32,767. problem where it really helps to The “u” ≥ ushort can store any whole number from 0 to 65,535. have the “wrapping stands for “unsigned” ≥ uint can store any whole number from 0 to 4,294,967,295. around” effect that you’ll read about in ≥ long can store any number between minus and plus 9 billion billion. a few minutes. ≥ ulong can store any number between 0 and about 18 billion billion. 124   Chapter 4 More free ebooks : http://fast-file.blogspot.com types and references The double HUGE Types for storing really and really tiny numbers 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: Wprhoegnraymounreeds ≥ double can store any number from ±5.0 × 10-324 to ±1.7 × 10308 with 15–16 to deal with significant digits. type is actually as common as float. A lot of people use it all the time, and rarely use float. cuusurarlelyncwy,anytouto≥ use a decimal decimal can store any significant digits. to store the number. Literals have types, too number from ±1.0 × 10-28 to ±7.9 × 1028 “Atiynlpiteteirniatloj=uysotu5rm;ce”oa, dntseh.aeS5nouwimshbaeenrlityteohruaattl.yypoeu with 28–29 When you type a number directly into your C# program, you’re using a literal… and ycVWooaunhlruteenrnopuylmr,oouyeporeuiucrseUtwdypeDrtienhoewn 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 try to assign a float literal to a double 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 or a decimal literal to a float, the IDE will give you a helpful message reminding you to add the right suffix. Cool! 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 an object can inherit from another one, and that object can in turn inherit from yet a different object. At the top of every inheritance hierarchy is the object class—that’s a special type that every other object inherits from. That’s really useful, because it means that you can assign any value, variable, or object to an object variable. You’ll about learn how a lot char more and obtyhtereinreClahtaepttoerea9c. h 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? More free ebooks : http://fast-file.blogspot.com you are here 4   125 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. in2nut,m14ibse7cr,o4s.m8Imt3o,6hn4olyld7us.sendumfboerrswhupoleto ranefrYauoeomlrluygb’wolelbirhniusgogs.letetholoatnbge Aupshtoort32w,7ill67ho. ld whole numbers byte holds numbers between zero and 255. long int short byte 64 32 16 8 These are the number of bits of memory set aside 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 accurate, 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. float double decimal 32 64 128 Tfvdhraeearcsicaeitmbitolaenylsspp.esltasLocaarerrese.gmefroorre bool 8 char 16 string depends on the size of the string 126   Chapter 4 More free ebooks : http://fast-file.blogspot.com 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 complier 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 Aidanlbotloetsugnhto’eitntcghwoeiomnrvtpkaio)lleu.areItssinhedoetorshetisesn(a’iwtnnhticcachruep. int short ttiTlrnhayttehienicssrghumopptr,auotkttephcsarauotspltea?ewnrcsgToeteu.hrlydeWovnacuh’tl.oaumtefpiiiitfnleirytnohtiuseo int hours = 24; 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. 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”; More free ebooks : http://fast-file.blogspot.com you are here 4   127 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 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 Try building your program. Uh-oh—you got an error that looks like this: Do this Check out how the IDE figured out that you 3 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: were probably missing a cast. 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 okay for C# to cram the data into the new variable. fVypcTtoaoahoarlusaukmstepeeu.htdstaeeeodrtmbhteacienhgnaueidsNnttnTueicnimanhgtlgeekorcweoikrfchfUleoTinptupethDsybteoaoheucwlorakwnst. short y = 78000; bool isDone = yes; 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. Tntnuhoumem3bbs2eher,or7sr’6stf8tr.tooyTompheb-iisgh3!o2ld,7s67 byte You can only assign “true” or “false” to a a value bool. of days = 365; nvAaeleubdeytaoefschuaopnrttoonfloy2r5ht6o.hldiYs.oau’ll 128   Chapter 4 More free ebooks : http://fast-file.blogspot.com 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? 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 When you’re nittyFtvaohhoa’stseeulstuioaeagcnnnoeutftdimemnholodogpbeuaiaeblttaeerlo,frnentd.laaoutondmahodtdtabf,teealrln different types, it automatically converts the smaller type to the bigger one. Here’s an example: int myInt = 36; float myFloat = 16.4F; 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. types and references Wrap it yourself! a(m“cyuTwamosoilhurdnocraegedusrp,lueaestlalt”’ofhsnoe.tdrcnhJ,ao“celuMscamswuntloycilutadsumpttc”loabhieoptbreneiurytu)tsp.3—tttY6ootoy5onhohu,SeuMo’lcwwlWciohegadinicennctatdh2isdfot15dowii0cn6osige9ts. 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; More free ebooks : http://fast-file.blogspot.com you are here 4   129 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; d = d / 123.456; The - operator subtracted the short from the long, and the = operator converted the result to a double. MessageBox.Show(“The answer is ” + d); This + operator is 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()); 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; 130   Chapter 4 More free ebooks : http://fast-file.blogspot.com types and references When you call a method, the variables must match the types of the parameters 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; } } Otapnhotaeinvshsalsyrerpeiiampamtrlbeiaanlatcemdehbeecootriadto—el’’llsrseetdaccdhnoaeoydlevleceeassdo.nNlud’toeye.ehostIratNhvaovejtauirtsstcioaainbhlplslasaeidss.seTtiothe 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. 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. You can assign anything to a parameter, or with the type variable, field object. if statements always test to see if something’s true Did you notice how we wrote our if statement like this: WtceehhxexeeapcdmilNkfiicdpsOilnt(eiTy’flstyesfsohcNorphameooverm)eecatk{ttnhoootinrwog)e.’xssoe“pnetil,firciyuif(toe!uly.ay’elYlsbsoNauouysoou)lcea“”hailfleniysc(kijtysuheistftseNrsussooaeemme=oeeur=tsthfdhitaniolrngsug’e“se.i)aff”sa.(l“syTieefhsuNa(styoin’e)sgs”Nb!oeorc(aa=“nui=sfeex(fac!aynllaesmisefN)a”tos.t)ioI”ann,teaopmnuodrienntcnto,odtaoelrways More free ebooks : http://fast-file.blogspot.com you are here 4   131 this table reserved vAdaocrtitauhaballlety,nwCaimt#hesd,noobneys-prgueivtseetriynvoegud@anaiwnmaefysrtotonotou,soeiffrtyesoheuervwkeeadynwtkoetryodw..oYrdous as can 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 132   Chapter 4 Answers on page 161. More free ebooks : http://fast-file.blogspot.com 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 travelled 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: batGunhetdettommrnaiisndx.imiomifzizee Tpthibsolladb.el is 12 tcFooonr1tartonhldes, tMsweaotxiNtmhuuemmeMrtiiocnUi9mp9uD9mo9w9pr9no. perty 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 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 messagebox 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. More free ebooks : http://fast-file.blogspot.com you are here 4   133 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 go all the way So a short number could up to 999,999. or a byte won’t cut it. double amountOwed; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs startingMileage = (int) numericUpDown1.Value; e){ DttdtchoiehdoaectncyhtinoyaruuomnomuglareetehlrmoaticvehvaUeamenlpbuDieeronfwtrno?m endingMileage = (int)numericUpDown2.Value; if (startingMileage <= endingMileage){ milesTraveled = endingMileage -= startingMileage; amountOwed = milesTraveled *= reimburseRate; label4.Text = “$” + amountOwed; } else { This block is supposed out how to figure many amnidlesthweenremturltaivpelyled 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? taoiSoWthnnfhedeeotcwwtuitsasi(ohtle)tlelidpnehmasgeaeberncttaamorhmhean.oeseldtdstMaeeoghrrenenessera:stetatgo.egohWedeewBseiasfopiygnixlraa.svyte, 134   Chapter 4 More free ebooks : http://fast-file.blogspot.com 1 Now add another button to the form. Make it so that the number of miles traveled is displayed on the form after you’ve calculated the amount owed. types and references tysChorlouaicw’vvkeeiltnechgdleitcinnkhueiasmdbbmcueeatrsltcsoaoufgnlaetmaebfilotesxhse.oruld 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. 4 Um, something’s not right… The number of miles always matches the amount owed. Why? More free ebooks : http://fast-file.blogspot.com you are here 4   135 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; TcoosfbtahptenmtrulheneaelhoitreesdlremeeadstisanuntsiTalbgeeoncasrwMntrrgoomedasMrme.ivavailpneeaisTctolgslalteeuuiiMhgagmsdeniegnsdeieslta.eaotangde } else { MessageBox.Show(“The starting mileage number must be less than the ending mileage number”, “Cannot Calculate Mileage”); } TyemohniuisrdliiecsonsbdgTeeMtrwtiaeolvrne—’etalnmogewoedd.iafnyd 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: mT = eM -= sM; aO = mT *= rR; weVshasaretinattbihlaeelsliyrnuapsmuerelepdsossleiiknemtitgehhllitisngabreye.ou 136   Chapter 4 More free ebooks : http://fast-file.blogspot.com types and references Objects use variables, 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 Using an object 1 Write a statement to declare the integer. int myInt; 2 Assign a value to the new variable. myInt = 3761; 1 Write a statement to declare the object. Dog spot; WltdikhheeecelnDatryyoapogteu,ioyihnnoauvasetuvasaatereciimatlabesalnsest. 2 Assign a value to the object. spot = new Dog(); 3 Use the integer in your code. while (i < myInt) { 3 Check one of the object’s fields. while (spot.Happy) { So it doesn’t matter if I’m working with an object or a 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. More free ebooks : http://fast-file.blogspot.com you are here 4   137 get the reference Refer to your objects with reference variables 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. Anytime you want to use that particular guy, you can reference it with the reference variable called Joe. 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: Titnhhsatetao’nsbtjcieaactltlien.dg Hcoedree’srtunhse. hNeoatphibnegfotrheeryeo.ur This variable public partial class Form1 : Form is named Joe, and will { Guy Joe; reference an object of type Guy. public Form1() { InitializeComponent(); Joe = new Guy(); } Trehfiserisentcheevariable… …and this is the object that Joe now refers to. Cwoonbirtjeyheaocttauirnlsgaosbtaeyulofrufemf,aceykaroeneurn’r—creeeifneiussrtsielnitakgodeiitmtofatlkaostitnleiagcrbk.aeinllgaabnietl HtJoheborijesee’crcsteo,tfdehwereirtrhiuhnengats.phtTeoahfviteat.rreeira’sblaen Joe Guy object #1 viTrsaerhtfieaehbrrOeloeNnucgLcehaYltltehwhdiesaJygroueteyfo.eorbenjeccet 138   Chapter 4 More free ebooks : http://fast-file.blogspot.com 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, point them at different things, but it’s the object that dictates what methods and data are available, not the reference itself. When your code needs to work This object is of type Guy. It’s a SINGLE object with MULTIPLE references. rhFeaofsremare1vn’sacrebisuatbttlheoisnc1ao_lblCejedlicct“k.Jmoee”thtohdat with an object in memory, it uses a reference, which is a variable joe programmer customebrrother dad heyyou whose type is a class of the object it’s going to point to. A reference is like tcAcaolnallsteisnhdsiitss“aDoknbeacejdeep”cion.tfginathareevfGaeruriyeanbclee unclejoe a label that your code uses to talk opviEbsaojvrianeeiatcrdbtytli.feoo,fnetberuhetoenftSthtAreheMyefsEeaerlelGlanubcyeels about a specific 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 okay, too—that’s what Joe’s kid does every day. trhaTrheiemfahlfoteeetrrfrmeeoeonranfackcredeeedisshfilfaftsofseeoternsaresteenohdntfiiistnftdfsmihaeitfimersnfteegenchsrtoo.GendEunntsytaae,mcuxsbhteee.cause More free ebooks : http://fast-file.blogspot.com you are here 4   139 that’s sanitation engineer thank you very much If there aren’t any more references, your object gets garbage collected If all of the labels come off of an object, no programs can access that object anymore. 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. 1 Here’s some code that creates an object. Guy joe = new Guy() { Name = “Joe”, Cash = 50 }; yWWloiokbhuheje’eernnc“etJyyt,oooeeiuutl”l’iutsnasagnelikdkCete#haayessorit“ugeon’nfreeecwirtr”seelntaascttopeepatitvnaheagnamrtiaeoanbbntjleee,wct. label on it. JOE “Joe” 50 Guy object 2 Now let’s create a second object. Guy bob = new Guy() { Name = “Bob”, Cash = 75 }; viNanrsotiwaabnwlceeess:h,oaanvneedfttowrwooeGarcuehyfeGorbeujnyec.cet bob “Bob” 75 Guy object For an object to stay in the heap, it has to be referenced. When the last reference to the object disappears, so does the object. JOE “Joe” 50 Guy object #2 #2 #1 3 Let’s take the reference to the first object, and change it to point at the second object. joe = bob; Now joe is pointing object as bob. to the same JOEbob “Bob” 75 Guy object poof! 140   Chapter 4 More free ebooks : http://fast-file.blogspot.com BafuirrtestftehGreeurnyeceoisbtjnoeocttlho…enger …icotosb.oljlIeetCcc’tts#igofonmon,raear!gnkadsrbttahrgeaeshes 12 3 4 types and references 5 Typecross Take a break, and 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 10 page, and take on the rest of the chapter. 14 6 8 11 12 13 15 16 17 7 9 Across Down 1. The second part of a vaAriacbrleodsesclaration 2. You can combine theDvoawrianble declaration and the _________ 4. “namespace”, “for”, “wh14il.e. T"”,nh“aeumssienecgsop” naadcnedp",a“"nrfetowro”"f,a"arwevheaixrlaei"ma, b"pulleesisdnegc"laarnaindtto"iononenwe"satarteement. 2. You can combine the variable declaration and t ____________ into one statement. of _____________ wordse. xamples of _____________ words. 3. A variable that points3t.oAavnaorbijaebclte that points to an object 6. What (int) does in this l68in..eWWofhhceaontde(ai:nnxto)=bdj(eoincetts) ynin;o this line of longer has caondye:rex5f.=eWr(iehnnatct)eyyso;ur program u5ms.eeWms htoorawyt oyrokuwritphrdoagtraamthaut’sseisntmoewmoorrky w ith data tha 8. When an object no longpeorinhatsinagntyoreitfe, riet'nscreesmpoovinetdinfgrtoomit,the he7a. pIf uysoiunwg ant to store a7.cIufrryeonucywvaanlutet,ousetothreisatycpuerrency value, use this t it’s removed from the hea_p_u_s_in_g_______________c_o_ll_e_ctcioolnle.ction. 10. What you're doing when you use th9e. ++=opaenrda-t=orarteothis 9. += and -= are this kind of operator kin1d1.oAf ovpaerraiatobrle declaration always starts with thi 10. What you’re doing strings together. whesntiycokutuwseo tshteri+nogpsetroagtoertthoesr.tick two 14. The type that holds the bigges t nu1m1b. Aervsa. riable declaratio1snt2ra.ilnwEvgae.yrsystoabrjtescwtithhatshitsh. is me t h o d that conve rts i t 14. 15. The The type type that that hstooldressthae111psoib567n.si..ggiTT\tlgehhineveelseeatfttntonnyeuduurpmrmeo\wrbrbtenheharurasroms.telebs_ent_rou_rm_e_bs_ea_r stsiyenqpgueleesnltechteatset11rvo23aon..lrulEWyenvhhuteoemornyiltdboyeborjue’cvtehgaost thi1s3m. Wethhoednthyaotuc'voenvgeorttsaitvtaoraiasbtrliengo.f this a avasrsiiagbnleaonfythvisaltuypeet,oyiotu can assign any t ype, you ca 16. \n and \r are _______ sequences 17. The four whole number types that only hold positive numbers Answers on page 162. More free ebooks : http://fast-file.blogspot.com you are here 4   141 #1 so many labels Multiple references and their side effects 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: 1 Dog rover = new Dog(); rover.Breed = “Greyhound”; 1 Objects:______ 1 References:_____ Rover is a Dog object with a Breed field called Greyhound. Rover Dog object 2 Dog fido = new Dog(); fido.Breed = “Beagle”; Dog spot = rover; 2 Objects:______ 3 References:_____ Fido Rover SPOT Dog object #2 Fido But is another Dog object. Spot is just another Dog object reference to the first object. #1 #3 #1 3 Dog lucky = new Dog(); lucky.Breed = “Dachshund”; fido = rover; 2 Objects:______ 4 References:_____ 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. poof! Rover SPOT DogFoibdjeoct Lucky Dog object 142   Chapter 4 More free ebooks : http://fast-file.blogspot.com 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:_____ More free ebooks : http://fast-file.blogspot.com you are here 4   143 swapping elephants #2 #1 #3 #2 #1 #3 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(); rover rintintin Dog object quentin fido Dog fido = new Dog(); Dog quentin = fido; Dog object Dog object 3 Objects:______ One new Dog object is created but Spot is the 4 References:_____ only reference to it. When Spot is set = to Rover, 2 Dog spot = new Dog(); that object goes away. spot.Breed = “Dachshund”; spot = rover; 3 Objects:______ 5 References:_____ Hcsfererteroaemttaoe#dnR,1eobwgvueotDre,sowFgahiwedonaboyj’Fs.eicodtbojiesisct spot rDinogtionbtjiencDtogroovbejrecDt oqgufeoinbdtojeicnt fido spot #4 #1 #3 3 4 Dog lucky = new Dog(); rintintin lucky.Breed = Dog charlie = fido = rover; Objects:______ “fBiedaog;le”;Cw#otbhhh1jaae,etnrcll,etiFeaFiv#diwidnoa3ogs.wmCsTaeohshtvaeesrtntdl,oiielltaFobfoientdoheobirnjedc.tDog object #2 DogDLUooCgrbKojoYevbcejtrecDt qocguheoanbrtjlieicnet #1 #5 7 References:_____ Dog #2 lost its last reference, and 4 rinTinTin = lucky; it went away. Dog laverne = new Dog(); laverne.Breed = “pug”; 4 Objects:______ 8 References:_____ When Rin Tin Tin moved to Lucky’s object, the old Rin Tin fido LAVERNE poof! spot Dogroovbejerct Dog object quentin #4 #3 riDntogiLnUotCbiKjnYect Dcohgaorbljieect #1 #4 #5 #3 5 charlie = laverne; Tin object disappeared. lucky = rinTinTin; 4 Objects:______ 8 References:_____ Here the references move around but no new objects are created. And setting Lucky to Rin Tin Tin did nothing because they already 144   Chapter 4 pointed to the same object. DogsrfpooiovbdtejeorrDciLtonUgtCioKnbYLDtjAcoeiVhgcnEatoRrbNlDEjioqeegcuteonbtjeicnt More free ebooks : http://fast-file.blogspot.com 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 garbage-collected. 1 Start with a new Windows Application project. Make the form look like this: Cbwulhitcickthionngdciosapnlllastyhlsuecti“nhLdisuac.mWinehdssoaaA”gmebI(o)x, . yfHoouerrnete’sheedthEteloecpclharasesnattdeic.algarssam Elephant Name EarSize WhoAmI() TutmphietestlsehWaigbsheaomrAineimcsnslIcua(ld)gueedmsebestothtxheh.oedMeansarahkmoseuiezls.deurpaeonptdhtehe 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 messagebox 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 messagebox, and the Lucinda button should pop up Lloyd’s messagebox. 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... More free ebooks : http://fast-file.blogspot.com you are here 4   145 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 garbage-collected. 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…”); } } TcifpntlhWaaicrMhiwltstseloieasnohejistdnwesse“ds’hcsoeu.teatteEwsfWghi.awslneiteedi.nDgotBFopdirtEhpoohoSekoirnaxlodyo.eum’nntsfpttststht;.cefo”tcaiaotmosnhtdtl,r.tieenhgetmeeehteent public partial class Form1 : Form { Elephant lucinda; Elephant lloyd; fHreorme’sFtorhme 1F.cosr.m1 class code public Form1() { InitializeComponent(); lucinda = new Elephant() { Name = “Lucinda”, EarSize = 33 }; lloyd = new Elephant() { Name = “Lloyd”, EarSize = 40 }; } ItbpfThtorteoLioheshiyLnfuaaeohotctenuubaiyriL’cnnsvjejidgeelnmnuwocadscoyttttheardohcy,ewpaehLotyonoirlHboihlllendogujeoftbeyerlecendotderLteneeletwtraolnuodonhsocnytdenetd.r’stiel . private void button1_Click(object sender, EventArgs e) { lloyd.WhoAmI(); } private void button2_Click(object sender, EventArgs e) { lucinda.WhoAmI(); } privaEhlltlolueelocpdyivhednoardin=adt=l=bhluuolchtloiotdynloedddnr;ae3;;r_;Click(objeTrccerhtfeeearrtese’esencannenodoebtnerhec,eawrusEisentvsawtetaenentmdcAeeornnot’gtfsfwEoaerlen)ptthha{tenot. MessageBox.Show(“Objects swapped”); } } (osodstenttihelfrhyinfinen,ekorgrbnseadeenbcasataontwuudafstitertahotrytomhrphuaaetetasyylsla’yfroaooesurfre’etvtatheehsbiezite). Why do you think we didn’t add a Swap() method to the Elephant class? 146   Chapter 4 More free ebooks : http://fast-file.blogspot.com Two references means TWO ways to change an object’s data 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: 1 Add another button to your form. types and references Do this 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. 3 OK, go private void button4_Click(object sender, EventArgs e) { lloyd = lucinda; lloyd.EarSize = 4321; lloyd.WhoAmI(); } YWtohuhe’orAellmocyIa(dl)linomgbejttechhtoe.d from SvAbaAofrtMitahebErtlehEtsehlreilesplofhcyeaordndetenacnoredbujntelsuhc,ceti.nda tBhuitnglltoyhdatplouicnitnsdaatdtoehse. same ahead and click the new button. Wait a second, that’s the Lucinda messagebox. ELlueLpclhoianynddt aO Didn’t we call the WhoAmI() method from Lloyd? bject bject Imt’essslaucgienbdoax’s… glEBliovauyertdsS?wirzeeefseuersteinntgcheti!shWe hat ELlueLpclhoianynddt aO lotlluonhcyeeidrnaedfa’asfn,edncsoitlnuslcocetinnghtdeehareoyaabrjpereoecinatnoltwtdhtiifaonfttteeBrhreeOcnhTcSaeAHnMgbaeeEratebwloeepbe.ojniCenctlhltoain.yngdgeasatn…tdo NdooavaonrettleyraewttithrshihetiNnatrtgOeesTnftc—ehhrbeteaehnnicegneignsg. you are here 4   147 More free ebooks : http://fast-file.blogspot.com 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: bvioYanofoiortuila[itab]chllioeezmu.almydtTAyiohArcneorr—namryabjityui=ns’dtevantllroeikhiwoaeekbbladeloinekoywcell[iaott1rth5hah]iteis;ti:rosn Ysbpoyeucsdiqfeuycailrnaegrebitrasanctkayerptresa,.yfoblylowed bool[] myArray; Telheims eanrtrsaywihtahsin15it. raitYetrofo’rseuacrayreunensvaecaoterbteijavheaabecnrlteina.aebirSwslroeaa.kyaeknyibnwedocraodufse Use each element in an it is a normal variable myArray = new bool[15]; myArray[4] = true; array like TeftlhihefiemsteshleninctoeonnoesdfebtiemsscytamAuhyrseAeravrtayrhlauteyeo[fo1ti]frr,sutteeth.iecsI.tmf’isyfAttrhhreay[0], 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 Iinostvfhamstermerioamerebemoladreorysrea,ywsmt,itoheunehvlteeinainpcrlihtrteuah.inyonkutgh 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. int[] heights; name heights = new int[7]; heights[0] = 68; 7 int variables You reference tienhadeceshex,obnbyeut weliisnokstreeknvsatairnaiolalrybmlea.l heights[1] = 70; heights[2] = 63; heights[3] = 60; heights[4] = 58; heights[5] = 72; heights[6] = 74; heights Array int int int int int int int 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. 148   Chapter 4 More free ebooks : http://fast-file.blogspot.com types and references Arrays can contain a bunch of reference variables, too You can create an array of object references just like you create an array of numbers or strings. Arrays don’t care what the type of variable is that 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. Dog[] dogs = new Dog[7]; dogs[5] = new Dog(); dogs[0] = new Dog(); TdaDrhoorgigsasylovinbaoerjfeiadcrbteelcsef,laeatrrnoeedsnhcaotelshdetnaon creates a 7-element array. tTinhhsetemasenacttewsionodflienxDeesosgc0(r)eaaatnnedd new put 5. 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. bject bject Tcilvnirhasseettraiatafonbeficrdleesstsset..vhlTeiennheaeDrorafoargyrcra,oeydnfeoietsroeantnlhycee Dog O Dog O An array’s length YeLoalcueone7maguncenaetigealvrnetlneuerthmhsmaoseyfeywpeoniahnnrutrcdetolseoai7psgnloea—lihgeinurrntdtwteisatyth.nhnh.hiLuecoiesSamihw.egroabnhIrmmrfgetiafrertasyaeat,hnydnyhyutos,teshu0iortnte’evhgnhfetaeaioiytntrgoa’deosl6urlt.ray Array 7 Dog variables Dog Dog Dog Dog Dog Dog Dog All of the elements in the array are references. The array itself is an object. More free ebooks : http://fast-file.blogspot.com you are here 4   149 sloppy joe sez: “it’s not old, it’s vintage” Welcome to Sloppy Joe’s Budget House o’ Discount Sandwiches! 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? Do this MenuMaker Randomizer Meats 1 Start a new project and add a MenuMaker class Condiments If you need to build a menu, you need ingredients. And arrays would be perfect Breads 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 GetMenuItem() 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 class has three fields to public class MenuMaker { The field called public Random Randomizer; Randomizer holds store three different arrays of strings. It’ll use them to build the random menu items. a reference to a string[] Meats = { “Roast beef”, “Salami”, “Turkey”, “Ham”, “Pastrami” }; Random object. Calling its Next() method will generate random numbers. } 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”. 2 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. public string GetMenuItem() { The GetMenuItem() method returns string randomMeat = Meats[Randomizer.Next(Meats.Length)]; string randomCondiment = Condiments[Randomizer.Next(Condiments.Length)]; a string that contains a sandwich string randomBread = Breads[Randomizer.Next(Breads.Length)]; return randomMeat + “ with ” + randomCondiment + “ on ” + randomBread; built from random } elements in the three arrays. The method puts a random item from passing Meats.Length to the Random the Meats array into randomMeat by 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. 150   Chapter 4 More free ebooks : http://fast-file.blogspot.com types and references How it works… I eat all my meals at Sloppy Joe’s! ybMTleouhsuetseaatltershsra.saanSnndtodoh7omar.mniazMtennerhuda.meNtobsneme.uxLrimtez(btn7eehg)ratrthmo.’sfeNrtegeehtrloxeeudamrttne(gesnerMttteshtseahianatnnrtusamho.nerbdLeMeoerqmneuoaagfntlutsmethloabe)rmezrreeagnryitvto.hes,astin’s Meats[Randomizer.Next(Meats.Length)] “MnRueomaabtstesriBesdeaefnfr”ao,rmarnazdyeroMofetasottrs4[in3.g]sS.oeIqtMu’saelgsaot“tsH[af0mi]v”e.eeqlueamlsents, 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(); MaUsneenewuaMninaoskbtejarenccotebjioneficttita’shliezReaRrnadtnoodmosimzetecrltafhsesie.ld to 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(); } Now you’re all set to generate six different random sandwiches using the GetMenuItem() method. Wpsrhrahoonewgdnroasymimxou,sdatrnihfudenfwestriicxehhneeltas.bels More free ebooks : http://fast-file.blogspot.com you are here 4   151 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 also call each others’ 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 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: Elephant lloyd = new Elephant() { Name = “Lloyd”, EarSize = 40 }; Elephant lucinda = new Elephant() { Name = “Lucinda”, EarSize = 33 }; 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 talkTo, string message) { talkTo.TellMe(message, this); } Let’s take a closer look at how this works. This method in the elephant’s TalkTo() Elephant class calls method. It lets one another elephant communicate with another one. lucinda.SpeakTo(lloyd, “Hello”); When Lucinda’s SpeakTo() method is called, it uses its talkTo reference parameter to call Lloyd’s TellMe() method. talkTo.TellMe(message, this); Lucinda uses talkTo (which has a reference to Lloyd) to call TellMe() this is replaced with a reference to Lucinda’s object lloyd.TellMe(message, [a reference to Lucinda]); So Lloyd acts as if he was called with (“Hello”, lucinda), and shows this message: 152   Chapter 4 More free ebooks : http://fast-file.blogspot.com 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. Dog fido; roRenifegehortebnjnecocewt,i.stTsheheteretf’soidononullyl. Dog lucky = new Dog(); types and references Lucky Dog object #1 #2 Now that fido’s pointing to an object, it’s no longer equal to null. fido = new Dog(); When we set lucky to null, it’s no longer pointing at its object, so it gets garbage collected. lucky = null; Lucky Dog object #1 fido Dog object poof! fido Dog object #2 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()”. Q: Why would I ever use null? A: There are a few ways you see null used in typical programs. The most common way is testing for it: if (lloyd == null) { That test will return true if the lloyd reference is set to 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.) Q: You keep talking about garbage collecting, but what’s actually doing the collecting? A: Remember how we talked about the Common Language Runtime (or CLR) back in 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. More free ebooks : http://fast-file.blogspot.com you are here 4   153 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: Go back to that stuff about value types. Now, why can’t I change a small number from a bigger type if it’s small enough? A: Okay. 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) C# 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. C# 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 and C# 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.  There are a few types (like short to int) that C# knows Sometimes you combine it with setting the value. how to convert automatically. Other than those, the  There are value types for numbers that hold different sizes of numbers. The biggest numbers should be of the compiler won’t let you set a variable equal to a value of a different type unless you cast it.” type, long and the smallest ones (up to 255) can be  There are some words that are reserved by the declared as bytes. language and you can’t name your variables with them.  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 They’re words like, for, while, using, new, and others that do specific things in the language. actual size of the data is.  References are like labels: you can have as many  When you’re using literal values, use the F suffix to indicate a float (15.6F) and M for a decimal (36.12M). references to an object as you want, and they all refer to the same thing.  If an object doesn’t have a reference, it gets garbage collected. 154   Chapter 4 More free ebooks : http://fast-file.blogspot.com 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 }; Elephant biggestEars = elephants[0]; Iteration #1 biggestEars.Earssize = _________ for (int i = 1; i < elephants.Length; i++) { Iteration #2 biggestEars.EarSize = _________ if (elephants[i].EarSize > biggestEars.EarSize) { biggestEars = elephants[i]; } This line makes reference point the at biggestEars whatever } elephant elephants[i] points to. Iteration #3 biggestEars.EarSize = _________ MessageBox.Show(biggestEars.EarSize.ToString());Iteration #4 biggestEars.EarSize = _________ } wBasiriextrhactyaitmrh(eeaefstusulei—nnctdtoienhlxdiis 1el)oilseoampenqedsnuttaiatlroettfrosatttehhsee length of the array. Iteration #5 biggestEars.EarSize = _________ Iteration #6 biggestEars.EarSize = _________ More free ebooks : http://fast-file.blogspot.com you are here 4   155 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 40 }; = 33 }; Dtsaehirdceroalynoyodo?upeWrlseethmmayeernmdttosbewoyrfoituthththathethinek that is? 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.Earssize = _________ for (int i = 1; i < elephants.Length; i++) { 42 Iteration #2 biggestEars.EarSize = _________ if (elephants[i].EarSize > biggestEars.EarSize) 42 } { } biggestEars = elephants[i];ttwtTrhhreeherfa’veoeceburkbigegsihonegefcegtensgthwiweeshehisafucilrsthoeesEdregsalooetlirmonofosgeapknret.heIaptseration #3 biggestEars.EarSize = _________ 44 MessageBox.Show(biggestEars.EarSize.ToString()); Iteration #4 biggestEars.EarSize = _________ } Tabbeobnlihniegideepggg,hecfgtgraoo,henemetrissptnatitlnprtoEEsoeohtaisapenertiartsndstsse.atxbrpotTpitoohwisgoinnenhtgwtneasesi…ttittsethovbotme.ytErtoIhfthvaeeeherliseseteospstcenhooneeaandatntwdrthostiteefhahlaenrttpeethxhheatenltoop biggest ears. 44 Iteration #5 biggestEars.EarSize = _________ 45 Iteration #6 biggestEars.EarSize = _________ 156   Chapter 4 More free ebooks : http://fast-file.blogspot.com types and references Code Magnets 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? int y = 0; refNum = index[y]; islands[0] islands[1] = = “Bermuda”; “Fiji”; islands[2] islands[3] = = “Azores”; “Cozumel”; int refNum; while (y < 4) { result += islands[refNum]; MessageBox.Show(result); index[0] = 1; index[1] = 3; index[2] = 0; index[3] = 2; } } String[] islands = new String[4]; result += “\nisland = ”; int[] index = new int[4]; y = y + 1; private { void button1_Click (object sender, EventArgs e) String result = “”; More free ebooks : http://fast-file.blogspot.com you are here 4   157 exercise solutions 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 button1_Click (object sender, EventArgs e) String result = “”; Higeenrtdes’esinxwi[thi]earlieazretrdha.ey int[] index = new int[4]; index[0] = 1; index[1] = 3; index[2] = 0; index[3] = 2; String[] islands = new String[4]; islands[0] islands[1] = = “Bermuda”; “Fiji”; islands[2] islands[3] = = “Azores”; “Cozumel”; int y = 0; int refNum; The islands[] array is initialized here. Tucphoenucsraintegesntuahtleet+lins=tersoinpoegnrtiaostobitru.iltto Ta hviasluwehfilreolmootphpeulls taihnneddiunesdxees[xi]tinaftrorrhaey islands[] array. while (y < 4) { refNum = index[y]; result += “\nisland = ”; result += islands[refNum]; y = y + 1; } MessageBox.Show(result); } 158   Chapter 4 More free ebooks : http://fast-file.blogspot.com Output 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 a class that will compile and run and produce the output listed. 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 types and references class Triangle { double area; int height; Hatephrpeeli’csraitgthhioten.e“nuAstsirnsyugm”peoliinintets’sfaiotnratthfheielteowp.ith 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 area 4, t5 area = 343 ta.area 27, t5 area = 18 x ta.x.area 27, t5 area = 343 y ta[x].area Triangle [ ] ta = new Triangle(4); Triangle ta = new [ ] Triangle[4]; Triangle [ ] ta = new Triangle[4]; ta[x] = setArea(); ta.x = setArea(); ta[x].setArea(); int x; int y; int x = 0; int x = 1; int y = x; 28 30.0 x = x + 1; ta.x x = x + 2; ta(x) x = x - 1; ta[x] ta = new Triangle(); x<4 x<5 ta[x] = new Triangle(); ta.x = new Triangle(); More free ebooks : http://fast-file.blogspot.com you are here 4   159 exercise solutions Pool Puzzle Solution AworTtffeehr’tfveifaeeeronrreeuggtrnloaecthrTeeiossanrb—i’nljtaienbnaceuagrt,tnlresyayyet! 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. class Triangle { Notice how this class contains the entry point, but it also creates an instance of itself? That’s completely legal in C#. double area; int height; int length; public static void Main(String[] args) { string results = “”; _in_t__x_=__0_;__ _T_ri_a_ng_l_e[_]__t_a _=__n_ew__T_r_ia_n_g_le_[_4_]_; __ while ( _x__<_4____ ) { _t_a[_x_]_=__n_e_w__T_r_ia_n_gl_e(_)_; _______ _t_a[_x_]_.height = (x + 1) * 2; _t_a[_x_]_.length = x + 4; _t_a[_x_]_.s_e_t_A_re_a_(_);______ The while loop creates the four instances of Triangle by calling the new statement four times. results += “triangle ” + x + “, area”; results += “ = ” + _t_a[_x_]_.area + “\n”; _x_=__x__+__1;___ } _in_t__y_=__x_; ___ x = 27; Triangle t5 = ta[2]; ta[2].area = 343; results += “y = ” + y; MessageBox.Show(results + “, t5 area = ” + t5.area); } void setArea() { _ar_e_a_________ = (height * length) / 2; } } 160   Chapter 4 More free ebooks : http://fast-file.blogspot.com types and references 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 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. 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. 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 else 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. 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 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 pre-defined 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. More free ebooks : http://fast-file.blogspot.com you are here 4   161 exercise solutions Typecross Solution 1N 2A M E 3R S 4R E S E R 5V E D E S A F I R E G 6C A S T I N G R N A 7D E M 8G A R B A G E N E L C 9C 10C O N C A 11T E N A 12T E I O E T Y O 13O P S 14D O U B L E T J 15C H A R M M A P L O U E 16E S C A P E I N 17U N S I G N E D T G Across Down 1. The second part of a variable declaration [name] 2. You can combine the variable declaration and the 4. "namespace", "for", "while", "using" and "new" are ____________ into one statement. [assignment] examples of _____________ words. [reser ved] 3. A variable that points to an object [reference] 6. What (int) does in this line of code: x = (int) y; 5. What your program uses to work with data that's in [casting] memory [variable] 8. When an object no longer has any references 7. If you want to store a currency value, use this type 16p2oi n tinCghtaopit,eirt'4s removed from the heap using [decimal] ____________ collect 10. What you're doing iwonh.e[ngayMorbuoaurgseee]ftrheee+eobpoeroaktosr t: o http:91//.1f+.a=Asatv-nfadirle-i a=.bballeroedgteshc lpiasorkati.tncidoonomfaol wp earyastsotra[rctosmwpiotuhntdh]is . 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. More free ebooks : http://fast-file.blogspot.com C# Lab   163 The Spec: Build a Racetrack 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... A Day at the Races 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 Betting 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. Welcome to Curly’s Betting Parlor Minimum Bet: $5 One bet per person per race Got enough cash? 164   More free ebooks : http://fast-file.blogspot.com A Day at the Races Betting 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 bets (after the race is complete). If he loses, that amount disappears from his pile. tSghhhoaeeeeybsloeaesuntepgd,su,bpyohylfuipss$lta1hc0hcaeeessh(grbeaagetcco$seae1,$0su1isf0deboehhwmtiesnoakrdbteeoyegftp$rshw1oe0timnh.wse,winhiodnirsoniwigcni.agns)aAh.ltI$f10 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. All bets: double-or-nothing Minimum Bet: $5 Up to $15 per dog Win: $$ added Lose: $$ removed sbsIoyfemstreyeeoafmulu,lywnbagycnootaodldelt.omprebaaucniltsdicdaeo handicap it! It’ll writing Sound fun? We’ve got more details coming up... More free ebooks : http://fast-file.blogspot.com    165 A Day at the Races You’ll need three classes 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. 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. jtWohbee’viscelatgsoisvefyniolluyoinnuetethdheetmoskebetluheioltddo.ns.Yoofur public class Greyhound { public int StartingPosition; // Where my PictureBox starts Greyhound public int RacetrackLength; // How long the racetrack is StartingPosition RacetrackLength MyPictureBox Location Randomizer 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 public bool Run() { Randomizer reference should point to the same Random object. // Move forward either 1, 2, 3 or 4 spaces at random Run() TakeStartingPosition() // Update the position of my PictureBox on the form // Return } public void true if I won the race We’ve you an TakeStartingPosition() { aidddeaedofcowmhmaetnttso to give do. // Reset my location to the start line } See how matches tuhpewcitlahsstdheiagcroadme? } TsfrteohrfreaemirGgethrnotecyfeehoaotrcuwohnatdrGhdore.ebyrJjeihugcoshttutnimdnPiatiokcibteajluiesrzcueetrBre. oiyxsopuornpeattsthseya Dsaoomvnae’trtiiaombveleesr,tyahoniundkjuytsothu’irns.ee..eddonteo. set 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 to move down the race track. Each instance of Greyhound uses a field called MyPictureBox to reference iertYnaihiogtceuhhi’atlfllGiozphrrieacmervtye.uhprotaeuosbnsoedmsx’astkionhebtesojeurcte 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 locatiPpMoo.yniXPonift+cM=typuPdri=iecsBtMtouyaxrPn.eicLBceoot;cxuabrtyeiBoadondxin.=gLopdc;iastt.i.a.aonnncd;ethtoenituspXdavtYlaeoolcuutaehtg:eeiot.tnp..oiatcodhtiftdeusrtcteXhuherercpeovinacottlruuderineta.o.t. em..o.ve forward box location on the form. 166   More free ebooks : http://fast-file.blogspot.com A Day at the Races Guy Name MyBet Cash MyRadioButton MyLabel UpdateLabels() PlaceBet() ClearBet() Collect() WGyfcmouiaheueylelltdnsohietboyttsjdooeuiUctnatspisnu,dMtslmaoitalyaoleBkni,zLeeaeaatnssbudterihtlees’s() initialized. public class Guy { public string Name; // The guy’s name public Bet MyBet; // An instance of Bet() that has his bet public int Cash; // How much cash he has // The last two fields are the guy’s GUI controls on the form public RadioButton MyRadioButton; // My RadioButton public public Label MyLabel; // My Label void UpdateLabels() { Olttahnhbceeeellssaayboomenuel’tssgehotteeesxMftofyrouLmrsa,iMnbygeoyluMR’tlalyodLbiooeanBbeaeubtol.lfTetoettxno!hte.cAhanndge // Set my label to my bet’s description, and the label on my // radio button to show my cash (“Joe has 43 bucks”) } Add your 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 iaRnrseetmarenemcpebrseersoeftnthBaeetdtb.beyts } This Guy bets is the uses to in the object } that represent application. public void Collect(int Winner) { } // Ask my bet to pay out The key object... here is to use let it do the the Bet work. The sets object initializer the amount, dog for and Bet just bettor. Bet Amount Dog Bettor public class Bet { public int Amount; // The amount of cash that was bet public int Dog; // The number of the dog the bet is on public Guy Bettor; // The guy who placed the bet public string GetDescription() { GetDescription PayOut // 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, // (“Joe hasn’t placed a bet”). } public int PayOut(int Winner) { nTasosehsviesebmreisabtllaininwgcdoaaimvsimsdtpouranlilnapgbcriotoergsdromafmesmdsaiangtgea.tfarsokm: tpuiHnoasiensttstthh:aeheYerGBoetuuef’yhtlelr’iscienosnisdnctieekta.enitayGtolwiiuzaohyteriermdw.siBletlelloft } // The parameter is the winner of the race. If the dog won, // return the amount bet. Otherwise, return the negative of // the amount bet. } More free ebooks : http://fast-file.blogspot.com    167 Here’s your application architecture 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. A Day at the Races TrtGehorfeeeaydrhesoenopgcuaensrsd,aatecrealarcasihnsy.sotcfaonnwctehaiiocnfhs four points the object Greyhound Greyhound Greyhound Greyhound object object object ws.Form object [] array System.Windo Visual ob ttttGoptfAhhhhbarhoremrrjesueeeeesyoreoecepnhbrtPigoGlejRcaueiftiuactbnnceyutdehtidrrtulieeoesoirioa,nsbnBevblcjiwBiiotuejezshetfuiosceaciattxrclttltoisshzos.cnho.eooeybtrfcInojthsodteu’entco’lromlltthgolfrsaeslps.toltaswfolYfohssoiosoletulahrurhtna’bleodvlee jects rray Greyhound Tibtohtsethaforoftrmstuhnpee.seedsartroayinsitwiahleizne Array of Greyhound references Guy[] a tbooTorbebehjajfteeeec,cBrtgtweessunth.chyiEecaosshsbajctaieahsocrftaroti.afehrylredtefcheecooranGseltelnueacydiens Array of Guy references ject Guy ob Guy ob ject Guy ob ect ject ect 168   ect Bet obj Bet obj More free ebooks : http://fast-file.blogspot.com Bet obj A Day at the Races When a Guy places a bet, he creates a new Bet object First the to place a form tells bet for 7 Guy #2 bucks on dog #3... Guy[1].PlaceBet(7, 3) ...so Guy instance keyword that he’s o#ttfoh2etBeceblrtelet,tatuthoseeirns.Bg..aettnheeowbtjehcits MyBet = new Bet() { Amount = 7, dog = 3, Bettor = this }; ect ject ject Form ob true The form tells the dogs to keep running until there’s a winner Wtstaeatehahlalolelceorsnhnotfgtpotdhttrhtoehmhegoeefusraorttsunraeranimcmrarnectia,tnktsog.e Guy ob Bet obj ...and place tsihnecebetth,ePGlaucyeBhaedt(e)nroeutguhrnmsonteryuet.o stsEoehoaeencihlfoaosdtpoohsgna’setshooRdufuolndgt(h)ewenomdndeotitmghhmoewdeirdncasihac. teec,eklsyso to as while ( there’s no winner ) { for ( loop through each dog, making sure there’s still no winner ) { have the dog run one pace } } ws.Form object [] array System.Windo The Bet object figures 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. Greyhound Guy[1].Collect(winningDog) MyBet.PayOut(winningDog) ect ject ject TFhoermGuoyb Payout() it should will add the result of Bet. to his cash. So if the dog return Amount; otherwise, won, it’ll return -Amount. Guy ob if ( my dog won ) { return Amount; } else { return -Amount; } Bet obj More free ebooks : http://fast-file.blogspot.com    169 A Day at the Races Here’s what your GUI should look like The graphical user interface for the “Day at the Races” application cttrhhaoEyMerYcnsoeeatosduyectuairPsoh’riglatngiltsucciostiptokyn.fiau:gfsaTsrtlas(aiephJzhbooPteefeoseohiixb,tfreecoomaBiofrutctonietrheuto)bfhldmdre,otarfoaeotewgnh’BnssttidaclohdlhhelefAeixhav(saolfGia)cvdoflioerctoeuetannsrdhaygntoherGirwnowoberfultnoiefetonftryeodhPmrhtor’wieostncntutsohohcnthuebehedsrojeeeretwtcoBarcootbasctoiujecootxettihknnnccre,ectsioat.aosmobci,nTnafketledehitrazltteoeoficehonnlfhr.tegugo.sttWorehpphnhmeaeoieas’rbrsonlnajtordehcerce,etf.wos.rherpeMPricoatpkeuerrestuByroetxoy’iwlstcYooeZhofonuSwinugcoitst’oztholerlnhhemtoeiMutt.lisen’rheoltalaedotctcuehhrehssetaeeectrGteLao.trceekhnfyegihPgtroiuhcaurtncepuedrrtooeourpBtbaecjoreikxftcyt, ToulafshbineetglhfwteohritNemhuMmsthehionreuiimclmdUuimpnuDipmpdoruawmotpneebrtetthyis control for the bet amount. wbbootAuhennhlttilelecythtaborohtneagnrtscueeateyae,girtnpubgegiylmuuauytwcecsse.aieTtnsncddhhateopenthrwlsoaeeebc’ssesberoeteaolatednoc.lintyo aWbEanenahytdceshnpBrslahoeaovrbGiwdeoueluyurshpSapbtsileanytAcleteuhshtseeeoastSpebliaztelcaoeteb,dsFeei.ltitxTceoothdvnoeeStriFrcnwouagrlrllssiert.e.eenst Opblnuactceteodan,llctbloiectkststaarhrties the race. You can download the graphics files from www.headfirstlabs.com/books/hfcsharp/ 170   More free ebooks : http://fast-file.blogspot.com A Day at the Races Placing bets Use the controls in the Betting Parlor groupbox 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. MtrlhhaWeyiebfsRheeaceGlradneuusinysohaciBneohgg.ubeutHjytethehcopaetnalsalMsucruopeesyisdfnuLeagpartadehbebansieetsclttee,s.his Eshaocwhs guupy’hs ecraes.h The minimum bet should be the same as the minimum value in the bet control. 2 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. blohOaubibnstjecetblecoetanBtn,utodpbhedtxispathltGe.aecurseyastdhiois 3 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. SocominantoschthneehergeyAotlwetwsbihnoeeuntypginu1bgby2eysdtb1o.lo2ugsc,.ekhTstishhee MgitesankeoerwanstuerneetwhaelilnstsathmaenecGsereeqoyufheonRucanenddofoombrj,eaycnotdusommshiagnrhuemt bosenerees.Ra abnudgomwhoebrjeecatll! If of each dog the dogs creates More free ebooks : http://fast-file.blogspot.com    171 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. A Day at the Races Diumnuatrgiilnegsonrteuhneofarcatrchoees,smtthwheienfsroautcrheetdroragaccke. You can download a finished executable, as well as the graphics files for the four dogs and the racetrack, from the aspDtrlaeaucrrreitndugn.a.n.tinnahegnew!drramacaceke,enwoshuibrleeettysohuceacdnaonbg’est Head First labs website: www.headfirstlabs.com/books/hfcsharp BdHanoeudnrte’ts’yseogeyueotjwuursoatnc’sthhooalufwnticniemodnutctothhoreyeyoasooulluu’yvrrectpeleresoactgorrdnyaeoemdu! r!mIniCnrg#eaplkrnoliobfwlee,lmeydso.gue 172   More free ebooks : http://fast-file.blogspot.com 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   173 More free ebooks : http://fast-file.blogspot.com 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. Khpealartnhntlieinmegneewpstloaiunmlndaitnrgeaste. hveenrtssp,ennodt 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! 174   Chapter 5 More free ebooks : http://fast-file.blogspot.com What does the estimator 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 • For each person on the guest list there’s a $25 food charge. • CcKshoaoleietsrdnh,tatslsesoae$hnns2adh0cvejaepuglilescairvetcephihnseaosrtttishcetoeeahncewd. lBi“eohuHneftetnaatailhltcte5ohcy%yhoocOmdal.iepsnCscthaiotoolosunoon,d”stcarinoihnngondktsotih.thsMeeeooHnetsloenyttachilprtoaeahvsyrpettasOiaer$pstp5tyasio,pertenrtovryiosepw.aaeirltlcoshootohnueotatl,soawielchhraoicfvhoheorl. • Tanholserormeuapal dgreeractodweroatthoioepntpsiao, rintts’ysfd$o7erc.5to0hrepacetoriospntesrotsfoodntehwceoit“rFhaaatnioc$yn3s0O. Idpfetaicoocnrl”iea—ntttihngagtofeecseo.wsAtiscthl$ie1tnh5tepcearn person with a $50 one-time decorating fee. encapsulation Here’s another look at this same set of costs, broken down into a little flow chart to help you see how it works: tpaSehorcem-heeapvneoegrfnestottn, hoacesotseswhteecsl.hlfoianicsaelisnpdirniivvcioedlvuoeafl Number of people. Food ($25 per person) Healthy Option? Juice and soda ($5 per person + Yes 5% discount on total cost) No Alcohol ($20 per person) Yes Fancy decorations? No Fancy Decorations ($15 per person +$50 decorating fee) Normal Decorations ($7.50 per person +$30 decorating fee) acWloshsotileofnomer-ostetaimccehhofgieuceeessstta, oftfhfeeicgrtuerteahreien. More free ebooks : http://fast-file.blogspot.com you are here 4   175 okay, 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 DinnerParty 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 NumberOfPeople you add an M after every literal you assign to a decimal value (10.0M). CostOfBeveragesPerPerson CostOfDecorations 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: SetHealthyOption() CalculateCostOfDecorations() 3 CalculateCost() public const int CostOfFoodPerPerson = 25; 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 Htnehereeed’Ds titnohneecrrcPelaaatrsste.ydicalgarsasmyofuo’lrl 4 cfuaTliipeehdblndeoattoSbleweapatstaneHhrdteeasamoCltnteohhtsweyteOhrOhepeft(tahBhlietoeeanrhvl(yet)orhoraympgOneteoptisottPhnieoo.trdnhP)eeurstesoosn up 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. Add this code to your form: DinnerParty dinnerParty; public Form1() { Ytboheuelo’lwlfodIrenmcit,laiaarlneizdtethCehoemdnpinoanndeedrnPtta(hr)e.tsye field four in lines InitializeComponent(); dinnerParty = new DinnerParty() { NumberOfPeople = 5 }; dinnerParty.SetHealthyOption(false); dinnerParty.CalculateCostOfDecorations(true); DisplayDinnerPartyCost(); } Set the default 5 Here’s what the form value to 5. The should look like. Use minimum should be the NumericUpDown 1 and the maximum .NPdDYSooEoyiiennusTstntndee,’FrmotoPnr.rWau’atsrmaientnnedyyeMwoteocwdehrlsaiskns.tsFagsongo,aeerabmlBmdseeecosds;ax”fpu.“arSstucoehsoemion.iywtgto(uh)r,at control’s properties to set should be 20. the maximum number of people to 20, the The Fancy minimum to 1, and the decorations box default to 5. Get rid of the should have Checked maximize and minimize set to true. buttons, too. This is just a property set tlaobeFlixweitdh3Dth, eanTdextthePrAoupteorStiyzeseptrotpoer“t”,ytsheet BorderStyle to false. 176   Chapter 5 More free ebooks : http://fast-file.blogspot.com 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 rctodWuohnTondgteyhfuuealhevoheabwaopItaiunenDbrlsdbhtleyumecuecah‑oyEmteltnatr.otachelewttuewhIlltittateioneiochththtdgn’grkseoheeehandicbtmehdneothysoevdnwchawetoaenirthllsglly7tohreodioesgu.fshCtltaohbalce{}nANNacpptolghresrdoumeettiodcdniwamhLpteatgoevathtelethhehscabeydroieoiodtitisnclonidiu.LmenaUsmkpmtaatntlphhueaehblveDetyapeeehoostpdofotlCiDgthawd.odtehtreionntTsethtsyNoendetDc.creoouoxiFFursnmt=sointiPlstlpraerecio=drlrmvtrtiliae1ecy—inraUnCy(cyttnoD)llepahcicaiPtestik.dDoiuesaameIurtrdnssttonIrms’P.ntaoeDtewliahnlnaTenertfgngiEcdydhtrorsoehy:o“erftSPtwtdlcoimlvecythaac”idiaasalalro.rrldpltttluinlCitosnealetatit.uddanogyrTyhstnIodlghCeofwet.tlsShec(ohahciytedu“ssnefoeoroosnlctNucictlenr’lha”(roatgmvuheaar(t)s)ems)sente;int,ngihabNtCniteteaeauodaA’lrhrttllmnelhssO.daddceItdenaiftsrP(lp’fdpctilouecTcOluclhltrUoalhrehpihamspyeettiirpetscsslmei.DeoecktitDieonsbtthnkovtohttoewaiyBhxthserruooonhceuicdufbceaoxehcoonrlbseteo2Crsitutlccfo-n..eomkctotsoCtelthrytdibfdohehchoeee.lleku.aetHribsfThcoeoeoecankhlrfll.itpemacthahtkd—y’rees)tidty;:’ll htbahunatdttl’osenraintsoecovl.iecnkted, private void numericUpDown1_ValueChanged( object sender, EventArgs e) { dinnerParty.NumberOfPeople = (int) numericUpDown1.Value; 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! TmbeheetphavoasdslueedwiylalosubaesebfnoadonlcefyarBnomopxa.trChahemecefktoeredrm. to the That will to the method in the class. wcTlilinalhlesesdsweitsilopallrafceyaigljltuurhtsteeheottuwomttoea-ttllhhicnoeoedsctmoysoeotutnshctaornhdedesa.tftTeohdrhemeisn.efctirohsnetd 8 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. More free ebooks : http://fast-file.blogspot.com you are here 4   177 exercise solution wv Here’s the code that goes into DinnerParty.cs. publcpppiouuucnbbbslllctiiilcccaisniddstneetccDCiiioNmmnsuaantmlleObrfeCCPFrooaoOssroftttdPOOyPeffeoBD{rpeePlvceeeor;rrsaaogtneiso=Pnes2r5P=Uetmn;ehsasiir0knusergs;vseaoastlnuthce;hoeenncsetovvadaelnreutecehafcasoainrnesCtitWtge’rothaCethlecstcsoeb.ateousnoelttlhlbarsOetctjeNehhSfeaocaueCeFdttmnto—ohf,gHboseoeitiedtertrdOraPm’.OsflueftIsirfDcftehePlPlysiedereaeOacsrtslotrspo.shpoorteltcneaiorht.iennaiToa(itt)tnhiseaea(slnn)izdteor public void SetHealthyOption(bool healthyOption) { if (healthyOption) { CostOfBeveragesPerPerson = 5.00M; } else { CostOfBeveragesPerPerson = 20.00M; } } tWtyhepeiunisfged“stif“aitf(eFm(aFenancntycya=)lw”=aiyntssrtuceeha)ed”ckobsfecifautsehe condition is true. 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); 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. 178   Chapter 5 More free ebooks : http://fast-file.blogspot.com 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. public partial class Form1 : Form { DinnerParty dinnerParty; public Form1() { ciWnoiestticaaalilszl eDsotioshnpelaalysaDbteihnlentefhroaPrtamrs’tshyolCwoaosdsttehdte.o InitializeComponent(); dinnerParty = new DinnerParty() { NumberOfPeople = 5 }; dinnerParty.CalculateCostOfDecorations(fancyBox.Checked); } dDiinsnpelraPyaDritnyn.eSrePtaHretaylCtohsytO(p)t;ion(healthyBox.ChtCehhceaknhegeedasl)tt;hoyOthpetiocnheacnkdboFxaenscoynbtohoeleafnosrmtoset true or false in the SetHealthyOption() and CalculateCostOfDecorations() methods. private void fancyBox_CheckedChanged(object sender, EventArgs e) { dinnerParty.CalculateCostOfDecorations(fancyBox.Checked); DisplayDinnerPartyCost(); } gaWoneidnng“afomanendcinyoBtuohrxeci”rhseeocvkeybnootuxhceoasun“lddhleesareltemhewytBhhaootxd’”ss. 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 recalculated and displayed needs to any time be the number changes or the checkboxes are checked. private void DisplayDinnerPartyCost() { decimal Cost = dinnerParty.CalculateCost(healthyBox.Checked); costLabel.Text = Cost.ToString(“c”); } } String formatting YacfIfooowmruym’hmvooaeualteapslieanrtpsuesamawrd“biatcyeth”ros,rteaeos“fn0aoThro%doSt”ewthcrfioyimonuorasgual(an)cn,dauwinsmth. bocTcleoaeornknvnevweuerimartttbhmseaitrnnithyuprtetveeraeocraeditnanhedbtcelaiesmgleoetaec,olahaplaonlcawdsuctre“errsnai,en”cn“ghc0tyuoo”s.fidnY(tigtoshpuhiatleatcssyae’sTnilotaoaSolaztsksoesrrianpionga)n(syu)stomoumitbrceeto“rpfnhrwv3ooed”igtrr.thtaomta!o More free ebooks : http://fast-file.blogspot.com you are here 4   179 something’s gone terribly wrong Kathleen’s Test Drive This rocks! Estimating is about to get a whole lot easier. Rfwsdaoheivbedno’’ndssreiitopnrnlgeapenlcaanolrsiifettnngyKtyafesa.naotrrShi,mhlheaepienmonddr.’istdnaonhwtis 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? Kathleen: Sure! I’ll have that for you in just one minute. Changing the Number of People value from 10 to and hitting enter shows as the total cost. Hmm, seems a little low... 12 $665 that 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? 180   Chapter 5 More free ebooks : http://fast-file.blogspot.com TrTDehuedarctunocirnecagsatntoi’otfhnfesbaetcmhhreoeigcuFhnkttab!nobcxyyo$n5ly. encapsulation 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. WDTnuhehmceeonbsereyarnotuusiohmtnobsuoertrbnssacutakphreeotnojF,uas$ttn7hc7ewy0ro. ng. 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? More free ebooks : http://fast-file.blogspot.com you are here 4   181 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 each others’ fields... and just how hard those problems are to spot. 5 people. $20 per person for drinks $25 per person for food $15 per person for decorations plus $50 fee. Total cost of drinks = $100 Total cost of food = $125 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 $25 per person for food $15 per person for decorations plus $50 fee. Total cost of drinks = $200 Total cost of food = $250 Total cost of Decorations = $200 182   Chapter 5 $200 + $250+ 200 = $650 BwTuehtisshwoiseu’lrtdehegneottto..t..al 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 drink cost. Old decorations. More free ebooks : http://fast-file.blogspot.com 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. private void numericUpDown1_ValueChanged( object sender, EventArgs e) { dinnerParty.NumberOfPeople = (int)numericUpDown1.Value; ToiDvnfhaiilntsuNnhelueiisnmrinePibnaetssrerthttoeayfsnfPcttoeeohroeomptfl.vheaelue DisplayDinnerPartyCost(); } This the CmaelctuhloadtecCaollsstotfhDe eCcaolrcautlaiotnesC()osmt(e)thmoedt.hod, but not So, when you make a change to the value in the NumberofPeople field, this method never gets called: public if (vFoaindcyC)al{culateCostOfDecorations(boolTfdoFhoreiasmsnnv’fcatriyrigas)etbtlec{caialsllelsededtitatgaoani$nd1,,2ist5indcfeoreotsmhn’itswhmcehenatnhtgohede. CostOfDecorations = (NumberOfPeople * 15.00M) + 50M; } else { CostOfDecorations = (NumberOfPeople * 7.50M) + 30M; } } Tftahhneactpy’srdowgehrcyaomrtahtreiuonnnusCmbabalcecurklacotoner.CrCoecsltitcOskfiintgsDetelfhceowrchahteeniocnkysbo(ou)xtaumgraanikne. s Hold on! I assumed Kathleen would always set all three options at once! People won’t always use your programs 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. More free ebooks : http://fast-file.blogspot.com you are here 4   183 protect your objects It’s easy 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. 1 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. NumberOfPeople = 10; CalculateCostOfDecorations(true); Form CalculateCost() returns $650 DinnerParty object 2 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. NumberOfPeople = 10; object Form 184   Chapter 5 CalculateCost() returns $575 DinnerParty nnspEtuoavimrlewltbnaryeyetrtphfwruoooraurpngseehKwrdltaryatoh, hneCngleufa.emolnrbcmetruo.dl..kidananotn’wdteCttsehohtaestrutept(wht)aehse More free ebooks : http://fast-file.blogspot.com Encapsulation means keeping some of the data in a class private 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). encapsulation “papooUrsfuwsisbfvunealmittcbyee”hoe.,enuttreh“fhapleitartnzi—vyiaCnoitefu#esrs”yfwotouioierlllldyejoauiuvsstre public class DinnerParty { private int numberOfPeople; ... wbDidIteofoi.nnr’yTnitesoeahuruedaPsvtweaeaanrtntntdekhtylnel,wstoipowrtCirst#mititnae’vukstneahmtbathbatyeeefrtirefikhe.OelaydytfowPupio’nrevrsievtdoaagptwnoelcth,eee.aanlOnflytiyioenholusdeutrdancenoeaccebnledajeorocentftloys public void SetPartyOptions(int people, bool fancy) { numberOfPeople = people; CalculateCostOfDecorations(fancy); } public int GetNumberOfPeople() { return numberOfPeople; } OngapCmuptodemeaoheododtebplprlhemcelwreo.eouadtbToiylshjfgheaotcecadphottttesasesognwtpirCgsvoatlueeoeynidlssltfe.yetohtnTvoreeeOuomherftradcyhtDaageta’ncelelicmtdwcmetiseaoanatsyknkrhtteeeehtarooesctnupiautnsirarmeeuroetimbsttneobythtrsfe.haor(tOeotf)onhtfeahte pesky bug. 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. More free ebooks : http://fast-file.blogspot.com you are here 4   185 spy versus spy Use encapsulation to control access to your class’s methods 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: 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. † ciaAgent RealName: “Herb Jones” Alias: “Dash Martin” Password: “the crow flies at midnight” 2 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. SecretAgent Alias RealName Password AgentGreeting() EnemyAgent Borscht Vodka ContactComarades() OverthrowCapitalists() 3 Seems like a foolproof way to protect the agent’s identity, right? As long as the agent object that calls it doesn’t have a the right password, the agent’s name is safe. Ticinnhlsasettsasac,nnicawceAehgioolefefntktEghobnebAejmSgeeyeccnAtrtgeiestinsAatang.nent AgentGreeting(“the jeep is parked outside”) TpahseswKoGrBd agent in his uses the greeting. wrong † kgbAgent “Dash Martin” ciaAgent The the CKIGABagoennlyt.gPeetrsftechte. alias of Right? 186   Chapter 5 More free ebooks : http://fast-file.blogspot.com But is the realName 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. public string RealName; encapsulation He left the field public... Why go through all of the trouble to guess his password? I can just get his name directly! ftSrheoetmyticonaugntysbiodeueratcvhcaeersiascebladles,ss.aansdpeuvbelniccmhaeanngesd, string name = ciaAgent.RealName; † kgbAgent Tmwheidetreheo’osdp.ennoTfhnoeererdeevateloNryacomanlele any field is to see! ciaAgent Agent Jones can use private fields to keep the 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! ofTafciheclededsiskfsgfbtbeeAhrceeganeuctnsietacAtloaghbseesjneeytsc’r.’tse can’t private instances ffJprirueoislvmtdastrteaeh,preelaanwcndeoorwbpldouhob. imldic,dyewnoiutrh private string realName; Yttohhuae’tdesnatelosmoryewsaatgnehtnettpocaasmsnwakgoeertdsutirsoepitrtih.vaattet, hoethfeierlwdise tdcKphooreedniev’eaptvtianieeslguxegmpysoeaoicynkutogreusitf’trsoi.euerlmduesasinknaoegndocwhuhtmaensenigtdeyhesooudtos More free ebooks : http://fast-file.blogspot.com you are here 4   187 keeping secrets Private fields and methods can only be accessed from 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. † pasBimrocnircsiv5tiieattsagtisesnedhnctoAetfoegisoeicensflni’datatsAtnhhgecaeieltavnshetse,’sr. AgentGreeting(“the crow flies at midnight”) The only ccOainanlAysgeaeennottthohebemjre. ct mi5Agent “Herb Jones” NtwchoiaaiwysAitgtsehhnpeatrtem’stti5trhAeyeaglmfenniueatclmdhcseta.anhreegeoptnrlyitvahtee, ciaAgent Q: Okay, so I need to access private data through public methods. But 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? A: Sometimes a class needs to keep track of information that is necessary for it to operate, but which 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 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. 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. 188   Chapter 5 More free ebooks : http://fast-file.blogspot.com 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. public 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? More free ebooks : http://fast-file.blogspot.com you are here 4   189 good ideas for easy 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. public 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 + “ and the secret ingredient is “ + secretIngredient; } else { } } return cookieRecipe; Tilcnohagtenr’eotodfnialeyccnoctwoeaskissyiettst.ohoiOsogureftdtiseeildrtdehaedciwosredheccoertleelyt. } 1. string ovenTemp = mySuperChef.Temperature; 2. string supplier = mySuperChef.ingredientSupplier; s#ctar1ni’ndtgo.jeussnt’tascsoimgnpialen because you int to a 3. int loyalCustomerOrderAmount = 54; 4. mySuperChef.secretIngredient = “cardamom”; #bsee2ccraeautnseIdngi#nrge4rdeidednioetnn’tatSreucpoppmrlpiievilraetaen.d 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 6. string at 375. recipe = Yum!”; mySuperChef.GetRecipe(56); svdlEeaoiclvydureaneenl’,CtttwuichshnthoigocaurmhngehgediersiyeAstontmuhtioel.lcuron6ebt0ajte—acenstddo’saistleoltoywcaioatlCnl ’tutvsoatpro5iram4inbetl,reAttchmhaaeoltluendt 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!” 190   Chapter 5 More free ebooks : http://fast-file.blogspot.com A few ideas for encapsulating classes encapsulation ± 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. More free ebooks : http://fast-file.blogspot.com you are here 4   191 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 example 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; } Wscoohueta’ndnoogbbfionedgtsyytbneaccrga,snmtOahcfkahFteae’nletlgdhec—irsietiffatiwetelitdhbheupyogrusgitv!eatatleso 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. public const int FeedMultiplier = 30; Tnoehefaeecdfhfseaec3rdom0wfe.brorags public int GetNumberOfCows() { return numberOfCows; } We’ll add a method to give other classes a way to get the number of cows. These accomplish the same thing! public void SetNumberOfCows(int newNumberOfCows) { numberOfCows = newNumberOfCows; BagsOfFeed = numberOfCows * FeedMultiplier; wWpeuxoebcrleudipcset}inodnttechhsaa.emtPevatlaCshrcaeiaaslbefClieafrssonterammlteeheta.etncepsarrmciivaseapltClioteawasfleeirzieciislnadgssseimt.ahinTleadhrfaPttiarossmtcPaaallkeCsetcasatsleetCrhfaeosiner,etvheery Atnttunhowmdoeo.bBhetNeraoorgweogs’OfesttfachFooemeuwreteesd’tsothffnhoioadestlywdtnmaociyas.skefcetohsratsnuthgrheeeed uppercase letters look like “humps” of a camel. 192   Chapter 5 More free ebooks : http://fast-file.blogspot.com encapsulation Properties make encapsulation easier C# has special kinds of methods that make it easy to encapsulate your data. You can use properties, methods that are executed every time a property is used to set or{pprerutuibrnvltaiheg{tcveealtiueinontf trtheeNftnuieluumdTttr,rmbhhehwetaisnbetuhNriisermncushmaanrOtbtigcsueOfhehrectemOfCasvfalabColtceCluchdeowoeeewsarwsosstofbyOrsppa.rtef;coIhtpkoeCe’fsirpnotartgyih(Wvwbmnaefaieoetsisc’tvtelekrlahi;liectrtYnrdnoeaiheuhgoda.dnmeeutb.fam’tblhldemIilheeet—eweraolcdltOfiiholttna’tafwsfhhrseCteoearnrahrtaoucpiwinusontarrssonishecaeverteanpafmpuystr“oNerroaenrtonplu”ipieftm)Nfmver.ibaireueteTleltmuyldrdihe.beOitsesdfrobewCOcyniofllualwcCmrobsoabmetwpecbirrsooi.Oonmnpif.eneCHgrtteohrwyee.s’s } set { numberOfCows cTdNaouhlelmiessdbni’estvraaOlloufsoeeCktotlwhiakascetcpeirctsosoopnhretarsattiahnysnaytisw’sphsaeacrttaa.ellmveEedevrteeenvvraestlru,heyiotuttgahimhcetetfuhtaieelhllydemhewatashsoosdneet = value; to. 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; When this line sets sNeutmabcecreOsfsoCrowseststoth10e , the BapnradigvsatOthefeFnneueumdpbdefartieOelfds C.tohwespfubiellicd int howManyBags = myFarmer.BagsOfFeed; myFarmer.NumberOfCows = 20; howManyBags = myFarmer.BagsOfFeed; naSocinwcceesysooturhecuapNnduagmtebetedritOBsfavgCasolOuwfes.Fseeetd, } EaAthvnfeedinegwltdehth,eointaucgirtchuenstqssuhoeertr,hiceewosdhsteiechthterarBeceacattegusssrsOnNosfru,Fm3pe0baee0dsrs.OifnfgieClidtowi2ts0lri.kuens More free ebooks : http://fast-file.blogspot.com you are here 4   193 private property (no tresspassing) Build an application to test 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. Do this 1 Add the Farmer class to your project: public class Farmer { public int BagsOfFeed; public const int FeedMultiplier = 30; private int numberOfCows; public int NumberOfCows { (add the get and set accessors from the previous page) } } 2 Build this form: Nusaems ethtehips ubbulitctoFnar“mcaelrcudlaattea”—toit write a line to the output. MMcSoeainntxtimirtmuohumlem’sNtVtouoaml5u3e,e0rait0cnoUd. p1i5Dt,soiwtsn 3 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 View 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() method to send a line of text to the IDE’s Output window. WriteLine() replaces the first parameter, “{0}” with value in and “{1}” with the second parameter. 194   Chapter 5 More free ebooks : http://fast-file.blogspot.com 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: 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! Fully encapsulate the Farmer class Automatic properties are a C# 3.0 feature. If you’re still using Visual Studio 2005 and C# 2.0, this code won’t work. We highly recommend that you use Visual Studio 2008 Express. You can download it for free! 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 adds an automatic code snippet 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 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 private. 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   195 More free ebooks : http://fast-file.blogspot.com 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 Do this! 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 So let’s change it to a read-only property that uses a backing field. 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 an automatic property, use a backing field: private int feedMultiplier; class to adding sTeeArrmotxpehoenfrteciniadstiealu.dvyFpnrpas-tesntribnoesoeeacidnp,nnteleMsysythetr.thetuteohIalaytttbetbdhriayapheemccloa’rkiatsaefsinskrncnae.sgloijatsnuBpsofssssiturutteiebtiatcnlllnradigiscckean,ieaencagfdrccoeeaeeev-tfenaasods,ildtuoniFMwnesrltayth,usri—hitelicmfettthi’iejievspturiallssd.iltecu,rae.n public int FeedMultiplier { get { return feedMultiplier; } } Sstinacretswwe itchhaangleodweFreceadseM“uflt”i.plTiehratf’rsoam pareptutbylicstcaonndstartdo naamprinivgatcoenivnetntfioienldy,owu’ell changed its name, so see throughout the it book. 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? 196   Chapter 5 More free ebooks : http://fast-file.blogspot.com 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, All you have to do to then an object initializer just won’t do. Luckily, there’s a special method that you can add to any add a constructor 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 to a class is add a method that has the same name as the parameters to the new statement. And you already know that new returns the object—so class and no return there’s no way for a constructor to return anything. value. 1 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 need a 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. Notice how there’s no “void” or “int” or another type after “public”. That’s because constructors don’t have a return value. The ‘this’ keyword in this.feedMultiplier tells C# that you’re talking about the field, not the parameter with the same name. public Farmer(int numberOfCows, int feedMultiplier) { } If we would this.feedMultiplier = feedMultiplier; NumberOfCows = numberOfCows; just set never be the private numberOfCows field, the called. Setting NumberOfCows makes NumberOfCows sure it’s called. set accessor NbbTiseuehfmcseoaebrtuefesrietrOwhsifteteCctfnoaheewneeinsddcgssamewltltueolt’tlahblicpeedcleioseserst,or. 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! public Form1() { InitializeComponent(); farmer = new Farmer(15, 30); YToidtobho’ujsaeetsacnn’tlasr’t.mewaWehhddeaaylvtlF,ekotintarhom’sirws1egtmt(oulhteirktanetahovtctdahohlueneiesst—c.flroanursocsmtt)iociarsenatdhnoooiwt! } HsWteharteene’smyweonhute,treyepxtecheiepttninet,hwwaatstticathtehfmaosernpttahrceaamlIlnesttteehlrleisStceonhnsaesttpriotupcp-taousrps.—eIstitinllotooookktsshjjeuusscttolnliskikteeruaacnntyyoorottmhheeertrhnomede.wthod. More free ebooks : http://fast-file.blogspot.com you are here 4   197 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. Toarnhddisintcahorenystsperacurocantmdoreotnheearssi.stTwthhoeepffaerireasdmtemotnueelrtsgi,pivlwieehsric.thhewonrukmbjuesrtolfikecows, 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 } We need a way feedMultiplier to differentiate the field called from the parameter with the set BagsOfFeed. Since “this” is always a reference to the current object, this.feedMultiplier same name. That’s where the “this.” keyword refers to the field. If you leave “this” off, then feedMultiplier refers comes in really handy. to the parameter. So the first line in the constructor sets the private 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: 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.) 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 symbol 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. 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 to the backing field in of the constructor, you’d use “this.”: feedMultiplier refers to the parameter, and this.feedMultiplier is how you’d access the private field. 198   Chapter 5 More free ebooks : http://fast-file.blogspot.com 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 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: So you can have ANY kind of statement in a property? A: 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: 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:Wait, a sec—is that why I don’t add a return value to my constructor? A: 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. Q: Can I have a get without a set or a set without a get? 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, but 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. Properties (get and set accessors) are a special kind of method that’s only run when another class reads or writes a property. More free ebooks : http://fast-file.blogspot.com you are here 4   199 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. public 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); What’s the value of amountOwed? MessageBox.Show(january.CalculateAmount(7).ToString()); 2. CableBill february = new CableBill(7); february.payPerViewDiscount = 1; MessageBox.Show(february.CalculateAmount(3).ToString()); What’s the value of amountOwed? 3. CableBill march = new CableBill(9); march.Discount = true; MessageBox.Show(march.CalculateAmount(6).ToString()); What’s the value of amountOwed? 200   Chapter 5 More free ebooks : http://fast-file.blogspot.com 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.) encapsulation 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”; } } } More free ebooks : http://fast-file.blogspot.com you are here 4   201 encapsulation prevents bugs Write down the value of the amountOwed variable after the code below executed. 1. CableBill january = new CableBill(4); What’s the value of amountOwed? MessageBox.Show(january.CalculateAmount(7).ToString()); 28 2. CableBill february = new CableBill(7); february.payPerViewDiscount = 1; MessageBox.Show(february.CalculateAmount(3).ToString()); What’s the value amountOwed? of 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. PcsPttLehrhrhtiaoieeccnweyegPc,eeeoArgttnceRth!satAithSssereMaolucicpcnEictotereTnosdiswrsEto,ocirRlrelneus,ocwntbtt’rootuoerttrtfkdh’ehsPoerperpsrafiavoctniarpeeyolaelutdhmreth.aleyhisrnTt.enege’httpriuuassretrenlvoaifeenmudneulep.btsbpIeeeeyfterrsntcytahooseue “Ttgthuhhmeeeb“ppatralholrsipa”se.m”rtetktheyey,irww.soh.rildgeuigsmuobmnabtlahlelslwsrreofnreegrfsertsoto public GumballMachine(int gumballs, int price) This parameter masks the { private field called Price, and } gumballs = this.gumballs; price = Price; the comment says the method is supposed to be checking the value of the price backing field. public string DispenseOneGumball(int price, int coinsInserted) Tiwbotsbhenhhyoel eaonprtan“ergtapf.ihiatipIie crstala” ddermsoak,hiee{}mesbostyenuemewtl’crtdaeoa .srrukb,dseeedi}}fe(ltsheigrrs{uee.mttcbuuoarrilnnnlss““IHPn-els=reeear1’st;seedyion>us=rerpgtruimmcboear)lel{”c;o/i/nsc”h;eck the field 202   Chapter 5 More free ebooks : http://fast-file.blogspot.com 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 If we want to fix the DinnerParty class, we’ll need a way to make sure that the CalculateCostOfDecorations() method gets called every time that NumberOfPeople changes. NumberOfPeople = 10; object CalculatecostOfDecorations() 2 Form Add properties We need to recalculate the decoration cost every time the number of people changes. CalculateCost() returns $650 and a constructor DinnerParty rCtdIfihaegelchcwotunerluaaammttmebaiooCkeunreonsstosti.usf(r)repewectoiahlpllacleatullwiatstahyeuepds dcreoaevtsteteurdryo,nftttithmheheene 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 always 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 which 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(); } More free ebooks : http://fast-file.blogspot.com you are here 4   203 exercise solution Use what you’ve learned about properties and constructors to fix Kathleen’s Party Planner program. public class DinnerParty { const int CostOfFoodPerPerson = 25; private int numberOfPeople; public int NumberOfPeople { get { return numberOfPeople; } set { numberOfPeople = value; ToaNnnlohsoeoawwtora’ftleylhchfaafetiloxcrrunltbuatehmthseietbnebgfcruolOtgirehfmntePthetscao!ootpsltcaehlmoaisfnogsptterhivcietaotsdwteei,ctKtoharhotaeuthrtelieo’senns. CalculateCostOfDecorations(fancyDecorations); } } private bool fancyDecorations; public decimal CostOfBeveragesPerPerson; public decimal CostOfDecorations = 0; orsBufeyrceapuelsctoiuhnplgaalettaectdhphareenovgpceeeorsrsy.ttyto,ifmyeodutecchoaernnamtumiaobkneesris public DinnerParty(int numberOfPeople, bool healthyOption, bool fancyDecorations) { NumberOfPeople = numberOfPeople; this.fancyDecorations = fancyDecorations; Be careful how you use } SetHealthyOption(healthyOption); CalculateCostOfDecorations(fancyDecorations); “this.”. You’ll need it to tell the difference between the parameter and private field public void SetHealthyOption(bool healthyOption) { if (healthyOption) { named numberOfPeople. } CostOfBeveragesPerPerson = 5.00M; } else { CostOfBeveragesPerPerson = 20.00M; } asfMocacnateckshyeseosdrNuercucemaonrybaoeutursiOeosntfistoPr.eienoptalehfesieetld public void CalculateCostOfDecorations(bool fancy) { So you’ll need to put “this.” in front of “fancyDecorations” because the fancyDecorations = fancy; if (fancy) { CostOfDecorations = (NumberOfPeople * 15.00M) + 50M; } else { fancyDecorations parameter masks the private field CostOfDecorations = (NumberOfPeople * 7.50M) + 30M; } with the same name. } public decimal CalculateCost(bool healthyOption) { decimal totalCost = CostOfDecorations + ((CostOfBeveragesPerPerson + CostOfFoodPerPerson) * NumberOfPeople); if (healthyOption) { return totalCost * .95M; } else { return totalCost; } } } 204   Chapter 5 More free ebooks : http://fast-file.blogspot.com 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 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   205 More free ebooks : http://fast-file.blogspot.com happy birthday baby Kathleen does birthday parties, 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? ahMnadovestwtrooitfdintogh.weitchhacnagkeess These are both the same as the dinner party. Cost Estimate for a Birthday Party • $25 per person. • Tgtdhooeecetrosherewaa“rtiFteianhgtntwchfyeeoeOno.poAptrtcimoiloiaennln”d—stetfccohaoarnrttaahcltseoiooscntoussps, $tgit1ro’sa5fd$pde7ee.5rtch0opeerparpestaroiropntneywsr.dsiIotefhcnaoawcr$aliite5thn0iotaon$sn3e0- time decorating fee. • When the party has four people or less, use an 8-inch cake ($40), Otherwise, she uses a 16-inch cake ($75). • Writing on the have up to 16 cake costs $.25 for each letter. The 8-inch letters of writing, and the 16-inch one can cake have can up to 40 letters of writing. The application should handle both types of parties. Use a tab control, one tab for each kind of party. 206   Chapter 6 More free ebooks : http://fast-file.blogspot.com inheritance We need a BirthdayParty 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. You’ll do all this in a minute—but first you’ll Here’s what we need to do: need to get a sense of what the job involves. 1 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. 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. BirthdayParty NumberOfPeople CostOfDecorations CakeSize CakeWriting CalculateCostOfDecorations() CalculateCost() 3 Label the first tab and move the Dinner Party controls onto 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 onto 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 to so that it uses its methods and properties. Q: 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: 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: How do I know what to put in the new class? A: 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). More free ebooks : http://fast-file.blogspot.com you are here 4   207 another kind of party Add birthday parties to Kathleen’s party planning program. tMprhaoekpteerystpueireesfotyrohuatthuesheoflddieelccdiusmraarlnendacsy. 1 Add the new BirthdayParty class to your program You already know how you’ll handle the NumberOfPeople property and the CostOfDecorations methods—they’re just like their counterparts in DinnerParty. Start by creating your new class and adding those. Then add the rest of the behavior: If the cake writing is too long ≥ for the cake, the set accessor cuts the backing field ≥ down to size. So you’ll need to make sure to ≥ reload the text into the text box every time the text changes or the number ≥ of people changes (in case there’s a long string and she cuts down to ≥ a smaller cake). Add a public int field called CakeSize. Make a private method called CalculateCakeSize() that sets CakeSize to either 8 or 16 depending on the number of people. You’ll need to call it from the constructor and the NumberOfPeople set accessor. You’ll need a CakeWriting string property to hold the writing on the cake. We’ll give you the code for this one. 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). Every string has a Substring() method that returns a portion of the string. CakeWriting uses it to cut the size of the cake writing down—if the number of people changes and reduces the cake size, you’ll need to cut down the string, too. Finally, add 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. BirthdayParty NumberOfPeople CostOfDecorations CakeSize CakeWriting CalculateCostOfDecorations() CalculateCost() We don’t want any other methods changing the value of CakeWriting. 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. 2 Update the form to add tabs 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 Name the first tab and move the Dinner Party controls onto it After you drag the Dinner You’ll drag the each of the controls that handle the dinner Party controls onto the tab, party into the new tab. They’ll work exactly like they do now, but they’ll only be displayed when that tab is selected. they’ll Dinner only be Party visible tab is when the selected. 208   Chapter 6 More free ebooks : http://fast-file.blogspot.com inheritance 4 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. TNatNnhhuadiemsmeDLetraiaitcnbbhUneeeuplmrsDecsPoonnawuttrmnhtr,eboyeClsrthBajeuibcrskttdBholodiekxase,.y, fancyBirthday, and birthdayCost. 5 You’ll need this property Click on the Birthday Party tab and add the new controls. “tfHioActooanadrpksg)dtpoei.vhyWeaUteBrhsiTciteetiearixktuianttseghsedBdr(feTaoaofeyxknrax”ndu.tcotlowtahpnserltvaoawrwblpohuerelealirttctaoianbyfilgtole’vsde Here’s the code for the BirthdayParty.CakeWriting property—it’ll come in handy: private string cakeWriting = “”; public string CakeWriting { get { return this.cakeWriting; } set { Did you notice how we left out some int maxLength; if (CakeSize == 8) maxLength = 16; of the brackets? else tTytestorhohoruoeir’osverlreopigntrmshghoeetepesfensosmrairtbzgaeyeextf,ihaimossenrouedamc.iatltIiklttheectne,acgnlneuhtsechbimcun.ektogIsrsrfteetthlihoctheeoae’smdmcbetpaaadolxkecoeLxkinilesnottingnozhggeatft,nhihtieteotlvdhagtsereidevieaxeoobtswnifleneabsniotttxoo’s. When you only have one statement in a maxLength = 40; 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 brackets around it. } } 6 Put it maxLength = this.cakeWriting.Length; this.cakeWriting = cakeWriting.Substring(0, maxLength); } else this.cakeWriting = value; all together tapElholvoerewtrtieyoednxsttloerbfniongxgtthhwhe,ahssseotnaryitnSohguue.’bllsTttnehrexiiesntdgo(on)treomccreauetktlheosoasiddtizttedhhocaewhtnawnrrtegiottei.untrghnesinato All the pieces are there, now it’s just a matter of writing a little code to make the controls work. ≥ Add a BirthdayParty object to the form. Make sure you instantiate it. ≥ Add code to the NumericUpDown control’s event handler method to set the object’s NumberOfPeople property. ≥ Make the Fancy Decorations checkbox work. ≥ 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. 7 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. Once it’s working, you’re done! More free ebooks : http://fast-file.blogspot.com you are here 4   209 exercise solution Add birthday parties to Kathleen’s party planning program. public partial class Form1 : Form { DinnerParty dinnerParty; BirthdayParty birthdayParty; TjinuhistteiaBlliikizreetdthhdienayitPnhsateratfnyocreinmos’tfsacnDocniensntiserruPcatrotr,y. 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. 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(); } } 210   Chapter 6 private void cakeWriting_TextChanged(object sender, EventArgs e) { birthdayParty.CakeWriting = cakeWriting.Text; DisplayBirthdayPartyCost(); } private void DisplayBirthdayPartyCost() { cakeWriting.Text = birthdayParty.CakeWriting; decimal cost = birthdayParty.CalculateCost(); birthdayCost.Text = cost.ToString(“c”); } Awisnolrtliotttihhnteegh,efintoNtrhemeulmlnijgbuueemsntrbcOeehfrafPsooefrtoopdpleseeeoaatplnilnedag,nCdawnaidtdkhiestWpmhlraeaiytkciitnnaghgkeesseuvstriazelueaetcsahc.reeessborusil,t 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. More free ebooks : http://fast-file.blogspot.com inheritance using System.Windows.Forms; public 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 fancy 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; this.fancyDecorations = fancyDecorations; The constructor’s calling the set accessor to set the cake writing, in case the parameter CalculateCakeSize(); is too long for the cake, so it’s got to this.CakeWriting = cakeWriting; CalculateCostOfDecorations(fancyDecorations); calculate the cake size first. } The constructor sets the properties and then private void CalculateCakeSize() { runs the calculations. if (NumberOfPeople <= 4) CakeSize = 8; else CakeSize = 16; } TtNChhuaeemlcCCbuaealarlkctOeueSflCaiPztoeeesotCpf(al)iekeemlsdSee.ittzIhteao(’csd)c.cemaselsltoerhdoadbnydsettthhsee private string cakeWriting = “”; public string CakeWriting { get { return this.cakeWriting; } set { int maxLength; The CakeWriting property that the cake’s writing is for the cake size. Its set makes sure never too long accessor checks if (CakeSize == 8) maxLength = 16; else tfnhoieetldctsaokLoeelnosignztge.h,Itfphrioetpneiurs,steiyts ttcohuetmsbatakcehkesinusrgterinitg’s maxLength = 40; if (value.Length > maxLength) { down to the right size. 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; More free ebooks : http://fast-file.blogspot.com you are here 4   211 exercise solution Add birthday parties to Kathleen’s party planning program. 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) CakeCost = 40M + CakeWriting.Length * .25M; else CakeCost = 75M + CakeWriting.Length * .25M; return TotalCost + CakeCost; } The CalculateCost() method is a lot like the one from DinnerParty, except that it adds the cost of the cake instead of the Healthy Choice option. private int numberOfPeople; public int NumberOfPeople { get { return numberOfPeople; } set { numberOfPeople = value; Mtsteohhvaleeaukrttisnyiiozgtnteht.iemohTfeeChatCetkhhaeoeekWtenhcrWueaitmrrkiiebnthegiainrslgsfeootmnfisleyaptmcehhcaoaoekpldsfilnseogcorcufshtugatrendethgoesewsrn.un CalculateCostOfDecorations(fancyDecorations); CalculateCakeSize(); this.CakeWriting = cakeWriting; } } This method is just like the one in the DinnerParty class. public void CalculateCostOfDecorations(bool fancyDecorations = fancy; if (fancy) CostOfDecorations = (NumberOfPeople else CostOfDecorations = (NumberOfPeople } fancy) { * 15.00M) + 50M; * 7.50M) + 30M; ScrtCtd3hodehauo6caoerkww-anwnnelgnhlcnsWeei—euttsnitlr,nsatiouotttttesoeirhheoinsfseengametincatte4hultsosae1ms-hs0ascasbcpegtu-eeateft’rrkplilseerwatoorsfcinfhtsslcilioetezonpbsenteose,epooen,aaprxcrlntutteftdthhoyeerir smaller cake. } 212   Chapter 6 Curly brackets are optional for single-line blocks Asobpt feyalrotclfteeuetm rcotltefyinlnytftbgorivmiryaanolecsi(udsikidneydetstoyrsiunoi—Dt’tpls=loaaTtbnhx0dlhahoevf;ecteoJkichr.oaueia}>snIDBcuEoidl}de. MessageBox.Show(“This is the subclass: ” + “ and ” + anotherValue); int anotherValue) { + baseClassNeedsThis constructor. 3 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! public class MySubclass : MyBaseClass{ This is how we send the base class the parameter its constructor needs. {pub/l/i:cthMbeyaSsrueeb(scbtlaasosefsC(ltsahtsersiNsneugebdcbslaTashseisCsl)iassstNheeedssaTmheis,Atwtshdehhieedeantbttetahrghsreeiaesotntrsclwiolnwapotesaihslsmlt.seoeegIrtsdotsVaehataglawollesyaCutyobaeh#ouea)pxnaaetbdrsroaaespymceoohaepucletllrucaeteprashs!n4elicmsotc ano kstnteshtraaur2tcu3btcsuot3htroo.trwoTsinnhteon More free ebooks : http://fast-file.blogspot.com kathleen still needs our help Now you’re ready 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 NumberOfPeople CostOfDecorations CostOfBeveragesPerPerson HealthyOption CalculateCostOfDecorations() CalculateCost() SetHealthyOption() BirthdayParty NumberOfPeople CostOfDecorations CakeSize CakeWriting 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() 234   Chapter 6 DinnerParty NumberOfPeople CostOfDecorations CostOfBeveragesPerPerson HealthyOption CalculateCostOfDecorations() CalculateCost() SetHealthyOption() BirthdayParty NumberOfPeople CostOfDecorations CakeSize CakeWriting CalculateCostOfDecorations() CalculateCost() More free ebooks : http://fast-file.blogspot.com 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.” ≥ Move the NumberOfPeople and CostOfDecorations properties into it so that they’re compatible with both DinnerParty and BirthdayParty. Do the same for the CalculateCostOfDecorations() and CalculateCost() methods. 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. 3 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. ≥ Uh-oh—we can’t override the CalculateCost() method here if we want to keep the form code the same, because our form needs to pass it a bool called healthyOption. So instead, we’ll overload it—which just means adding a new CalculateCost() method to the class that takes different parameters. So you’ll use exactly the same declaration for the method that you used at the beginning of the chapter. But you can still take advantage of inheritance by calling base. CalculateCost() to access the CalculateCost() method in the Party class. Yaobuo’ulltleoavrenrloaallding in Chapter 8—this is just sneak preview a to give you a leg up on it later. 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. More free ebooks : http://fast-file.blogspot.com you are here 4   235 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! public class Party { const int CostOfFoodPerPerson = 25; private bool fancyDecorations; This the DcoindneerwPaasrtmyovaenddstBriratighhdtayoPuatrtofy classes and into Party. public decimal CostOfDecorations = 0; public Party(int numberOfPeople, bool fancyDecorations) { this.fancyDecorations = fancyDecorations; this.NumberOfPeople = numberOfPeople; The Party constructor does everything that was previously in both the DinnerParty and BirthdayParty constructors. } private int numberOfPeople; public virtual int NumberOfPeople { get { return numberOfPeople; } NumberOfPeople needs to be virtual set { because BirthdayParty needs to override numberOfPeople = value; it (so that a change to the number of } CalculateCostOfDecorations(fancyDecorations); 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; } Tidtndohioenennnmetedorioecvfceapolaitrtrianhttetibieooocsn,toPdhsacoerabtliciitysru.tldmahTtuadphikaolaeinyctsaiatsswneeadndyse in multiple classes. public virtual decimal CalculateCost() { decimal TotalCost = CostOfDecorations + (CostOfFoodPerPerson * NumberOfPeople); if (NumberOfPeople > 12) { TotalCost += 100M; } return TotalCost; } } Tebxehtceaenucsdoessttithceablycbuirclatatldliioannyg npteaheredtsbyatosoevebcrelraiasdsevsmirietttuh(aoaldnmd).etalhsood 236   Chapter 6 More free ebooks : http://fast-file.blogspot.com inheritance public class BirthdayParty : Party { public int CakeSize; public BirthdayParty(int numberOfPeople, bool fancyDecorations, string cakeWriting) : base(numberOfPeople, fancyDecorations) { CalculateCakeSize(); this.CakeWriting = cakeWriting; CalculateCostOfDecorations(fancyDecorations); } BCTtoiahrletcduhocldaomtanyeostCPstraaurkocteftySoitrzchoeren(e)slwt,ierojsuursckott.noTlrtikhhedeeindtbh.iatesecoalcdlllasss private void CalculateCakeSize() { if (NumberOfPeople <= 4) CakeSize = 8; else CakeSize = 16; } TmbiniherettthhhCoedadalBcyiuisrlpatsatphreedtCcaiieafyskPi,ceaSsrtoitzoyiet(c)sltaassy.s private string cakeWriting = “”; public string CakeWriting { get { return this.cakeWriting; } set { int maxLength; if (CakeSize == 8) maxLength = 16; else TpinrhoetpheCeratkByeiWrsttrhaitdyisanygiPntaratcty class too. 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; CofacCvainarealdlcsrlctcurutuliladclahatatdetelneeceCdnuCao,ladoisbnttsdte(etc)(i)ahttauehmlstseePeooatcintrtohethsoteneydde.ocecsfodlatssstotsth’btsoeehacta’kse, } public override int NumberOfPeople { get { return base.NumberOfPeople; } set { base.NumberOfPeople = value; CalculateCakeSize(); this.CakeWriting = cakeWriting; } } } ToaNsinivchzuecemePre.arsNbsirTedoutrmerhyOebtnfaeeshPlreeseeOotdoofspganPletceeetocosiesnporsleseePoxtcareahprclarcntutouetypleateedbtdrhseet.ecytatsoeuhhtseacesaacltlctahcokbeeeasssseeo.tr Continues on page 238. More free ebooks : http://fast-file.blogspot.com you are here 4   237 great job! (HTerhee’rset’shneolacshtancglaesstointKhaetfholeremn’scosdoelu.)tion. public class DinnerParty : Party { This public field is only used in dinner parties, not birthday parties, so it continued public decimal CostOfBeveragesPerPerson; stays in the class. from p.237 public DinnerParty(int numberOfPeople, bool healthyOption, } bool fancyDecorations) : base(numberOfPeople, fancyDecorations) { SetHealthyOption(healthyOption); CalculateCostOfDecorations(fancyDecorations); TDnPcoeaainwlrdlntsoecySrowPenchatsoatrHntrtsetuyatcrlthtcuoeclhartysooOslcrdpadtlaildisnod,ntt(ht)he.heen public void SetHealthyOption(bool healthyOption) { if (healthyOption) CostOfBeveragesPerPerson = 5.00M; else CostOfBeveragesPerPerson = 20.00M; } TsthaeysSeextaHcetallythtyhOepstaiomne(.) method public decimal CalculateCost(bool healthyOption) { decimal totalCost = base.CalculateCost() + (CostOfBeveragesPeDriPnneerrsPoarnty*neNeudmsbaerdiOfffPereeonptle); if (healthyOption) CalculateCost() that takes a return totalCost * .95M; parameter, so instead of overriding else it we overloaded it. It calls the return totalCost; CalculateCost() method in Party using } } the the base keyword, and then adds cost of the beverages and adds in The program’s the healthy option discount. perfect. It’s so much easier to run You’ll learn all about my business now—thanks so much! how overloading works in Chapter 8. Uh-oh—there’s still a potential bug still 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! 238   Chapter 6 More free ebooks : http://fast-file.blogspot.com Build a beehive 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: inheritance 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. 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. Twtdwbooehoorierbsdkskeoedeernrrdaseoco—apchnvdaetajn,ohiolwaeabdbnn.opdle.SrlTioosstthghosreehsadheqdmoouojweeuwiestssinntlal’atlksnflendirslogeiewxuacartsslejlssyoiwgobwhcnusaahtttritcehhihfjeaowtjbjthooshitbbcenhhrheeteaebo’sdsehetaiom. 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. 2 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. More free ebooks : http://fast-file.blogspot.com you are here 4   239 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. private workers: Worker[] private shiftNumber: int ≥ 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. AssignWork() WorkTheNextShift() ≥ 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 find a worker to assign the job to, or false if it couldn’t find a worker to do that job. CurrentJob and ShiftsLeft are read-only properties. ≥ 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. Worker CurrentJob: string ShiftsLeft: int private jobsICanDo: string[] private shiftsToWork: int private shiftsWorked: int DoThisJob() WorkOneShift() The queen uses an array of Worker objects to keep track of all of the workers and what jobs they’re doing. ≥ 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 that’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. String.IsNullOrEmpty() sdacEtnuoarricetrnhmeghnapbtittsel:yeyeSissdttttohrorieirinnnregggs.eIaimisftNjpsouthbcleyluO’sbroryrrwEeacnmnihtutpelitlcnj,yokgfb(inCafglaoussrerhraihoseitnssCthtnuerJerrionxrwbgeti).nsetSjw.oJoiblol.abrCwep#torurorkpgneeivrrettsrcyuayen–ouiffitaig’ntlulhrebeeaesoCyeuuqtwruraiaefylntthtoJoe’osb 240   Chapter 6 More free ebooks : http://fast-file.blogspot.com 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 textbox 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 nextShift button calls the queen’s WorkTheNextShift() method, which returns a string that contains the shift report. the user is only allowed to choose items from the list. The Shifts box is a NumericUpDown control called shifts. aNnadmesetthiitsstMexutltbiLoxine“report” property to true. L“sQIwnUhi\tnuouhirsmfoease\ttkettbnhnate”ecrrehroleta,eotmbpcssoaojiehedenwrslacyddctwidttal,oadethprwtgehokeaahefetnsincrelehsihqharnirsiiaueesftstepttdbnheorcresori.eeintnsagsgk.. public Form1() { InitializeComponent(); Worker[] workers = new Worker[4]; EpwaahrcaahtmWjeotobersrk,eitrankonbaojrwercsatyh’soowcfontsstotrrdinuogc.ts otrhattakteesllonite 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 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. More free ebooks : http://fast-file.blogspot.com you are here 4   241 exercise solution public class Worker { public Worker(string[] jobsICanDo) { this.jobsICanDo = jobsICanDo; The constructor just sets the JobsICanDo } property, which is a ShiftsLeft is a read-only property that calculates how many shifts are left on the current job. public int ShiftsLeft { string array. It’s private get } { return shiftsToWork - shiftsWorked; because we want queen to ask the the worker } to do a job, rather than private string currentJob = “”; public string CurrentJob { make her he knows check whether how to do it. CotjonueblrlylrsneptenrethodeJpseoqrbtutoeiysebntaehwrdahetoiacndhe-. get { return currentJob; } } 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 work to him—he checks his JobsICanDo property to see if if (!String.IsNullOrEmpty(currentJob)) return false; for (int i = 0; i < jobsICanDo.Length; i++) if (jobsICanDo[i] == job) { he knows how to do the job. currentJob = job; this.shiftsToWork = numberOfShifts; shiftsWorked = 0; return true; } return false; } Wcehmeepcutksye.difIt!t—’shtejhusesttrNilOnikgTe iscohpNeeOcrkaTitnognru—tllotoosree if something’s false. public bool WorkOneShift() { TtWheolerl kqhOiumneeetSnohuifwsetosr()kthmteehtwehonoredkxettro’s srheitfutr.nTs hterumeeitfhotdhisonislythe vdqreueorepiyneognrlattcsthatenhsahjatoidfbdtt. hTatehhlbaianteteehwtweao’iyslltt}hbheee } done after this shift. if (String.IsNullOrEmpty(currentJob)) return false; shiftsWorked++; if (shiftsWorked > shiftsToWork) { shiftsWorked = 0; shiftsToWork = 0; currentJob = “”; return true; } else return false; Take a close look at the logic here. First it checks the currentJob field: if the worker’s not working on a job, it just returns false, which stops the method. If not, then it increments ShiftsWorked, and then checks to see if this is the job’s done by comparing it with ShiftsToWork. If it is, the method returns true. Otherwise it returns false. 242   Chapter 6 More free ebooks : http://fast-file.blogspot.com inheritance public class Queen { public Queen(Worker[] workers) this.workers = workers; } private Worker[] workers; private int shiftNumber = 0; { Tbtsohehhroceeduamelqudr,susees.bieneoTncnheackebeeslehectpeohst’nseoshytte’crrhrhueeacantaorgosnrserlaiygytsnoeheontedfesm, wt.wn..hohoeoororkftgeeiihrevveseledrsnp’srctsilhvveaaaeestmlsuee. public bool AssignWork(string job, int numberOfShifts) { for (int i = 0; i < workers.Length; i++) if (workers[i].DoThisJob(job, numberOfShifts)) return true; return false; } public string WorkTheNextShift() shiftNumber++; { When she the first do it, she the job is oafmnsooseuivngeadnsns,dotwnthoertriokemstteaohtsehshoinegdernxirnwtego.trWuhkrimehnresntb(hweaeehbsij,ceohesbh.swetIhfosotphsacerattnchsaednwlo’otitohp). string report = “Report for shift #” + shiftNumber + “\r\n”; for (int i = 0; i < workers.Length; i++) The queen’s { if (workers[i].WorkOneShift()) wdlswimoWhneorpieeofrketrkttenhkerodoTra’idsntnhtgdhsetoteNeoaawlnetrdlxsoeudttprsesh.okSaerahcatihft() report += “Worker #” + (i + 1) + “ finished the job\r\n”; if (String.IsNullOrEmpty(workers[i].CurrentJob)) report += “Worker #” + (i + 1) + “ is not working\r\n”; else if (workers[i].ShiftsLeft > 0) report += “Worker #” + (i + 1) + “ is doing ‘“ + workers[i].CurrentJob + “’ for “ + workers[i].ShiftsLeft + “ more shifts\r\n”; else report += “Worker #” + (i + 1) + “ will be done with ‘“ + workers[i].CurrentJob + “’ after this shift\r\n”; } return report; } } We already gave you the constructor. Here’s the rest of the code for the form: Queen queen; Tkooehbfeejeprcfetaof,rermrweefhnueiccsreehessnicintteostttuqorhuneetehhwneaosfrQikaeuenledreanotrborjaeycts. 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...”); } private void nextShift_Click(object sender, EventArgs e) { report.Text = queen.WorkTheNextShift(); } TgehneernaetxetsShaifrtepbourttt, ownhitcehllsittdheispqluaeyesnintothweorrkeptorhte next text shift. box. She aoTdaqvnsuihassepeiiwegllaanhnab’yesslwstseiAhogatrensorksJmigodeotnbsrooWsabnatoguorhetwtkebt(ooo)ajrxonkmbwedc.eoraetr,lphklaeseonnrdtdd’hsitneog More free ebooks : http://fast-file.blogspot.com you are here 4   243 you’re not done Objectcross Before you move on to the next part of the exercise, give your brain a break with a quick crossword. 1 1 5 5 2 3 2 4 3 4 6 6 7 7 8 8 9 10 9 10 11 11 Across Down Across 5. This method gets the value of a property. 7. This method returns true if you pass it “”. D12o..wAIf ny_o_u__w_a_n_t can override methods from its base class. a subclass to override a method, mark the 5. This me8th. Tohdegceotnssttrhuectovrailnuea osufbaclparsospcelarstys.doesn’t need the same 1.mAe_th_o_d_w_i_th_thciasnkeoyvweorrrdidine tmheebthaosedsclfarsosm. its base class. 7. This me_th__o_d_raestuthrnescotrnusetruifcytooruinpitassbsaiste“”c.lass. 2.3I.fAyomuetwhoadntinaasculabscslathsast’storuonvaesrrsidoeonaams iet’tshionsdt,amntiaartekdt.he 8. The con9s.tAruccotnotroinl oan saufobrcmlatshsatclelatsssyoduocersenat’et ntaebebdedthaeppslaicmateions. m4e.thWohdatwaitshutbhcilsasksedyoweosrtdo irneptlhaecebaasmeetchloadssin. the base _____ as t1h1e. Tchoisnstytpruecotfocrlainssitcsabna'tsbee cinlastsasn.tiated. 3.cAlasmse. thod in a class that’s run as soon as it’s instantiated. 9. A control on a form that lets you create tabbed applications. 11. This type of class can't be instantiated. 4cl.a671Ws..0TsW.hA.hahissatutcabyocosnluauta’sbriesncsuldasboseainsssgedthwocishleaekssnestyeaowsdrodaerndapdltcaosoculcoebanclalltatohmsesaeemcstlhaeosmsdbdeinersctlhoaefrathtbieoans.e 6.cTlahsissitcionnhteariitnesd bfraomse. classes and subclasses 7. What you’re doing when add 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 250. 244   Chapter 6 More free ebooks : http://fast-file.blogspot.com inheritance Use inheritance to extend 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 virtual so the Worker can override it. Bee public ShiftsLeft: int virtual mrSeeotmmubertenrimsvaeilnsuewcslea’asllnsdsdhipoarwgivryaatomues. oiaGsAtvoneledlatrtbrHhwveioedioernerstqekuuycietaeCorel.nsonmsnucsaemoutnnmedhspouhwtmdoio,neoresnhkoy(eo),ornsmnseoeyecwtaodhenfi’oflildftneahhtrdeeoerdnsittutabhlyiect.l.abWsBaseseu’elstl ccmblaaeanseksse GetHoneyConsumption(): double The worker just needs to subclass Bee overide the ShiftsLeft method with the one you already wrote. The queen needs to Queen Worker change her report to add private workers: Worker[] CurrentJob: string honey consumption data. private shiftNumber: int ShiftsLeft: int That means she needs to add each worker’s private jobsICanDo: string[] honey consumption—and AssignWork() private shiftsToWork: int since she consumes honey WorkTheNextShift() private shiftsWorked: int herself, she’ll need to inherit from Bee and override its virtual DoThisJob() WorkOneShift() GetHoneyConsumption() method. Add Existing Item WteEftfhaa(hoxhoe.snleDeyrpddns,leeeoenwsrctvcreiah,ehegowyraronnanuednptyiggrdnrooeh.pocu.tasjdsieetr)hTholctseeaath.ctvnne’ItehsTDadaImafhtEDtroaeh,etEltseidsspwsoeeawfwotulrc-eiaroi,lelceyclpatsrealNniyirngy‘d(oOAteho.urTtudaebec-ddsyxwaxccdeanhE)lhrinatcaxcaftnknhiiligswsdeltteeeoam.osisnyn,—tAsgatithntadoeghdI’ndtseetdnte.iahafpmTlmemrbw’yohaaeapfojceksyreurpkesocIoaDtjamstaceduoeEcnrgd,ttaeto.shwmoahoeyTideeloflymhuifooimenderuicrrnaem’thelsuakltah,,eannetmnrsgenoaoeaneeevlkedsuwaittwegtahtaifcsoretopeounitrewrpreoeiidetajfntesoitathcnoymotietonfewe’haugsasdestcpSpndhahotreocolooelidceustdjlsetewas,pcisiafortdttstnoio.elcfjefosheiiso.Aglcernotinneu’srt you are here 4   245 More free ebooks : http://fast-file.blogspot.com 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, the second-to-last shift he uses 11 units, the shift before that he uses 12 units, etc. So if the bee’s working (meaning its 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. ≥ Those 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 read-only 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. tapHchreciervemeas’t.ssieTnagbhgyaaotnododwetfahrayeuurllyetoc,oulaafsansvdt’oshioudpnmrlbyobup.mgeYrsaotkiunieessythoohoureurlmdmpeprmtuoahbgkolriedacmsfifsiienclcadaonsurosrtaeenhdcdetrblmyyc.eloatnshseodnceslaesdss 246   Chapter 6 More free ebooks : http://fast-file.blogspot.com inheritance 3 Make the Worker clattfmHoshriesenotstmsheai:erngBYrheWooeeuerto,,rrociktdatyehonoreufunburcrsloebeoan-umdstictlvhdlraieBcunykctesotlaeouioggrnrhet!piatlrHuyotaajconvermedcytatpt.tthhiWceiecahWlI“elDyonn.roEtkHoehowvrewielrlcIcDlljoaouEasnmsdvped”innirsehiepiregnlrrahtoiytt!rs 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() by adding the a honey consumption line to the report. Add a loop to add up the honey consumptions for each worker and also find the worker with the largest honey consumption—do it before the queen tells each worker to work each 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. Gobmminvaoeeertttrt,hhhrotoieodhddtebesh”aye—IysoDeouQwuEmhuwceeeaaaentnunnhttyooocodtmvluaoeascrptsoarrivliecaldesanreasldlr.uytitSdtholeeyiemslpteaaescsntpt“daiacpcltalueithlbtley’llhil.cefill 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 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! More free ebooks : http://fast-file.blogspot.com you are here 4   247 exercise solution tcHhoeenrseWu’msorptktheieornBacenaedlccQulalaustese.ionIntctldahosasetess’s.thuseedbabsiyc honey both public class Bee { public Bee(double weight) { this.weight = weight; } atTathhwhHaaeototrnBkceseaeeyelrtCcsuocclnlioaatsntssusesmuWsmhpehateiosgsiow.hant(mc)foumincesheltdtrhhuoaocnndtedoyr public virtual int ShiftsLeft { get { return 0; } } Inheritance made it easy for you to update your code and add the new honey consumption private double weight; behavior to the } ythhQchloaauauivress’dedescenehbshr.aeaateInndontgdemwaaWioalflouokotrltedkoefr p}ublidieircoflfeustvb(e(uilSccwcrrehooeontinninucfssgscaotuuhuolnsmmtmnsLpppsduett>tuomfiiimuptoo1opbtnn5ntli=0ieo===)*on=nG;079;e).1t5+.H;3oS5nh;eiyfCtosnLseufmtp;g1It5foie0ostmhnuge(pIl,if1etfS)tb1bfth,hheayhte2ieee{fen,tb3ntwblheche5seeee.cfeL%eioIgtchfec.nhh,oafossanshuhntssmemse1uunipmoscmhsotroheaezeinissjosfeosnt1runtb70hmoo..a,5;ejn.tsohIbfe, n duplicated code. public Form1() { Only rest otfhethfeorfmorcmonisstreuxcatcotrlycthahnegseadm—et. he 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); } The only change weights need to to be the form added to is that the the Worker constructors. 248   Chapter 6 More free ebooks : http://fast-file.blogspot.com inheritance public 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 ... The Queen class needed a few changes, starting with inheriting from Bee. pbapsfArynoaroldslopatsmedetohrshdvatBeetiiyntregWrietdoiodtenartehcnkstaledaeoktrroehahtvscateehlvairaeoeBrsnWisbeid.teaenes.iseSgekechhdeotcifynelawtsdpstasosrLwrrucadaecomsftntetotsottropertarruihndocehatpjenueorsdrrtit,teyd public 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; } public string WorkTheNextShift() { double totalConsumption = 0; for (int i = 0; i < workers.Length; i++) cGmwTaoedoemhtrtdeeHkheeooWdurndpo’et,srywokaGCiTntteodhhhtneesHtauNohtmenteopxeonptyttciCStaoalhhonlalin(cfs)tsotuhnmmc(se)auerplmtthlsohpiaowotsendnia(oac)nthl.ooop totalConsumption += workers[i].GetHoneyConsumption(); totalConsumption += GetHoneyConsumption(); // ... here’s where the orignal code for this method goes report += “Total honey consumption: ” + totalConsumption + “ units”; } TexrhceeetpruetsrttnhoafrteWiptoorarkdTtd;hsetNheexthSohneifytl(i)neisttohtehseamreep,ort. public override double GetHoneyConsumption() { double consumption = 0; double largestWorkerConsumption = 0; int workersDoingJobs = 0; The queen overrides the Bee’s GetHoneyConsumption() method to do her honey calculation. It finds the worker with the and adds either largest consumption 20 or 30 to it based on how many workers are working. for (int i = 0; i < workers.Length; i++) { This loop if (workers[i].GetHoneyConsumption() > largestWorkerConsumption) looks at the consumption largestWorkerConsumption = workers[i].GetHoneyConsumption(); if (workers[i].ShiftsLeft > 0) of all the workersDoingJobs++; workers and } finds the consumption += largestWorkerConsumption; one with if (workersDoingJobs >= 3) the largest consumption += 30; consumption. else If there are 3 or more workers doing jobs, the queen needs 30 consumption += 20; more units of honey; otherwise, return consumption; she needs 20 more units. } } More free ebooks : http://fast-file.blogspot.com you are here 4   249 crossword solution Objectcross Solution 1S U 2V 3C B I 4O O 5A C C E S S O R V N L 6H A T E S 7I S N U L L O R E M P T Y I S N A R R E S H L I U R E 8P A R A M E T E R S D C E T R I O C T 9T A 10B C O N T R O L H A Y 11S T A T I C E Across 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] Down 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] 250   Chapter 6 More free ebooks : http://fast-file.blogspot.com 7 interfaces and abstract classes Making classes keep their promises Okay, okay, 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   251 More free ebooks : http://fast-file.blogspot.com worker bees, unite! Let’s get 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 Tcoapbaebtitliteiresretporetsheenwt olifrekienrtbheeehsiv. e, we’ll need to add specialized • All bees consume honey and have a weight. • Queens assign work, monitor shift reports, and tell workers to work the next shift. • All worker bees work shifts. • Sting patrol bees will look for enemies, and need to be sting them. able to sharpen their stingers, • Nectar collector bees gathering nectar and are responsible for finding then returning to the hive. flowers, bsLteooeorsekdsdelipifkefenedwrieneng’ltlondneaettdhaetfojoorbbetthahebelywe odtrook.er 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. nhcWteTaclwahelvahseessecyfseta’eeslBonlastewchedeuehxaoraantenanndes’lgtr.dnleeedlaWomtdtoohuykhrecekshleei.kre 252   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes We can use inheritance to create classes for different types of bees Here’s a class hierarchy with Worker and Queen classes that inherit from Bee, and Worker has subclasses NectarCollector and StingPatrol. ctiHonhnefersouerwm’msepiagwtthhiiotoennraeiansbdsothuotorneedy. Bee Weight HoneyConsumption() iaosHbfekoreutepth’tsew.wionhrfekorirnemgaasltlhiiofnts Worker Job ShiftsToWork Queen Worker[] ShiftNumber HwnRoeheneemedryeeeCmdwobeenexsroutvmhreoaprwtrhioootdnnhe(ee)yh?qmeureHeteehnroed’s. This is what the new subclasses will look like. fNSretocimntgatPrhaCetorlolWelcoatrnokdrerinchlearsist. class StingPatrol : Worker { int StingerLength; bool enemyAlert; public bool SharpenStinger (int Length) ShiftsWorked ShiftsLeft {...} public bool LookForEnemies(){...} DoThisJob() WorkOneShift() AssignWork() WorkTheNextShift() HoneyConsumption() public void Sting(string Enemy){...} } StingPatrol StingerLength EnemyAlert SharpenStinger() LookForEnemies() Sting() NectarCollector Nectar FindFlowers() GatherNectar() ReturnToHive() class NectarCollector : Worker { int Nectar; public void FindFlowers (){...} public void GatherNectar(){...} public void ReturnToHive(){...} } phAaonrlddticttuhhleeasreintfcoolaresmsaecasthiojonb. What happens if you have a bee that needs to sting and collect nectar? More free ebooks : http://fast-file.blogspot.com you are here 4   253 interfaces for jobs An interface tells a class that it must implement certain methods and properties 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: public class Queen { private void DefendTheHive(StingPatrol patroller) { ... } } ct n object r object I wish you guys could help defend the hive. Queen obje NectarColla NectalColla 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. Maybe 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. tEpbSeoaqevhsceueasanaulciNtisafteenotc’tittotahajehreNuexCsqertpouceletDslceeaetenctrsftCeaoaaondrldSdSleoTtstcbiihtsnjntoeeggcHriPPntiaagvo,ttebsprr(jh)aooeetllcmrtrrsoet.eetlifflhleemorrceedeatnnnhcc’oeetd. s 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 that it makes the compiler throw errors if it ASNbhleetecectrcuanomraubCtldeoerDlsaleodecmfdteeonaradnsrTedechfodeenHrifdeivfnemicc(ee)utlittnhhsottadoetacwdtaoa,llrkebkedustwaitthha.t would doesn’t find all the methods required by the interface in every class Plus, the DefendTheHive() and that implements it. Those methods can be coded directly in the class, AlternateDefendTheHive() methods would be identical or they can be inherited from a base class. The interface doesn’t care except for the type of the parameter. If she wanted how the methods or properties get there, as long as they’re there to teach the BabyBeeCare or Maintenance objects to when the code is compiled. defend the hive, she’d need to keep adding new methods. 254   Chapter 7 What a mess! More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Use the interface keyword 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. 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 might be solved by adding a field to an interface, try using a property instead – the odds are Interface names start with I Witjatgauhoshnslatodetnitnnahettsmoevyaoeawepyrstesismehtyy“reuoaIo”curutI—htDocnIerEwenueaetniastdtdeitheoleelrtirSaaosatnntenydhnauasonipbentdpltia.tsecenhr,Yarkocbonfwauualsimstcneceae.aNi,IktniyeE.nomssTTyuieadoehkseuienherfrtsoaoeulenr’iyylrsfdofeyunma.omrocueJeartcrusksohus.eetdlolefde that it’ll do what you’re looking for.. Yinotuedrfeacclaerelikaen this: hfdIainaevttledearsp..fr.S.aoocbpeeutsrthtdetioeyhnse.’dtyonsct’atonrheave Any class that implements public interface IStingPatrol { int AlertLevel { get;} int StingerLength { get; set;} bool LookForEnemies(); int SharpenStinger(int Length); } cppmhomirArmameooenvtpgtppyehlreiheloarceaomdmtl.ldalesisenowmssatf,onustnosdhttt’rtahhtetisshee this interface will need a public interface INectarCollector SharpenStinger() method that { takes an int parameter. void FindFlowers(); Eibnamvaetneueeorattrtycofhhttmaoehucdariaentslgcliyicilsnaainuslmalsssy.eineddaSpeinnuoitbtnaalsneitilrcdlof.eoafcetahree }icISmSaitnpnclienepmgvvaPtesooashntiiitsirtsddotIlAaSGRkrNteeaeiYfnsttegaroPhunebaerntjerncrceoNTt,leo.ytocHhutiatavreYmnto((aeuh))mtadh;;teoos.ndim’sYtpoilnwuemrtwiethrneeittsitenhtitteeh.rcefoacdcoeed,feojirnusttthhteehceilarssEpisuvabeurlitycotmihniatntegircfainallcyae 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: public, because private void DefendTheHive(IStingPatrol patroller) you’ll use it to 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 define the public doesn’t matter which class she passes to the method. As long as it implements IStingPatrol, the DefendTheHive() is guaranteed that the object has the methods and properties it needs to defend the hive. methods and properties of Queen obje ct Now that I know you can defend the hive, we’ll all be a lot safer! any class that implements it. you are here 4   255 More free ebooks : http://fast-file.blogspot.com a little bit nectarcollector and a little bit stingpatrol Now you can create an instance of NectarStinger that does both jobs Q: 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 You use the colon operator to declare an interface, just like you do for code…right? A: 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 Interfaces aren’t about preventing you from from a class, in which case it’s just a list of interfaces (in no particular order). You implement an interface with a colon operator, just like you inherit. TIiSmhtpiislnegmcPleaanststrsionlIh.NeercittsarfCroolmlecWtoorrkaerndand 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 class NectarStinger : Worker, INectarCollector, of the interfaces is that now you’ve got a way to have a IStingPatrol { public get The sets NtehcetabraScktiinngger field for the ApLrleooroptkeLFrtoeryvEeilnneimtises() method. } public get set } } int AlertLevel { { return alertLevel; }Yminootureecraftnahcauesneifonyeou separate them int StingerLength { with commas. { return stingerLength; } { stingerLength = value; class that does any number of jobs. Let’s 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 public bool LookForEnemies() {...} IStingPatrol reference—and that reference can point to any object that implements IStingPatrol, no matter what public int SharpenStinger(int Length) the actual class is. It can point to a StingPatrol, or a EihiOnwnavtoesttuhrhhlaeydeernmmwwWiN’cnteieil}esthltatleceecshhtsnrbooio.atfmeddyrapoaCciubeloell.eclertcetoao{ppptdre.uuuo.bbbaant.llldNh}iiieeaccccttShavvvterioooSnjogtiiiPbidddnagotefrFGRroiaebloonttbwtdhujoherFerckatlrne,oNTritweobecHeerti.sav(retcsaT)((siohtmr))aheietnne{.ghng.{{beeoeres...bee...iwantrec}..hsemke}}tvininareglsatuchefaterisoerolveuidetnrsd, 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 the interface, because 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, because inheritance brings along a lot of extra baggage— you’ll have to inherit every method, property and field, not When you’ve got a class that implements an interface, it acts just like just the ones that have to do with the specific job. any other class. You can instantiate it with new and use its methods: Can you think of ways that you could still avoid duplicating NectarStinger bobTheBee = new NectarStinger(); code while using an interface? You could create a separate bobTheBee.LookForEnemies(); class called Stinger or Proboscis to contain the code that’s specific to stinging or collecting nectar. NectarStinger and bobTheBee.FindFlowers(); NectarCollector could both create a private instance of Proboscis, and any time they need to collect nectar, they’d call its methods and set its properties. 256   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Classes that implement interfaces have to include ALL of the interface’s methods 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 on the previous page. 2 Add a Bee class to the project Don’t add any properties or methods yet. Just have it implement IStingPatrol: public 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: “YfdITiyoSmmooouhtreepu’eitlslnleethcgvmnsoooPeoeedmraetinmytptioirnipmemlnoeldeeptlermlmhteiorneembhfeneateaitntrtnlhlt’htyeesoee”vfrnwscefeeolraaartynscrtseo.s.rs 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! More free ebooks : http://fast-file.blogspot.com you are here 4   257 clowning around Get a little practice using interfaces Interfaces are really easy to use, but the best way to understand is to start using them. So create a new Windows Forms Application project, drag a button onto the form, and get started! Do this! 1 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: public 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: public 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: meaitYnvueyoetttpureoheyrmdof“daopaptnrcup’ioetbcup,albeinblcrlleiye”tcec.yidmanuasatsikndeoedesitthe 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. 258   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes 4 Here’s the interface—did you get it right? public interface IClown { string FunnyThingIHave { get; } void Honk(); } oaictsHmbeahecjtpnaerll’ateectastm’csshsc,eca.aoenistnnstst’aloelatrxighln.aoeismoRtfkperiaemlelecliadekcdomsee-,fsbasboeoanurfrntl,yiewiiwnnlpidttthreehoetrrnpooffeuayartoocctteeuayhseinr Okay, now modify the TallGuy class so that it implements clown. 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: public class TallGuy : TallGuy IClown will implement the IClown interface. 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: TyWIaaibCoandnhrultllddoaoGeitkwsrumaefnylttela,ththcwoyheaheofoat.ouu.It.dDltwdpsaphEhrnreiioednmoinmpmspttrilyisthoehseoeaempedut!lenlerisntntyatgooiiedus X ‘TallGuy’ does not implement interface member ‘IClown.Honk()’ 6 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 read- only 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!”. Here’s what it’ll look like: public string FunnyThingIHave { get { return “big shoes”; } } public void Honk() { MessageBox.Show(“Honk honk!”); } Aiwtmtlwlihpitometlhrerehkme.ea,eMjinegunvtesottetssentrifatfogicnanecheceteaessitsfarohcaeraicqt.tpeusrYidsjroouooeptTucawvsresetohonshshrcyideiadtesawrrtwetnyeeohthimtnwnithapcwnute’tiahuatgrltietlttalnrhlytadehcsfooaatdooadutmntmccyahtFheenlcpleahetuleaig—slsinheleesssarlndo,ateniyyagtdmdobsThisahutetnmtcHathletochstoiatnseentaotnigdsrgtgkhtsIisdn,ionHeasyaorgrtbasto.wovuuuiewsetnirvoldhlneemioaer.tet.eydIdmittoaeectdsaphnonuo’etbdsdl,isociatsyhe 7 Now your code will compile! Update your button so that it calls the TallGuy object’s Honk() method. More free ebooks : http://fast-file.blogspot.com you are here 4   259 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, or a Robot object or a 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… Yrittanoehhntufoaeeastcrreraferinanmraceepcyesflr,.eeterbmBaheuteuantntetcteyawhsonIohuWaladatoctrsrarnkynmaeeo’wytarun.oiyicnNnfassdotntIwiaaWfdnnfoyotceroeirkaiusestenrcoeptafoaniknncithlnaadsvsseeosf objects! Iitfnhstyeaocnuottmiarptyileetraonwtiihlnletceormfapclaei,n. 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 fred = new NectarStinger(); Remember how you IStingPatrol george = fred; could pass a BLT reference into any The first line is an ordinary new statement, creating reference called Fred class that expects a and pointing it to a NectarStinger object. Sandwich, because BLT inherits from Sandwich? Well, this is the same thing—you can use a 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: NectarStinger in any NectarStinger ginger = fred; method or statement that expects an IStingPatrol. 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. Eomurbhvttseoejaehhfrenveeeecea,trtnmieanwhneccitohntcacueetenehgrnesohfysdrdayofotstcouaehouci.ionesnly fred 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. george ginger NectarStinge 260   Chapter 7 More free ebooks : http://fast-file.blogspot.com r object interfaces and abstract classes Interface references work just like object references 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! 1 Create a couple of bees This is totally familiar stuff by now. StingPatrol biff = new StingPatrol(); NectarCollector bertha = new NectarCollector(); BIFF StingPatrol BERTHA NectarColle ctor Let’s assume that StingPatrol implements the IStingPatrol interface and NectarCollector implements the INectarCollector interface. ctor 2 Add IStingPatrol and INectarCollector references You can use interface references just like you use any other reference type. IStingPatrol defender = biff; INectarCollector cutiePie = bertha; Tccinrahsenetasatoennectlyenweoopwofsitnrataetfcaeelanrmseesinnnctttehessarutftsaoeicmeeinxprtlieseetmfrienefrngaetcnoescbseijtte.aocttsa. nYou SdtienfBgPeIanFtFdroelr cutiePie NeBcEtaRrTCHoAlle 3 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. SdtiengfPeantdroel r cutiePie NeBcEtaRrTCHolAle biff = null; This object didn’t disappear because defender is still pointing to it. cutiePie 4 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(); SdtiengfPeantdroel r NeBcEtaRrTCHolAle ctor gatherer ger NectarStin More free ebooks : http://fast-file.blogspot.com you are here 4   261 ctor 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. 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 But which of the worker bees can collect nectar? In other words, we want to know interface? if the class implements the INectarCollector interface. We can use the is keyword to find out exactly that. A: No, not at all. Yes, a property “wAaisro”llrrakttyeohreosoefwraotcWrhokoreubkrteeserwasihs.r.ieWchien’ltlaynupsee of Worker[] Bees = new Worker[3]; Bees[0] = new NectarCollector(); Bees[1] = new StingPatrol(); Bees[2] = new NectarStinger(); WWeclawleooomtin’gorlhvoedlipkeiebtcedcluhhtgetrosohoieontdbtotngoesu“heageiemssagshn”noihjswdatotasorhbhiovnopro.eenrafa.oaaytigprrShneuoereoerrfacaetyrwtlii,laeeogrs’uhlltt for { (int i = 0; i < Bees.Lengthi(s;=w=oi)rk+fso+rlik)ientaenrfeaqcueasls operator if (Bees[i] is INectarCollector) inside an interface looks very similar to an automatic property—like Job and Left in IWorker interface on the next page. But they’re definitely not automatic properties. You could use 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: { TINheisctiasrlCikoellseacytionrg,iniftetrfhaisceb.e..ediomptlheims.ents the public job { get { return “Accountant”; } } and the compiler will be perfectly happy with that, too. You can also add a set Bees[i].DoThisJob(“Nectar Collector”, 3); accessor—the interface requires a get, but it doesn’t say you can’t have a set, } } Nccooolwllleeccttthoianrtg, we we ckannowastsihgen nectar. biteetihseajonbecotfar 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? 262   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Interfaces can inherit from other interfaces When we draw an interface on a class 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 diagram, we’ll show inheritance using dashed lines. interfaces simply accumulate all of the methods and properties from the interfaces they inherit from. public interface IWorker { string Job { get; } WItWheoe’vreoktecrhreeirnattieendrtfeaarcfneaectwehsat inherit from. (interface) IWorker Job ShiftsLeft int Left { get; } DoThisJob() WorkOneShift() void DoThisJob(string Job, int Shifts) void WorkOneShift() } (interface) Any class that implements an interface that inherits from IStingPatrol StingerLength IWorker must implement its methods and properties EnemyAlert When a class implements an interface, it has to include every property and SharpenStinger() method in that interface. And if that interface inherits from another one, then all LookForEnemies() of those properties and methods need to be implemented, too. Sting() (interface) INectarCollector Nectar FindFlowers() GatherNectar() ReturnToHive() public interface IStingPatrol : IWorker { int AlertLevel { get;} int StingerLength { get; set;} bool LookForEnemies(); int SharpenStinger(int Length); } ihtliHminukhetpgeerleeeeraIm’Wdfstaeioftncirnfhetkyee,serbrcesIuShanitamtcnnetienngegoieIrnPwS,fataabtiincutnryetgo.iPnlciI.tahltatesmrrlsoioatotlkskhesafstraom AIiSmctplialnesgmsPeatnthtraottlhimmesupesltemmneeotnthtosodnsly... .iI.nW.bhouertrkitetsrhefinrmtoeemrt,fhatocodeos.tohfistihneterface (interface) IWorker Job ShiftsLeft DoThisJob() WorkOneShift() More free ebooks : http://fast-file.blogspot.com you are here 4   263 Icanhascheezburger The RoboBee 4000 can do a worker bee’s job without using valuable honey 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. RoboBee ShiftsToWork ShiftsWorked ShiftsLeft Job public class Robot { DoThisJob() Tcolhnaissgsa,isssoooluinrreo.bboatsisc Robot can run public void ConsumeGas() {...} } public class RoboBee : Robot, IWorker { private int shiftsToWork; private int shiftsWorked; public int ShiftsLeft bdmTiimenoehehpa.eetlnerPhsRmieetoeirstjbfno’ftoesbcBrsatoeoI!mWefroocRabrloaokwtsbesoro, r.tbkTueatrhnadctan TimImhWepeotlerhRmkooedebrnsotiBfnsertaeoelmrlcftlaathcshesee. {get {return shiftsToWork - shiftsWorked;}} private string job; public string Job;{get{return job;}} public bool DoThisJob(string Job, int shiftsToWork){...} public void WorkOneShift() {...} } IIfntRerofbaocBee, ethdeidcno’tdeimwpoleumldenn’tt everything compile. in the IWorker Remember, for other classes in the application, there’s no Any class can implement functional difference between a RoboBee and a normal worker bee. They both implement the IWorker interface, so both act like ANY interface as long worker bees as far as the rest of the program is concerned. But, you could distringuish between the types by using is: if (workerBee is Robot) { // now we know workerBee // is a Robot object } WoimrepiclneatmneersnfetaesceworhwaosturbkccelalrasBssseees with “is.” as it keeps the promise of implementing the interface’s methods and properties. 264   Chapter 7 More free ebooks : http://fast-file.blogspot.com 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(); IiNbAmuelptlclettwmahereeCsndetoolbnloee’ttcehtsekoirnrmo. ipwnltewmerhefincathceIosWn, oelriskkeer, Bees[2] = new Worker(); We’re looping through each bee... We can’t call INectarCollector methods for (int i = 0; i < Bees.Length; i++) { on the bees. They’re of type IWorker, and if (Bees[i] is INectarCollector) { don’t know about .Is.N.eaeencditfacrihtCecoimkllipenclgetmotreo.nts INectarCollector methods. INectarCollector thisCollector; thisCollector = Bees[i] as INectarCollector; thisCollector.GatherNectar(); NOW we can call INectarCollector methods. WtairmenepauIlNtseemetc“ehtaniasts”raoCttboioojlelnsec.actyt,oArS 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 = new IWorker[8]; 1. (Bees[i] is INectarCollector) Bees[0] = new NectarStinger(); Bees[1] = new RoboBee(); Bees[2] = new Worker(); Bees[3] = Bees[0] as IWorker; 2. (Bees[i] is IStingPatrol) Bees[4] = IStingPatrol; Bees[5] = null; Bees[6] = Bees[0]; 3. (Bees[i] is IWorker) Bees[7] = new INectarCollector(); More free ebooks : http://fast-file.blogspot.com you are here 4   265 it looks like one thing, but it’s really another! A CoffeeMaker is also an Appliance 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.. Appliance PluggedIn Color ConsumePower() public void MonitorPower(Appliance appliance) { } // code to add data to a household // power consumption database This code would appear later on in the program to monitor the coffee maker’s Himcneoorntneshi’utsemoarpprtmtoihoegentrahpfmooodwrteoar house. power consumption. CoffeeMaker CoffeeLeft FillWithWater() MakeCoffee() Oven Capacity Preheat() HeatUp() Reheat() CoffeeMaker misterCoffee = new CoffeeMaker(); MonitorPower(misterCoffee); AybtEoepavucpkealenciusaasntneacheopCr.uaeogfsfshefrietteenhMtceehaMekteoomrniaistitnsoerAarPCpsopouwlbfieacfrnlea(ce)sesrmoeoebfftjeehrcoetnd,ce 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 = new IWorker[8]; 1. (Bees[i] is INectarCollector) Bees[0] Bees[1] Bees[2] Bees[3] Bees[4] = = = = = new NectarStinger(); new RoboBee(); new Worker(); Bees[0] as IWorker; IStingPatrol; NectarStinger() implements the IStingPatrol 2. interface. 0 and 6 (Bees[i] 0, 6 is IStingPatrol) Bees[5] = null; Bees[6] = Bees[0]; 3. (Bees[i] is IWorker) Bees[7] = new INectarCollector(); 0, 1, 2, 3, and 6 266   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Upcasting works with both objects and interfaces 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(); We’ll start by instantiating an Oven object and a CoffeeMaker object as usual. 2 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: AkkpiipttlccihhaeennncWWeaa[rr]ee[[k01i]]tc==hemonilWsdatTreoeraCs=otfynf;eewe;Appliance[2Yab]oro;urtahcyacnoofufsfaeepeupplmicaaankscteerisnsgtahtnaodtcocrvaeenantshe. oladn 3 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 coffee maker methods and properties powerConsumer through the Appliance reference even if you know it’s really a CoffeeMaker. So these is an Appliance statements will work just fine, because they treat a CoffeeMaker object like an Appliance: reference Appliance powerConsumer = new CoffeeMaker(); powerConsumer.ConsumePower(); But as soon as you try to use it like a Coffee Maker: powerConsumer.MakeCoffee(); tTrpoeohfwideseorrleiCAnneocpenpw,sluiosamonn’ectirte citcsohamaninpngiolsAen.lpybpelbciaeanuucsseeed pointing to a CoffeeMaker object. your code won’t compile, and the IDE will displays an error: X ‘Appliance’ does not contain a definition for ‘MakeCoffee’ copnoswuemrer CoffeeMake 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. More free ebooks : http://fast-file.blogspot.com you are here 4   267 r object upcasting is easy downcasting is risky Downcasting lets you turn your appliance back into a coffee maker 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. Here’s our Appliance reference that points to a CoffeeMaker object from the last page. 1 We’ll start with the coffee maker we already upcast Here’s the code that we used: Appliance powerConsumer = new CoffeeMaker(); copnoswuemrer r object 2 powerConsumer.ConsumePower(); But what if we want to turn the Appliance back into a CoffeeMaker? CoffeeMake The first step in downcasting is using the is keyword to check if it’s even an option. The javaJoe reference 3 if (powerConsumer is CoffeeMaker) // then we can downcast! 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 points to the same aCsofpofweeeMrCaoknesrumobejre.cBtut it’s a CoffeeMaker mcraeelftlehtroehdne.ceM, askoeiCtocfafnee() CoffeeMaker inherits from Appliance, it still has its Appliance methods and properties. r object if (powerConsumer is CoffeeMaker) { CoffeeMaker javaJoe = powerConsumer as CoffeeMaker; javaJoe.MakeCoffee(); } copnoswuemrer jCoafvfeaeJMoaeke When downcasting fails, as returns null 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. if (powerConsumer is CoffeeMaker) { Uh-oh—these don’t match! Oven foodWarmer = powerConsumer as Oven; foodWarmer.Preheat(); tyrpooeoufwueetsrrereCynaoctennosueuldnml doreswerfnuiecspraeNssnteOctTeit,totawhnintisuOhllhv.“eaaAnpspn”oed,bntjswe.h.ch.ete.nfoSyoooduWwthaerrnymer } 268   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Upcasting and downcasting work with interfaces, 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: Oven misterToasty = new Oven(); misterToasty. (interface) ICooksFood Capacity Any class that implements ICooksFood is an appliance that can heat up food. HeatUp() Reheat() As soon as you type the dot, the IntelliSense window will pop up with a list of all of the members you can use. olaipmetnnoaildiysscnttatpepnirrgonToeigannpocteeatcrrsoeittatslyasieantsait.syl.Ol.pOaveobnev,funetsOnotovihboetyebjn’osejumcerttceechtf,taeseshn.rooednsce Oven Capacity Preheat() HeatUp() Reheat() Microwave Capacity 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. More free ebooks : http://fast-file.blogspot.com 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   269 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 that. 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. Q:What if I want to put a method body into my interface? Is that okay? 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 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. Uh-oh—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: public 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: Click on 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. 270   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Extend the IClown interface and use classes that implement it. IClown (interface) FunnyThingIHave 1 Start with the IClown interface from the last “Do This!” on page 258 Honk() public interface IClown { string FunnyThingIHave { get; } void Honk(); } 2 Extend IClown by creating a new interface, IScaryClown, that FunnyFunny FunnyThingIHave IScaryClown (interface) inherits from IClown. It should have an additional string ScaryThingIHave property called ScaryThingIHave with a get accessor but no set accessor, and a void method called ScareLittleChildren(). Honk() ScareLittleChildern() 3 Create these classes: ≥ A funny clown class called FunnyFunny that uses a private string variable to store a funny thing, and 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!” ScaryScary ScaryThingIHave ScareLittleChildern() 4 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! More free ebooks : http://fast-file.blogspot.com you are here 4   271 no no! nooo! noo! no more scary clowns! Extend the IClown interface and use classes that implement it. public interface IClown { string FunnyThingIHave { get; } void Honk(); } public interface IScaryClown : IClown { string ScaryThingIHave { get; } void ScareLittleChildren(); The Honk() } method just uses public class FunnyFunny : IClown { this set accessor public FunnyFunny(string funnyThingIHave) { this.funnyThingIHave = funnyThingIHave; } private string funnyThingIHave; public string FunnyThingIHave { to display its message—no need to have the same code twice. You could have implemented the IClown method and 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 implements IClown, ScaryScary implements IClown FunnyFunny too. public class ScaryScary : FunnyFunny, IScaryClown { public ScaryScary(string funnyThingIHave, int numberOfScaryThings) : base(funnyThingIHave) { this.numberOfScaryThings = numberOfScaryThings; } private int numberOfScaryThings; public string ScaryThingIHave { }priv}p}autbelgiMveceotsivsd{oaigbrdeueBttSotucxora.nnrS1eh_“LoCIiwlt(iht“calBkveo(eCooh!b”ijlGe+docrttnecunhsm(aeb)!ne”dr{)eO;rf,ScETbaitYavnenhoohreycaueaytanrIuc’TtSisSstahcAecnswairayhrfsnrgoyyerygsuCtoSysmldcooaeaouw+)FrnFnny’uuten“{rneonenkdbyfynsjFeFoetpruwcuoeintnnndunicfybsyee.eertrcBttsehaouhfau”tetesj;eruyaecsoStsnl}oucckwaeaecnrnyaeyywnqiSs’cuotclarsoalcdswrae.ynrt,y. 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. 272   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes There’s more than just public and private 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 them: 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: pmmfWriaeeeivrmladkcbtesaeedlrlasanaw.cdiActceplnhasryssotsmpm’hseeeormmdtpeibiufetebsihreliorictcd.asosn,r be ≥ 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 clases 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. If you leave off the access modifier when you declare a class member, it defaults to private. If you leave off the access ≥ protected means public to subclasses, private to everyone else modifier when you declare You’ve already seen how a subclass can’t access the private fields in its base class—it has a class or an interface, to use the base keyword to get to the public members of the base object. Wouldn’t it then by default it’s set to be convenient if the subclass could access those private fields? That’s why you have the internal. And that’s just protected access modifier. Any class member marked protected can be accessed by fine for most classes—it any other member of its class, and any member of a subclass of its class. means that any other 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. 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. ≥ sealed says that this class can’t be subclassed There are some classes which 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. Sbmbieucnceoathhacdlaeenaiindrtfugbis’itseeeeisarnntai.atochcTtecemoehna–owsalndsytaeii’ytfdasaci.fcedcflreoae,sescssstns’t you are here 4   273 More free ebooks : http://fast-file.blogspot.com minty fresh scope Access modifiers change scope 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: smycMeohoeuaadrknwifgehoeiawettrthnheebeseraexrcpeotkrcrworsttiosoeyeccophtsuroaeilgvnduaegttteaieso.cncta.eonsTds hen 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. The “this” keyword also of a variable. It says to the current instance of changes the C#, “Look the class to scope at find public interface IClown { whatever I’m connected to—even if that string FunnyThingIHave { get; } matches a parameter or local variable.” void Honk(); } public interface IScaryClown : IClown { string ScaryThingIHave { get; } void ScareLittleChildren(); } This is a really common way to use “this”, since the parameter and backing field have the same name. funnyThingIHave refers to the parameter, funnyThingIHave is while this. the backing field. 2 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. “Bthyisa”d, dwiengtolpdublpiucblcilcasFsunFnuynFnuynFnuyn(nsytr:inIgClfouwnnny{ThingIHave) { C# that we’re this.funnyThingIHave = funnyThingIHave; talking about the backing field, not the parameter that has the same } protected string funnyThingIHave; public string FunnyThingIHave { mSLWceoeatorchkyhoSaadcnn.agdredyse.SetchhaiosrwetLoiittptralofetfCeehccittldesrdte.nh(e) get { return “Honk honk! I have ” + funnyThingIHave; } name. } public void Honk() { MessageBox.Show(this.FunnyThingIHave); } } When you use “this” with tells C# to execute the a property, set or get it accessor. 274   Chapter 7 More free ebooks : http://fast-file.blogspot.com 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 Access Modifiers does, too. Take a look at how the ScareLittleChildren() method accesses the funnyThingIHave backing field—it can do Up Close that because we used the protected access modifier. If we’d made it private instead, then this code wouldn’t compile. public class ScaryScary : FunnyFunny, IScaryClown { public ScaryScary(string funnyThingIHave, int numberOfScaryThings) : base(funnyThingIHave) { insumprbievartOef, SwchaircyhTihs ings wiftnoiyseutplldiadcn.acblSeeooofaofbnallSeybctaaaocnrkoysitSenhecgeairrty. this.numberOfScaryThings = numberOfScaryThings; } private int numberOfScaryThings; public string ScaryThingIHave { get { return “I have ” + numberOfScaryThings + “ spiders”; } } public void ScareLittleChildren() { MessageBox.Show(“You can’t have my ” The protected keyword itpnresiltvlsaatnCce#estootfoevmaerasykuoebncesloaemsxse.ctehpitng } } TTushheaett“’hsbeaasnveao”ltuhkeeerfyrwwooamrydttthoeelclbshaaCsne#g+ecltasocsbso.pae.se.funnyThingtyiItItfoohHuitaswoaanewyn’pvdorseuuoerlledbtrf)ceocltcra;at.sufesBsudeoun,ftnttyhhwFTeahuhtnecinnnomygmwFaIpHdeuialenevcnrehiyta.tpnovrgiisevgiadbivtleee, 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(); } Since this button click event handler is not part of FunnyFunny and ScaryScary, it can’t access the protected funnyThingIHave field. Iiotnfs’sidaoenuytitsFiduonnenlyyoFfhuabnvonetyahocrccelaSssscsaetrso,ySstochaetrhpyeuobsbltijcaetcmetemsm.ebnterss More free ebooks : http://fast-file.blogspot.com you are here 4   275 eew, 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 just 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. Q:Why do I need to use a property? Can’t I just include a field? A: 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 a 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 your working with a truck object, a horse object, a unicycle object, or a car object. The way each of those objects do 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 to everyone else. Interface references only know about the methods and properties that are defined in the interface. 276   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Some classes 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. public class Shopper { ArtStudent public void ShopTillYouDrop() while (TotalSpent < CreditLimit) BuyFavoriteStuff(); BuyFavoriteStuff() } Engineering Student 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: public 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: public 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? More free ebooks : http://fast-file.blogspot.com you are here 4   277 i can’t believe it’s not an interface! An abstract class is like a cross between 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! fmccAnrlaoeaoltmslmseshteedotasadthnamsoen,imdunjsaetuttbnsesthtritmafsrltapiaokclcrheeetma.mwsemhenaetettnhdhaoetoldclhdlaaeb.ryboIasndtithnyriehoarienscirttibitnugt ≥ An abstract class is like an interface When you create a class that implements an interface, you agree to mcmmmOoaaenemrrttlykpkhhioloaateddb.hcssaYti.lnatorItsfuasoc’clltlyaaaobslescusctallaaaprrsbsunassstce,tmtsrtaoachnirncaeetannabaohysbmrtaooirvunuiea’ttulcltatwhhebooa.sntwve’rtattcoot 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. Timybfshooaeceudrto’yvhonae,opcrdaprebnoeeidstcseioetnoan.enlcwAlerootefrctthkoheeainanbctccgsrlltaaehwrsstaassiteseechssta. so X Cannot create an instance of the abstract class or interface ‘MyClass’ iciTcannoobsshdtdtsitaesae,nr!netatjTruciiaratshttoteremelcieiakasotnemhcbiioplentaidctlseaswserurowwsfuweiiatltodcyhhnneoo’.’tuumttihlsleeasatitvnneygyyoouu 278   Chapter 7 More free ebooks : http://fast-file.blogspot.com 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. AHthestrereir’osprhaoyccskilcaesstssCttluhobatduisftefhseerteOonbtsjeenpcdltavnielltes. Here’s an public class PlanetMission { public long RocketFuelPerMile; public long RocketSpeedMPH; public int MilesToPlanet; example... It doesn’t make sense to set these fields in the base class, because we don’t know what rocket or planet we’ll be using. public long UnitsOfFuelNeeded() { TomnhiesesitoaonstsV—reoonpnuhesy.sticoisMtsarhsa,veantdwo public class Venus : PlanetMission { public Venus() { MilesToPlanet = 40000000; RocketFuelPerMile = 100000; RocketSpeedMPH = 25000; 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.”; } } public class Mars : PlanetMission { public Mars() { MilesToPlanet = 75000000; RocketFuelPerMile = 100000; RocketSpeedMPH = 25000; } } TfsihfurahbopeycmpolceauonsPnssilensawtssntrhesauetencnt.ttBoFitaruhutsteeelfNttPohehrlaeordtnseeeehetdeff(idMi)eeillrdtaderrsscsietwtsalohynnte.d’yoStVouingeshewenteuhtrsasihtteeetmd? 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... More free ebooks : http://fast-file.blogspot.com you are here 4   279 abstract classes avoid this mess Like we said, some classes 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()); } WmbiytyoehutewRhnadoositcdvkhzideeteterrFSioebup.dyeeAleNtzndoedeMredodwPi,evhHidted,h(ne)is happens. stfotiTwhnrnaasaholrtystmetna’ss’enPtuidttwlpa.i.wpahnoBtreesiretuteedtMtd.etwiWtnsheoseeitodiopwnnirhdebcoer,elbreaalisetnsmds 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 declaration abstract keyword to the tells C# this is an abstract class class, and can’t be instantiated. Now C# will public abstract class PlanetMission { refuse to compile public long RocketFuelPerMile; our program until public long RocketSpeedMPH; we remove the public int MilesToPlanet; line that creates an instance of public long UnitsOfFuelNeeded() { PlanetMission. return MilesToPlanet * RocketFuelPerMile; } // the rest of the class is defined here } 280   Chapter 7 Flip back to the solution to Kathleen’s party planning program in the previous chapter on pages 236–238—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? More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes An abstract method doesn’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 dropdown box with a list of any methods that you can override. Select the SetMissionInfo method and fill it in: public 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... Tsbheohuaeritssitnatahbonaeysntimprcriplanaolctsegtsemrramtefmnhaetactwteht—ooihndnie’thtieSsdrceiojottuemsMsstpnfii’lstrlesiok.iohmenaIwvPnehflaaoant(e)btyomModueyi’tsd,shioodn If we add that method in and try to build the program, the IDE gives us an error: It really sucks to be an abstract method. You don’t have a body. 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. public class Venus : PlanetMission { public Venus() { SetMissinInfo(40000000, 100000, 25000); } Wfcoarlvbhaoesesmrtsnr,riaayydncooetuuaabminlnlseehteoterdfhraiocttidttoss. public override SetMissionInfo(int milesToPlanet, long rocketFuelPerMile, int rocketSpeedMPH) { this.MilesToPlanet = milesToPlanet; this.RocketFuelPerMile = rocketFuelPerMile; this.RocketSpeedMPH = rocketSpeedMPH; } } you are here 4   281 More free ebooks : http://fast-file.blogspot.com worth a thousand words 本页已使用福昕阅读器进行编辑。 福昕软件(C)2005-2007,版权所有, 仅供试用。 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: What’s the Picture ? 1) public interface Foo { } (interface) 1) Foo public class Bar : Foo { } 2) public interface Vinn { } public abstract class Vout : Vinn { } Bar 2) 3) 3) public abstract class Muffie : Whuffie { } public class Fluffie : Muffie { } public interface Whuffie { } 4) 4) public class Zoop { } public class Boop : Zoop { } public class Goop : Boop { } 5) 5) public class Gamma : Delta, Epsilon { } public interface Epsilon { } public interface Beta { } public class Alpha : Gamma,Beta { } public class Delta { } 282   Chapter 7 More free ebooks : http://fast-file.blogspot.com 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. Given: Click 1 What’s the Declaration ? 1) public class Click { } public class Clack : Click { } Clack 2 Top 2) public abstract class Top { } public class Tip : Top { } Fee 3 Fi Tip 3) public abstract class Fee { } public abstract class Fi : Fee { } Foo 4) public interface Foo { } 4 public class Bar : Foo { } public class Baz : Bar { } 5 Beta Zeta Alpha Delta Bar 5) public interface Zeta { } public class Alpha : Zeta { } public interface Beta { } public class Delta : Alpha , Beta { } Baz Clack Clack Clack KEY extends implements class interface abstract class More free ebooks : http://fast-file.blogspot.com you are here 4   283 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: 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. You can’t really think you’re more important than me. You don’t even use real inheritance—you only get implemented. 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. Interface: Nice. This oughta be good. 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! 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 4) Zoop Boop 5) Delta (interface) Epsilon Gamma (interface) Beta Fluffie Goop Alpha What’s the Picture ? 284   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Abstract Class: You might be overstating your power a little bit. That’s exactly the kind of drivel I’d expect from an interface. Code is extremely important! It’s what makes your programs run. Really? I doubt that—programmers always care what’s in their properties and methods. Yeah, sure, tell a coder he can’t code. Interface: 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. 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. Okay, 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! Whatever! 2) public abstract class Top { } public class Tip : Top { } 3) public abstract class Fee { } public abstract class Fi : Fee { } 4) public interface Foo { } public class Bar : Foo { } public class Baz : Bar { } What’s the Declaration ? 5) public interface Zeta { } public class Alpha : Zeta { } public interface Beta { } DfimreolptmlaemAinelhpnhterasitBasnedta. public class Delta : Alpha, Beta { } More free ebooks : http://fast-file.blogspot.com you are here 4   285 multiple inheritance sucks I’m still hung up on not being able to inherit from two classes. If 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 sublcass 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! TfSSerhcloeormvewiesAnMioMWnoiovdaviteniePhd(l)apMyrmeooerpvt,eiehraTotndyhd.,eabBttoooetotrh.hboiovntehrherriiidntheettrhihete Television MoviePlayer int ScreenWidth ShowAMovie() MovieTheater ShowAMovie() ShowAMovie() IpmMWurtfasoooheegpvaaiesintbtehreoTutohtrwythaehhepibaafpsvtoteaiultnelmustsrhees,hd?simefwoabiSHftdychoerSbm-edcoeefritTfnoehWfrehe-neTirdWTaeettlniVedhetvrtimshvinao—oelvnuesieedaassysn.,datnod HomeTheater ? HwWohmheiencThyhoSeuhaotcwaelrAl MoSbhojovewicetA(?)Mmoeviteh(o)donrutnhse Avoid ambiguity! 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(). 286   Chapter 7 More free ebooks : http://fast-file.blogspot.com 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. public Nose { ; string Face { get; } } public abstract class : { public virtual int Ear() { return 7; } public Picasso(string face) { = face; } public virtual string Face { { ;} } string face; } public class : { public Clowns() : base(“Clowns”) { } } public class : { public Acts() : base(“Acts”) { } public override { return 5; } } cHoemrep’lsetteheC#entprryogproainmt.—this is a public class : { public override string Face { } get { return “Of76”; } 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 int Ear() this this. face this.face i i( ) i(x) i[x] get set return class 5 class 7 class 7 public class i.Ear(x) i[x].Ear() i[x].Ear( i[x].Face Acts Nose Of76 Clowns Picasso Answers on page 306. More free ebooks : http://fast-file.blogspot.com you are here 4   287 form of... a bucket of eagles! Okay, I think I’ve got a pretty good handle on objects now! oypfryTcforeiolruoahvuis’gsoetvrtsrleeuaiadidstnbmsaeiteaostajernnaunsodatsodtrahbouynfaupbcdatiloejlardednyy,icine—onotsuguowpsbrruhcaywotcoleoalgonuusrtdyldaiohceatmuaacritnmwno’tmasiCtnosbhg#hii.onnwek 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 called 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 princples 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. This just means having one class or interface that inherits from another. ttopphohatErrafenhoitnvepcpioarettaatbrsphrjectestesliuactfyeltsoasaisentftealteedisnoehtsdndawih,ntoetammtrnekoieekndreattnsenwheauepsoieslrstled.ycnhstsraurelpotsaaundiotcnblaykigllntiecgat Inheritance Abstraction Ycmatornhouedar’artetetegihnueeashnnienecrgrhliaaatasls—sbfmsrmotoororrmdaeacebitlstspit.toernhcaaifcwttihc—setnccallaryastossssueessw,ith Encapsulation Polymorphism “TpmCthfohiaeaomleyansremnmwtysoswoaor“rukhipmndeehtnaniyhnsoomaiynunn”krfmoolocibrtafomjnedeyrsace”at?.lly 288   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Polymorphism means that one object can take many different forms 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 eyes open for polymorphism in the next exercise! 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 for it. 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 the code that 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; 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. Upcasting by using a subclass in a statement or method that expects its base class. spot = new Dog(); zooKeeper.FeedAnAnimal(spot); paIfansdsFeDDeodoggAintnAohneFirmeiteasdl(A)frneoAxmnpiemActanlsi(m)a.anl, Atnhiemnalyooubjceacnt, Creating a reference variable whose type is an interface and pointing it to an object that implements that interface. IStingPatrol defender = new StingPatrol(); This is upcasting, too! Downcasting using the as keyword. void MaintainTheHive(IWorker worker) { if (worker is HiveMaintainer) { TturahseekefseeMsraeaasnnicyetnoIttoWpaooitinrnhtekTaehwroeHrHikaievsrvea.eMp(aa)rianmmteeattehiron.deItr HiveMaintainer maintainer = worker as HiveMaintainer; ... More free ebooks : http://fast-file.blogspot.com you are here 4   289 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. Location Location is an abstract class. That’s why 1 Start with this class model Name we shaded it Every room or location in your house will be represented by its own Exits darker in the object. The interior rooms all inherit from Room, and the outside class diagram. places inherit from Outside, which subclass the same base class, Description() 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 Room Decoration Outside Hot Location, Room and Outside classes to it. 2 You’ll need the blueprint for the house This house has three rooms, a front 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. Front Yard Living Room Dining Room Kitchen This symbol is an exterior door rboeotmw.eeTnhtehree’sfraolsnotaynaredxtaenrdiorthdeoolirving between the kitchen and back yard. Garden isInnosmaiderekelaiondcd-atooifnolnyaspderaeoccpoherrhattayvi.oen Osroeuattdshi-deoeOnlluoytcbsaitodoieolencaslnacsapsnrhobapeserahtoyt, called Hot. Back Yard 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. 3 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 location that has one (the front yard, back yard, living room, and kitchen) should DoorDescription implement IHasExteriorDoor. The DoorDescription read-only property DoorLocation 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). 290   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes 4 Here’s the Location class To get you started, here’s the Location class: public abstract class Location { public Location(string name) { this.name = name; Tpfriheoelpdec,rowtnyhst’iscrhbucaitscoktrinhgesetfresiealtddh-.eonnlaymNe ame TrdtotEwdtehhfeohietxeselselcui(ttcywrDrnnhrs’inaehl[beielspmei]YesovDctdolcseaivoohrivfreeuoctettaissri’inapetrltcohunrlttlrraredidsidinicfiillodopn)ihereiangmn.tgeneoahsidIideonlopttttiititsmgsnrt.lhsttyhe.o,iao,oinspctsiotudenso}fbthora.cncehtlnualeyeadlclsitsn}ppp}p}esgsuruubibblvlliaigig}ctceceettLsvost{i{sf}drctrrtoeearirtrrsttineuicuingtan+(dirrogulgiefinnNr“nsp[nansd.tc(td]amteridiemenrsYiieosEeaicop!sncx;{mnru=t=criegiir+it;ps0oEi=psDte;nxpt;}eieit“isoi+ti.ocne=so”nrx<.n;;i=i“LptEe+t“sx”n=iYigToott+t“Lolhnuosh,ofoec’.E”caaa{rtLx-;ptltuleheiiibooent1olnnfisgs)cctft[rtEoeaohihnfxnl;]eneidl.terocesioiNttnnw+afhscgi+meieetrsn)elodiLig;rtnpi.aRnen{slhobiahtfesapcscemaettaeatlrrnrtesniehattkaminotiececaabcnfethretee,prare“srsctobav,:lmauyiattLt+trsr.hoisi”oaat—yficn;csboakalyauetonmsiudcoeoancdfnTwaaDtdawt’ietsnnohinteceieldleldcmlyaslaaocnpopdrRaeOrreveexddioaeurptdtortattemritsointhioiudnddehncr,eeelea.ss 6 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. Here are the class declarations to give you a leg up: Gdeettatilsheabcolaustsetshsetmarotnedthneowne—xwtep’lal ggeiv.e you more public class OutsideWithDoor : Outside, IHasExteriorDoor { // The DoorLocation property goes here // The read-only DoorDescription property goes here } public 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! More free ebooks : http://fast-file.blogspot.com you are here 4   291 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. 6 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. Garden Outside obj BackYard Outside obj t FOostIuHbruhbjtoaaecnsstclEitadtiYsxme,staWwpreolihrdeftiimhcoiOhDresnDuoaittsoonssroaidr.e LivingRoom is an instance of RoomWithDoor, which inherits from Room and implements IHasExteriorDoor. DoorLocation DiningRoom Room objec ec t ect Door objec or object t FrontYard OutsideWith DoorLocation LivingRoom RoomWithDo Exits[] Yiainmotsupuelebrstmfcaalearcnsettseaoditnfd.bOuOaiunlddtedisneiidngdhet.ethrNhieteossIweHfaitrtswoE’smoxttcRielmaorseoisomerts,Dottofhhoieanrtioshthtehremis. Exits[] Exits is an references. array of Location LivingRoom has 7 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. one exit, so its Exits array has a length of 1. ≥ 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 RoomWithDoor livingRoom = new RoomWithDoor(“Living Room”, Exits is an “an antique carpet” , “an oak door with a brass knob”); own field in the form class. aLrschoreraorfesctaeaahtyrtteiwesionsoofclnioenr≥nsee,efearfYneordnucoternhsCtaitrnYeaitar.tde.OEbx上 相jiet面 当cst这 于s=行 用()n是 {}em里w初e的th始Lo参o化dc数na对et多e象id次os数nto调[组p]用o的p{构u语la造b法tae函c,thk数eYEaxrid有L可t,os一以c[ga]点natierof不iwndel是e?d太ni抽n明}e象白a;c类:h ,ob为jec何t: TAccuahnruyelsstyeehbiaanrnrgaeceekrlseretosrw..ill 292   Chapter 7 More free ebooks : http://fast-file.blogspot.com 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 textbox 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. Hsteehtreeu’CspowwmhhbeaortBe opyxoop.uu’lllates abCnuloticttkhoentrhteloogcmaotoHvieoernet. o This is a multiline TextBox that displays the Description() of the current location. It’s name is description. The ComboBox contains a list of all of the exits, so name it exits. Make sure its DropDownStyle is set to DropDownList. 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. TwamtsgenhhooatieTksettnexhribntyruuigteooetruutivoi’gtoroirhsserniTbfVidilhnasieoselsiooaDboenrr.lorl.eyIooiYtnprovo’vr.msiusiosicpbiwcbaelailelrtelnethdyby ≥ 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 textbox 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. Hsineidnletecx:tWeodfheintndhyeeoxucoincrhrtoehospeseocnaodnminbigtoelombcoaxintiwotinhlleibnceotmthhebeoEsbxaoimtxse,[ia]tssatrhreay. YlybtAaooooecnuuLcao’aatltoclnuicahosnaneoenet’rbteDiojdoheujnocituntotsrtortoe:LtffdthYoeoayotcrwtpuaehenrtneiccim“ofaeocpnos.butlrjeSrimesmroicnf’eets’nten.yvtctoeauLsunrofrIwtHceieahanaltotnsdEiutLogixnnohtt.coDeLaitrtogo’ioiesocortranpLDtotfioioohncioneetar.litdn,digooinso”r More free ebooks : http://fast-file.blogspot.com you are here 4   293 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. public interface IHasExteriorDoor { string DoorDescription { get; } Location DoorLocation { get; set; } } Here’s the IHasExteriorDoor interface. public class Room : Location { private string decoration; public Room(string name, string decoration) : base(name) { this.decoration = decoration; } cTraoenhnadesdt-aRrdouodncotlsmyoarDclbsaeaecstcsoksriinantthgheieorfniiftepsiledrlfodrfp.ooemrrttyLh.oeIctastion public override string Description { get { return base.Description + “ You see ” + decoration + “.”; } } } public 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; } } } The RoomWithDoor class inherits fItHrhaoasmtEtxRthoeeormriooraoDnmdodoirmo.epsIl,tembdueotnetsisteavedrdystahing tdDDlaooerocoseoatoctrrrhrLiDieeopqontecucsioiotcarnnrthesidaitpootrtfnbui,toyctahnthIeoHreareadn.efsdoIxEetotrDxreeatnorlleescoioroaerirdLoatsrddooDcotdtaooosthr.oeiro.n 294   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes public class Outside : Location { private bool hot; public bool Hot { get { return hot; } } public Outside(string name, bool hot) : base(name) { this.hot = hot; } Outside inherits backing which is method is a lot like Room—it from field Location, and adds a for the Hot property, used in the Description() extended from the base class. public override string Description { get { string NewDescription = base.Description; if (hot) NewDescription += “ It’s very hot.”; return NewDescription; } } } public class OutsideWithDoor : Outside, IHasExteriorDoor { public OutsideWithDoor(string name, bool hot, string doorDescription) : base(name, hot) { this.doorDescription = doorDescription; } private string doorDescription; public string DoorDescription { get { return doorDescription; } lIfOiHkruaeotsmEsRidxoOoteumWetrWisitioidhtreDDhDoaoonoordro,riin.amhnpedlreimittsenlotosks a lot } private Location doorLocation; public Location DoorLocation { get { return doorLocation; } set { doorLocation = value; } } 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! More free ebooks : http://fast-file.blogspot.com you are here 4   295 exercise solution (continued) Here’s the code for the form. It’s all in the Form1.cs, inside the Form1 declaration. public partial class Form1 : Form { Location currentLocation; Tofhiswihsichhowrotomheisfobremingkedeipsspltayreadck. RoomWithDoor livingRoom; Room diningRoom; RoomWithDoor kitchen; OutsideWithDoor frontYard; OutsideWithDoor backYard; Outside garden; Tovafhreitahfbeolersrmotooumseksseientphtethsreeachrkoeufoseefr.eenacceh public Form1() { InitializeComponent(); CreateObjects(); MoveToANewLocation(livingRoom); } The the form’s constructor creates objects and then uses the MoveToANewLocation method. private void CreateObjects() { livingRoom = new RoomWithDoor(“Living Room”, “an antique carpet”, “an oak door with a brass knob”); erttnWaihehgceehhehdetconsolbainnttjsefoehs’oceseitsrncmsfsao,toannrfatdsmnitirotrpsncituaarcsttetisoteaottrhe. es 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); tHheered’soowrhedreescwreipptaiosns to diningRoom.Exits = new Location[] { livingRoom, kitchen }; the OutsideWithDoor livingRoom.Exits = new Location[] { diningRoom }; constructors. 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; toFhboejreircttdhseo, owIrHealonsEceaextdtioetrnoiso.sreDtoor Here’s where the Exits[] array for each instance is populated. We need to wait to do this wucnroteuailldtanedf’t,tehbraecvaealulastneyhotethihinnesgtrwatniosceepsuwtaeriento each array! } 296   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes private void MoveToANewLocation(Location newLocation) { currentLocation = newLocation; TdihseplaMysovaeTnoeAwNleowcaLtoiocnatiinont(h)emfeotrhmo.d 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’ names to it. Finally, we set its selected description.Text = currentLocation.Description; index (or which line is highlighted) to zero so it shows the first item if (currentLocation is IHasExteriorDoor) in the list. Don’t forget to set the goThroughTheDoor.Visible = true; ComboBox’s DropDownStyle property else to “DropDownList”—that way the goThroughTheDoor.Visible = false; } Tcuhrisremnatkleoscatthieon“Gdooetsnh’rtouimghpltemheendtooIHr”asbEuxttteornioirnDviosiobrle. if 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; When the user the “Go here:” clicks button, it moves to the location selected in the combo box. MoveToANewLocation(hasDoor.DoorLocation); } } tWIHoeadsnEoewxedtncetraoisotruDcseuorotrrheenstoaLswokeceacytawinoonrgdettoinaaconcredsesrto the DoorLocation field. But we’re not done yet! 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! More free ebooks : http://fast-file.blogspot.com you are here 4   297 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 Add an IHidingPlace interface “CAclrdaesdasteEsexfaisrtnoiemnwgtpIhtreeomjfe”icrtsft,eaaptnaudrrteusotefottahdheedIDetxEhee’rscise. 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 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 3 hiding place, so it’ll Add a class for have to inherit from your opponent RoomWithHidingPlace instead of RSoo oemve.ry door will raolsoomhwavitehaahnideixntgerpiloarce. 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 it 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. ≥ Add a Check() method that takes a location as a parameter and returns true if he’s hiding in that location, or false otherwise. 4 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. 298   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes 5 Okay, time to update the form You’ll need to add a few buttons making them visible or invisible, Ycbwooehumfilobuersoeet,bhtoeehxxegceaetxpmotaepcttitslhwyarotutnhbtneuhitnestgayo.m’rnees and way only the as visible TotWhWpohidpheh1oenee0nnneibtyniutnotthmuo’tesanhckgMelieaiscsomtktvteeehxih(tefti),siormtbbnsohteulyxetts,htotfooanoandnerrdmti1dns0civ,csaipostltilluhbasinmelyettee.shdse.. to the form. And we’ll get depending on the state of a little more intricate with the game. Tdhoen’tmindedelde btoutsteotn’istscaTlleexdt check. You property. T“coht“tbhfhnuahCuhoeilnsyesthcerdektaiTvesnacoireatpskntxirmlh3btahtoue”elcheoneeepmdrtobrioeofftbuoorwoetp“mtydietCtthoh’r,oshhihuetdnte’ehryeahhcyie.bdekioidhesW”iiunidbnid’ncghflu”lgihaeto.npaunltgplrlsnooaleoigapwnctoeclet’eamdesw.doc—iIesfltthblsrh’ooyssoawamtyn,, 6 Make the buttons work There are two new buttons to add to the form. Flip back to ≥ The middle button checks the hiding place in the current room and is only visible when Chapter 2 for you’re in a room with a place to hide using the opponent’s Check() method. If you found a refresher on him, then it resets the game. DoEvents() and Sleep()—they’ll come in handy. ≥ 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 textbox, 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 the opponent. It resets the opponent object so that he starts in the front yard again—he’ll hide when the user clicks 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 the player 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! More free ebooks : http://fast-file.blogspot.com you are here 4   299 exercise solution Build on your original house program to add more rooms, hiding places, and an opponent who hides from you. jtHuhesatrteh’sraestthouenrennsestwtrhiIenHgindafimniegelPdolafwcietthhinetahegridefitancgaec.pclIaetcsseo.r public interface IHidingPlace { string HidingPlaceName { get; } } public class RoomWithHidingPlace : Room, IHidingPlace { public RoomWithHidingPlace(string name, string decoration, string hidingPlaceName) : base(name, decoration) { this.hidingPlaceName = hidingPlaceName; } private string hidingPlaceName; public string HidingPlaceName { get { return hidingPlaceName; } } TfacrdhooendmsitRngrRouootcmothmWoeriHtasnhieddHtinisdigmiiPntpglslaePcbmleaaeNccnekatimsnceglIaHspfsirdieoiinlnpdhge.erPrtliaytc.seTbhye public override string Description { get { return base.Description + “ Someone could hide “ + hidingPlaceName + “.”; } }} public class RoomWithDoor : RoomWithHidingPlace, IHasExteriorDoor { public RoomWithDoor(string name, string decoration, string hidingPlaceName, string doorDescription) : base(name, decoration, hidingPlaceName) { this.doorDescription = doorDescription; } private string doorDescription; public string DoorDescription { get { return doorDescription; } } citcRmtdSoahooiankanooosdencntmresegrWteauaRwolcitstoethootohoiddhmHrnieeit.ieWndcegRiiiiddtsnopegheotldPdDamhclaoaaWeetocviherenti.irathdiyTmnsHinheihrcdgeeooriaonnpinotmgsldantPclfrywlesarue,iccotntewmhdoesra private Location doorLocation; public Location DoorLocation { get { return doorLocation; } set { doorLocation = value; } } } 300   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes public 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 just like RoomWithHidingPlace IHidingPlace does. public override string Description { get { return base.Description + “ Someone could hide ” + hidingPlaceName + “.”; } }} public class Opponent { private Random random; private Location myLocation; TsotfhaerRtOainpndpgoolnmoec,nawtthicoiclnah.ssIittcocunrsseetasrttueocstmaoronvetewarkaiennssdtaoamnclye between rooms. public Opponent(Location startingLocation) { myLocation = startingLocation; random = new Random(); } public void Move() { if (myLocation is IHasExteriorDoor) { IHasExteriorDoor LocationWithDoor = TumhrnaohotosveimelaMsiht5toa0ovfse%ia(an)drcdsmahonaeaodntrchoheimuodsdoiinlnfogfgcigarptotslhatiineocgneci,.hsteahkcnrekdoysuwkigofehredtpits—h.emiTfcohuvsreionnr,geiinttt myLocation as IHasExteriorDoor; if (random.Next(2) == 1) myLocation = } bool hidden = false; while (!hidden) { LocationWithDoTkitoehreetp.ogsDutlotorsooupreoiLnfwgohtcuehnanettiiMtil otofnhviene;(d)vsamraieartbohloeomdhiwidsidttehhnisaiswhtihdriliueneg—lopoalpan.cdeIt.it sets int rand = random.Next(myLocation.Exits.Length); myLocation = myLocation.Exits[rand]; if (myLocation is IHidingPlace) hidden = true; } } public bool Check(Location locationToCheck) { if (locationToCheck != myLocation) return false; else return true; The Check() method just checks the opponent’s location against the location that was passed to it using a Location reference. If they point to the same object, then he’s been found! } } We’re not done yet—flip the page! More free ebooks : http://fast-file.blogspot.com you are here 4   301 exercise solution int Moves; (continued) Htcnlhueamresesbl.oeaIcrrtaeotufiasolenlmsst,othvtheehesemftieohtlpedopsopknlieaneeynptetrhtearhnaaFdcsokrtmmhoafe1de. wTsWsoeihentet,sahnFduaoopdttretmidwth1heaoecnnooblpnyoypsootodluenrisaeufpnnclittarpo,ysartsarncaistdtrmseaetarmtthteeeerssnuspattrgohetesehReewtoehbsspeejrtetnohcGgtyeraosamg,umaem.()e. Location currentLocation; RoomWithDoor livingRoom; RoomWithHidingPlace diningRoom; RoomWithDoor kitchen; Room stairs; RoomWithHidingPlace hallway; RoomWithHidingPlace bathroom; RoomWithHidingPlace masterBedroom; RoomWithHidingPlace secondBedroom; public Form1() { InitializeComponent(); CreateObjects(); opponent = new Opponent(frontYard); ResetGame(false); } OutsideWithDoor frontYard; OutsideWithDoor backYard; OutsideWithHidingPlace garden; OutsideWithHidingPlace driveway; Opponent opponent; private void MoveToANewLocation(Location newLocation) { Moves++; currentLocation = newLocation; RedrawForm(); } private void RedrawForm() { exits.Items.Clear(); The new MlocoavteTioonAaNnedwLthoecnatrieodn(r)awmsetthhoedfosertms. the 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; check.Text = “Check “ + hidingPlace.HidingPlaceName; check.Visible = true; } else check.Visible = false; if (currentLocation is IHasExteriorDoor) IdpdCnHWrooauieowdemrpsinrnenenece,gr’natePtbtsdyutlhLat,atctosvehwcoheeaeevwtaa’hvrireieoeHdinafciiobdneanolgrinelbnye.gjpnuePlgscaceoeltcatecatwesotNhhtaiaeocnmhe goThroughTheDoor.Visible = true; else } goThroughTheDoor.Visible = false; RedrawForm() populates the combo box list, sets the 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. 302   Chapter 7 More free ebooks : http://fast-file.blogspot.com 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! More free ebooks : http://fast-file.blogspot.com you are here 4   303 oops, i did it again (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 + “.”; } Moves = 0; hide.Visible = true; goHere.Visible = false; TbduihsteptlaoRynesssetetxhGceeafpmtien(at)lhmmeee“stHshaidogdee!,”rteohsneeetnsimntvahikseiebsgleaa.mllet. hIet check.Visible = false; goThroughTheDoor.Visible = false; exits.Visible = false; } private void check_Click(object sender, EventArgs e) { Moves++; if (opponent.Check(currentLocation)) ResetGame(true); tdLuLhWhosiuoadewcatcinkncwacigctpalayeoinosp,sittnsnlwattctiersteooe,ctfttdaoebohnirusteetapuhnnlsHaecCeyeiIdusH,tratiisnhrmdhogeeieePnniatgtlnoasPLabcdlmkjeaooeeNcceecyeastawotnm.rf’oitoeerfntdgfehiirisveteeeolnadc.e else RedrawForm(); } private void hide_Click(object sender, EventArgs e) { hide.Visible = false; for (int i = 1; i <= 10; i++) { opponent.Move(); 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). description.Text = i + “... “; Application.DoEvents(); System.Threading.Thread.Sleep(200); } fdiRnroeoeCmzsheneam’ntp.btereerrfDr2eo?sEhWvietintstehslof(u)tafnirtdo,mtthhFeelaptsrehoxygtTrbahomixnglooks description.Text = “Ready or not, here I come!”; Application.DoEvents(); System.Threading.Thread.Sleep(500); goHere.Visible = true; exits.Visible = true; MoveToANewLocation(livingRoom); } 304   Chapter 7 TgiTobsnatphuvhmapetiesoretihntb.oMieslndTenoe.otahvfTneebftdTuhofotettiAtnrmhhoNseoteintevpewctilcs.oahLomFyitunoebhingcnroetaaitsiltobnliynotod,texonoih(tt1)eve0hsismmlaiiibtavsealiktnenmsedh,gtsaoaaktdrtnreoehdtoclelsiamsttltsf.lhtsehiehlrefnest RedrawForm(). More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes 1 2 Objectcross 3 4 5 1 6 2c 3 b od y 8 m 6 p9 10 l 8 i 9 e 10 7 4 5 7 11 12 13 14 13 11 12 14 a b s t r ac t 15 16 15 i n he ri t s 16 f 17 i 17 e 1188 l d Across Across 3. 4. WC#hadtoaensna't346b...asWCWltlro#ahhwaedctnot_aeymns_one_ua'tbt_phas_alotlrs_oadsw_catd__mo_s_uee__bt_s_hc_n_ola_'d_ts_sd_hino_taoe_hvs_aeen_rm'_titheainatnhhvoceedreit.tahnactee.xpects its 6. When youbpaasessclaass,uybocul'aresusstinogathmis eOtOhPodprtinhcaiptle.xpects its DDoowwnn 1m1mO..oOoWWrrPeehhpaeaernignngeyceyoniponuelreuema.rlmoacvllaoecsvclsaeotsmhcsamottmothhnamemtyoteahntlhleoimnydhesaetfrlhrlitooifnmrdohssmep,freriytcooifmfuric'orecsmlpau,sseysinceogisfuitcth'oriecs lausssinegs tthois O2O. IfPapcrlainsscitphlaet.implements an interface doesn't implement all base class, y8o.uT'hree OusOiPngprtinhcisiplOe OwhPerperyinoucihpildee.private data and only 8. The OOP pexripnocsiepltehowsehmereethyodosuahniddfeielpdrsivthaatteodthaetraclaasnsdesonnelyed expose thosea1c0mc. eOestnshetoood.fsthaenfodurfiperlidncsiptlheastoof OthOePr tchlaatsysoeusimnpeleemdent using access to. the colon operator 10. One of th1e4.foEuverrpyrminecthipoldeisn oanf OintOerPfactheaist ayuotoumimatipcalellym_e_n_t__u_s_in__g__. 2o.fIiftsamceltahsosdst,hgaetttiemrspalendmseenttetsrsa, tnheinnttehrefapcroejedctoweosnn't't implement all o_f_i_ts__m__e_t_h_o_d.s, getters and setters, then the project won't _57_.._AE_nv_ear_by_tsht_rina_gc_ti_ncl.aasnsinctaenrfaincceluidseaubtootmh aatbicsatrlalyct and 5_._E__v_e_r_y_th__in_g_ mineathnodins.terface is automatically 79..AYnouacbasnt'tra__c_t_c_l_a_s_s__c_a_nainncalbusdtreacbt coltahssa. bstract and the colon ope1r5a. tYoorur class that implements an interface that __________ 14. 15. YEovuerryclmasefm1srt7ohet.mohmAdabantenianroiscmtchatepoensorles.iinnmmtteeeorfdrnafifatciseecr,eatthhnieasintn'asytuenootruoftanmvecaeaeliddtitctfhooaarilmtlayn_py_l_et_h_mi__neg__n__tina__sl_l_ido__ef__iat_sn_. from anotherinintetrefarfcaec. e, then you need to implement all of its _1_1_. A__cl_a_ss__th_a_t i_mpmleemthenotdssth. is must include all of the methods, 91g111.e23.Yt..tAoTeWrhucshelacaaitsansydnksoe'suttyeh_dwttao_eotrr_wsdi_mittrhh_epa_taultn_erint_minsd_teete_rfnruin_feate_scsife.taahnnis_a_mb_su_t_sra_t _cin_t_cc_llu_ad_sesim.apllleomfetnhtse methods, gaenttientresrfaacned. setters that it defines. members too1.8. Object __________ Programming means creating programs 1126.. WAnhinatteryfaocuedcaonw't tiethchannicainllyteinrfcalucdee a __________, but it 17. An accestshamt coodmifbieinretyhoautr'sdantoatavnadlcidodfeortoagnetyhtehriningtoicnlassidseesaannd interface. objects. 1c3a.nTdheefiniiessgkeettyewrsoarndd rseettuterrnssthtartuleooikf jaunst _lik_e_o_n_e_f_ro_m_t_h_e_ implements aonutisnidteer. face. 18. Object __________ Programming means creating programs 16. An interface can't technically include a __________, but it that combine your data and code together into classes and can define getters and setters that look just like one from the objects. outside. More free ebooks : http://fast-file.blogspot.com you are here 4   305 exercise solutions Pool Puzzle Solution from page 287 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.piiHnnretorPopeiec’tsrahtsweysho.ce,orwneshtticrhhuecittAocritn, shwechrliiactshss fgceratollmss .sttIhoterepcdaosnsisnetsrt“uhAcetcoftras”ce public interface Nose { public class Acts : Picasso { int Ear() ; public Acts() : base(“Acts”) { } string Face { get; } public override int Ear() { } return 5; } public abstract class Picasso : Nose { } public virtual int Ear() { public class Of76 : Clowns { } return 7; } public Picasso(string { this.face = face; } public virtual string get { return face } string face; face) Face { ;} Patttbprhohupoeeterpyaeec’iarrrtlaedt’ssaiseany!pstyoeIwurtctrfha’hseencecreoteatdlsyoieinepr,if vftaahlciedebptorotothpoaemrvetoytfhaetthe Picasso class. public override string Face { } get { return “Of76”; } 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 += ( i[x].Ear() + “ ” + i[x].Face ) + “\n”; public class Clowns : Picasso { public Clowns() : base(“Clowns”) { } } } MessageBox.Show(result); } } iafrFnrehaaeteccurderietenfepsidisrntoeaihpndeetgroievnttatylPu.haeieBcccaoosesftussbhsotcoolrhaafenstdsthehsa.etm 306   Chapter 7 More free ebooks : http://fast-file.blogspot.com interfaces and abstract classes Objectcross solution 2C 3B O D Y 1A B S 4M U L T I 5P L E M T 6P O L Y M O R P H I S M U B 7C I A L O L 8E N C A P S U L A T I O N E 9I T C C 10I N H E R I T A N C E R S O E T N 11I 12I T A 1O3 NM E N 1A4 B S T R A C T P T J E L 15I N H E R I T S R E 16F A C F M I T T 17P R I V A T E E E C N L 1O8 R I E N T E D Across Down 3. What an abstract method doesn't have [BODY] 1. When you move common methods from specific classes to 4. C# doesn't allow _____________ inheritance. [MULTIPLE] more a general class that they all inherit from, you're using this 6. When you use a pass subclass to a method that expects its OOP principle. [ABSTRACTION] base class, you're using this OOP principle. [POLYMORPHISM] 2. If a class that implements an interface doesn't implement all 8. The OOP principle where you hide private data and only of its methods, getters and setters, then the project won't expose those methods and fields that other classes need ___________. [COMPILE] access to. [ENCAPSULATION] 5. Everything in an interface is automatically [PUBLIC] 10. One of the four principles of OOP that you implement using 7. An abstract class can include bothyaobustararcet hanedre 4   307 the 14. colon Every ompeetrhaotodr in[INaHn EinRteITrfAaNceCEisM] aoutroemafrtiecaellyeb__o_o_k__s__:__h_t.tp:_9//_.faY__os_ut_-cf_ai_lne_'t_.b___l_o_m_g_es_tph_o_od_ts_..c_[o_CmOanNaCbRsEtrTacEt] class. [INSTANTIATE] More free ebooks : http://fast-file.blogspot.com 8 enums and collections Storing lots of data Finally, a way to organize my boyfriends! 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   309 More free ebooks : http://fast-file.blogspot.com nurse sharks and carpenter ants Strings don’t always work for storing categories 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: “OoSfutrienbagcePehamwtroaornlka”egreo’mrse“jnoNtbecsuotsfaintrgwCaaorslelterkcietnpogtr”lit.kreack OisonutuprhapeoccrrootdjnossetbSsrwtuoticunhtlgadotrPaaaeltlvorbewonele,tthNdheooesuecegst.havartluhCeeos lplterocotgborerapmaansodsneldy Worker buzz = new Worker(“Attorney General”); Worker clover = new Worker(“Dog Walker”); Worker gladys = new Worker(“Newscaster”); sTmhahokuiseldcnao’ndtyeascleloonmwseptiflheoser,senaotbypepreeo. sbTlaehsmev. aWBloiudrtkdetarhtecasl.aessjorbesaldlyon’t You could probably add code to the Worker constructor to check each string and make sure it’s a valid bee job. Although, if you add new jobs that bees can do, you’ve got to change this code and recompile the Worker class. But 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 okay to use. 310   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections Enums let you enumerate a set of valid values An enum is a data type that only allows certain values for that piece of data. allowed So we jobs: could define an enum called Jobs, and define the This is the name of the enum. The stuff inside the brackets is called the enumerator list, and each one of them is an enumerator. The whole thing together is called an enumeration. public enum Job { Tdwuethosiahteiesnehsigemlnara’stotuntcsheooienamnmgrvumeeamcaaktuer,etorrsbaaeautintntnogddre paste. } NectarCollector, StingPatrol, HiveMaintenance, Each of valid used job. as a tAJhonebyssecvaiasnluabee. BabyBeeTutoring, EggCare, HoneyManufacturing, Swtceihutperhalrywaahbtocreloaemecaetmc.hahi,ngvaanwlduietehnda But most people just call them enums. Now, you can reference these with types like this: This is the name of the enum. tyFhoieunaewlnlayun,mtt. hferovmalue Worker nanny = new Worker(Job.EggCare); Any other values aren’t allowed. You can’t just make up a new value for the enum. If you do, the program won’t compile. Wtpoea’rvaaecmcceehptatenrgWetodyrpkteeh.re.JWoobrskaesr constructor its private void button1_Click(object sender EventArgs e) { Worker buzz = new Worker(Jobs.AttorneyGeneral); } Hferroem’stthhee error you compiler. get X ‘Jobs’ does not contain a definition for ‘AttorneyGeneral’ More free ebooks : http://fast-file.blogspot.com you are here 4   311 names are better than numbers Enums let you represent numbers with names 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 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. This enum is inside the DogCompetition class (a lot of the time, your enum won’t be inside any class!) , so if you want to use it outside the class you’ll need to call it DogCompetition.TrickScores. class DogCompetition{ TTrhiicskiSsctohreesDeonguCmo. mpetition. You can cast an int to an enum, and you can cast public enum TrickScore { an enum back to an int. These don’t have tpamtoanhurdebltteyisicpaoiulnmuelaeacrnnaanynomurmegdsbieveertr,o. } Sit = 7, Beg = 25, RollOver = 50, Fetch = 10, ComeHere = 5, Speak = 30, Supply a then the stands in nfnaoumrm.eb,erthtehnat“=n”a,me Tanunhmeinb(deinretxi)tocfraesp2tr0ets,eel(nlisnttst.)hTSeroiccsokimnScpceiolerTrer.SticopkeStackuorrtneu.trSnhpsiesaitikntihnoatstohe the int value 20. ... // code later in the class int value = (int)TrickScore.Fetch * 3; voSafilnuc1ee0t,Fotet3hic0sh.sthaats eamnenintdesexts MessageBox.Show(value.ToString()); TrickScore score = (TrickScore)value; MessageBox.Show(score.ToString()); You can cast the enum as a number and do calculations with it, or you can use the 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 index numbers by default. The first item YaetyroqooeuTuutrTacuilcracraitknncloSlskccSs“3acocSs0ortoper,re.eaeas.S.ncTkSoio”pnir.Snecettaerkgbvi.enaatSglcus(oke)s,wetisithoten 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: Yaeoxucilsatcsasonnlipkiuettstaohnwisn,enoourumtitsiindcseaidnoef public enum TrickScore : long { Sit = 7, Beg = 2500000000025 aTvashluliosenstgiesnl,lsntohtteheiTncrtioscm.kpSicleorretsoetnaurmecaltass. } yIfouy’dougettrietdhitsomceossmapgiele: this code without specifying long as the type, Cannot implicitly convert type ‘long’ to ‘int’. 312   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections Use what you’ve learned about enums to build a class that holds a playing card. v 1 Create a new project and add a Card class Card You’ll need two public fields: Suit (which will either be Spades, Clubs, Diamonds, Suit 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”). Value Name 2 Use two enums to define the suits and values. Make sure that (int)Card.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)Card.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(Card.Suits.Spades, Card.Values.Ace); string cardName = card.Name; The value of cardName should be “Ace of Spades”. Ttcolhaamstsawkteialkltenhseisetdwwooarpkca,ornyasotmurerutcCetraosrr.d 4 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 Cards.Suits and another random number between 1 and 13 as a Cards.Values. To do this, you can take advantage of a feature of the built-in Random toatWhvhemaharteenlntoloaahyntdooeediunr,’wg.v.i.ae.tyM’gsotoctorcaellcmaleaosodlnsrl ethatiiRiTgnnanihvttntiesdsnnoatiuumntelmmytlhsbbrRreeaaRerrnneaBBddndeeoodifttmmofmwwIeree=neteetnonnnet01egrwaaweeatnnryuddRsr31a=tn3no=drac=oaavrmnlalar(dliutna)oesdn;mNod.aetmoNx.meletN.xaeNt(sxe()ttx)m1(t;4(be)1tuht;,odu1n:4d)e;r 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() constructor. 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. More free ebooks : http://fast-file.blogspot.com you are here 4   313 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. public class Card { public enum Suits { } Spades, Clubs, Diamonds, Hearts 2zfWe,irhreseottn,cit.tyhoeeumsdienocnot’nthdespilseisct1i,fitysheveqaultuahelisr,tdothise public enum Values { Ace = 1, Two = 2, Three = 3, Here’s where we set the value of Card.Values.Ace to 1. Four = 4, Five = 5, Six = 6, Seven = 7, Eight = 8, Nine = 9, Ten = 10, Jack = 11, Queen = 12, King = 13 } public Suits Suit; public Values Value; tofWhfieehlCedCnasa,rrydydo.oSuucuslicaetastssn,.usjpiunscyteouuyrsoeuS’SuriuetitinassniiddnsetVeoaaflude public Card(Suits suit, this.Suit = suit; this.Value = value; } Values value) { TTccoahoSnentvtgerearintktgee(ad)acdcmtevoesatsnaohtrosatdgfreoirrneogtft.uhrtenhsNe iatwmsaeynapamrnoepeenrutmy’s public string Name { } } private get { return Value.ToString() + “ Here’s the code up the name of for the button a random card. that pops void button1_Click(object sender, of “ + Suit.ToString(); EventArgs e) { }crmoHaavesenettrdrhelot’oosmoaddwtntehhuodemergbReeeenanwruneemdrto.ahumtsaeet.Ntawehxeet() Random random = new Random(); Card card = new Card((Card.Suits)random.Next(4), (Card.Values)random.Next(1, 14)); MessageBox.Show(card.Name); } 314   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections We could use an array to create 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 index 0, the next card at index 1, etc. Here’s a starting point—a Deck that starts out with a full deck of 52 cards. public class Deck { private Card[] cards = { new Card(Card.Suits.Spades, Card.Values.Ace), new Card(Card.Suits.Spades, Card.Values.Two), hIwwTtea’rohsyeuisljdttuaoshtcrrorsoaanauvbtygebihndrsuetepevchailecaaaetlrld.eatedtchioken. new Card(Card.Suits.Spades, Card.Values.Three), // ... new Card(Card.Suits.Diamonds, Card.Values.Queen), new Card(Card.Suits.Diamonds, Card.Values.King), }; 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? More free ebooks : http://fast-file.blogspot.com you are here 4   315 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: Card object Card object Card object This but iatr’sraoynlyhasstoariLngen3gtcharodfs.7, ct6Iahnreaddyrese’xr. eeesqnu3oat,l4thoo, l5dn,uinlalg,ndsaony 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, which would hold the index of the last card in the array. So our 3-card array would havea Length of 7, but we’d set topCard equal to 3. natWurrelral’alclCyk.aaodrAfddnyhraeoinfwtdeorpemexCanancaryebd.ocvaferiedtlsdopatCroearkidneethpahse a TmFheretarhmeoe’sdwaobcrutkiultatlhliynattaondtoAheresre.aNxyEa.RcTteslyizte(h)at. 3 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 it 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 toCard, 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! 316   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections Lists make it easy to store collections of... anything The .NET Framework has a bunch of collection classes that handle all of those nasty issues that come up with you add and remove array elements. The most common sort of collection is a List. Once you creat a List object, it’s easy to add an item, remove one 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: 1 First you create 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. List cards = new List(); List o bject Ycliorstueasotpneeldycifthihoeleddsliennowcwehsetnthoiysou Card objects. 2 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 match whatever type you specified when you created your new List). cards.Add(new Card(Card.Suits.Diamonds, Card.Values.King); cards.Add(new Card(Card.Suits.Clubs, Card.Values.Three); cards.Add(new Card(Card.Suits.Hearts, Card.Values.Ace); You can add as many cards as you want to the List - just call its Add() method. It’ll make sure it’s got enough “slots” for the items. If it starts to run out, it’ll automatically resize itself. List o bject King of Diamonds Card object Ace of Hearts Card object 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. Three of Clubs Card object you are here 4   317 More free ebooks : http://fast-file.blogspot.com wow, what an improvement! Lists are more flexible 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(); 2 Add something to it. Egg x = new Egg(); myCarton.Add(x); 3 Add something else to it. Egg y = new Egg(); myCarton.Add(y); 4 Find out how many things are in it. int theSize = myCarton.Count; Actrhneeearwtee’dsLniosotntohtbihnjegechitneaiipst. But yet. Now the the Egg List expands object.... to hold x t..h.aendseceoxnpdanEdgs gagoabijnectto.. hold y x 5 Find out if it has something in particular in it. bool Isin = myCarton.Contains(x); dENegofgwiniinytsoeiudlyeccatonhmeseelaibsrtac.chkTfthoirrsuewa.noyuld 6 Figure out where that thing is. int idx = myCarton.IndexOf(y); The index for x would be 0 and the index for y would be 1. 7 Find out how much the list will hold. int limit = myCarton.Capacity; This will tell you the number of objects the list can hold before it has to resize itself. 8 Take something out if it. myCarton.Remove(y); poof! x When we removed y, we left only x in the List, so it shrank! 318   Chapter 8 More free ebooks : http://fast-file.blogspot.com 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 Aexsseucmuteetdheinseorstdaetre, moenneLtaissfattreer aallnoWtehefri.lled in them exactly right, a couple for you... so just make your best guess. regular array List myList = new List (); String [] myList = new String[2]; String a = “Yay!”; myList.Add(a); String a = “Yay!”; String b = “Bummer”; myList.Add(b); String b = “Bummer”; int theSize = myList.Count; object o = myList[1]; bool isIn = myList.Contains(b); Hint: You’ll one line of need code than here. more than More free ebooks : http://fast-file.blogspot.com you are here 4   319 one size fits all Your job was to 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. List List myList = new List (); String a = “Yay!” myList.Add(a); String b = “Bummer”; myList.Add(b); int theSize = myList.Count; object o = myList[1]; bool isIn = myList.Contains(b); regular array String[] myList = new String[2]; String a = “Yay!”; myList[0] = a; String b = “Bummer”; myList[1] = b; int theSize = myList.Length; object o = myList[1]; 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. 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. 320   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections Lists shrink and grow dynamically 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: SoWhfeo’eSrCeholdoeseeoctlba.jreicntgs a List called List shoeCloset = new List(); shoeCloset.Add(new Shoe() You can use a new statement inside the List.Add() method. { 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” }); int numberOfShoes = shoeCloset.Count; foreach (Shoe shoe in shoeCloset) { shoe.Style = Style.Flipflops; This returns the total number of Shoe objects in the List. shoe.Color = “Orange”; } The Remove() method will remove the object by it’s reference; RemoveAt() does it by index number. This foreach loop goes through each of the shoes in the closet. shoeCloset.RemoveAt(4); The Clear() method removes all of the Shoe thirdShoe = shoeCloset[3]; objects in a List. Shoe fifthShoe = shoeCloset[5]; shoeCloset.Clear(); shoeCloset.Add(thirdShoe); if (shoeCloset.Contains(fifthShoe)) tWwatodeehdetscewaloedvotaehrodseehnrdeor’eesbtfssahetbcreiekelflln,iocsmbtreuie.sstsWineg. 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. 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. ffoarceta,cthheloyopwsorwkorokn oannyarcroallyesc,ttioono.! In Here’s the Shoe class we’re using... public class Shoe { public Style Style; public string Color; } public enum Style { Sneakers, Loafers, Sandals, Remember, the Style inside enum isn’t the Shoe Flipflops, class, so it’s just Wingtips, Clogs, “Snottyle“.SShnoeea.kSetrysl”e,. } Sneakers”. you are here 4   321 More free ebooks : http://fast-file.blogspot.com membership has its privileges List objects can store any type 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 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(); Ltdyoisp,teas)ncodarntvhbeeernyeqirtuehisteterriacvtefriveyew.fStleohxinitbghlseeym(aodlrlooew.wihnagtaanyrrays The .NET Framework comes with some generic interfaces that let the collections you’re building work with any and all types. List implements those interfaces and that’s why you could create a List of integers and work with it using 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(), Insert() come from. IndexOf(), and public class List : IList, ICollection, IEnumerable, IList, ICollection, IEnumerable T. his is where Add(), Clear(), CopyTo(), and Remove() Tfohriseaincthearfmaocneg loettsheyrouthuisnegs. come from. It’s the basis for all generic collections.  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 an 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. 322   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections Code Magnets private void button1_Click(object sender, EventArgs e){ 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); List a = new List(); public void printL (List a){ if (a.contains(“two”)) { a.Add(twopointtwo); } a.Add(zilch); a.Add(first); } a.Add(second); a.Add(third); string result = “”; if (a.Contains(“three”)){ a.Add(“four”); } foreach { (string element in a) } result += “\n” + element; MessageBox.Show(result); } if (a.aI.nAddedx(Offo(u“rftohu)r;” ) ! = 4) { } } printL(a); string zilch = “zero”; string first = “one”; string second = “two”; string third = “three”; string fourth = “4.2”; string twopointtwo = “2.2”; More free ebooks : http://fast-file.blogspot.com you are here 4   323 exercise solution Code Magnets Solution private void button1_Click(object sender, EventArgs e){ List a = new List(); string zilch = “zero”; string first = “one”; string second = “two”; string third = “three”; string fourth = “4.2”; string twopointtwo = “2.2”; a.Add(zilch); a.Add(first); a.Add(second); a.Add(third); if (a.Contains(“three”)){ a.Add(“four”); } ttnoChoeuaovttnueghrwyhehogyulietist’“tfss2,iga.eu2dvre”dened declared here? a.RemoveAt(2); RemoveAt() removes the element at index #2—which is the third element in the list. if (a.IndexOf(“four”) != 4) { a.Add(fourth); } if (a.contains(“two”)) { a.Add(twopointtwo); } printL(a); The printL() method uses a foreach loop to go through a list of strings, add each of them to one big string, and then show it in a message box. } Tetlhehrmeoeufngothrseaailnclhotfhloeotplhisegtoes and prints them. public void printL (List a){ string result = “”; foreach { (string element in a) } result += “\n” + element; 324   Chapter 8 MessageBox.Show(result); } } More free ebooks : http://fast-file.blogspot.com enums and collections Q: So why would I ever use an enum instead of a List? Don’t they solve the same problem? A: Enums are a little different than Lists. 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: Arrays take up less memory and take less CPU time for your programs. If you’re doing something that’s really performance‑intensive—like the same operation thousands and thousands of Okay, honestly, we’re talking about a really, really tiny performance boost. Like if you have to do the same thing millions of times a second, use an array and not a list. times –then you might find that a List will cause your program to slow down significantly. 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 one? 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. Q: Okay, 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’s inside the bag, and not about how it’s displayed. 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. Generic collections are actually a recent addition to C#—they didn’t exist in the early versions of the language. But they’re so useful that people rarely use non-generic collections any more... which is why we won’t be talking much about them. When you create a new List object, you always supply a type—that tells 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. Tfiognanhescenteteastrnptaecehrlecamwitfoofi“cregkvLetesnnyieswptrteiith,cch”oatunhargenehoyfnLealtyrisysstspptteecooc.lriaftesihscein C# what type of data that it’ll store. A list can store a value type (like int, bool, or string) or a class. Ttagisehenaaetar’wsischpweochcloeiafltlieisccttgihenioensntereeesnotdofuiuffgaffheLritseoinsattwllotfarorbkooomwunteita.tnhIyytAtp’sehN.itnYBhgeutytywopuate’yhv.eetTsLhheaaietstnt’ysscoolwuafhssyar. you are here 4   325 More free ebooks : http://fast-file.blogspot.com 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 List(); You saw this code a few pages ago—it creates a List and fills new Shoe objects. it new with 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” }); The same Collection Initializers are a C# 3.0 feature. If you’re still using Visual Studio 2005, you should download Visual Studio 2008 Express for free from Microsoft, otherwise this code won’t work. code rewritten using a collection initializer You can create a collection initializer by taking each item that was being added using Add() and adding them to the statement that creates the list. List shoeCloset = new List() { The statement to create the list is followed by curly brackets that contain separate new statement, separated by commas. new Shoe() { Style = Style.Sneakers, Color = “Black” }, new Shoe() { Style = Style.Clogs, Color = “Brown” }, new Shoe() { Style = Style.Wingtips, Color = “Black” }, new Shoe() { Style = Style.Loafers, Color = “White” }, new Shoe() { Style = Style.Loafers, Color = “Red” }, You’re not using new limited to statements }; in the initializer—you can include variables, too. new Shoe() { Style = Style.Sneakers, Color = “Green” }, A collection initializer makes your code more compact by letting you combine creating a list with adding an initial set of items. 326   Chapter 8 More free ebooks : http://fast-file.blogspot.com Let’s create a list of Ducks Here’s a duck class that keeps track of your extensive duck collection. (You do collect ducks, don’t you?) Each duck has a size—this one is 17 inches long. Some of the are mallards. ducks enums and collections Duck Size Kind Quack() Swim() Eat() Walk() You’ve got some Muscovy ducks. Awnododyodue’cveoygso. t a few The KindOfDuck enum isn’t in a class, which is very common for an enum. Most enums you’ll run across won’t be inside classes. Here’s the initializer 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. List ducks = new List() { public 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. public enum KindOfDuck { Mallard, Muscovy, Decoy } We’ll use an enum called KindOfDuck to keep track of what sort of ducks are in your collection. new Duck() { Kind = KindOfDuck.Mallard, Size = 17 }, new Duck() { Kind = KindOfDuck.Muscovy, Size = 18 }, 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 }, }; More free ebooks : http://fast-file.blogspot.com you are here 4   327 getting your ducks in a row Lists are easy, but SORTING can be tricky 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 a 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. You could sort a list of ducks by size... Sorted smallest to biggest... ...or by type. Sorted by kind of duck... Lists know how to sort themselves 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 it how to sort your own classes. 17” duck 11” duck bject bject Duck object List o 11” duck Duck object 14” duck Duck object 328   Chapter 8 Sort() Duck object List o 14” duck After the list of ducks is sorted, it’s got the same items in it—but they’re in a diferent order. Duck object 17” duck Duck object More free ebooks : http://fast-file.blogspot.com enums and collections Two ways to sort your ducks The List.Sort() method already knows how to sort any type or class that implements the IComparable interface. That interface has just one member—a method called CompareTo(). Sort() uses an object’s CompareTo() method to compare it with other objects, and uses its return value (an int) to determine which comes first. 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 class that implements IComparer. That interface also has one method. The List’s Sort() method uses the comparer object’s Compare() method to compare pairs of objects, in order to figure out which one comes first in the sorted list. An object’s CompareTo() method compares it with another object One way to let our List object sort is to modify the Duck class to implement 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 sorted list, CompareTo() returns a positive number. You can make any class work with the List’s built-in Sort() method by having it implement IComparable and adding a CompareTo() method. Here’s a Duck class that sorts itself based on duck size: public class Duck : IComparable { public int Size; When you implement IComparable, you specify the type being compared when you have the class implement the interface. public KindOfDuck Kind; public int CompareTo(Duck duckToCompare) { MlmSoddIAiooifeutuznkstcctedikhrkta’eofC’sistidflisooeSusmltfrbtimdznipihgarlesaeiaglsklrtygzefeee’arreriTcei,,trenoolohdiis(mtttt.i).shp.rrItmaefeeTrhettseetthauusihhrmrostoinntes}dshshesse1-i.rz1e. ,eielflss(eertrrehieetifttusuur.rr(nSnntih1z-0i;e1;s;.>Sidzueckesseamweilltaylpweayins match: each. { ytYoyoupuewscaaonnft dicnoomtwhphaeartmieseovtenrshod. if (x.Size < y.Size) return -1; if (x.Size > y.Size) Tionhfte,tCahnoedmtphyaaprsee(ty)womou’erpteahrsoaodmrteritenetgru.sr:nbsoatnh } } Your List will return 1; return 0; 0oacbsomjmetechpataensrssissathomohneualctd(autlscbhiuenelgasttertieothaniwst)o.ed issPho“osguirtldeivaegtoe1ra”mfettahenarsnoobyb.jjeecctt x y. Ago-b1efmoeraensobojbejcetcty.xxshisou“lldess than” y. x sort differently depending on how you implement IComparer. 330   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections Create 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 saw a few pages code you already ago to initialize the list. List ducks = new List() { ... }; DuckComparer_bySize dc = new DuckComparer_bySize(); ducks.Sort(dc); Ynoeuw’llDpuacsksCSoomrpta(r)ear_rbeyfSerizenecoebtjeoctthaes its parameter. Sorted smallest to biggest... Multiple IComparer implementations, multiple ways to sort your objects You can create multiple IComparer classes with different sorting logic depending on what you need to do. Then you can call the comparer you want when you need to sort in that particular way. Here’s another duck comparer implementation: cctTooymhmpipepsa.arcrRioenemgmtphetamehreeberiernrus,imonwrdtKhesexinnbdvyya, oldyuuoeuusc.’kre class DuckComparer_byKind : IComparer { } public int Compare(Duck if (x.Kind < y.Kind) return -1; if (x.Kind > y.Kind) return 1; else return 0; } x, D“lcmueNloetceosmsakstpnuitaicsnyrhegeap)hunheot”Wep{nbKwrruahetieomnsa“h.epcdvgeedoWeiOrnrmededftaoapueDnitueacdxseskrutie,rsefcvhddfskaeitoenlnuv.cidccakthklsuos’eKaorifnedstoHhasrieentntrdaeesnd’oLdsriatsintninsbMgfeSewoxofuoraoosfmrMcrnkoepluaivlmstleyDtloba,soegre.wcferdohts,yhihcc.oeoahwrmn.dceeoEsnamnubreumeesmfsuossreed DuckComparer_byKind dcKind = new DuckComparer_byKind(); ducks.Sort(dcKind); Sorted by kind of duck... More free ebooks : http://fast-file.blogspot.com you are here 4   331 pick a card any card IComparer can do complex 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. public class DuckComparer : IComparer { public enum SortCriteria { } SizeThenKind, KindThenSize, This way enum tells the object to sort the ducks. which Htcldooaeeomrktkeepes’sasrarmtatehinemtdehoushceraoekmpwse.cuobItptmloiascprslCaSeomxrootmercttplteBaahrsrysese,(ftdb)oiuuemctldkesitt.thood public SortCriteria SortBy = SortCriteria.SizeThenKind; public int Compare(Duck x, Duck y) { if (SortBy == SortCriteria.SizeThenKind) if (x.Size > y.Size) return 1; else if (x.Size < y.Size) return -1; else if (x.Kind > y.Kind) This if statement checks the SortBy field. If it’s set to SizeThenKind, then it first sorts the ducks by size, and then within each size it’ll sort the ducks by their kind. return 1; else if (x.Kind < y.Kind) return -1; else return 0; else if (x.Kind > y.Kind) Instead of just returning 0 if the two ducks are the same size, the comparer checks their kind, and only returns 0 if the two ducks are both the same size and the same kind. return 1; else if (x.Kind < y.Kind) return -1; else if (x.Size > y.Size) return 1; else if (x.Size < y.Size) return -1; ItksfahinmeSdneoortkfthinBeddyc,uocitsmkhn.pe’tIanfrsietetrthcfeotimortswptSaoirzsedoesruTtcthkshesebniayKrrietnsihdzte,eh.e else return 0; } } DuckComparer dc = new DuckComparer(); dc.SortBy = DuckComparer.SortCriteria.KindThenSize; ducks.Sort(dc); HFwbjceuieehrrsfastecotn’asrgbneweyhesoct’cewadhhtlelaiiwntnnwegsght’aiedndaygnouuttcbsokhiejnaeseet.ctSetlhfio’sisriitstetSlcds(aooo)srm.rinttuNpBssatouryhwiateelrfs.yioTodeobulbuhdjcjeecekcnacstnt.. dc.SortBy = DuckComparer.SortCriteria.SizeThenKind; ducks.Sort(dc); 332   Chapter 8 More free ebooks : http://fast-file.blogspot.com vv Create five random cards and then sort them. enums and collections 1 Create code to make a jumbled set of cards Add a button to a form 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. You can view everything written to the output by selecting “Output” from the View menu while the program’s running. 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: public 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 a window: If you click on “Implement interface IComparer”, the IDE automatically fills 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. oiWtutraiptduedtLs wianienl(di)noemwt.eothtohdis, Your IComparer object needs to sort the cards by value, so the cards with the lowest values are first in the list. More free ebooks : http://fast-file.blogspot.com you are here 4   333 look it up Create five random cards and then sort public class CardComparer_byValue :theImC.oTcItoHCmhhmepoiesrpmaeabirp’mrsuaeepirltsrlteehsatti”lo,.uSn{oewosfthr,itacttk(hhh)eeeshmnactesatwtrhoohdenoicedrsao.mrsrSudetiosttirnshatg.on,(dd)w: thfCaiicorkhmsetspuasaernse(). public int Compare(Card x, Card y) { msRirItsfeeeattsmtmxhueeorammhdnlleaben1seirm.tr,a,sImrfbbeeeoditnxgtdui’gashretntrverhale-yvletua.1eu.luren, if (x.Value < y.Value) { return -1; } if (x.Value > y.Value) { return 1; } if (x.Suit < y.Suit) { return -1; } if (x.Suit > y.Suit) { Tesfwaxhiermeerscseteeuntvt’satetwldauoetexi—efremecttxeuhuntaartetnnsddm.sotneyalaythneasgmveteethntethse return 1; } return 0; } } tsItfhaetnsoeanmmeeeno—tfssotwhreeerteouthrhinte,rztefhroeou.rcarredtsurmnust be private void button1_Click(object sender, EventArgs e) { Console.WriteLine(“Five random cards:”); List cards = new List(); Here’s a generic List of Card objects to store the cards. Once they’re in the list, it’s easy to sort them using an IComparer. for (int i = 0; i < 5; i++) { cards.Add(new Card((Card.Suits)random.Next(4), (Card.Values)random.Next(1, 14))); Console.WriteLine(cards[i].Name); } Console.WriteLine(“Those same cards, sorted:”); cards.Sort(new CardComparer_byValue()); foreach (Card card in cards) { Console.WriteLine(card.Name); } } 334   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections Use a dictionary to store keys and values A list is like a big long page full of names. But what if you 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. dic tion ar y gdThueoehfwsiissneyiidtosuiotitnhlo)eoinakke(duyyipoc.tuIatio’nsary. • •• A book that lists the words of a language in alphabetical order and gives their meaning. This is the associated value. It’s the data with a particular key. Here’s how you declare a Dictionary in C#: Dictionary kv = new Dictionary (); TaonhteeystepeyapgreoeeflsoikrientLthheisetkrao.nTdyohuaencedrmectelyaapnrees for the value. tTtthhyheepeesdkeieanytr,eatp.ahrneedsaentnghtleetsbyerpcaeoscn.kdeTtihsseaislfwiaarlswytsays And here’s a Dictionary in action: private void button1_Click(object sender, EventArgs e) { Dictionary wordDefinition = new Dictionary(); rTkeehayilss,ddaicinctdtioiosntnaarrriyny:gstheaarssmst,thraeinndvgaldvuaeelf.ueiInstit’fsioolrnik.e a TmyathoenhuetdehaAvodddadidlcduti(eksi)soehnytoasowry. wordDefinition.Add (“Dictionary”, “A book that lists the words of a ” + “language in alphabetical order and gives their meaning”); wordDefinition.Add (“Key”, “A thing that provides a means of gaining access to ” + “our understanding something.”); wordDefinition.Add (“Value”, “A magnitude, quantity, or number.”); Add() takes a key, and then the value. } if (wordDefinition.ContainsKey(“Key”)){ MessageBox.Show(wordDefinition[“Key”]); } HIttehreleo’ovsakhlsuoekwinfydooruotfgheleitkketehyaenavtaarltruhaeiysfioinnrddeaexxk-.egye.t CthoentdaiicntsKioenya(r)y.tHelalsndyyo,u if a huh? key is in you are here 4   335 More free ebooks : http://fast-file.blogspot.com map anything to anything The Dictionary Functionality 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 the 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. string lookupValue = myDictionary[“some key”]; ± Remove an item. Just like a List, you can remove and 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. myDictionary.Remove(“some key”); ± Get a list of keys. You can get a list of all of the keys in a Dictionary urcoKseaneimncnyeosgh.vaeaVavraeaelKutkueehensyyeiqc,CuastaeonhmlieanelpDpaveeaicacDlutrteiico.iatnnToiayonhrnaynaaturkmnywn;bdoaeawyrnl,soyowwofkhhepeatyntimaytpeoopsu—eralteormwos kooevxukepae. cyotsrly through it using a foreach loop. You’ll usually use a Keycollection like this: ± Get a list foreach (string of values. key in myDictionary.Keys) { ... Keys is a property of your dictionary has string keys, sd}oi;cKteioynsairsyaocbojellcetc.tiTonhisofpasrttriicnuglsa.r You can get a list of all of the values in a Dictionary using a ValueCollection. Most of the time, you use a ValueCollection with a foreach loop too: foreach (string value in myDictionary.Values) { ... }; Since this dictionary has foreach identifier will be string values, a string. the 336   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections Your key and value can be different types, too 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. The Duck object has a Size field and Types enum that are set inside its constructor. Hdtdoeeurcctelka’hssr.eewWddhe.iec’Ilrtltei’aolldntasdhtreoyerd,aecigchintvuiioonmfngbaetirtrhyseaiasdunundciqkuse ID number as the key. Dictionary duckDictionary = new Dictionary(); duckDictionary.Add(5155, new Duck() { Kind = KindOfDuck.Mallard, Size = 15 }); duckDictionary.Add(6256, new Duck() { Kind = KindOfDuck.Mallard, Size = 14 }); duckDictionary.Add(2799, new Duck() { Kind = KindOfDuck.Mallard, Size = 13 }); The how Count property many key-value tells pairs are int howMany = duckDictionary.Count; in the Dictionary. Console.WriteLine(“There are {0} ducks.”, howMany); If you need to pull the keys and values out of a dictionary, you can use a KeyValuePair<>. This loop assigns the tctouhrrirodeuDngthucktke,hyeo/nvweahlauotele palaotioripm. e, foreach (KeyValuePair idDuck in duckDictionary) Console.WriteLine(“Key/value pair: {0}: {1}, {2}”, idDuck.Key, idDuck.Value.Size, idDuck.Value.Kind.ToString() ); foreach (Duck duck in duckDictionary.Values) tEhveervyaluKeeyisVaaluDePucakir, has you acakneyuseanidtsafviealldues.. Since Console.WriteLine(“Duck size: {0}”, duck.Size); foreach (int key in duckDictionary.Keys) This foreach loop goes through all of the values in the dictionary. Console.WriteLine(“ID Number: {0}”, key); And the this keys fouotreoafchtlhoeopdipcutlilosneaarcyh. of Here’s the output that this code writes to the console. More free ebooks : http://fast-file.blogspot.com you are here 4   337 all hands on deck 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. Then you’ll build a form that shows you the contents of two Deck objects. When you first start the program, 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. You can use a button’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. tRrEheeaessceehRtt2eDodfebrcuatktwh(t)Deomenrcseekstfe(h)itro1smdtaeantcdnahdlolsdt.thheen fimsUtrhosoomvemweotTvtdwoeheDsoceetkLcthki#wes1to2sBbeduolteetxoccttkcodseon.edncWitskcrhaco#erllnidsc1k.tteohde, TnstSthahhhhumeeuefsefnfeadflpreblpees2urh(dt.)ourtpfTamorfwnheilaseettt1yhaehoarcedenDad,dlelaecnckdk.. 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) { Take a look at how we used the listBox1.Items.Clear(); foreach (string cardName in deck1.GetCardNames()) foreach loop to listBox1.Items.Add(cardName); add each of the label1.Text = “Deck #1 (“ + deck1.Count + “ cards)”; cards in the } else { deck to the listBox2.Items.Clear(); listbox. foreach (string cardName in deck2.GetCardNames()) listBox2.Items.Add(cardName); DhTcuaopehpndceptkaertRnooeesblssdjtertwocahitwtebshDe.tewiwncohkta(lthi)seetmvbteeorwtxohod label2.Text = “Deck #2 (“ + deck2.Count + “ cards)”; } } 338   Chapter 8 More free ebooks : http://fast-file.blogspot.com 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 the other that takes an array of Card objects and loads them into the deck. The Deck stores its cards in a List—but it keeps public class Deck { it private to make sure it’s well-encapsulated. Deck Count private List cards; private Random random = new Random(); public Deck() { If you don’t pass parameters into the constructor, it creates a complete deck of 52 cards. cards = new List(); for (int suit = 0; suit <= 3; suit++) for (int value = 1; value <= 13; value++) Add() Deal() GetCardNames() Shuffle() Sort() cards.Add(new Card((Card.Suits)suit, (Card.Values)value)); } This overloaded constructor takes one public Deck(Card[] initialCards) { cards = new List(initialCards); parameter—an it loads as the array initial of cards, deck. which } public int Count { get { return cards.Count; } } public void Add(Card cardToAdd) { }}publCcrciaaeacrrtrddudCsrsaC.n.raRAdreCddmadDTor(eovdcaDeTaleAor(atDdil(eTniaot=nlAd;dicednax)dr);ed;xs)[i{ndex];oticTrCotfhaeuahetnt0rteudddh,roDeeenofocaserbcklatjaadlfhebrecemrrdyateoeldfmpttfeefaohrcrrstooeksdohdimn—mneecgadietttlt.eihottharepoelestmdbimhtoyeoein.cdvepkeYidnasocldaseuatsneirhodnxdefg HcpsYttIioairfthoonnmo’eutltpntle:erccohbrToaaaeetclnrs’haysdDletpreSehwasdiLnsaeesisllliil(ettssi)tncihhbtstdBaeemeeendoledxeltxiitczIrshntthoeeed.ocfer.teddoxl,..y ImsnhootvuehlTdaotDdcoeacsnkeo,tbthuhitnetgo. n public void Shuffle() { // this method shuffles the cards by rearranging them in a random order } public string[] GetCardNames() { // this method returns a string array that contains each card’s name } public void Sort() { cards.Sort(new CardComparer_bySuit()); } } TKAhneaeotpt’hlclelrimcakhkiinnegti:ttTheehaes“yRfeotsroemtsemDeaeikfceksy#oitu1rr”esbahulultyftfeoliannsgyuncttooidletyeowsutorgykeostu. raSthhurfefel-e(c)armdetdheocdk.. You’ll need to write the Shuffle() method, 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. More free ebooks : http://fast-file.blogspot.com you are here 4   339 exercise solution Build a class to store a deck of cards, along with a form that uses it. public class Deck { private List cards; private Random random = new Random(); public Deck() { vmodHaueeeltucraeskenis’dssoertftuhohn5enes2eifcnlooscouinaodrsrptedssrelsuot.pcohaItptrrooartuuthsgteeahhsttataitgmhoeneceesrsf,setooatuetnhrdceresosfuuoapigterhcrsl.ootsmTouhppiehtl.ae.1Ttt3ehe cards = new List(); for (int suit = 0; suit <= 3; suit++) for (int value = 1; value <= 13; value++) cards.Add(new Card((Card.Suits)suit, (Card.Values)value)); } public Deck(Card[] initialCards) { cards = new List(initialCards); } Hhwaeitsreht’swdotifhfoeevreoertnlhoteardpeacdroancmsotenrtsuetcrrtsuo.crt—ortsh, iseacclhass 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; } ArfTsetdohmrrdeaotimvAghehedesttdahfCooaacdrrnawddraasddrDlddifess—rtaol.atmTmhceeahtytrehhdeuDostdeleiossattlat,hmrheaeeenmtdplehirsttoethdth. oetdys 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 string[] GetCardNames() { string[] CardNames = new string[cards.Count]; for (int i = 0; i < cards.Count; i++) TcrfOtoTNnoeihhuneeflehletecwleewedmercoCoteiSlitfnaidntehnosrcd’tustediNpfanhsbsdofnsee.tyiopclwneTaoenCtt(Cnie)hnaohc,atterfeermionditdnegwLsgstitartoifhrheunstetsbiopn’oeetdaidteestCntscosa’yctalimnilcaaorscmklgrdelcseeoe..samdtrrepdtsy. CardNames[i] = cards[i].Name; return CardNames; } public void Sort() { cards.Sort(new CardComparer_bySuit()); } } YchforoouelrrdatlGoaeolelpatt,nChbaaeurrtdrcaaNitryadmctohenusaal(tmd)’esmasb.lesiTotghhueoisnsdeoounfngeoeherdeutassoectsho.a 340   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections class CardComparer_bySuit : IComparer { public int Compare(Card x, Card y) { if (x.Suit > y.Suit) return 1; if (x.Suit < y.Suit) return -1; if (x.Value > y.Value) return 1; if (x.Value < y.Value) return -1; return 0; } } Deck deck1; Deck deck2; Random random = new Random(); Ssdfcaooairirfrrsetfsetteicin,ntroggehamnenbpbcdyayesurtviiestsahudlsietutnoeah.niratsletTyhaechiinfoelvomattotplhnuhalileeisyrkseed suits match. Iisboopnftnensr,atcleeytwaeveduaieeomsdixudeueessnoncee’ftotuadnst—c.ueheasoTsiwtnisfhioeghfiruessilirttefdwwsah/othieeosraelefkspmvesreteiefhnvetious returned. public Form1() { InitializeComponent(); ResetDeck(1); ResetDeck(2); RedrawDeck(1); RedrawDeck(2); } Tndeheeecdkfss,otraomnd’rsetscehotnensttrhituecdttrowarows 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((Card.Suits)random.Next(4), (Card.Values)random.Next(1, 14))); deck1.Sort(); } else deck2 = new Deck(); } You’ve already got the RedrawDeck() method from the instructions. idtncTtehsrootcaeaktaprnt.eicmcseRkeesaethnsoayeodftwnerteDcawmiknneagdce#nkomyd(m1p)e,c.tctcakyahrrdi#dsdse2smcw.keiIi.tltslhItagofodieunasiifnseshtisyreo—sasttjofuhufosestfredsclboerryoceapkasn,todteraootnmadian.Ndngtedehtwxehtne() We’re not done yet—flip the page! More free ebooks : http://fast-file.blogspot.com you are here 4   341 information overload (continued) yNbouautmrtioncngo2dy_eo.CuIrlficckto,hnteestreco.lw,s eymroaeukcweasolluietlddnab’tulottktnoeonaw1s_iewCrhliitccohk,read button’s code you were looking at! private void reset1_Click(object sender, EventArgs e) { ResetDeck(1); RedrawDeck(1); } cHoedree’sfotrhethreesftoromf.the private void reset2_Click(object sender, EventArgs e) { ResetDeck(2); RedrawDeck(2); } private void shuffle1_Click(object sender, EventArgs e) { deck1.Shuffle(); RedrawDeck(1); } dTrpeerhsceeektst,tetyobhrsueitsnmhtpurolfenefds—lreafariwterhstiet. 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) if (deck1.Count > 0) deck2.Add(deck1.Deal(listBox1.SelectedIndex)); tucsooenrftirsgeoullre’sectSoeeudltecawtnhedidcIthnhdceeanxrmdportvohepeeitrty RedrawDeck(1); from one deck to the other. (If RedrawDeck(2); } site’lseclteessd,tshoanthzeerbou,tntooncadrodeswas } nothing.) Once the both decks need to card’s moved, be redrawn. 342   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections You can build your own overloaded methods 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. Do this! 1 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 2 change the namespace line to Add some new overloaded match the methods name of to the the new project card class. yItonfoaumyacoecruscepeadastosceendt’t.(hleidkCeo aotrlhddinsc,almyaosesus’plblaycoens.plCyeacbrifedy)ai.nbgleits 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, Card.Suits Suit) { if (CardToCheck.Suit == Suit) { return true; } else { return false; } } matOoevletitbrhetlooldesatsdpa.etrdaiccm,tbiectuethowidtrs’its dignoogno’sdttathtoaivcgeet public static bool DoesCardMatch(Card CardToCheck, Card.Values Value) { if (CardToCheck.Value == Value) { return true; } else { return false; } } 3 Add a button to the form to use the new methods. Add this code to the button: Yboauc’kvetoseetnheovseorlulotaiodnintgoaKlraetadhlye.enF’lsip 6poavoernrtlyopaapdglaeendsn2iCn3ag6lcp–ur2loa3tg8reaC—moysotinu()Cadmhdaeptetdheoardnto the DinnerParty class. Card cardToCheck = new Card(Card.Suits.Clubs, Card.Values.Three); bool doesItMatch = Card.DoesCardMatch(cardToCheck, Card.Suits.Hearts); 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. More free ebooks : http://fast-file.blogspot.com you are here 4   343 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 all on the next page in step #3. You just have to type it in—which may seem like you’ve got 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 a player places a book on the table, that may cause him to run out of cards. If it does, 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. 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. 344   Chapter 8 More free ebooks : http://fast-file.blogspot.com 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 you have that card. TNsechnaraimsebeelTneepsdxhrtoowtBphe,oerixntt’ytcsohsdneeittsparrtobololegsdrtha,eomxbutludstNtahaitmarvteses.h.oiItnusldthbise gettSanhoemaitsbbelusetictsdhrt.iesosteIntanbS’rsulthlttaoetgrtdeot,tn..’bsdIuttNis’saaibtmdleiessdtapabrorloentpdcseerionttuyhte These are TextBox controls named textProgress and textBooks. The player’s current hand is displayed in a ListBox control called listHand. You can set its name using the Name property. bmcoSoofaexnktettesrht.toehlhestewmtRooeraTTedareOxdunet-l—Byonotplxhyraottpeewxrtitlly etmbSnoueeattaFbtnlatoselnhsiiAeitts.sckbTaa,ushntaas’tntotodonbnw’sesiealtlpNsrdatietimsshssaeeebEdglpen.aramoTibtpelh,eeersdwtthfaypoircrrtthomosp.ewrtilly We’re not done yet—flip the page! More free ebooks : http://fast-file.blogspot.com you are here 4   345 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 yourself will have to work with it. public partial class Form1 : Form { public Form1() { InitializeComponent(); } private Game game; This is the only interacts with. Ictlarssuntshtathetwhehofleorgmame. private void buttonStart_Click(object sender, EventArgs e) { TpochrrooenpdtEeirsrnaotablybloeleensndaatbhlees form. if (String.IsNullOrEmpty(textName.Text)){ MessageBox.Show(“Please enter your name”, “Can’t start the game yet”); return; } game = new Game(textName.Text, new string[] { “Joe”, “Bob” }, textProgress); buttonStart.Enabled = false; textName.Enabled = false; buttonAsk.Enabled = true; UpdateForm(); } abiWnnusdhttetantonhncye,eonduoirfsseatdbtarlhreateswGtashatnemheewe“Scfgtloaaarmsrmste,.,eGintaambclere”esabttuehtsetao“nAn,sekw” private void UpdateForm() { This method listHand.Items.Clear(); clears and foreach (String cardName in game.GetPlayerCardNames()) repopulates listHand.Items.Add(cardName); the ListBox textBooks.Text = game.DescribeBooks(); that holds textProgress.Text += game.DescribePlayerHands(); the player’s textProgress.SelectionStart = textProgress.Text.Length; stesSUcecncrxrsdroiot,nolllgllsstsloToSdtoieofChdlweeaistcnrpttheltieaetooxry(net)Sta’bstlhtoikaetxoerobntottocotheaminttsuidothcmhe. hand, and then textProgress.ScrollToCaret(); updates the } text boxes. private void buttonAsk_Click(object sender, EventArgs e) { textProgress.Text = “”; if (listHand.SelectedIndex < 0) { MessageBox.Show(“Please select a card”); return; dmmtTtooheohwtevetnehhfdoSetld,eaolsteeshnhtccidetnhr,geiooSlanltccsnSuredrttoxslahtoloTrebnrtooc.tCxeleaixnicrtetue’srtmbs(ooo)rxves } if (game.PlayOneRound(listHand.SelectedIndex)) { textProgress.Text += “The winner is... “ + game.GetWinnerName(); textBooks.Text = game.DescribeBooks(); } } buttonAsk.Enabled = false; } else UpdateForm(); PmTbluaahttyetcOophnnleaesyRteiootrussnsevdeeal(el)iucfetm.saeTntoyhhneoeodfGo.fatmhteeheoctlcahasesrrdpsplalaaynysdearcsrliohcuaknvsdetauhsecina“grAdtskht”ehat 346   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections 4 You’ll need this code, too You’ll need the code you wrote before for the Card class, 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]; The Peek() method peek at one of the without dealing it. lets you cards in take a the deck } public Card Deal() { return Deal(0); } Staoocmraeeroadnde.ofIoffveytrolhoueaddtoeodnp’tDofietatlp(ha)estsdoeacnmkya.kpeariatmaetlietrtsl,eiteadseiearls public bool foreach ContainsValue(Card.Values (Card card in cards) value)Th{e ContainsValue() the entire deck for method searches through cards with a certain value, if (card.Value == value) return true; return false; and returns true if it finds any. Can you guess how you’ll use this in the Go Fish game? } public Deck PullOutValues(Card.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; } caaIYgmtaneoevrdtulatdo’llhrsauoleoekiutdb,snsuopefrwioutonkthl.rlshesoneaaftnyPhnycoeueaumlwclrOabdroduusduteitlscfVdkratooltfhuwmhaeietttst(hh)chmeoetaddhtdeoececshtcekok, . public bool HasBook(Card.Values value) { int NumberOfCards = 0; foreach (Card card in cards) if (card.Value == value) NumberOfCards++; if (NumberOfCards == 4) return true; else return false; } The HasBook() method checks a deck to of four see if cards it of contains a book whatever value was passed as returns true the parameter. It if there’s a book in the deck, false otherwise. public void SortByValue() { cards.Sort(new CardComparer_byValue()); } TdehcekSuosrintgBtyhVealuCeo(m) pmaertehr_odbysVoarltuse the class. Still not done—flip the page! More free ebooks : http://fast-file.blogspot.com you are here 4   347 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. public class Player { private string name; public string Name { get { return name; } } private Random random; private Deck cards; private TextBox textBoxOnForm; jyLoobouoiwks htcaoltosfetillhyleianmtteethahecohmdesotfahrotedhsseu. pcpoomsmedenttos—dto.heYyoutrell 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 line break (“\r\n”) at the end of every line you add to the TextBox. } public List PullOutBooks() { } // see the facing page for the code public Card.Values GetRandomValue() { // This method gets a random value—but it has to be a value that’s in the deck! } public Deck DoYouHaveAny(Card.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, Card.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 string[] GetCardNames() { return cards.GetCardNames(); } public Card Peek(int cardNumber) { return cards.Peek(cardNumber); } public void SortHand() { cards.SortByValue(); } } 348   Chapter 8 More free ebooks : http://fast-file.blogspot.com 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 List PullOutBooks() { List Books = new List(); for (int i = 1; i <= 13; i++) { Card.Values value = (Card.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; } hotoYAofunhposmepekutoi’Farlinhlsnoee)rhhunmAaasftnevCosaeddrasswkrtwahdoanhEen(yebn)dVnucmEtifalthdeRirhnetdYeydThsopWaoadtlstaOh.kchyaTaeetforrrhovdemerapratslfclaktooayisacrreahdsfdrtseokstd(r—ohbfneotivoetethr’vrlhei.alssliTculcouoeaonhso.rmesekddpos.tufebtBhcyertooronhttudehhagenhd 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(Card.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! More free ebooks : http://fast-file.blogspot.com you are here 4   349 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. public class Game { private List players; private Dictionary books; private Deck stock; private TextBox textBoxOnForm; public Game(string playerName, string[] opponentNames, TextBox textBoxOnForm) { Random random = new Random(); this.textBoxOnForm = textBoxOnForm; players = new List(); players.Add(new Player(playerName, random, textBoxOnForm)); foreach (string player in opponentNames) players.Add(new Player(player, random, textBoxOnForm)); books = new Dictionary(); stock = new Deck(); Deal(); players[0].SortHand(); } 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 // 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.” } 350   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections 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 (Card.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 string[] 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.\r\n”; else description += “ cards.\r\n”; } description += “The stock has ” + stock.Count + “ cards left.”; return description; } appnmdDdHnlluuiaeaaicdmrcryydttiebeeneibi’orregsousnranimaaltnaidorndhirghfyeyahiwbnciimanhutytsgascoioaoeteasuytntdl’elsahhlelarbeawdwcyuovihhGtse.oweohkeTpitstalw!hhanaWeneoySfnynnieoonne.rrnpuy’yreesmoloaarsubnuycN’ae’lehllaarmlrtmul.neooseBeoetft(ephu)odatbetnmoloooottoentoohktgehkpsehoermoutoretdpfohhf:rmartoettYiohrghoufeehyeugoaot’hnrclmuluehbetmanfethlceobohheeuaeoodnrpbldtdoot.iotoeooifTpo—nkschftbmtreooithoenohearwdlkoateisstoetetknhhctahenoefhanenomnehderriawpgoldsahlnoaleeeolyspettrhse More free ebooks : http://fast-file.blogspot.com you are here 4   351 exercise solution Here are the filled-in methods in the Game class. public class Game { 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) { Card.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 stnotmocooAefouaapwfct5rdpbktdoeho.acen,.aonraetnkIyrnfsdthdt,behsaobheagoyefspakprklddmsalsoayremetyfeaaehorlwptriar’nusshtlgoaleaosrhuuept players[i].AskForACard(players, i, stock); if (PullOutBooks(players[i])) { textBoxOnForm.Text += players[i].Name + “ drew a new hand\r\n”; int card = 1; while (card <= 5 && stock.Count > 0) { players[i].TakeCard(stock.Deal()); card++; } } players[0].SortHand(); As soon as the player clicks the “Ask for a card” button, the game calls AskForACard() with that card. Then it calls AskForACard() for each opponent. if (stock.Count == 0) { textBoxOnForm.Text = “The stock is out of cards. Game over!\r\n”; return true; } } return false; } ooApvnlfaeytrte.ehrreI’fstfihhotaernmirsd.,o,TuPtnlhoadeymniOsanitkpeelRacyosheuuerdnced,ks(ti)tht’ersoedgtseaiusemrpnleiafsysteotdrrhuteiesn.gtaohmredee’sr public bool PullOutBooks(Player player) { List BooksPulled = player.PullOutBooks(); foreach (Card.Values value in BooksPulled) books.Add(value, player); if (player.CardCount == 0) return true; return false; } Pidhfueol’elhsOse,gu’sottthBgeoonytookgfsceo(at)urrdlaosdcoadklresefddttshtwraooiftuhthgieshrtbwhaoaeoprksldasasym,deeiirtc’tvsariocleunatearu.rdrIynsf.stAhtoenrsdueeei.f 352   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections Tpsolhaeyitefruo’ssrembsoDnoekeessdcdsriicbttoeiTodnhiaserpBylaoyoinktaso(l)iwsttoorodtfsu.rbnootkhs,e public string DescribeBooks() { string whoHasWhichBooks = “”; foreach (Card.Values value in books.Keys) whoHasWhichBooks += books[value].Name + “ has a book of ” + Card.Plural(value) + “\r\n”; return whoHasWhichBooks; } public string GetWinnerName() { Dictionary winners = new Dictionary(); foreach (Card.Values value in books.Keys) { string name = books[value].Name; if (winners.ContainsKey(name)) winners[name]++; else winners.Add(name, 1); } int mostBooks = 0; foreach (string name in winners.Keys) if (winners[name] > mostBooks) Owgidtdtanhhoi’cmclaalteittetiuo.tsntpnehEelhaaeeeraaydycelGsadh;rsieittctpgtotlsoWacitofyavinnaeirgdanlrduurue’’esrsryreiNninbcsaogaeamutemltltnheeehed(wpei)sinhcwgduaokiamonemkwendbeseeoe.y.rnursAp.ion,nTtfdtothhbhaeteoo’sks mostBooks = winners[name]; bool tie = false; string winnerList = “”; foreach (string name in winners.Keys) if (winners[name] == mostBooks) { ttpNohleaaxyftetirgvtuawrhlueietethgihantemhaeneuvlammoroboikasestbrltebohofcroaokbluslogeohhdkastsm.htoeIhsttadtBpicuotttohiksoesn.ary if (!String.IsNullOrEmpty(winnerList)) { winnerList += “ and ”; tie = true; } winnerList += name; } winnerList += “ with ” + mostBooks + “ books”; if (tie) Now that we know which player has the most books, the method can come up with a string that lists the winner (or winners). return “A tie between ” + winnerList; else return winnerList; } } We’re not done yet—flip the page! More free ebooks : http://fast-file.blogspot.com you are here 4   353 exercise solution (continued) Here are the filled-in methods in the Player class. public Player(String name, Random random, TextBox textBoxOnForm) { this.name = name; this.random = random; this.textBoxOnForm = textBoxOnForm; this.cards = new Deck( new Card[] {} ); tIHtoersteeh’tsestpihtresogpcroreinsvssatttreuecxfttioerlbdofsxoarsnadtyhitneghPewlaahydoedrjsocianlaelsdins..e textBoxOnForm.Text += name + “ has just joined the game\r\n”; } public Card.Values GetRandomValue() { Card randomCard = cards.Peek(random.Next(cards.Count)); return randomCard.Value; } The look GetRandomValue() at a random card method uses Peek() to in the player’s hand. public Deck DoYouHaveAny(Card.Values value) { Deck cardsIHave = cards.PullOutValues(value); textBoxOnForm.Text += Name + “ has ” + cardsIHave.Count + “ ” DoYouHaveAny() uses the PullOutValues() + Card.Plural(value) + “\r\n”; method to pull out and return cardsIHave; return all cards that } match the parameter. public void AskForACard(List players, int myIndex, Deck stock) { }publCAiascrkDdFev.ocoVrkiaAdlCsuatAerossdck(kFrp,oalrnaCAdyaCoeramrdrVs.da,V(laLumlieyusIet=nsdooc{pmklV,aaylreuarens(d,)o;miVnatlumey)I;ndex,TAiacshsakruellaFsrseneodtdrahAobremCeyoactttrawdhhroee(d)roofmpvArepesrootklmnohoeraontAddthesCse.d—aTrhidtahn(is)gd.eotansned textBoxOnForm.Text += Name + “ asks if anyone has a ” + value + “\r\n”; int totalCardsGiven = 0; for (iifnt(iPDile!ac==yke0mrC;yaIprinlddas 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.\r\n”; cards.Add(stock.Deal()); } If no cards were handed player has to draw from over, the the stock } using its Deal() method. 354   Chapter 8 More free ebooks : http://fast-file.blogspot.com enums and collections And yet MORE collection types... 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 that, 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. Tcamchoroloeelnrsettetctahlacieiokrtneeoslwny,oeitttsthohoteo.rh—caotbtmuyetypeoitsnu’hroeefse Use a Queue when the first object you store will be the first one you’ll use, like: ≥ Cars moving down a one-way street ≥ People standing in line ≥ Customers on hold for a customer service support line ≥ Anything else that’s handled on a first-come, first-served basis yoAmoneueqaunpyesuoutuethpiinasuttllfotiortuhshttee-foqifnirusefittuierotsbtiosj-eutocshuteet. t,fhwiarhtsitch 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 ≥ A stack of books where you want to read the most recently added one first ≥ 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! Tfisihrtesthsetoalbacjsketcitsonftehiratstth-agtionecsloamisntet-soooututht—eotsfthaeitck. Generic collections are an important part of the .NET framework 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 collections. Yeboneuucmacueasrnea,tthehoewtyhevrimeorup,glehumsaeenfsttoarIceEkancuohmrteqoruaebulee,! A queue is like a list that lets you put objects on the end of the list and use the ones on the front. A stack only lets you access the last object you put into it. More free ebooks : http://fast-file.blogspot.com you are here 4   355 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. Peek() lets you take a “look” at the first item in the queue without removing it. Queue myQueue = new Queue(); myQueue.Enqueue(“first in line”); myQueue.Enqueue(“second in line”); myQueue.Enqueue(“third in line”); myQueue.Enqueue(“last in line”); Hipttoeuhrerledmleye’sts’rlhltwetocmhhoetemrohyeeuetwowqeuoeuntfetauidetnin.dh.teWhfhqeoeuusneraumwe,ee string takeALook = myQueue.Peek(); 1 string getFirst = myQueue.Dequeue(); 2 string getNext = myQueue.Dequeue(); 3 int howMany = myQueue.Count;4 myQueue.Clear(); ocTiTfnnahtielhrloeesonttutoftthiitrhDeensetemefqxsiDerutosce.uteoutqnepu(dole)afuocpenetu(—e)lhlsetsphhutqilefhulsatentusteehxu.etp The Clear() mrotebehmtjeeohcqvotedusseufaerl.lom MessageBox.Show(“Peek() returned: “ + takeALook + “\n” + “The first Dequeue() returned: “ + getFirst + “\n” + “The second Dequeue() returned: “ + getNext + “\n” + “Count before Clear() was “ + howMany + “\n” + “Count after Clear() is now “ + myQueue.Count); 5 The the queue’s number Count property of items in the returns queue. 356   Chapter 8 Objects in a queue need to wait their turn. The first one in the queue is the first one to come out of it. 1 2 4 3 5 More free ebooks : http://fast-file.blogspot.com 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 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. Creating a stack like creating any is just other Wastbatnhahnaecedictnkkoes,tmyoitihontseueornoppntnuiuotossthtehcaoemhsps. generic collection. 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(); 2 string getFirst = myStack.Pop(); 3 string getNext = myStack.Pop(); 4 int howMany = myStack.Count; ttoWhhfhaeftemntwhoyaseotsustarpdeaoccdpeken,datyn. oitiuteegmmet 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); 5 1 2 4 3 5 Toonbhjeaeclasttstatchokabtjiseycttohueypofuulilrpsutt off of it. More free ebooks : http://fast-file.blogspot.com you are here 4   357 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? sfLtoaeuctrk’sitosefemtsst—urpiinnagtss.htiascckawsei,tha Don’t worry—you don’t give up anything when you use a queue or a stack. It’s really easy to convert a Queue object to a List object. And it’s just as easy to convert 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 to be used. Stack myStack = new Stack(); myStack.Push(“first in line”); myStack.Push(“second in line”); myStack.Push(“third in line”); myStack.Push(“last in line”); Ittttooo’saaaenaqloisustytehu,teearo,ntdscthoatencnvhkeecr.notpcytophtyahttehsqteuaelciukste 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”); Accloolpllfieeocdutriioninttsoe.mtshewenreew ...and you can always use a foreach loop to access all of the members in a stack or a queue! 358   Chapter 8 More free ebooks : http://fast-file.blogspot.com 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 and the TakeFlapjacks and EatFlapjacks methods. public class Lumberjack { private string name; public string Name { get { return name; } } private Stack meal; public enum Flapjack { crispy, soggy, browned, banana } 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 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. This listbox is called line. TtErhehaeditsrFnbaelwuaxtptttjaohlcunekmsslbihsemotruebjltoadhxcok.dd,e,qcauaelnludehitshen When in the tnhaemuesetrexctlicbkosx“AtoddthLeuBmrbeearkjfaackst”L, aindedqtuheueen. ame WgoLornuhooltyeounkpwablyhaloootaxuwt,tsdtthtrhheaheegaeyfdtuosdhshrFeoemrulsaeladtpuojRatbaccoedkhmisneoa_acBtkmCiuceltoaidcntllk.eoynmolifcenotktnshthotredhmoeltsmaoitnaftnaiogduttrimheee. private void addFlapjacks_Click(...) { Flapjack food; if (crispy.Checked == true) food = Flapjack.crispy; “Nelosteeift”hesysnpteacxia.l else if (soggy.Checked == true) food = Flapjack.soggy; eellsseeffioofoodd(b==roFFwllnaaeppdjj.aaCcchkke..cbbkraeondwann=ea=d;;trPttoeuheeetk)(hq)euerfueietr.ustrnlsumabreerfjearcekncine You’ll need to add a RedrawList() method to update the listbox with the contents of the queue. All three buttons will call it. Here’s a hint: it uses a foreach loop. } Lumberjack currentLumberjack = breakfastLine.Peek(); currentLumberjack.TakeFlapjacks(food, RedrawList(); ThohweM(Niaunnmtye,)rahicnoUdwpMtDahoenwylna.bcVeoalnlitsurcoeal)lli;sedcanlelexdtInLine. you are here 4   359 More free ebooks : http://fast-file.blogspot.com exercise solution private Queue breakfastLine = new Queue(); private void addLumberjack_Click(object sender, EventArgs e) { breakfastLine.Enqueue(new Lumberjack(name.Text)); name.Text = “”; RedrawList(); } private void RedrawList() { int number = 1; We the ctawlloedbutthteonlisst“bnoexxt“IlninLei”n,et”.he label between line.Items.Clear(); taotfTmhdfhoeehdertteelliehhasuRaoectmcdiehbrbhdoelurxqoorsauo.efjwepasuLcteatkhiosseatmnop(duu)tltlo foreach (Lumberjack lumberjack in breakfastLine) { line.Items.Add(number + “. ” + lumberjack.Name); number++; } if (breakfastLine.Count == 0) { groupBox1.Enabled = false; nextInLine.Text = “”; Tlfahibriesstl ifwluitmsthbaetinrefjmaocerknmtaintuiptodnhaeatbqeous eututhe.ethe } else { 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(); } public class Lumberjack { private string name; public string Name { get { return name; } } private Stack meal; public Lumberjack(string name) { this.name = name; meal = new Stack(); } TmheethToadkeuFpldaaptjaecsktshe Meal stack. public int FlapjackCount { get { return meal.Count; } } public void TakeFlapjacks(Flapjack food, int howMany) { for (int i = 0; i < howMany; i++) { meal.Push(food); }} llumoTmoehbpteehtrEoojdaapctukrFsi’nselatsmpajoeauawctlk.hsitlehe public void EatFlapjacks() { Console.WriteLine(name + “’s eating flapjacks”); while (meal.Count > 0) { Console.WriteLine(name + “ ate a ” + meal.Pop().ToString() + “ flapjack”); } }} 360   Chapter 8 More free ebooks : http://fast-file.blogspot.com 3 8 9 Collectioncross 1 4 5 6 enums and collections 2 7 10 11 12 13 14 15 16 17 18 19 20 21 Across Down 3o.nAenspinesctiafiA3wnc.coctAeyrrnpkooesfisn.awss_tita_hn_c_oen_e_o_fs_pa_e_c__i_f__ic___t__yc_po_el_.le_c_ti_o_n_ocnolyllewcotirokns ownitlhy 12..D1vTT.ahohTleiuwhsegecsnegonellenerecicrtiioccnocliolsellcfeitrcisottni-ointnh,atfihtrslaett-tosleuyttosuymouamp akpeykseytos vtaolues 6. A specia6l.kAindspoefclioaol pkitnhdatoof nlolyopwtohrkast onlcyowlleocrtkiosnosn collections 4.2T.hTehbisucilot-lilnecctlaiosns itshafitrlsett-siny,ofuirrsptr-oogurtam write text to the 9. The output nam9teh. eTohofeuthtnepaummteetohfotdhyeomueutsheodtoysoeunudseatsotrsinegndtoathstering 10. How you remove something from a stack to ou4ttop. Tuththee built-in output class that le ts your program wr ite te xt 5.5A. Amemtheothdotdo tfionfdinodutohuotwhomwanmyatnhyintghsinagres ianrea icnoallection 10. How yo1u1r.eAmnoovbejescotmtehtahti'nsglikfreomanaasrtraacykbut more flexible 7.cTohlleecotniolynmethod in the IComparable interface 11. 13. ATwn oobmjee1d1cti35htf..otfhATedwarsmeto’sinnemtltiakhpeetaochldraaaontsmdosasefwritringeaiturhyasrbtceahluoaerteusms.ts.a.oiwmfreiaethfcnleeatrxhmtibeaelisenbaumotbejdenicffatemriseenibntuat 8.78M..TMohseot spotnroplyfreomsfseeiosthsnioaodlnpainrloptjerhcoetjseICcsottmsarspttawarriatthbwltehiiitsnhtetrhfisace 121. A2n. Aonbjoebcjtetchtatthimatpilemmpelenmtsenthtisstinhtiesrifnatceerhfaeclpeshyeolpusr list sort parameterscoallreec..t.ion itsycoounrtleisnttssort its contents 15. 19. AAnmeeaths122yod901w...taHoAAyonlfliwtgogeueaykrnseeoyeueorpwriucettamrcyiafoocatlvkloeeccokestferoicteomaapnietnsettrgoihmaobicnrjpekiglecesoftmfriseocnmainttaeatghqcoiusoreliilueneesctetirofnace 1411. 46H..oHTwhoiwysocyuoolauledacddtdsioosnmoimsetefhtiirnhsgitn-tgiont,aolaqasutqe-uuoeueute 161. 7T.hHisowcoylloeuctaiodnd issofmirsett-hinin, lgatsot-oausttack 20. All generic collections implement this interface 21. How you remove something from a queue 11781a.. 8THs.htoTaiwshckimysooemurtheqaotudhdedourdeseotrumertneustrhtnihnsegtnhtoeexant esoxtbatjceokcbtjetoctctoomceomofef off of of a stack or queue you are here 4   361 More free ebooks : http://fast-file.blogspot.com crossword solution Collectioncross solution 1D 3G E N E R I C 4C C O 8S 9W R I T E L I N E 2Q 5C U 6F O R E A 7C H U U O P I S N E M E 10P O P O 11L 12I S T P C N L C A I A 13O V E R L O A D E D R F R M E I Y 14E P T C 15C O N T A I N S O A 16S Q R T 17P 18P T U 19E N U M 20I E N U M E R A B L E R O S E C U N H K K 21D E Q U E U E Across Down 3. An instance of a ______________ collection only 1. The generic collection that lets you map keys to works with one specific type. [generic] values [dictionary] 6. A special kind of loop that only works on collections 2. This collection is first-in, first-out [queue] [f ore ach] 4. The built-in class that lets your program write text 9. The name of the method you use to send a string to to the output [console] the output [writeline] 5. A method to find out how many things are in a 10. How you remove something from a stack [pop] collection [count] 362 1 1. ACnhaopbjteecrt8that's like an array but more flexible 7. The only method in the IComparable interface [list] More free ebooks : http://fa[sCto-mfilpea.rbelToog] spot.com 13. Two methods in a class with the same name but 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. More free ebooks : http://fast-file.blogspot.com C# Lab   363 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. 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. Tvpihleaewyegorafmfetighhwetinsdduhoniwsgeegoninveemwsiheaesn.reovtehrehead The player can pick up weapons and potions along the way. The player and enemies move around in the dungeon. The player moves using the four Move buttons. Hwdtctehhrlhiraaeceetywk’’Asssritetotaetnhcmabeuacsornpkxrtleaibhtanyeuretetmolrpytu’lsonatundyoisneitnvtreoeg’qhsn.ueutipTspoiietcrhikeyettme.,hdpIealttanuhiydtpsaeh,etruomaswn.esds TthWhihtheeepnegonaitenmhmteeys’spsfhloahoryiwtetsrphyoeaoitnupttltaasyhcgekeorsnadaunmnodwbenene.renmOeoymnf,ciees. the hit points get down enemy or player dies. to zero, the Tuasnhededsedtrfoionauktrptboautctikotneosnn.esmairees 364   Head First Lab #1 More free ebooks : http://fast-file.blogspot.com The Quest The player picks up weapons... 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. Aedoleqtifvbuhefileaplesrcprsekeodnfhb.taoDdvxreaiafmaanfrageowgeruesiend,ntdestoroamwtreewhaaneeopganeoeplnny,oesnamanwtmideotesraatkctnhkhsedeyiiifnytfc’sohaeniructeesu.enrdtrdileryinfe—tcftlteyirhoeennytwhhaivlee ...and attacks enemies 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 player, so Right attack the right of he hits the button. The attack causes the bat’s hit points to drop, from 6 to 2 in this case. Higher levels bring more enemies There are three different kinds of enemies: a bat, a ghost, and a ghoul. The first level only has a bat. The seventh level is the last one, and it has all three enemies. Atcoawguhsaeorsudlhsmetaohvveyespdlqaaumyiecarkg,leyand when it attacks. The bat flies ainratmearaonocruduannuottdsmhelseosyof.apmWldasemayhwmeeahrnlaal,tgite.’s Tppallhmaaeyoyeeugrnrh.t,oAistotsfamstodotoavanmecsaakgssseloia.twn’sdlycctlaoouswesaetrsodastmthehedeium More free ebooks : http://fast-file.blogspot.com you are here 4   365 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. TpdrihsoeppleadryutendygeouofsnintigthsteehlffeoriBsmaa.cksgtraotuicndiImmaaggee, MBpraaockpkeegrrstuoyruenidstIhsmeeatgetLo aNyoonuet. Each of these icons is a PictureBox. HTataitbtlapecoLkinatbysuo,tutmtoPonavsneemalre. entalbludtitspolnasy,eadndin a Download the background image and the graphics for the weapons, enemies, and player from the Head First Labs website: www.headfirstlabs.com/books/hfcsharp 366   Head First Lab #1 More free ebooks : http://fast-file.blogspot.com The Quest Everything 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. ibtArtoaiefgcmhtFktse.rr-oTtcnhyhltaoiac”tutk,’vateeorhnneaesudntprdhiesceeeskdneppddlltaahtyyueeheprer.n’sitinciheocrnoPesneicsattwnuaedryaepsB“oeanolbexcoictvcoeon“”nsBtartrnioyonlgs, The inventory contains PictureBox controls, too You can represent the inventory of the player as five 50x50 PictureBox controls. Set the BackColor property of each to Color.Transparent AdmfmyleHidouotaaaenrudcttkagmheltdceeneloteiwirFnbcnaoielk.ilcawrlohUcPsohmntknsieeocoernLatvteoerteuhafrrhyeb3teoeots0BwhuPhSewxoiempctix3eztlhbai0emuaaccr.rtoseapeionIgtrBtstuteoehnhosr.poddxeoewfom.lrsretstU—osotyunmstope’stthettowtethhhheeeen ftftCohrhoreoenmnt“ftBrdo,orrealmissnnigdgonnveteweerorhdlicaFscophrtmooeamnartkcae”nhnoidanwosntbddwhaoehc“r.ikSc.eihnnTdothnhateetos’sIaBDrwaeEhc,kaint”so (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: Y5o0ux’l5l 0neePdictfuivreeBmooxrees 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: trtWehhshaetetnfoowftrehmatephsoephnloaicuiycoledonrnss’eetqBtouoitFprhdsixeeoernBdSeSotrioyndflgeelerttShoatenyNdwloeetnaohepf.eons, 2 columns, 4 rows... 8 cells for your hit point statistics. vaEanlaudceshyodcueurlclianhngasutphadeaLtgaaebmetelh.oinseit, More free ebooks : http://fast-file.blogspot.com you are here 4   367 The Quest The architecture: using the objects You’ll need several types of objects in your game: a Player object, several sub-types of an Enemy object, and several subtypes of a Weapon object. And you’ll also need one object to keep up with everything that’s going on: the Game object. Toyaounhtudisaiefinsleoijtmtu’issemtsnotemraheorevdetge,ehtnheaeoiprlwslaalotynoehvrehe,oreewvntieecmtw.hy.eWfpiegl’alulyregersive ct ct ect ec t y> Player obj TTWwwdihheirhlaeleeepccfontaoGnllyrosla,mntwohmeirnetoeheeGvfneatyerohommbieuneiejtrpseoe.lfacorbyatFrjeecmortchsrt’s,s’masMnMooodbvvleejeseb(u)tttumootGrnbehnasjtemheisscofetocdstrl.iamciTnkkeahetsndahdtt,ehtmdhgeeaeeaimtnflhspoeo.urwtdmitGfhraotmmheeTshroeohofwetebrehrevjee’esenrgc,oaenhm,laynesoojtaunWseaLtewiLsnaeteiaPjalelpatvoyoenelL,ri,st Enemies; public Weapon WeaponInRoom; Twcahenlel’s-teendacoraepaosnukylatayhtienadgs..p.inuianbplipocrtohpperrroipawetroetridwesist, ihjfutsEthnememma.kyeasnudreWtehaepofnoramre The game keeps a private Player object. The form will only interact with this through private Player player; methods on Game, rather than directly. 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 a Top, Bottom, Left, and Right field, and works perfectly private Rectangle boundaries; for the overall game area. public Rectangle Boundaries { get { return boundaries; } } public Game(Rectangle boundaries) { this.boundaries = boundaries; player = new Player(this, Game starts the dungeon, object in the oadunutdngwceriotenha.taesboaunnedwingPlbaoyxerfor new Point(boundaries.Left + 10, boundaries.Top + 70)); } public void Move(Direction direction, Random random) { player.Move(direction); foreach (Enemy enemy in Enemies) enemy.Move(random); } eMdnireoemvceytmiieonnntatihrseasnifdmooprmlme:dgmiirvoeevcsetuitosn,h.eanpdlamyeorveineatchhe public void Equip(string weaponName) { player.Equip(weaponName); } public bool CheckPlayerInventory(string weaponName) { return player.Weapons.Contains(weaponName); } public void HitPlayer(int maxDamage, Random random) { player.Hit(maxDamage, random); } These are all great examples of encapsulation... Game doesn’t know how Player handles these actions, it just passes on the needed information and lets Player do the rest. 370   Head First Lab #1 More free ebooks : http://fast-file.blogspot.com The Quest public void IncreasePlayerHealth(int health, Random random) { player.IncreaseHealth(health, random); } TAgehttetaapclkat(yu)errnisatatoltmmaocosktvse,.eaxnadcttlyhelikeeneMmoievse(a)l.l public void Attack(Direction direction, Random random) { player.Attack(direction, random); foreach (Enemy enemy in Enemies) enemy.Move(random); } GtdheeettReNramenwdinLoemewvLehole(c)raetmiteootn(hp)oladwc,ielwl ehcniocemhmeiweisinllahnuasdnedwiyteaitnpoons. 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 public void NewLevel(Random random) { level++; random location within the rectangle that represents the dungeon area. switch (level) { We only added the case for case 1: the level 1. It’s your job to Enemies = new List(); add cases for the other levels. Enemies.Add(new Bat(this, GetRandomLocation(random))); WeaponInRoom = new Sword(this, GetRandomLocation(random)); } } } break; Finish the rest of the levels Wbpg(lleaaua’nmevydeeeprotostnhhalioleyoruneslgadaoadmntn’yetdrhgaooaodonsemedsarfainreoedrrtdehpdtepohotpeitoinoitbvoneiln.oun,enSttoopthrooieytfntifothtonehrh)e.eloenveel It’s your job to finish the NewLevel() method. Here’s the breakdown for each level: Level Enemies Weapons 2 Ghost Blue potion 3 Ghoul Bow SiLnoetvifheel t2phl,eanyboeltru’hesinpingovtaeinpotnpeoiarsrysstfoirlnlom this level. 4 Bat, Ghost Bow, if not picked up on 3; otherwise, blue potion 5 Bat, Ghoul 6 Ghost, Ghoul 7 Bat, Ghost, Ghoul 8 N/A Red potion Mace Mace, if not picked up on 6; otherwise, red potion N/A - end the game with Application.Exit() bTLtehheeevinserluoes5ndelydhpaoaustppipa.oelnraerfasrdoiyfm More free ebooks : http://fast-file.blogspot.com you are here 4   371 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. MYcPinaoolhnauve’’yetlrlerirtobinesaflyniarndboisnsmtEtsatrnniataetncm.ittayit,,aestwdoeh. ich Mover (abstract) Location: Point Nearby(locationToCheck: Point, distance: int): bool Move(direction: Direction, boundaries: Rectangle): Point Player inherit afnrdomEnMeomvyerboth wicaWtlhnaeadestasap’sdsdiaedirgraeaogdmifrnoaegrrtmeoetynrtuo.srountmtovoaatklsuheeeiess Nearby() takes a point, and figures out if it’s awwitahyinfraocmertthaeinobdjisetcatn. ce Mactsaholavtcethuleatmtadoekuvsenesmgweaehonendtr’iesrwebtocohtuuelindodennbaaders.iepwso,einalltndof Player Weapons: List HitPoints: int Attack(direction: Direction, random: Random) Hit(maxDamage: int, random: Random) Equip(weaponName: String) Move(direction: Direction) Enemy (abstract) HitPoints: int Move(random: Random) Hit(maxDamage: int, random: Random) Weapon (abstract) PickedUp Location PickUpWeapon() DamageEnemy() The the Player Move() class overrides method. Add a Direction enum aMYnodouvePc(al)anyoecnralblnooNtwhe.aErbnye(m)yand 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. Enemies don’t have an Attack() method because their attacking is built into Move(). 372   Head First Lab #1 More free ebooks : http://fast-file.blogspot.com The Quest The Mover class source code Here’s the code for Mover: public abstract class Mover { private const int MoveInterval = 10; protected Point location; tcaShavirnano’ictluaegbshpleerttothttoeehcseptuueblbodclcliaacptsrsgioeoepsnt,e..rt.mthoeieentslhyfoaordrreemawdoeonblidytjeecftine. public Point Location { get { return location; } } protected Game game; public Mover(Game game, Point location) { this.game = game; this.location = location; IonbstjeacntceasndofaMcuorvreernttalkoecaitniotnh.e Game } 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 { return false; } } The Nearby method checks a Point against location. If they’re within distance of returns true, otherwise it returns false. this each object’s current other, then it public Point Move(Direction direction, Rectangle boundaries) { Point newLocation = location; switch (direction) { case Direction.Up: if (newLocation.Y - MoveInterval newLocation.Y -= MoveInterval; break; case Direction.Down: if (newLocation.Y + MoveInterval newLocation.Y += MoveInterval; >= <= boundaries.Top) boundaries.Bottom) tbnciTthoneareuwhnianee,odsPridMtaoitigrironoiryentve,came.ttil(touIi)oPfvrneornm.eiistneotItttnfuh.ehhrioietntsdssteap break; case Direction.Left: if (newLocation.X - MoveInterval >= boundaries.Left) newLocation.X -= MoveInterval; break; case Direction.Right: if (newLocation.X + MoveInterval <= boundaries.Right) Iotsfsutthtaeatsyrhinstdeeietwnehgtneldhopecoslaaionbmtctoiaeou.tnnaidosnatriihsees, newLocation.X += MoveInterval; break; default: break; } return newLocation; } } Finally, this new location is returned (which might still be the same as the starting location!). More free ebooks : http://fast-file.blogspot.com you are here 4   373 The Quest The Player class keeps track of the player The Player and Enemy objects need to stay inside the dungeon, which means they need to know the boundaries of the Here’s a start on the Player class. Start with this code in playing area. Use the Contains() method the IDE, and then get ready to add to it. of the boundaries Rectangle to make sure they don’t move out of bounds. public class Player : Mover { private Weapon equippedWeapon; foArflol mPofladyitreherectaprraeocphceiedrsdts.eiens private int hitPoints; public int HitPoints { get { return hitPoints; } } private List inventory = new List(); public List Weapons { get { List names = new List(); foreach (Weapon weapon in inventory) names.Add(weapon.Name); return names; AmienquvPuletlinapitpyoloeernryewc,eaabatnuptoahnoctsladiimnneo.nly } } PfrlaoymerMinohveerri,tsso public Player(Game game, Point location); } : base(game, hitPoints = 10; location) { TcitahslelshpittlahPyeoeinbrta’sssectoconlas1ts0srucacontndosrttrshueectntsor. ttlohhciesatGpiaoasnmseetsoainntdhat base class. 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); } The Equip() method tells the player public void Equip(string weaponName) { to equip one of his weapons. The Game foreach (Weapon weapon in inventory) { object calls this method when one of the if (weapon.Name == weaponName) inventory icons is clicked. equippedWeapon = weapon; } } } AobPjelactyeerqoubipjpeecdt actanaotnilymeh.ave one Weapon 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. 374   Head First Lab #1 More free ebooks : http://fast-file.blogspot.com The Quest Write the Move() method for the Player Game calls the Player’s Move() method to tell a player to move in a certain direction. Move() takes in the direction to move (using the Direction enum you should have already added). Here’s the start of that method: This the the mfhooarvpmepmeniessnctwlihcbekunetdto.onnes of on 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 Move is in base class. the Mover } } You’ve got to fill in the rest of this method. Check and see if the anWnedheednaspttpoehaedrpisilanapytpeehraepriicnfkvresonumtpotrayh.ewedaupnogne,oint 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. tTimnhvhaaiektsii’nbWsgleenatowphtohenetwnhaeentadhjpoeofbnop’rsolamfPyeitwcrhtilepulirchPekablsanoydxietlerucpl.a..ss. Add an Attack() method, 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, TmepwihntlehauestiymcheAwhoretad’wasntpdeatAoachntapkasot(tR)naa.actlilnksad(hke)aoeqvmswueiiaploalpbDnefjdeiiArgceuttacrtn.tedaTicoohcknuea(t)ll from the Direction enum). Here’s the method signature: public void Attack(Direction direction, Random random) { // Your code goes here } Iprifpnoelvtamteyiohoneventre,oswrdteyirhtaienapnfkfosrntAoeitimtrst. aattchhkee() 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” word to see if a Weapon is an implementation of IPotion. More free ebooks : http://fast-file.blogspot.com you are here 4   375 The Quest Bats, ghosts, and ghouls inherit from 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 public abstract class Enemy : Mover { private const int NearPlayerDistance = 25; private int hitPoints; Move(random: Random) Hit(maxDamage: int, random: Random) public int HitPoints { get { return hitPoints; } } public bool Dead { get { if (hitPoints <= 0) return true; else return false; } The form property be visible tcoanseueseifthtihsereenaedm-yonslhyould in the game dungeon. } public Enemy(Game game, Point location, int hitPoints) Each : base(game, location) { this.hitPoints = hitPoints; } subclass of Enemy public abstract void Move(Random random); When the player attacks an enemy, it calls the implements this. public void Hit(int maxDamage, Random random) { enemy’s Hit() method, which subtracts a random number hitPoints -= random.Next(1, maxDamage); from the hit points. }prorteetcutrend(bNoeoalrbyN(egaarmPel.aPyleary(e)rL{ocatiTfominhegteu,rhEeodnoeumftryowmchlaemstsohvienerhre,itrw’istheincdehatrithtechNaenepaulrasbeyyet(r)o. NearPlayerDistance)); } protected Direction FindPlayerDirection(Point playerLocation) { Direction directionToMove; if (playerLocation.X > location.X + 10) directionToMove = Direction.Right; else if (playerLocation.X < location.X - 10) directionToMove = Direction.Left; else if (playerLocation.Y < location.Y - 10) directionToMove = Direction.Up; else directionToMove = Direction.Down; return directionToMove; idDfrtbnIefiiahirglrosaeeueyretcrcodptietcouleialionraooyfnsunetetstrteo’oes’dhsnwtmeluhlFhmoooeeeicvrnnceateedeathnmPtitetaooylhtmanwieyn,yaoteeirpetraendllDnd’allssdlysfiretuiyteerrshooleceduetitsmtiuwptoirholnnohanev(iyec)aehr. } } 376   Head First Lab #1 More free ebooks : http://fast-file.blogspot.com The Quest Write the different Enemy subclasses 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: public 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 passes 6 starts to the with base 6 hit class points, so it constructor. public override void Move(Random random) { // Your code will go here } } EEsuanbcechmlayosfsbeastsheMecsoelvaessrsu.,bwclhaiscshesinthteurn Tsohmeebwahtatflrieasndaormoulyn,dso it uses Random to fly in a random direction half the time. Otiuthnn’ecltleiflstaotnrihlmleebnwpeelomainnyy’ettrhhadfesisinpgnilaosamhymeesoi’tsrteEahnenhyeitlmemvipeoeoslri.enl.itstsB, ut Bat The bat starts with 6 hit points. It’ll keep moving towards the player Move() and attacking as long as it has one or more hit points. When it moves, there’s a 50% chance that it’ll move towards the player, and a We’ll have to make 50% chance that it’ll move in a random direction. After the bat moves, sure the form it checks if it’s near the player—if it is, then it attacks the player with sees if an enemy up to 2 hit points of damage. should be visible at every turn. Ghost Move() Ghoul Move() 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 towards the player, and a 2 in 3 chance that it’ll stand still. If it’s near The ghost the player, it attacks the player with up to 3 hit points of damage. and ghoul use Random to make them move more 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, slowly than the player. there’s a 2 in 3 chance that it’ll move towards 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. More free ebooks : http://fast-file.blogspot.com you are here 4   377 The Quest Weapon inherits from Mover, Weapon inherits each weapon inherits from Weapon from Mover because it uses We need a base Weapon class, just like we had a base Enemy class. its Nearby() and And each weapon has a location, as well as a property indicating Move() methods in whether or not it’s been picked up. Here’s the base Weapon class: DamageEnemy(). Weapon (abstract) PickedUp Location PickUpWeapon() DamageEnemy() public abstract class Weapon : Mover { protected Game game; private bool pickedUp; public bool PickedUp { get { return pickedUp; } } private Point location; AfbaoecprcdimecsiksscpeoaldranUytepuodsewfaeitngahyupimrosenogrtesehht..oa.tutldhoneu’tt. public Point Location { get { return location; } } public Weapon(Game game, Point location) { Every in the wgaemapeonduhnagseoan.location this.game = game; this.location = location; pickedUp = false; } Tfitiheheldacss,onn’atsntdbreusecenttospripcsikceektdesdutUphpeyetgtoa)m.fealsaend(bleoccaautsieon public void PickUpWeapon() { pickedUp = true; } public abstract string Name { get; } EiAhmatopcwtlheamtcwkhee(ana)ttpmowaneetNachpalaoomsdnseatnpthertaeotadpcsedkrtset.otyeramndineasn Ew“N“pr(iMtBe“raeasaSotcomapphwuwnceoeroae”nrnr”)m’ts.,sdey”pp, ruoPfbtooleirficnoctt(rieiefadtnaebatc(nsbrhNetogdemroei(ayaltsEr.ctnbHt=aeyiDnm(tvagcye(omaendiameeadge=nmme.eyaAEP0m.gtnl;yLeteao,amydiccyeinark(irstaD(nLtginiDtoaaodricnmnoredace,mecate.)ctmiEt;tiao 0) { visibility of the enemy showBat = true; enemiesShown++; PictureBox just a bit. controls in } } // etc... Yainnoduy’ololunrneefefodorretawtcohhemlogoohrpoe—uli.fonsetaftoremtehnetsghliokset this 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. 382   Head First Lab #1 More free ebooks : http://fast-file.blogspot.com 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; bow.Visible = false; redPotion.Visible = false; bluePotion.Visible = false; mace.Visible = false; Mmutpraaatkwcceikhtshdutrohbeweusngyesoiunftrahmtachteoesn.yatrIrdteoo’lsdsn’’ietfanfasmiymcauettlsotchet.nod 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) { weaponControl.Visible = false; } else { weaponControl.Visible = true; Eimtva’sekrebyeietlensvepiclicohknaesidnovunispei,bwlweee.anpeoend. If to } if (game.PlayerHitPoints <= 0) { MessageBox.Show(“You died”); Application.Exit(); } if (enemiesShown < 1) { Application.Exit() immediately quits It’s part of System.Windows.Forms, the program. so you’ll need the appropriate using statement if you want to use it outside of a form. MessageBox.Show(“You have defeated the enemies on this level”); game.NewLevel(random); UpdateCharacters(); } If there are no more enemies on the level, then the player’s defeated them all and it’s time to go to the next level. More free ebooks : http://fast-file.blogspot.com you are here 4   383 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. 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/ 384   Head First Lab #1 More free ebooks : http://fast-file.blogspot.com 9 reading and writing files Save the byte array, save the world Okay, 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   385 More free ebooks : http://fast-file.blogspot.com islands in the stream C# uses streams to read and write data A stream is the .NET Framework’s way of getting data in and out of your program. Any time your C# 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. Whenever you want to read data from a file or write data to a file, you’ll use a Stream object. input = stream.Read(); bytes read from the file Main form input contains data read Stream obj from the stream You use Stream aobject... ect .w..iatnhdtthheefsitleredaimrewctolryk.s And if your program needs to write data out to the file, it can use another Stream object. stream.Write(output); output contains data to write to the stream bytes written to the file ect Main form stYsathomreueeap.umrseocoaebsjdseicfistf,etrbheuentt Stream obj 386   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files Different streams read and write different 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 isStotsryoeowaunmc. aisn’atninasbtsatnrtaicattecliatsso,n ToSfhtertseehaemarmecelatjushsso.tdssoimnethe Close() Read() Seek() Write() fsmEpueenatcccithhfoioisdcnusabtlcaoitlnaytds.hspaatrdodcpelsarsts’ises FileStream MemoryStream NetworkStream GZipStream Close() Read() Seek() Write() Close() Read() Seek() Write() Close() Read() Seek() Write() Close() Read() Seek() Write() FileStreams let you read from and write to files. MemoryStreams let 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. Things you can do with a stream: 1 Write to the stream. You can write your data to a stream and 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 insert data at a specific place. A GZipStream lets you compress data so that it takes up less space and is easier to download and store. Streams let you read and write data. Use the right kind of stream for the data you’re working with. More free ebooks : http://fast-file.blogspot.com you are here 4   387 so much easier A FileStream writes bytes 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 Create a new FileStream object and tell it to write to the file. MtoakaenysuprreogyroaumadtdhatusiunsgesSsytsretaemms..IO; FileS 2 The FileStream attaches itself to a file. tream obj aAttFailcehSetdretaomonceanfoilnelyatbea time. ect ect FileS tream obj 3 Streams write bytes to files, so you’ll need to convert the string that you want to write to an array of bytes. 69 117 114 101 107 97 33 This talk ims ocraelleadboeuntcoitdilnagt,earnodn.w..e’ll Eureka! 4 Call the stream’s Write() method and pass it the byte array. 69 117 114 101 107 97 33 ect ect FileS tream obj 5 Close the file so other programs can access it. 388   Chapter 9 Fbltooighcrakgdteeetdaft,li.ilanenOgduttnhootetirlchwlyeoiorsseuep, cartloohsgtsererafeymaiolsmeurcwiassinltal’trbeeausme. FileS tream obj More free ebooks : http://fast-file.blogspot.com reading and writing files How to write text 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 links it to the file. Then you can use the StreamWriter’s Write() and WriteLine() methods to write everything to the file you want. StreamWriter creates and manages a FileStream object for you automatically. 1 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 also 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. StreamWriter writer = new StreamWriter(@”C:\newfiles\toaster oven.txt”, true); FileS Stream ject ect Writer ob tream obj Pftetuihsaltceibsatnpaiaonemsrgeca\@htnaliertiflnaeloscrrftaCrelno#resnstw,trtlliioinonkefget., rt\wehtaitethfoourt 2 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.ToString()); The toaster oven ... ... is set to 350 degrees. ject ject File Stream Writer ob Stream ob 3 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(); More free ebooks : http://fast-file.blogspot.com you are here 4   389 write it down The Swindler launches another diabolical plan The citizens of Objectville have long lived in fear of the Swindler. Now he’s using a StreamWriter to implement another evil plan. Let’s take a look at what’s going on: This tells liitnewchreeraetetshethfeileStwriellambeW. riter object and The path that the interpret an escape Ssstetthqareureeta“ns\mc”eWw.airtsihtteahrned@soteassrnigt’tn osfo StreamWriter sw = new StreamWriter(@”c:\secret_plan.txt”); sw.WriteLine(“How I’ll defeat Captain Amazing”); WriteLine() sw.WriteLine(“Another genius secret plan by The Swindler”); adds a new line after writing. sw.Write(“I’ll create an army of clones and “); Write() sends sw.WriteLine(“unleash them upon the citizens of Objectville.”); just the text, with no extra string location = “the mall”; line feeds at for (int number = 0; number <= 6; number++){ the end. Can you going on variable ifnwiigttuhhrisethcooeudtleow?cahtaito’ns sw.WriteLine(“Clone #{0} attacks {1}”, number, location); if (location == “the mall”) { location = “downtown”; } else { location = “the mall”; } } sw.Close(); Cfudsiloloiennsg’eta.(n)cdTlfoarhseneeyesttrehuexepstosautdnrryoceeeacssmnot’.nthneegceStttiorwnesraimttotWetrnhiteiferyiosu 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} second, and so by on. the Tcohdiseisabwohvaetptrohdeuces. 390   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files StreamWriter Magnets Suppose you have the code for button1_Click() shown below. sw.WriteLine(Zap); Zap = “red orange”; return true; 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! } private void button1_Click(object sender, EventArgs e) { sw.WriteLine(Zap); Flobbo f = new Flobbo(“blue yellow”); sw.Close(); StreamWriter sw = f.Snobbo(); return false; f.Blobbo(f.Blobbo(f.Blobbo(sw), sw), sw); } public bool Blobbo (bool Already, StreamWriter sw) { public bool Blobbo(StreamWriter sw) { sw.WriteLine(Zap); Zap = “green purple”; return false; } retuSrtnrenaemwWriter(“macaw.txt”); } } } private string Zap; public Flobbo(string Zap) { this.Zap = Zap; } public class Flobbo { if (Already) { } else { public StreamWriter Snobbo() { Output: More free ebooks : http://fast-file.blogspot.com you are here 4   391 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); } public 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; } public bool Blobbo (bool Already, StreamWriter sw) { if (Already) { tdTiswihfooefvedeBrreellconolbtaabdrpoaea(td)ri—oamnmitseet’swtheigotrodhst. sw.WriteLine(Zap); sw.Close(); return false; } else { sw.WriteLine(Zap); Zap = “red orange”; return true; } } } Make files with sure when you close you’re done them. Output: 392   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files Reading and writing takes two objects Let’s read Swindler’s secret plans with another stream, a StreamReader. StreamReader works just like a 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 = new StreamReader(@“c:\secret_plan.txt”); PtSoatsrrseetaamhdeRfefraioldemeyrio’nsutcowoantnshtteructor. StreamWriter writer = new StreamWriter(@“e:\emailToCaptainAmazing.txt”); TtShwhaiistndpwlreiorllg’srgaepmtlaneu,mseaasnildeadaSttSorteCraemaapRmteWaaidnrietAremrtaotzorinewga.rdittehae file 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); EtdhnaadttOaftleSefltltsreyuaonmureiiasfdtthihneertpehr’eospnfeorilte.y } writer.WriteLine(); writer.WriteLine(“Can you help us?”); oTtuhhteistrloeoaotdpheerrewaanrddisteawrr.liinteesfirtom writer.Close(); reader.Close(); Mystoaruke’raeemsjuutrshetattroeyacodluoinsogepeaenvf,erielyeve. n if More free ebooks : http://fast-file.blogspot.com you are here 4   393 don’t cross the streams Data can go through more than one stream 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() ject object ject File Crypt File Ugestinsgwarintotremnadl iFreilcetSlytrteoama, your data file as text. I’ll create an army of Clones and CryptoStream Close() Read() Seek() Write() Stream ob CtYeroxyutpwttoroSittaerenaomrm. al I’ll create an army TcayohnonedunrCegctirvteyeexpsdttto,thSboatuttraefaFeimnlielceriSssyttprrteeeaadmm. , tNhoeweynocrurypFtieldeStterxetamtowrtihteesfile. CryptoStream inherits from the abstract Stream class, just like the other stream classes. *3yd4ÿÖndfr56dì¢L1═ *3yd4ÿÖndfr56dì¢L1═ oStream Stream ob 394   Chapter 9 You can CHAIN streams. One stream can write to another stream, which writes to another stream... often ending with a network or file stream. More free ebooks : http://fast-file.blogspot.com 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. public class Pizza { private ____________ _______; public class Pineapple { public Pizza(__________ _______) { const ______ d = “delivery.txt”; ______.Writer = Writer; public _____ ______ } { North, South, East, West, Flamingo } public void ______(______.Fargo f) { public static void Main() { Writer._________(f.ToString()); __________ o = new ____________(“order.txt”); Writer.__________(); Pizza pz = new Pizza(new __________(d, true)); } pz.________(Fargo.Flamingo); } for (_____ w = 3; w >= 0; w--) { Pizza i = new Pizza (new ___________(d, false)); public class Party { private ____________ Reader; i.Idaho((Fargo)w); public Party(____________ Reader) { Party p = new Party(new __________(d)); p.___________(o); __________.Reader = Reader; } } public void HowMuch(__________ q) { o.___________(“That’s all folks!”); o.__________(); q._________(Reader._________()); Reader.__________(); } } } } Note: each snippet from the pool can be used more than Stream once! HowMany HowMuch HowBig int long string enum class ReadLine WriteLine Reader Writer StreamReader StreamWriter Open Close public private this class static for while foreach = >= <= != == HowSmall ++ -- Fargo Utah Idaho Dakota Pineapple More free ebooks : http://fast-file.blogspot.com you are here 4   395 a serious dialog Pool Puzzle Solution ToTofhSittshreeinnguom(u)tipmsuetuts.hedodwtitohpirtinst a lot public 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”); HtSttpehPthhareierreszesop’zPsaiurnaamgotg.rhWgIhtderetyraaaihhcmetcehone.l(tarF)Iosrtfsatym.rhcteTgpartohotehhieanemmotitntdeemtsifpttooabaorseltosrpehosrsep,isntto. Pizza pz = new Pizza(new StreamWriter(d, true)); pz.Idaho(Fargo.Flamingo); for (int w = 3; w >= 0; w--) { Pizza i = new Pizza(new StreamWriter(d, false)); i.Idaho((Fargo)w); Party p = new Party(new StreamReader(d)); p.HowMuch(o); } o.WriteLine(“That’s all folks!”); o.Close(); } } public class Pizza { private StreamWriter Writer; public Pizza(StreamWriter Writer) { this.Writer = Writer; } public void Idaho(Pineapple.Fargo f) { Writer.WriteLine(f.ToString()); TSfwhftmireeirleileetdPtae,huimszsaoWizndFnadgsar.irtcitgtlehaosressieIardnksauTehmaoeosSp(pst)trrioamvinatetgth(ehe)od Writer.Close(); } } public class Party { TriStethsaredHesPaomawarRMtlienyuaecdchfel(arr)sosfmmhieeattldshh,oaadtand iSttrteoaamRSetardeearmWanrditewrr.ites private StreamReader Reader; public Party(StreamReader Reader) { this.Reader = Reader; } public void HowMuch(StreamWriter q) { q.WriteLine(Reader.ReadLine()); Reader.Close(); } } 396   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files Use built-in objects to pop up standard dialog boxes 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. .slNieklEeeTctthihniasgsOadpfieanilloFegitleboDooxiapelesongb. ufioltr in, TFdhoiailsdloeigsrBtbrohoxew. seDialog ShowDialog() pops up a dialog box Displaying a dialog box is easy. Here’s all you need to do: We’ll these walk you steps in through a minute. 1 Create an instance of the dialog box object. You can do this in code using new, or you can drag it onto your form out of the toolbox. 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 button or the 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). More free ebooks : http://fast-file.blogspot.com you are here 4   397 dialog boxes are objects too Dialog boxes are just another .NET control You can add Windows standard file dialog boxes to your program just by dragging them to your form –just drag an OpenFileDialog control out of the toolbox and drop it on 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. “ofiNtuotordnmoo-fewvsinhstu’ehtanel”aytpojopuuoeslatdbrromaxoeg.nainytsour When you drag a Toolbox and onto displays it in the component out of the your form, the IDE space underneath the form editor. The InitialDirectory property changes that’s first displayed when the dialog the folder opens. openFileDialog1.InitialDirectory = @“c:\MyFolder\Default\”; openFileDialog1.Filter = “Text Files (*.txt)|*.txt|” + “Comma-Delimited Files (*.csv)|*.csv|All Files (*.*)|*.*”; twdttocTphihhharaeshaalothoetnpboggetwoFserbyht.itlopotttyexwohes,merleusotpufofcsfiolhftynteioalhreusses ooopppeeennnFFFiiillleeeDDDiiiaaallloooggg111...FCCihhleeeccNkkaFPmiaelteh=EExx“iidssettfssau==lttf_rafuliesl;ee;.txTttutohsh”eead;rsteistpdprloraieeoysspneat’rntoteoeierxpsreisonttreulomplnetasthshefaeigldeediariolfiorvgetp.hbaetoxh DialogResult result = openFileDialog1.ShowDialog(); if (result == DialogResult.OK){ OpenSomeFile(openFileDialog1.FileName); } aDuDnsieidasrploDlhagiiyRtaletotsghuhRelete.dsOiuTaKlltho.abgCtua’btsnotcaxoennlu.eisfIintnug’hmlleitbthsehitaSstehCtoaywontDcuoeiclaD.aloinagl(uo)sgeRmteesotuhlctoh.dOe,cKkwhiwfichhtethrheeeturusreonrrscnaloictketdheOK, 398   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files Dialog boxes are objects, too An OpenFileDialog object shows the standard Windows “Open” window, and the SaveFileDialog shows its “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 buttons or results, so a simple bool wouldn’t be enough). When you drag a save dialog object out of the toolbox and onto your form, the saveFileDialog1 = new SaveFileDialog(); fIDorEm’jsusItnitaidadlizs eaCloinmepolinkeentt(h)ismteothyoodur. 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); } TparhsoeopnSerhttohiweesDOwiapoleorngkF()eilxeaDancditallFyogilteohNbeajemsacetm.e The SaveFileDialog “sSotbaajvneedctaasr.pd.o.”pWsdiinuapdlootgwhsbeox. The Title property lets you change this text. pIsotnTrmppihoeteehepcitneaeisfhdlrSDoititeahdyihdloro.eewpgiconDftpbootisolardhxluyoeepgra(n)d Change the “Save as type” list using the Filter property. ifWnilhtee,hneittsFhifeleuNlulsaepmraetchphroisoopsseeasrvteayd. TrSlweuehhtshteoeiuswcrDrhyDncioeabliudialucoltfkogbegtRiygd(oeu)n.tsrumehtletehoteuhtod More free ebooks : http://fast-file.blogspot.com you are here 4   399 directory assistance Use the built-in File and Directory classes to work with files and directories Like StreamWriter, the File class creates streams for you to 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, you can use it to make changes to your file structure easily. Things you can do with a File: 1 Find out if it 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 tsaItfhafetyilioFecu,il’mreyeIoenutfghoomoinidcgglsha.sttsowinbasenttedaotdiongocfraeualsotitnegoaftnhiwenosFtrakilnewcecitlaohsfs’s iFTiFttisihlleteeOIonpcFfuleiaoslesnesaIRnindtfed.ooaeadcsYcl(oace)uesxsscscmedapieontttesschyroEjoeduuxasttiihnesaajvtabuesosntut(etow)theinivemnsetserstaatyanmhtntohecidieanwt,goaeofytr.he Tifsahsbeteetortnlefyrordsiufaitfseemrdeanfllcoenruimbsibgtehjraotbosft. haectFioilnes class and is FileInfo Things you can do with a Directory: 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. Use the Delete() method. 400   Chapter 9 More free ebooks : http://fast-file.blogspot.com 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 a @ in front of the string that contained the filename? A:The Write() and WriteLine() methods support escape sequences like \n and \r. 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 linebreak in the output: string twoLine = @"this is a string that spans two lines."; Q:And what do \n and \t mean again? A:Those are escape sequences. \n is a linefeed and \t is a tab. \r is a return character, or half of a Windows return—in Windows text files, lines have to end with \r\n. 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 repesented 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. 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 individal byte to a character—for example, E is 69 and a is 97. 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: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? A: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:What if I want to create my own dialog boxes? Can I do that? A:Yes, you definitely can. You can add a new form to your project, 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:Why do I need to worry about closing streams after I’m done with them? A: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. More free ebooks : http://fast-file.blogspot.com you are here 4   401 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 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”); What the code does 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”); 402   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files Use File Dialogs to open and save files (all with just a few lines of code) You can build a program that opens a text file. It’ll let you make changes to the file, and saves your changes. with very little code, all using standard .NET controls. Here’s how:. Do this 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. This text is a multiline box. 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: private void open_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { name = openFileDialog1.FileName; textBox1.Clear(); OCpliecnkFinilgeDOipaelnogshcoownts rtohl.e textBox1.Text = File.ReadAllText(name); } } 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); } } TWpcWdahoereremti’ttlialRneiolgAleofailounldkTptAejhauoxleltsntTt(Fett)xaihhltmeeef(me)ecntwleaaihnxnsoptsddma. sgpoTearashegr.aeet. ’s 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 dialog OpenFileDialog start in a specified directory. ± Filter the OpenFileDialog so it will only show text files using the If you don’t add a filter, then the drop-down lists at the of the open and save dialog bottom boxes will be empty. Try using this “Text Files (*.txt)|*.txt” filter: Filter property. More free ebooks : http://fast-file.blogspot.com you are here 4   403 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 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 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”); What the code does Check if the C:\SYP folder exists. If it doesn’t, create it. Check if the C:\SYP\Bonk folder exists. If it does, delete it. 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\”, Get a list of all files in C:\Windows that “*.log”, SearchOption.AllDirectories); 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”); File.Encrypt(@”c:\SYP\Bonk\weirdo.txt”); This is an alternative to using a CryptoStream. 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. 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 = Declare the myTime variable and set it equal Directory.GetCreationTime(@”c:\SYP\Bonk”); 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. 404   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files IDisposable makes sure your objects are disposed properly A lot of .NET classes implement a particularly useful interface called IDisposable. It only has 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 You’ll learn official C# definition of IDisposable. Go to your project and type more about IDisposable anywhere inside the code. Then right-click on it and select “Go “Go To To Definition” from the menu. It’ll open a new tab with code in it. Expand all Definition” of the code and this is what you’ll see: later on. Declare an object in a using block and that object’s Dispose() method is called automatically. namespace System { // Summary: 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 // associated with freeing, releasing, or // resetting unmanaged resources. 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 cTsdeoehldefeecirnteti’tsh“iGaoatnohdfTaoeonrfdDiyaneenffyseiinavtaitt.ruiiroaenb”li,en,atonhdbejetIchDteEoIrDtEhmaetwtihllelotdas.utJyooumustaaturictigaohlmltya-tjciuclmiacplklyroijnguhmittp attnoodtthhee 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. More free ebooks : http://fast-file.blogspot.com you are here 4   405 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: Afoullsoiwngedstbayteamneonbtjeisctalwdeacylsaration... tTdhihfeefsteeroep“nuotsifnfgyr”ooumstratcthoeedmeoe.nnetss are at .w..aitnhdintchuernlyabbrlaocceks.of code 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”); naucTcobsrariohennmveagesatuelsesltiedoskatbettiajnheetamecnettyemho.nebetnjetcst otWbhhjeeecDntitsbpheoeisneug(s)iunsgmeedstthiastodermunoe.fnttheends, Every stream has a Dispose() method that closes the stream. So if you declare your stream in a using ItsnStotatbrtheyeiasmsmwcean—ctsleaw—,shsstiochishetrhwouebanjs.De..dcwistehpciobclsaeheri(nec)gdlomusinseeestdththohiedseupossotfiinnrgettahemde . statement, it will always close itself! Any time you Use multiple using statements for multiple objects use a stream, you should You can pile using statements on top of each other—you don’t need extra sets of curly brackets or indents. ALWAYS using (StreamReader reader = new StreamReader(“secret_plan.txt”)) using (StreamWriter writer = new StreamReader(“email.txt”)) { // statements that use reader and writer } Yswtoirulledacmolonss’etnotnwhee,emdbetacouatucosaemllattChiecloasulelsy(in.)gosntattheement 406   Chapter 9 declare it inside a using statement. That makes sure it’s always closed! More free ebooks : http://fast-file.blogspot.com Trouble at work Meet Brian. He likes his job as a C# developer, but he loves taking the occasional day off. But his boss hates when people take vacation days, so Brian’s got to come up with a good excuse. Sorry I’ve gotta leave early, boss. My cat’s got a vet appointment. reading and writing files 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! You can help Brian out by building a program to manage his excuses 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. Baohslntrilmeioaornfpseelawhlaecailecslnt,otesfxsaocttfuloehsoteelkds’mseeie.rnlpetto This asterisk appears when a form has unsaved data. 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. Save an excuse Select a folder 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. More free ebooks : http://fast-file.blogspot.com you are here 4   407 brian needs excuses Build the excuse manager so Brian can manage his excuses at work. Excuse Description: string Results: string 1 Build the form LastUsed: DateTime ExcusePath: string 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” messagebox. ≥ 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. ≥ The form knows when there are unsaved changes. When there are no unsaved changes, the text on the form’s title bar is “Excuse Manager”. But when the user has changed any of the three fields, the form adds an asterisk (*) to the title bar. The asterisk goes away when the data is saved or a new excuse is opened. ≥ The form will need to keep track of the current folder and whether or not the current excuse has been saved. You can figure out when the excuse hasn’t been saved by using the Changed event handlers for the three input controls. teccfaWhvrloeiaecrthntakmeettxnfeotahinyenbaaoldnodiutCdx.,dlhdetoyarrouonabugfgaleoedr- 2 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): private void UpdateForm(bool Changed) { if (!Changed) { RmeemanesmbNeOrT, t—hseo ! this.description.Text = currentExcuse.Description; this.results.Text = currentExcuse.Results; this.lastUsed.Value = currentExcuse.LastUsed; YkToeorheuip’nsllotptnarerateachdmkeaeoftfoferirtemlhidnihsdainissctayactotheuausrsn.gwfehoder.tmhetro ttieshhmie3NspOtecyxTh.ceucnskues}Mllpifoaartkhe}etilhtfsihFese(itt.!lhhfFSeiiootDssrlra..mditTTCeneeehrg.xxa.TttnbIegusx==etNtdtou““nl=EE=lxxoOFccCpriuuheElssanmeeenp.gatGMMeyeaadf(tnn;ocLaalduaggerseertrrreW”*bnr;”rti;oEtwxecTseuismreeDbeftU.(vuihopreEciuelsdndxubttafslcrteciurhCe-ehalseFhcadnoaenlnsidrncgPtlmogkeeaEner(txodttsynhchrofee)uutuove)srerhE)nee—xftt.coithnEurhehpsmxaeeutncn.tdhiunirlctsseeto’reesnasPtnuifnarcppoeoturtlhstaoy)nsocdyo.uooT.nttuotThhtSreehoonteIlrDscchiawEalnlinlglg(e); 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. 408   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files 3 Make 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 (use 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: YumMoseiuentsgchsaaotngdheedBtihoospavxeltIacryolaonltlaohdpwieassdrEayMmoxuecetlstaesomarga.stepBeioconixfi.ycSohanowb(y) 4 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: rIMtmSfehheteettosuswhhroaoenvgdaseeurBDsYtleooehiraaxsad/ltBcoeNlguidlcRotektteMsdssouine“aylNsstlo.soY.oaugN”egso,sebpN.Btoexohcoeixfpbn.aSyyrShtauhosmhowienwe(gt)()er. 5 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. More free ebooks : http://fast-file.blogspot.com you are here 4   409 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(); Ttoobhbhjejeeecccfttuo,rrfrmtoehnreutstesehesxelefccRiutesaleednddshofatmosoldcEshetxraoc,nruegrseeetdmh,beeuamtncbdtueorrknr.eewenhptetaEhxRecraunsoderomnot private void folder_Click(object sender, EventArgs e) { folderBrowserDialog1.SelectedPath = selectedFolder; DialogResult result = folderBrowserDialog1.ShowDialog(); if (result == DialogResult.OK) { selectedFolder = folderBrowserDialog1.SelectedPath; save.Enabled = true; open.Enabled = true; Itfabhnuetdthtfteoohnruesmsn.erseansvaeeblselecttshetedhfeaolofdtoehlrdeernrat,mheree } } 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; } saveFileDialog1.InitialDirectory = selectedFolder; sHeetref’os rwthhereeStahvee filters are As dialog. saveFileDialog1.Filter = “Text files (*.txt)|*.txt|All files (*.*)|*.*”; saveFileDialog1.FileName = description.Text + “.txt”; } DialogResult result = saveFileDialog1.ShowDialog(); if (result == DialogResult.OK) { currentExcuse.Save(saveFileDialog1.FileName); UpdateForm(false); MessageBox.Show(“Excuse written”); } AfTbtolohlhrteiFstT“iowleFmexisiltlleo(scf*Faoi.utl*feshse)eT.(tS*ywpa.oevt”exrtodd)wri,aoslapotndgodobwsoohnnxoe:watofunotperhien 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(); if (result == DialogResult.OK) { currentExcuse = new Excuse(openFileDialog1.FileName); Use the DialogResult enum 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); } } 410   Chapter 9 More free ebooks : http://fast-file.blogspot.com 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 return true; false;MessageBox.Show() also DialogResult enum that returns a we can check. } 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 public class Excuse { not update the input controls. HCffothwioecthiffnChaerreaahosaslheltndetrtlutagacmhsapnhUaenhmerd’geosdscapmeteeanendttatdeegtaanrhtaievethtristrnehdseleeteodneekt,FehttthtsfobtethiroerrohaonhriEmurragpefeetem,nguxn(xei.hdet)ra.cc,wreslunuIteeafsedsrdeeds,asdenty public string Description; public string Results; public DateTime LastUsed; public string ExcusePath; public Excuse() { ExcusePath = “”; } public Excuse(string excusePath) { aTrrehraeadyR,aalalnndodfomtthhEeenxctcuehsxoetobsfeusitletasonrinauntsdehosemDseairlreerccattyeodrinyfd.GoelexdtetFroilieonspt(eo)nta. on OpenFile(excusePath); } public Excuse(Random random, string folder) { string[] fileNames = Directory.GetFiles(folder, “*.txt”); OpenFile(fileNames[random.Next(fileNames.Length)]); } Wsootpueaertnmeefamdidleeeasntswsutierrlvleeeaartmlywo.atuTysismehebaatewucwesliaonysged. 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()); } } public void Save(string fileName) { using (StreamWriter writer = new StreamWriter(fileName)) { writer.WriteLine(Description); writer.WriteLine(Results); Hsdistcneoeaasrcitleidlltaee’sedsmrewoeCdffnhlotoetrarsheceueu(os)stmSihanmetuegsertteusiontsahm.iamonatWdgWteeimircsiaetlnleytr!, writer.WriteLine(LastUsed.ToString()); } }} More free ebooks : http://fast-file.blogspot.com you are here 4   411 i’m the decider Writing files usually involves 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 a variable enum—we’ll want against each of to compare the four SmtermebaemrWs raintderwdrietpeenadidnigffoenrewnhticlhineonteoitthe matches. We’ll also write if none of them match. something different 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”); else if (part == BodyPart.Knees) writer.WriteLine(“the knees are knobby”); else if (part == BodyPart.Toes) Is=uftp=awtw[eeromiputetsineniotgans],ts)hte”irhsioee“nvsiefwrofe(apneiafdnr/dtoevlseer. writer.WriteLine(“the else toes are teeny”); We’ve got we didn’t fainfdinaalmealstechin. case writer.WriteLine(“some unknown part is unknown”); } } 412   Chapter 9 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. More free ebooks : http://fast-file.blogspot.com reading and writing files Use a switch statement to choose the right option Comparing one variable against a bunch of different values is 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 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. A switch statement compares ONE A switch statement lets you compare one variable against many values in a way that’s easy to read and is compact. variable against Here’s a switch statement that does exactly the same thing as the series of if/else statements on the opposite page: enum BodyPart MULTIPLE possible values. { Head, Shoulders, Knees, Toes, } Ytkaoehubya’uwtlln’oscsrthgdaoorifnftogldwlotiiwfotfehbedertebhcnyeotmtspwphoaietsrscveihbadrleiaagvbaaleliunests. private void WritePartInfo(BodyPart part, StreamWriter writer) { switch (part) { Every case ends with “break;” so C# knows where one case ends and the next begins. case BodyPart.Head: writer.WriteLine(“the head is hairy”); break; case BodyPart.Shoulders: writer.WriteLine(“the shoulders are broad”); break; aswToswtfhphiaataetctrcaeebthmsvoieeckedsruneylyttafwhoroifaoslvltroaatdwlchussoeaeem.gtrsapihweiaensirtsetch You can also end a –catsheewpirtohgr“aremtuwrinll” compile as long as there’s no way for one case to “fall through” to the next one. case BodyPart.Knees: writer.WriteLine(“the knees are knobby”); break; Each of these cases consists case BodyPart.Toes: of the case keyword writer.WriteLine(“the toes are teeny”); followed by the value break; to compare and a colon. default: After that is a series of writer.WriteLine(“some unknown part is unknown”); statements followed by break; “break;”. Those statements } } cewSaxiwtseeihctsucataherddesetfmaifatauetnlmtcohe:nenebdtloos. cfckatnthheeantodtgheetrs will be executed if the case matches the comparison value. More free ebooks : http://fast-file.blogspot.com you are here 4   413 asleep at the switch Use a switch statement to let your deck of cards read from a file or write itself out to one 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. Card.Suits suit; switch (suitString) ( case “Spades”: tTsvthahalauetteeshmtwaoeistncctaohmisssupticataartlesletemoadrgeeanfditrnosistmnt.aaaTrtshmtsiesrwtinshiwgto.hidtcah The switch statement lets you test one value against a bunch of cases and execute different statements depending on which one it matches. suit = Card.Suits.Spades; break; case “Clubs”: suit = Card.Suits.Clubs; break; case “Hearts”: Etsistothamaecetehxsewevmocaifteuluntctethehssaeliguasnaenlelit.ncoisIlaftfsitettthhlhhieenieteyvfssaomalclulaooebtmwrcipienhnaa,grke.s suit = Card.Suits.Hearts; break; case “Diamonds”: suit = Card.Suits.Diamonds; break; default: The default line comes at the end. If none of the cases match, the statements after the default get executed instead. MessageBox.Show(suitString + “ isn’t a valid suit!”); } 414   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files Add an overloaded Deck() constructor that reads a deck of cards in from 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. public Deck(string Filename) { Tcsthhraiisrnaglcintueseirnt.geTllashsaCpt#acspetlioatssspatlihtseeptsahtreraitnngoer“xStiCxard cards = new List(); of Diamonds” into the array StreamReader reader = new StreamReader(Filename); {“Six”, “of”, “Diamonds”}. while (!reader.EndOfStream) { bool invalidCard = false; string nextCard = reader.ReadLine(); string[] cardParts = nextCard.Split(new char[] { ‘ ’ }); Card.Values value = Card.Values.Ace; switch (cardParts[0]) { case “Ace”: value = Card.Values.Ace; break; case “Two”: value = Card.Values.Two; break; case “Three”: value = Card.Values.Three; break; case “Four”: value = Card.Values.Four; break; case “Five”: value = Card.Values.Five; break; case “Six”: value = Card.Values.Six; break; case “Seven”: value = Card.Values.Seven; break; case “Eight”: value = Card.Values.Eight; break; case “Nine”: value = Card.Values.Nine; break; case “Ten”: value = Card.Values.Ten; break; case “Jack”: value = Card.Values.Jack; break; idmsiTcnohaahetetsissccsh,ikhegstsewnhlsetiientdhaecrehtvitgaofohslitutrtseashe.ttveeaeIfwlmiufoeeirtnidtt value variable. case “Queen”: value = Card.Values.Queen; break; case “King”: value = Card.Values.King; break; default: invalidCard = true; break; } Card.Suits suit = Card.Suits.Clubs; switch (cardParts[2]) { case “Spades”: suit = Card.Suits.Spades; break; case “Clubs”: suit = Card.Suits.Clubs; break; case “Hearts”: suit = Card.Suits.Hearts; break; case “Diamonds”: suit = Card.Suits.Diamonds; break; default: invalidCard = true; break; We do the same thing for the third word in the line, except we convert this one to a suit. } if (!invalidCard) { cards.Add(new Card(suit, value)); } } } More free ebooks : http://fast-file.blogspot.com you are here 4   415 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. 416   Chapter 9 More free ebooks : http://fast-file.blogspot.com 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 2 Object serialized 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. 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. Tfhieisldosb, jwecidtthhaasntdwohebi0gyh0tt1e.0010011000110 Width Height The out the vasatnldrueeapsmuam.rpeedsucinkteod 00100101 01000110 file.dat a(tialnsTnfoilakdfoohverorneeeegdtatwsithcnwhitodehsaiorttttteoahhtyfntthpcaahheeeineteldisfovtCoafitfhlbLreleiijteeaRie“ghlbcdmfheltnseitole.oe)rlevab.aeddatjrlesaeeutcret”s, 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. More free ebooks : http://fast-file.blogspot.com you are here 4   417 save the cheerleader But what exactly 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 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 allweather radial tires... aren’t those things all part of the Car object’s state? What should happen to them? TtohoofpehfaaaTCrnPptapiaErresoesnnfeosgonbibntigjtjeeoeescrcottstbtohsjhbae,eatjmcaeset?nc,r,tdtesafo.aneoTr—Laehriwnosrctshaeeare Car object List Engine obje ct The Engine object is private. Should it be saved, too? object Tire [] array object Eorobeabfjcjeeehcrctetosnfs.chetDashsoetiottpshaoosotsswheeennrngeeerd to be saved, too? 418   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files When an object is serialized, all of the objects it refers to get serialized too... ...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. “ggSrrooamupeph.p”oefopcloencnaelclttehdisobwjheocltes a WtathnhoeyeanKfniyeoenotldnuheealtrshokoabbtjCej#echctat,st.ioat serialize looks for reference “Fido” DoggyID ob ject t ject t Breed.Beagle 4 years old 32 pounds 14” tall Collar objec Kennel object Dog object One the this of the fields of Kennel object is List that contains two Dog objects, so C# will need to serialize them, too. List object 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. “Spike” DoggyID ob Breed.Mutt 6 years old 18 pounds 11” tall Collar objec Dog oDobrfeojfgeteghryceeItDnlcienasen—dtotChaoenlyyladrootanhr’eterhtoahbvejeeecntds. More free ebooks : http://fast-file.blogspot.com you are here 4   419 serialized for your protection Serialization lets you read 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 BinaryFormatter 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(); Now just create a stream and read or write your objects Use the Serialize() method from the BinaryFormatter object to write any object out to a stream. OTocprpheeeenantWFaenirslietea.Cex(nir)seet.waintgfe(iol)en.meYeuotsuhinocgdaFn ile. Stream output = File.Create(filenameString); formatter.Serialize(output, objectToSerialize); output.Close(); ICfloysoeu()uwseillabuesicnagllsetdataeumtoemnta,tically. And once you’ve got an object serialized out to a file, use the BinaryFormatter TotstbhhrjeaeencaStmebru.aiiaTnldldihiznawegt(r’)asitmaemseewttihthhooooldeduttltoaottkoewesaraisatineerit object’s Deserialize() method to read it back in. The method reference, so you need to cast the output so that it matches the type returns a of the reference out yourself! variable you’re copying it to. Stream input = File.OpenRead(filenameString); SomeObj obj = (SomeObj)formatter.Deserialize(input); input.Close(); WtotobyhjpeceencatsotyfobtuaohcbuekjseerfcetrDtoeuymsroenuar’rivaseatlliurzreeeeaa(tm)doi,tnmdog.oarnte’ctahdftoahrneget 420   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files If you want your class to be serializable, mark it with the [Serializable] attribute 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, string, 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 Create a class and serialize it Do this 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 pockets even after you close your program. [Serializable] public class Guy You need to of any class add this in order attribute to the to serialize it. top 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(); } You’ll need these two using lines. The first one is for the file and stream methods, and the second is for serialization. 2 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. More free ebooks : http://fast-file.blogspot.com you are here 4   421 i like milk on my serial Let’s serialize and deserialize 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 you created in Chapter 7. 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 all of the classes serializable Add the [Serializable] attribute to all of the classes you added to the project. If you don’t do this, C# won’t let you serialize the classes to a file. 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( TdrtheahicneskdcCoarmanerdadctatecrshldaeassnnstaefodmrdiotpsmtuyssotimnhgee last chapter. (Card.Suits)random.Next(4), (Card.Values)random.Next(1, 14))); } return myDeck; } private void DealCards(Deck DeckToDeal, string Title) { Console.WriteLine(Title); while (DeckToDeal.Count > 0) { Card nextCard = DeckToDeal.Deal(0); Console.WriteLine(nextCard.Name); } Console.WriteLine(“------------------”); tdtTmheheehcetekchcoDaaonnrdesddoadslleCpe.oraafilrnsfdtesso(af)icthtthooef } 422   Chapter 9 More free ebooks : http://fast-file.blogspot.com 4 Okay, prep work’s done.. now serialize that deck reading and writing files 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 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); } yTtottwiahuhthrkeesiriseteBsSSeaceeisdaanrrsn.aiiietyaarllyaiioozzFbuaeDotj(bree)lmctectmoakatematotttabehsrrjtroekirdbceoeut.dbat—jmeewa—ciunttisdnhing DealCards(deckToWrite, “What I just wrote to the file”); } The BinaryFormatter’s private void button2_Click(object sender, EventArgs e) { using (Stream input = File.OpenRead(“Deck1.dat”)) { BinaryFormatter bf = new BinaryFormatter(); Deck deckFromFile = (Deck)bf.Deserialize(input); aDnesOebrjiaelcitz,e(w)hmicehthisodjusrtettuhrens general type that every C# } DealCards(deckFromFile, “What I read from the file”); object why we inherits need to from—which cast it to a is } 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) { using (Stream output = File.Create(“Deck1.dat”)) { BinaryFormatter bf = new BinaryFormatter(); for (int i = 1; i <= 5; i++) { Notice how the line that reads a single deck from the file uses (Deck) to cast Yoasonnaueomtceohabesnjtrerscetetraoimaatfl.ihz}teeer} } Deck deckToWrite = RandomDeck(random.Next(1,10)); the output of Deserialize() bf.Serialize(output, deckToWrite); to a Deck. That’s because DealCards(deckToWrite, “Deck #” + i + “ written”);Deserialize() returns an object, but doesn’t necessarily know what type of object. private void button4_Click(object sender, EventArgs e) { using (Stream input = File.OpenRead(“Deck1.dat”)) { As long as you cast the BinaryFormatter bf = new BinaryFormatter(); objects you read off the for (int i = 1; i <= 5; i++) { Deck deckToRead = (Deck)bf.Deserialize(input); DealCards(deckToRead, “Deck #” + i + “ read”); stream there’s to no the right type, limit to the } number of objects you can } serialize. } 6 Take a look at the file you wrote Open up Deck1.dat in Notepad. It may not be quite something you’d read on the beach, but it’s got all the information to restore your whole deck of cards. More free ebooks : http://fast-file.blogspot.com you are here 4   423 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, 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’s useful—it shows you how letters are encoded into numbers. StslecehtrleeotclHeltredbtSorhwheeiwnnAularennittadtillecfyrloisocn.uktFroiaennnaddcitht.he As soon letter, as its you click Unicode on the number HsheobwreswupleitntterheSshtinatiussnbuamrb.eTr he 0nu5mEb9e.r—T“hhaetx’s” afohrexsahdoretci.mal “aYtpHnuhoedtuex”tciWtahrinenainnddcoiSocownlcisvbcieeukcnrtatt“tliDcofiuntielc,actt”emoo—nortdid:eteero’cs,pi“ecm10n,l5aic5l1iktE3u.9stui”nph,g,e UUplnnaiticcfoooddreemiCss.oaTnnasokirentdaiuusmmt,irnyauntsdteaiantnddwaroldoroksdkeaavcterlootpshseediprrbowygerabasmnitosen:a-nhpdtrtodpfi:fi/tf/egwrrewonwutp.ucncoiacmlolepdduet.toerrhge/ 424   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files .NET converts text to Unicode automatically The two C# value types for storing text—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. Do this! 1 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(); TtboyhteaeRsneetawhdaAatrllrwBaeyyrteoefsr(e)baydmteietnshfotrdhoamrtetctuohrnentsfaiianles.reaflleorfenctehe 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 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: Console.Write(“{0:x2} ”, b); ilHneetbxtaeusresse1sA6t, thsheorn6ouuBmghbiseFresqtu0oalrttehoprro1eu0sge7hn.t9 naunmdbers 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 backwards? 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! More free ebooks : http://fast-file.blogspot.com you are here 4   425 take a byte out of crime C# can use byte arrays to move data around Since all your data ends up encoded as bytes, then it makes sense to think of a file as one big byte array. And you already know how to read and write byte arrays. Haroreefrraeadt’ysh,detoahtpaeeranrcianoaytdn.oeinbtpyouttcersset0arteetahmar,obauyngtdhe 6 Hello!! byte[] greeting; greeting = File.ReadAllBytes(filename); 7 byte variables TAojcaufhrrhrsiidrtslareaenaiyrugsyessexoiasgntafeghcsytttatoiattluhwyte.rrtmiceiobtavymktestehereesonttsewh.osoouWttdttehhh’afeetrtoeorbtyththeee When byte text aitsrhrienayprreoovugetrrsatemoowardrfietirlees,tottohh.ee !!olleH 72 101 108 108 111 33 33 “HftToehhrleleotsU!e!h”nenicucomhdbaereranscutmaerbreesrisn Array.Reverse(greeting); File.WriteAllBytes(filename, greeting); 7 byte variables 33 33 111 108 108 101 72 Now the bytes reverse order. are in 426   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files Use a BinaryWriter to write binary data 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(). Do this! 1 Start by 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’; aOstItnfhpdaeerynrsotWetu’sarauriotstbneerse(aF)ontvidmlheeere.nCrtweehrrweoiatadloitr,nneegwea(.)dhit,Tiyci,thhfie’rtlorlo’pelmsle’tsnbatsalrholttsweohabeittenhegeaxeinwwisnFatifinyilnigelga..en—odnife 2 To use a BinaryWriter, first you need to open a new stream with File.Create(): using (FileStream output = File.Create(“binarydata.dat”)) { 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); 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. 4 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); Write down the output in the blanks below. Can you figure out what bytes ttuhdHsohoieifewnrsfgetsel’tasorCrrneahitngnatghriwtialnaietctnintsh:dg.etSarAchthlMnsrsa,uoinram,sgpoybUs.oetncurhiacectnoaodsnbteterleoivnlaolglku.NheusaEpsT correspond to each of the five Write() statements? Mark each group of bytes with the name of the variable. __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ - ___ bytes More free ebooks : http://fast-file.blogspot.com you are here 4   427 an amalgam of data float and int values take up four bytes when you write them to a file. If you’d used long or double, then they’d take up eight bytes each. 8_6_ 2_9_ e_8_ 0_2_ 0_6_ 4__8 6_5_ _6_c 6_c_ 6_f_ 2_1_ 2_f_ 8_1_ 0_0_ _7_4 _f_6 _d_8 f__5 4__3 4__5 - 2__0_ bytes intValue stringValue byteArray floatValue 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. IcbfayltcyeuosluatfuorsroemttohheecxoWntivnoedrodtwectsihmeasle, 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 BinaryReader to read the data back in 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. Don’t take our word for it. Replace the line that reads the float (You’ll with a call to ReadInt32(). need to change the type of floatRead to int.) Then you can see for yourself what it reads from the file. 1 Start out by setting up the FileStream and BinaryReader objects: using (FileStream input = File.OpenRead(“binarydata.dat”)) { 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(); hoaiBEnonniwaeyntcahpphmraeayarvrRncaaayolemmuraeeberdttyeteetcerytrre(pss)et,tthtybhoaphuatetasr.tetiRMateredsleoal.tssodtuwBBrndinynostmanerte’styht(R)ehnoetedadeaaddktienears 3 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); } Here’s the output that gets printed to the console: int: 48769414 string: Hello! bytes: 47 129 0 116 float: 491.695 char: E 428   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files You can read and write serialized files 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 to the inner workings of a serialized file. Do this! 1 Serialize two Card objects to different files Use the serialization code you’ve already written to serialize the Three of Clubs to card1.dat and Six of Hearts to card2.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: T“stwConhhmahheemiarecpefehtwsilapewoerarraec9(dsle”isk,tweihnee used), but iutn’sremadosatblyle. 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(“card1.dat”); byte[] secondFile = File.ReadAllBytes(“card2.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]); Tdtbdidehihiffeeefcfneotestramrwicemepoannealtt.fr.c.eibflldbaeyissultesbtesay,wrltaeetaertshrr’ebsaesyyeays’rdslebli,eaybislntiojeztueeost.atdlhSmteHiwtonyOoosctceWtawno 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! More free ebooks : http://fast-file.blogspot.com you are here 4   429 celebrate our differences Find where the files differ, 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 Take a look at the console output to see how the two files differ The console should show that two bytes differ: Byte #218: 1 versus 3 Byte #266: 3 versus 6 That should make a lot of sense! Go back to the Card.Suits enum from the last chapter, and you’ll find that 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 toRhfeemntehtmehbeseerbriyhatollieweznengtduthmhfebiolenefra?stmhIweefsiplflyialoebcu.eerwdniaafsmfeienrsceplnautdceetdiosoa.dsifpfaerrtent, Hrciasntehmg,poaamrcrnineeh,g.saeietfn(nhRtgtebihensyemgsttuesetihmutehi#btaaestt2ruoi,f1toa8yn,toedtihunihbfreefytncoethawreewren,densatesnsebrhdrilyaooialcuwrilzaleirdzteaiteiddbodiinnenfg.gf)ialiieblttelheoamuttitogfhtile 4 Write code to manually create a new file that contains 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[218] = (byte)Card.Suits.Spades; If you found firstFile[266] = (byte)Card.Values.King; different File.Delete(“card3.dat”); byte numbers File.WriteAllBytes(“card3.dat”, firstFile); in step #3, substitute Now deserialize the card from card3.dat and see if it’s the King of Spades! them in here. 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 card3.dat. 430   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files Working with binary files can be tricky 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’d exhausted all your other options, and really needed to just look inside? Looking at that picture, it’s pretty clear that Notepad just isn’t the right tool. Here’s the serialized Notepad. That’s not card, going opened up in to be useful at all. Ya(o“nCudhc“aaVpnatlemurea9”k)”e,).aoBnudtutathtfeheawnta’tsmhenionotgfs—atlllhikteehnatathmeheeseplnpaufcmuel.wnaemuessed(“Suit” 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 stripped out. More free ebooks : http://fast-file.blogspot.com you are here 4   431 69 73 6e 27 74 20 74 68 69 73 20 66 75 6e 3f 0a Use file streams to build a hex 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 hex 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 numeric value of each byte in the the file. 0000: 57 65 20 74 68 65 20 70 -- 65 6f 70 6c 65 20 6f 66 We the people of 0010: 20 74 68 65 20 55 6e 69 -- 74 65 64 20 53 74 61 74 the United Stat 0020: 65 73 2c 20 69 6e 20 6f -- 72 64 65 72 20 74 6f 20 es, in order to 0030: 66 6f 72 6d 20 61 20 6d -- 6f 72 65 20 70 65 72 66 form a more perf 0040: 65 63 74 20 75 6e 69 6f -- 6e 2e 2e 2e ect union... And we’ll We’ll add the number at the beginning of each line by using need to the offset of the first byte in the line. replace the garbage Each of those numbers—57, 65, 6F—is the value of one byte in the file. The reason some of the “numbers” characters have letter values is that they’re hexadecimal (or hex). That’s just another way of writing a number. Instead of with periods. using ten digits from 0 to 9, it uses sixteen digits from 0 to 9 plus the letters A through F. 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 hex You can put hex numbers directly into your program—just add the characters 0x 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); tjdSuootstnru’istnlekgne.iFteCoe. dromntsaootl(el)e.WaurrsneitsaenpLyaitrnahemi(n)eg,tsneoerwsyou 432   Chapter 9 More free ebooks : http://fast-file.blogspot.com reading and writing files StreamReader and StreamWriter will do just fine 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)) { int position = 0; A if StreamReader’s EndofStream field there are characters still left to read returns false in the file. Ttcatethhnaohhrdaciesaorhwupaolloogrcuhinohftitniepeptttwpflciruigshsnhtrooehnoee.eisratmstii(ret(i}ef![criiflr]h.ons(eaWnt(eiabrriswwduai+itrr=efct= 250) { buffer[i] = ‘.’; } } string bufferContents = new string(buffer); writer.WriteLine(“ ” + bufferContents.Substring(0, charactersRead)); } TtFToaUtbefhnioyhhl}xdeeta-tbr.teWheytos’feahtshrxdiweeilbt–esniedttescw.AurtehamuxiBhltulnvtepBushayeetilyfrt’uvrtSeiatelwetselthussohare(ue,rrle)rnslkowaedtrsuom’hseeogvijRraechauwdrehs1ytapr21ooidirn2t8fnuoeerl.7irbaynlsaedeitcsnmu“ooffmb.naoadutprrUie”ralfsr!taieni.yle Estsrttoevrateirsrnuetyrgein.nsswgItnhrtaiehtntrehgeitsnhhcuacemhsabbasaeeer,rgsaiintuocnfbirtnescgethtrua(rrpsrnoiaRsscnietttgeiahorednms fe0titsihr)ha.ssotte(dtLci—ttohothrakhaetreabdaaRrcceeiktntatueaordtnrBtssthlahReoeepacitarekorcd(peay)coo.hffmartteathhcehetoledorosp Here’s a bonus exercise: See if you can figure out how to use the BinaryReader class to fix the problem! you are here 4   433 More free ebooks : http://fast-file.blogspot.com 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() that 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. 434   Chapter 9 Q: When should I use File, and when should I use FileInfo? A: The main difference between the File 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: Why is it called a byte order mark? A: 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. TcietanhnciasotddeeniinlfclgfoFsedriailenetng.WthitsrEittcnpaec:lA/ole/ldldTuinneUgixcTtoo(bdF)je-e.oc8ttro,g. w.uYhsoeiuchaca.dNnifElfeTearreunnsetms oebrnyecodadbeifonaugtubltUy. npYiacosousdineg More free ebooks : http://fast-file.blogspot.com reading and writing files Change Brian’s Excuse Generator 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. Hint: What keyword can you use inside of a class that returns a reference to 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 any more. Change the dialog boxes, default filenames and directory search code so that they work with *.excuse files instead. 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 oennecaopfsutlahteiofnowuras ppoHcrrfoeoirrngheecro’isapOwmlaOeusnsPsbimenpexagtrakittmneechspriolpy.esloeeusr? More free ebooks : http://fast-file.blogspot.com you are here 4   435 exercise solution Change Brian’s Excuse Generator 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 } private void open_Click(object sender, EventArgs e) { // existing code openFileDialog1.Filter = Sottpheaenndtdariiracdlkogshaebvroeex.aensddo “Excuse files (*.excuse)|*.excuse|All files (*.*)|*.*”; // existing code } [Serializable] public class Excuse { public string Description; public string Results; public DateTime LastUsed; public string ExcusePath; ETeisxxhttceeounoshsenialoycvnleacishtista.pncaghseasentsgoettothhetehfefoirlem 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)]); } private void OpenFile(string excusePath) { this.ExcusePath = excusePath; BinaryFormatter formatter = new BinaryFormatter(); Excuse tempExcuse; using (Stream input = File.OpenRead(excusePath)) { Tfrinaohsrnetdetcoahomdneseot“xf.recux“ucc*stueo.ssrtexn”fetoee”rxdtfsloeiltnaeosdsi.iolnongok 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. 436   Chapter 9 More free ebooks : http://fast-file.blogspot.com Filecross 1 5 8 2 9 reading and writing files 3 4 6 7 10 11 12 13 14 15 16 17 18 19 Across 6. The method in tAhecrFoilessclass that checks whether or not a specific file is on the drive6. The method in the File class that checks whether or 190. .TThhisesatabtsetrmaectnct ln9sianw.osdTtsiihctatcaihshstaepsstsettFacatithiftleeeeimcSmefetenrinelndetatiomisnfodainnicchataehtsreeiestsdtirnfhirsvoeiedmeendaosfwaitccahssetaintesimdeenat 11. A non-visual co1n0tr.oTlhtehaatblsettrsaycotuclpaosps tuhpatthFeilsetSatnrdeaamrd iWnhinedriotws sfrom “Save As” dialog bo1sxt1a. nAdanrodnvWisiunadlocwosnt"SroalvtehAast" lets you pop dialog box up the 15. How you write1n5u.mHboewrsyoinu bwarsiet-e1n6umbers in base-16 16. If other you don’t methods ocar lp1l1lort67coh..kgiTsIerfhadmeymooeSpsuttehrcdnoeaoadsnnm,o't’tyRocooteauphalreledntsrehtrmriitesmeamtemhteohtcdohosdouodtldr,hyapborteuorrlgeorsacatdkmrseesddaacmoatpance'otinnuoltspdooebane it 17. The StreamRecahdaerr[m] aerthroayd that reads data into a char[] array 18. An encoding sy1esa8tc.ehAmcnhtheanarctaoacdtsiesnriggnssysateumniutheantuamssbiegrntsoaeuancihuecnhuamrabceterrto 19. Use this statement to indicate which statements should be executed when the value being tested in a switch statement does not match any of the cases Down 1D. Tohwisnclass has a method that writes any value type to a file 21..TTheissctlaatsics hmaesthaomdeinthtohde tAhraratywcrlaitsesstahnayt tvuarnluseatnypaerray backwards 3dt2a.aor.TtraTahahfieyneilbeseaavtncaektinniwtcphaumartendctdsohlneotrdrotihlnatt hgeetAsrrruanywclhaesnsetvheartstoumrnesoanne modifies the 43..TThhiesecvlaesnst hhaasndmlearntyhsattatgiectms eruthnowdshethnaetvleert syoomuemonaenipulate folders 5m4..oUTdhsiifinsiegcsltahtshissehOdaaOstPampianrnianyncsipitnlaeptuimctamckoeentsthriotodals ltohtaetalseiterytoou maintain your code 7m. Iafnyiopuldaoten’ftouldseersthis attribute to indicate that a class can be written to a5m.saUtrisneiatnamgint, hByiisonuOarOrycPFopdorerminacitpteler mwiallkgeesnietraatleotaenaesirerorrto 87.. TIfhyisouBdinoanr'tyFusoermthaitsteartmtreibthuotedtroeainddsicaanteotbhjeactt afroclmass acasntrebaemwritten to a stream, BinaryFormatter will 1g82e..nT\enhrisaantBedina\arnraeyrrFerooerrxmaamttpelersmoeftthhoisd krienaddsofasneoqbujeecntcefrom 1a3.stTrheisamclass lets you perform all the operations in the File class for a s1p2e.c\ifinc afinled \r are examples of this kind of sequence 14. This method sends text to a stream followed by a line break More free ebooks : http://fast-file.blogspot.com you are here 4   437 exercise solution Filecross solution 1B I 5E 8D N N 2R 3C 4D E H 6E X I S T 7S V 9B R E A K R E E A C E 10S T R E A M R N E R G C I E Y P S E T A R W 11S A V E F I L 12E D I A L O G L I R U A I L 13F L T A I S R I C Y Z A 1W4 A I E T L P R B Z R I 15H E X A D E C I M A L L E O I T E N N 16C L O S E F 17R E A D B L O C K L 18U N I C O D E N 19D E F A U L T 438   Chapter 9 Across 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 [s t re am] 11. A nonvisual control that lets you pop up the standard Windows "Save As" dialog box [s ave f i le di a l o g] 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] Down 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] More free ebooks : http://fast-file.blogspot.com 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 pages 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   439 More free ebooks : http://fast-file.blogspot.com mo’ programs mo’ problems Brian needs his excuses 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. Saaolanwumtaeeyxoscofull’osweoBokrtriniokag.ng.fe..otr 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? hgBiesrnielaarnpa’tstoogpro.trutnhneinegxocnuse Aehpaxnarccvocueebonpluhbtenaemitonendnwf.l.oee.adrmd. uidstn’t 440   Chapter 10 More free ebooks : http://fast-file.blogspot.com 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; Cpdaaorlulsibnelgeadvsaotluurbeinl,eg.lPikaaenrds3e2r(“e.3t2ur”n) will a 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(); 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 4 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. 5 More free ebooks : http://fast-file.blogspot.com you are here 4   441 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”); Cocba#juescehtaastnnoIonavidafleliodaaCthao,swtanEtdxoctecrpaytsitinogna.tHoodneoyBiteewill float howMuchHoney = (float)myBee; HoneyBee anotherBee = new HoneyBee(12.5, “Buzzy”); double beeName = double.Parse(anotherBee.MyName); anifTttuooFhmrkeogmbnrieoPavmretwaa..rstistT“EehBh(oax)uawcztsemtz’tpseryottiw”nihocghionoysd.ninnv’ittewaraattcnhetsrttrsootrwyiaanosignu double totalHoney = 36.5 + 12.5; string beesWeCanFeed = “”; for (int i = 1; i < (int) totalHoney; i++) { beesWeCanFeed += i.ToString(); } float f = float.Parse(beesWeCanFeed); Tb6afe0hloenesaudWtfmiogebwrCietiralsllontoiFtnphheaiertwtdo.iwlblTtihcgahar,neetraaOentc’vdsoeenrntatforalysoiwtniwnrasEgiynaxgtaconecufpacmltlrolbeiaaoedtmnr.ciwtaintinhhtooolvdaer 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. 442   Chapter 10 More free ebooks : http://fast-file.blogspot.com int drones = 4; int queens = 0; int dronesPerQueen = drones / queens; exception handling dDItiiv’vsiiddreeeBaalnylyyZeneaursmoyEbtexorcetbpyhtrizoonewr. oaJ.ust Ddmoiavnki’detinskugnroaewniytt’nshuenmovbtaelurzeebroyofzbqeerufooeraeelwnyasoyu,s throws you can ptrheisveknitnditofjusetxcbeyptcihoenc.kEinvgenthife divide it into drones. you value to 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. More free ebooks : http://fast-file.blogspot.com you are here 4   443 mmm fudge When your program throws an exception, .NET generates an Exception object. You’ve been looking at .NET’s way of telling you something went wrong in your program: an exception. In C#, 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 int anArray[] = {3, 4, 1, aValue = anArray[15]; 11}; obviously going to cause problems. ex-cep-tion, noun. 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. aiAitnllstgotseohnaoeennrduaaantstheayasoniautdnrlehopdabrsjoeeagxcbrctaoeumpwttiitroiuhtnn.,s E xception obj Tmwcsehyaervelssoeltsnsneaegtxgtmechat’esanhtptdmahttaiewaotmenclroaitseorutebyslmeljosedlafecdyattoeadhulhiltenawogosehfxtuaapchttee’htspeotiotnh.e ect You can see this detail by clicking on the View Detail link in the unhandled exception window. .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 the problem (even if you’ve got thousands of lines of code). 444   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling Q: Why are there so many kinds of exceptions? A: 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: So what is an exception, really? A: It’s an object that .NET creates when there’s a problem (more about that in a minute). Q: Wait, what? It’s an object? A: 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” and “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: Okay, I still don’t get it. Sorry. Why are there so many different kinds of exceptions, again? 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 are 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. 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. Exceptions are all about helping you find and fix situations where your code behaves in ways you didn’t expect. More free ebooks : http://fast-file.blogspot.com you are here 4   445 nobody expects the ... Brian’s code did something unexpected 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 Okay, 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 RandomExcuseButton_Click(object sender, EventArgs e) { if (CheckChanged() == true) { CurrentExcuse = new Excuse(random, Folder); 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)]); BWaeninendgimnoodu!fseTtxthbhteeehreata’tsrr’yrstianhpygea.sttaortruahsyee. 446   Chapter 10 More free ebooks : http://fast-file.blogspot.com 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 messagebox. private void RandomExcuseButton_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 { if (CheckChanged() == true) { CurrentExcuse = new Excuse(random, Folder); UpdateForm(false); } } By checking for excuse files in the folder before we create the Excuse object, we can prevent the exception from being thrown—and pop up a helpful message box, too. 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. More free ebooks : http://fast-file.blogspot.com you are here 4   447 the exception family tree All exception objects inherit from 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 was going on in memory when the exception occurred, and what led up to the exception. (There are others, too, but we’ll use those first.) ToeofxSctaelrplitnoigof(n)’tsghfeenieienlrdfasotraemnsadatrisoeuntmuimnrnatsrhyiet in a string. Exception Message StackTrace GetBaseException() ToString() pMyraoEoenupsxyrescaroeogttpweihteneisaornenadxcnccldaaeasnpnmsyt.ebiooStentohehocxyedlotrasues.Esnecdxsaec,ndeapwnltdirkiioteunese IndexOutOfRange Exception Message StackTrace GetBaseException() ToString() FormatException Message StackTrace GetBaseException() ToString() OverflowException Message StackTrace GetBaseException() ToString() DivideByZero Exception Message StackTrace GetBaseException() ToString() Igeditctuwnixiva’nhfshceneaefeisxrcepledehpuertaxeisaeiflococnrlfsytnentnoeeepsru,dtaemeswxibenoalaaecfotnncsectuytpalsjtituuiaottthssibnyrtouheopaonatueetbwtthsiayinsoac..oNtnthltfo.h’EhsoeYrTkcooianuwugnsiantg 448   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling The debugger helps you track down and prevent exceptions 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. 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 its name and shortcut key. (Those shortcut keys come in really handy.) otTpuvorpheoerrwgurhDtnaehemnaebuypitngorouoott’glrhobreoeaalrdmbIDaeicbriEnouo.ngonsgSr.liyodngesyrhoyouotw’uollrs hhoavveer Stop: end the program and exit the debugger. Continue: run until the next breakpoint is hit or the program ends. Show next statement: scroll to the next statement that’s going to be executed. Step over: execute the next statement. If it’s a method, execute it as a single statement. Step out: run the rest of the statements in the current method, and break when it’s done. Break all: break the program immediately and jump to the statement being executed. Restart: stop execution and start the program again. Step into: execute the next statement. If it’s a method, execute the first statement in the method. Debugging means running your code line by line to see what happens When you break Whenever you run your program inside the IDE, you can always pause it at any time by hitting the Break All button in the toolbar (or choosing the command from the Debug menu). This causes your program to stop in its tracks and show you the line of code that it’s about to run. It turns that line of code yellow to show you that it’s the one that’ll run next. If you press Continue, then your program will keep running as if you’d never stopped it. But you can also step through your code, which means executing the current line and going to the next one. If the next line is a method, then you can step into the method, which causes the debugger to jump to the first line of the method and highlight it. Or you can step over the method, which executes the whole thing. If you’re inside a method, you can step out of it, which causes the debugger to execute the rest of the statements in the method and break at the first line after it returns from the method. You can also inspect and change variables and fields in your code using the Watch window. Just right-click on a variable in the code and select “Add Watch”, and it’ll appear in the Watch window—or you can type it directly into the Watch window. Then its value will be displayed. If it’s an object, you can drill down into its fields. inside the debugger, the IDE stops your program and displays the next line of code that it’s about to run highlighted in yellow. Then you can move forward line by line until you find your problem. More free ebooks : http://fast-file.blogspot.com you are here 4   449 you don’t know where that watch has been Use the IDE’s debugger to ferret out exactly 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. It’s a good place to get some practice with the debugger, because you know exactly what you’re looking for. (That’s a luxury that you don’t have most of the time!) Debug this 1 Use a breakpoint to break—or pause—your program 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, and select “Toggle Breakpoint” from the Debug menu (or press F9): Trberhdeeadkdpoeotbiunigtngstearhsesrhleeodfwtsl-inyheoasunrwditmharagbinig. IHDoEverwiollvesrhoawnyyofuieiltds or variable value. and the Taiesrxhrteeochwyueetlinelnoewxwtthhleeilnnineleeitfwttirth-uhehnsaad.neydbeulmglogawerrginwill The IDE turned the line red and put a circle in the left-hand margin. That’s the debugger’s way of telling you that it set a breakpoint on the line. Now, when you debug the program in the IDE, execution will stop on that line. Give it a try—run the program in the IDE (using the same “Start Debugging” command you’ve been using all along). When you reproduce the problem, the line should turn yellow, with an arrow pointing to the code. Now your program’s temporarily paused. The “Start Debugging” menu item’s turned into “Continue Debugging,” iDuaINnDsteiopnoEbwrguotgcygthgoorheimuanemgmIkDd”an—eiEnosbdwb.u“egSfcwgtoaeharuryrsretbtuuhynieonltuin’rge too. Click it—the program will pick up exactly where it left off, starting with the line you put the breakpoint on. 2 Step through the application Sysrtoeuuatnrhnt-ainvDgieseyntboohuuegrbgrsipnaeragmokeg-proaawisnmht.esn Use the Step Into command (using either the toolbar or the F11 key) to move through the application line by line. When it gets to the line that creates the new Excuse object, it’ll jump straight into the constructor that you fixed. Step past the first line so it sets the fileNames variable. Then hover over the variable to see its value. 450   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling 3 Use the Watch window to reproduce the problem One really powerful feature of the debugger is the Watch window, which lets you check the value of variables and fields in your objects. Hover your mouse cursor over the “Length” part of fileNames. Length. Then select all of fileNames.Length, right-click, and select “Add Watch” from the menu. It’ll get added to the Watch window (which is in the same pane as Output—you can bring it up by selecting “Watch” under Windows in the Debug menu). Then add each piece of the statement: first random.Next(fileNames.Length). It should look something like this, depending on how many files are in the folder you pointed to—in this case, we had five, so fileNames has five elements: We’ll use the Watch window ttohartepcraoudseudcetthheeepxrcoebplteimon. We’ll start by adding the fileNames array. You need to break (pause) the program before you can add a watch. 4 Set fileNames equal to an empty string array Double-click in the empty space in the Watch window underneath the two watch variables. You’ll get a cursor. Type this in: fileNames = new string[0]. Watch the top row in the window—as soon as you hit enter, the value of fileNames will change to {string[0]}. A re-evaluate icon should show up next to the random.Next line—click on it and its value gets set to 0. So what happened? The Watch window has another very useful feature—it lets you change the value of variables and fields that it’s displaying. And 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). 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 Reproduce the problem that threw Brian’s original exception This icon tells the Watch window to reevaluate mtheethNoedx. t() 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. More free ebooks : http://fast-file.blogspot.com you are here 4   451 make a break for it Q: How come Brian’s unhandled exception window looked different than 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. Just 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. 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’s got 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. 452   Chapter 10 More free ebooks : http://fast-file.blogspot.com 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() a t System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHa awmBaItaaitpnskelraoextorostrbykysFlsefeionmnilrglisekmew.et,aiotttbthehdceeetarrshue—eserewwiaahiltisizche ndler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) a t System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) a t System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream You can learn a lot from the serializationStream) call stack, which tells you a t Chapter10.Excuse.OpenFile(String ExcusePath) in C:\Documents and Settings\Administrator\ which methods were running. My Documents\Visual Studio 2005\Projects\Chapter10\Chapter10\Excuse.cs:line 40 You can see that the Excuse class’s OpenFile() method was being called from its a t 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 constructor (“.ctor”), a t Chapter10.Form1.RandomExcuseButton_Click(Object sender, EventArgs e) in C:\ which was called from the Documents and Settings\Administrator\My Documents\Visual Studio 2005\Projects\Chapter10\ “Random Excuse” button’s Chapter10\Form1.cs:line 146 click event handler. 3 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? More free ebooks : http://fast-file.blogspot.com you are here 4   453 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. 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. 454   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling Handle exceptions with try 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 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 thinks like print a friendly error message, instead of letting your program come to a screeching halt: private void RandomExcuseButton_Click(object sender, EventArgs e) { // ... code you added a few pages ago goes here ... try { iWs htehTntYrehtrhooxaayriuwcnsnyendbsiep,ts.llxtioatntccirghoehktnep.ewt}ciitoahn ti}cMfhes(CU{sCupahrdgeraecetBTabnlkneohoeceCtFxkxcchEo.iaemptaxrSmtceincmhodhngu(oiakhtesfweaeynldea(ywdolf(lerord)=sl.lomewei=n)anng=e;sittwhcatotnrEttauxhienecs )us{e(ranbeidbsnrlIxatPoefucnoacutneitktnhgepmeeoenxtwtmxoci,ethoaoreexnerencnpct’yd,tttcel.stiyFopboghBdtilneanooeieutsocittnrnkltueeshhisishxtfeddutaaehatecpcearlo,apuotmftestrawhtnicengestash)ddh,that.tebei;ntrtmlhoytt’lecehlrnbkrygtlooewwctikll. program immediately jumps to the catch “Your excuse file was invalid.”, statement and starts executing “Unable to open a random excuse”); the catch block. } } Theaxhncisdepliistnigto:hnsetmoseipmssptalhgeeest,parknoindgdrkaoemfe,pewrxrucintenepitnoigou.tn the 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? More free ebooks : http://fast-file.blogspot.com you are here 4   455 risky business What happens when a method 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. 1 Let’s say your user is using your code, and gives it some input that it didn’t expect. a user gives input to your method ˙∆å˚ß∂ıÏÔ˚œ∑ˆ øƒ¥∂∫√˚Ω∆¬˙√˚ ÔÒÎ˙˚∆¬åߥ∂ÒÅ ∆˚åƒ˙ß∂∆˙å∆˚ß ƒå∂ß˙˚ƒ∆˚å∂ß∂ ´˙®£√•√∂¨∂¬∆ƒ ƒ˜å∂√˚祃´∂ˆ´ ∂å˚∆ƒ´∫®˚´¨√∂ public class Data { public void Process(Input i) { if (i.IsBad()) { explode(); } } } user some input a class you wrote 2 That method does something risky, something that might not work at runtime. ““rrRuuunnnnttiinmimge”e.”eSrjrouomstres”mp.eeoapnlse“rwehfieler your program to exceptions is as 3 You need to know that the method you’re calling is risky. public class Data { public void Process(Input i) { if (i.IsBad()) { explode(); } } } a class you wrote public void Process(Input i) { if (i.IsBad()) { explode(); } } I wonder what happens if I click here... user 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 Wow, this program’s really stable! 4 You then write code that can handle the now your program’s robust 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(); } } } 456   Chapter 10 user your class, now with exception handling More free ebooks : http://fast-file.blogspot.com exception handling Q: So when do I use try and catch? A: 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, names instead of dates, and they pretty much click everywhere you could possibly imagine. And 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: That’s what the catch block is for. A catch 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—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. Q: Is the debugger only used to troubleshoot exceptions? A: No. The debugger’s actually 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 value 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 the Watch window. What’s it for, again? 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 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. 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. viawAsaninlndruydeunsoocnnwhtilanyhnjgaugl.tasetRsstyeaoysafuotsfuacerlhmcotatnangyktgoeaehudseirntdwpthariehltoleagpbrrWeianoamugtmnr,cdaeahmomnndoer.y, 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. More free ebooks : http://fast-file.blogspot.com you are here 4   457 go with the flow Use the debugger to follow the try/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... Debug this 1 Make sure that you’ve incorporated all of the code from this chapter into the Random Excuse button in your Excuse Manager. Place a breakpoint on the first line in the Random Excuse button’s Click 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 a not a valid excuse file (any other sort of file will cause it to throw an exception). Press the Random Excuse button. The debugger should break the program at the breakpoint you placed. 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: Place a breakpoint on the first line of the Random Excuse button 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. Make sure you use the Step Over (F10) command in the debugger so it doesn’t step into the CheckChanged() method. 2 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 tdEthehxebacutucgsogcenersreotabrjtjuueecmcsttpot,srhttehoe code. 458   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling 3 As soon as the debugger executes the Deserialize() statement, the exception is thrown and the program jumps straight to the first statement in the catch block. It short-circuited right past the call to UpdateForm() and jumped 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 grey 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. More free ebooks : http://fast-file.blogspot.com you are here 4   459 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 RandomExcuseButton_Click(object sender, EventArgs e) { string[] fileNames = Directory.GetFiles(Folder, “*.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, Folder); } } catch (Exception) { CurrentExcuse = new Excuse(); CurrentExcuse.Description = “”; IhBwEfaauxvsttechucyensroeoeEuaowtxdbaecojydues.ckoetnSfocoawokntnndtshothewcraliuctencagatnrotwosrchoianthutstht’rbsaaolnoilwnlccsekiCtaoscunfrrfereiEeaextnlxcdteecssEpu.stxaeiconunes,ew.we CurrentExcuse.Results = “”; CurrentExcuse.LastUsed = DateTime.Now; MessageBox.Show( “Your excuse file was invalid.”, “Unable to open a random excuse”); } finally { UpdateForm(false); } } } tUTtghhephrteedeswEafrxtiuacnennuFsaweeoxhlccerletomypnht(setbir)orlno,uoccrbaktunontdmrotaicstkul’aeelclnsacraeseelsuxssdrofceeuocplutaltythlliaortitnethaeUwdifapesaxdtncthauheetsrxeceoc.owuFnsnose.t,rrSimutoc’(ltilf)ocrall Did you notice how catch was followed by (Exception)? When you have a catch statement, you can follow it with a specific kind of exception telling it what to catch. If you specify (Exception) or leave it out, it catches all exceptions. But if you only wanted to catch a SerializationException, you could specify that inside the parentheses instead. Or you could use an IOException, which will catch any file input or output problem. 460   Chapter 10 More free ebooks : http://fast-file.blogspot.com 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. More free ebooks : http://fast-file.blogspot.com you are here 4   461 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 than 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: Okay, so now what’s a handled exception and what’s an unhandled exception? A: Whenever your program throws an exception, the runtime environment will search through your code looking for a catch block that matches it. If you’ve written one, the catch block will execute 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. Then, you’d call the exception unhandled. Q: What was that bit about specifying a particular kind of exception to catch? Why would I ever want to do that? A: You usually don’t want to catch every kind of exception. In fact, you should do your best to avoid catching Exception, and instead catch specific exceptions. For example, let’s say you wanted your Excuse class to prevent a FileNotFoundException from getting back to the form—say, if you wanted to make it so that if you tried to open a file that wasn’t found, it would automatically create a excuse file with that filename and give it some default values. Then you could add a try block followed by catch (FileNotFoundException). Then if a file isn’t found, the class can handle it—but an IOException or SerializationException would not get caught, and the exception handler you added to the form would catch it. But if you do that, you have to make sure that there’s some method in the call stack that does have a catch-all exception handler, otherwise the exception would be unhandled. And that would cause the users to see the ugly “unhandled exception” crash. Q: What happens when you have a catch that doesn’t specify a particular exception? A: A catch block like that will catch any kind of exception the try block can throw. Q: If a catch block with no specified exception will catch anything, why would I ever want to specify? A: 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: 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 half way 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. 462   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling 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. public class Kangaroo { ___________ fs; int Croc; int Dingo = 0; public int Wombat(int Wallaby) { _______ __; try { if (________ > 0) { __ = _____.OpenWrite(“wobbiegong”); Output: G’day Mate! Croc = 0; } else if (________ < 0) { Croc = 3; using System.IO; public static void Main() { } else { ___ = _____.OpenRead(“wobbiegong”); Kangaroo Joey = new Kangaroo(); Croc = 1; int Koala = Joey.Wombat( Joey.Wombat(Joey.Wombat(1))); try { Console.WriteLine((15 / Koala) + “ eggs per pound”); } catch (___________________) { Console.WriteLine(“G’Day Mate!”); }} }} catch (IOException) { Croc = -3; } catch { Croc = 4; } finally { if (______ > 2) { Croc ___ Dingo; }} Note: each snippet from the pool can be used more than once! ________ ______; }} return Exception IOException NullPointerException DivideByZeroException InvalidCastException OutOfMemoryException ef i fs int j FileInfo File Directory Stream ++ -= += FileStream == != Dingo Wallaby Koala Croc Platypus More free ebooks : http://fast-file.blogspot.com you are here 4   463 one object’s trash is another’s treasure Pool Puzzle Solution public static void Main() { tJtrehiomteeueyWrs.W,nrsoaitmnzedbeLarttionh(.ee)T()itshhtaciotradltclehatdruimsoteweshriatee DivideByZeroException. 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!”); The clue that this is a FileStream is that it has an OpenRead() method and throws an IOException. }} public 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 { iBTcatanuhldttliesodkitcte.oehLndpreesaovtweoiterpraeocnnoplsoneIsO,naeEidttfxhitloceehpeepefcntiafrsilosliettlnedh.,tew“imwfheoiilcbehibtai’cesgagauoisnne.gs” if (Wallaby > 0) { fs = File.OpenWrite(“wobbiegong”); Croc = 0; } else if (Wallaby < 0) { Croc = 3; } else { fs = File.OpenRead(“wobbiegong”); Croc = 1; }} catch (IOException) { Croc = -3; } catch { Croc = 4; } finally { Yttlaooohgcueackmialeno.ldrsiIeetfoa’lpfdlyeiylonteu,hskrandwonoowhdwne’nitatfn,hytayoItohuOue’ryEetofxuridlyceoaelntwwepoialtlywosipbiteeohhnanvi.te if (Dingo > 2) { Croc -= Dingo; }} return Croc; }} 464   Chapter 10 More free ebooks : http://fast-file.blogspot.com Use the Exception object to get 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 some something unexpected and throws an exception. Uh-oh—what the heck happened? exception handling object 2 Luckily, its try/catch block caught the exception. Inside the catch block, it gave the Exception a name: ex. try { DoSomethingRisky(); } catch (Exception ex) { When you specify a specific 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, “An error occurred”); } E An An 3 The exception object stays around until the catch block is done. Then the ex reference disappears, and it’s garbage collected. string message = ex.Message; object EX xception obj ect More free ebooks : http://fast-file.blogspot.com you are here 4   465 playing catch Use more than one catch block to handle multiple types of exceptions 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 code from 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. Yetmoxheucetechppaoetndriotantiln’osseongTtecotaSdltlaarttilhnaoegti(n)otfo 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); } If you won’t use the Exception object, } there’s no need to declare it. catch (IndexOutOfRangeException) { vat.Emptied = true; } tWfofigshuiiehrletetaesytn’oIger/fiexyetOnoereeuccaxeruhnhxaategalmcecevedcki.epnasteItfsftdioceoovrhnnie-n.osaretaTanoel,yllrhtidceefehexaxelrctactn.esehtpcIpeintttrhc’ieitloolabnhnwctlioasthtccsehhckhcaoaaskttdn, befwilw,nooiadcrllskenax’t catch (IOException ex) { already caught. worker.AlertQueen(“Log file is corrupted: ” + ex.Message); } catch (Exception ex) { This catch which it can ubsleoctko agsesitgnins ftohremaetxicoenptfiroonmtothteheExvacerpiatbiloen ex, object. It’s fine for blocks to use twoworker.AlertQueen(“An unspecified error the + “Message: ” + ex.Message + “\r\n” happened: ” same name (“ex”) + “Stack trace: ” + ex.StackTrace + “\r\n” for the Exception. + “Data: ” + ex.Data + “\r\n”); } finally { vat.Seal(); worker.FinishedJob(); } ecstTsoxuoeobmhcnejeidtmespiaicnavtstiitnridt:osyaheMntpe.oeebefmreysxtetsznichnaeeteeprgntouctes”iaoe),ldns;lwaSstwththtaiiancracdhetkceoh;hwkapaatTrsni’ondsrtpaahteDrsehcsateoemitceI,eisaDaswts,iEnhaewigdct(heh“hiwAcyeghiottiEuvths’eoexdsmmtcenyhpepooetttruiemmidoaeanslly } 466   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling One class throws an exception, another class catches the exception Of course, throw and one method in catch its own a single class exceptions. can 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. 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. TootpphheeeinnsifnBuigsleeinetngPahrmeFoefifleifill.eoeO,rpotebahnje(ep)cr.ptorI’ffsoiglcetroahndmesarttebra’uoscmfatbiolpserrotoeubhxtlape.temcitts’ll stream = File.Open(profile); new BeeProfile(“prof.dat”) ct Hiv e object caTttanohhteeercrxeheBaciesdetope,PtaFsiroofiolneifil.t.eiOlTepwbheuoeentnb(tjh)ietivcutetnwhhrdataesirnwdnide’ntdl’etd. Bee Profile obje ...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. iWiNtntoratietgriaecceLienpohtsgoosEwintttth’shreeype(aB)xscesmeeepedPttrhiaoolofnodi,nl,geloaotgnbsodjietttchhtueesnihnitgvehi.rtosws try { stream = File.Open(profile); } catch (FileNotFoundException ex) { WriteLogEntry(“unable to open ” + profile + “: ” + ex.Message(); throw ex; Hiv new BeeProfile(“prof.dat”) e object try { prof = new BeeProfile(“prof.dat”); } catch (FileNotFoundException) { Hive.RecreateBeeProfile(“prof.dat”); } Bee } Profile obje ct NaiBtttcsrohohaenewemarencennoPwrewcweraiaachonBiltntoefevegcriraninelhtlregiaPtedntrcihtttothfeoehfeiixtvelhlieeoloceienbvegxateaepcoctmehtebttehipejopireeot,nripcneii.oreotts—fornTtbribiclnhaooleayeenr.ntmcdpHhrataiebnitsrsvadysaueticsknetaegse, you are here 4   467 More free ebooks : http://fast-file.blogspot.com your very own exception Bees need an OutOfHoney exception Exception Message Your classes can throw their own exceptions. For example, if you get a null parameter in a method StackTrace that was expecting throw new a value, it’s pretty common to ArgumentException(); throw the same exception a .NET method would: Your methods can throw this exception if they get invalid or unexpected values in their parameters. GetBaseException() ToString() 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. public class OutOfHoneyException : System.Exception { your Exception Message StackTrace GetBaseException() ToString() public OutOfHoneyException(string message) : base(message) { } } public class HoneyDeliverySystem { ... public void FeedHoneyToEggs() { You need to create a class for your that exception and make sure it inherits from System. Eocvaxencrelpopaatsdisoinna.gnNteohxtecieccpeotnhiosotnwrumwceteso’srraegseo. we if (honeyLevel == 0) { throw new OutOfHoneyException(“The hive is out of honey.”); } else { foreach (Egg egg in Eggs) { ... } public partial class Form1 : Form { tnhIfheivivseet,rhctoeghdreeeet’sewtxhihlcolrenorpewutynino.innantwdhilel Tienhxsitcsaetpnhtcerioonowfsobtajhenecetw. ... private void consumeHoney_Click(object sender, EventArgs e) { HoneyDeliverySystem delivery = new HoneyDeliverySystem(); try { delivery.FeedHoneyToEggs() } catch (OutOfHoneyException ex){ nalYeienkxoedecudedacptnoatoyniwodonchotaabhtttyeceorhvnehaearaxmnccyedeuolpsjuetutosiitomtn. , MessageBox.Show(ex.Message, “Warning: Resetting Hive”); } } } Hive.Reset(); Iowtcnfooonrtrttkhehiiinsnseeugtceba.oeisnTteecs,,heaceiftnaodhntnehwlwyheoeirwvhckeaia,vyrnesuotdinossotokhotueeuthetaspiotmoftfubhlhyeahotoppnonureretyoygtcnraiinosangnm’te the code to reset it in the catch block. 468   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling public static void Main() { Console.Write(“when it “); ExTestDrive.Zero(“yes”); Console.Write(“ it “); ExTestDrive.Zero(“no”); Console.WriteLine(“.”); } class MyException : Exception { } Exception Magnets Arrange the magnets so the application writes the output to the console. } } } output: when it thaws it throws. Every value “yes” or 37 type—including constants like or true—has built-in methods. So “yes”.Equals(t) returns true if the variable t contains the string “yes”. if (“yes”.Equals(t)) { Console.Write(“a”); Console.Write(“o”); Console.Write(“t”); Console.Write(“w”); Console.Write(“s”); try { } catch (MyException) { } finally { throw new MyException(); doRisky(test); Console.Write(“r”); } } public class ExTestDrive { public static void Zero(string test) { static void doRisky(String t) { Console.Write(“h”); More free ebooks : http://fast-file.blogspot.com you are here 4   469 a little review public static void Main() { Console.Write(“when it “); ExTestDrive.Zero(“yes”); Console.Write(“ it “); ExTestDrive.Zero(“no”); Console.WriteLine(“.”); } class MyException : Exception { } Exception Magnets Solution Arrange the magnets so the application writes the output to the console. output: when it thaws it throws. This line defines a cMcuaysutEgohxmtceienxpcaetpcitaoiotnnc, cwhahllbiecldohcgkeitns the code. public class ExTestDrive { public static void Zero(string test) { try { Console.Write(“t”); doRisky(test); Console.Write(“o”); } catch (MyException) { Console.Write(“a”); The Zero() method either prints “thaws” or “throws”, depending on whether it was passed “yes” or something else as its test parameter. } 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. TifhidsolRinieskoyn(l)ydgoeetssn’etxtechurtoewd the exception. static void doRisky(String t) { Console.Write(“h”); if (“yes”.Equals(t)) { throw new MyException(); } Console.Write(“r”); } } pTtahhsresoewddsotRahinsekeysxt()creinmpgteti“ohynoedsif”.ointl’ys 470   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling  Any statement can throw an exception if something fails  Each try can have more than one catch: at runtime. try { ... }  Use a try/catch block to handle exceptions. Unhandled exceptions will cause your program to stop execution and pop up an error window. catch (NullReferenceException ex) { // these statements will run if a // NullReferenceException is thrown }  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. catch (OverflowException ex) { ... } catch (Exception ex) { // Any exception that hasn’t been // caught will jump to this block }  The Exception object gives you information about the exception that was caught. If you specify an  Your code can throw an exception using throw: Exception variable in your catch statement, that throw; variable will contain information about any exception thrown in the try block: throw new Exception(“Exception message”); try { // statements that might // throw exceptions } catch (IOException ex) { // if an exception is thrown, // ex has information about it }  There are many different kinds of exception that you can catch. Each has its own object that inherits from Exception. Try to avoid just catching Exception—catch specific exceptions.  You can create a custom exception by inheriting from the Exception base class. class CustomException : Exception;  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 easy way to avoid a lot of problems: Remember, when you declare a reference in using gives you try and finally for free a “using” statement, its Dispose() method is automatically called at the end of the block. You already know that using is an easy way to make sure that your files always get closed. But what you didn’t know that it’s really just a C# shortcut for try and finally! using (YourClass c = new YourClass() ) { // code is the same as this } YourClass c = new YourClass(); try { // code } finally { c.Dispose(); } iiftsstWtiasnaahkaltDeiwlnelnayigmsyypteasooondsuctevama,(ul)nslayeetkomdeaua.eg’rtseueuhsrooienfdg More free ebooks : http://fast-file.blogspot.com you are here 4   471 an ounce of prevention Exception avoidance: implement IDisposable to do your own clean up 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 ? iwuawImDsnoapidrnyilskgeppitmnosrogetsoanaabwbttvllesieoetmmiihdtises..nacaMtnoysmraemackanleoalylnsyssuteertixmfehcfeaeyetpocytutoiiuovu’nesrese 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 clean up code in the Dispose() You can only use statement if it otherwise, your a class in a implements “using” IDisposable; program won’t compile. method, like this: class Nectar : IDisposable { YusoeuryooubrjeocbtjemcutstwiitmhpilnemaeunstinIgDsitspaotseambelentif. you want to private double amount; private BeeHive hive; private Stream hiveLog; public Nectar(double amount, BeeHive hive, Stream hiveLog) { this.amount = amount; this.hive = hive; this.hiveLog = hiveLog; } public void Dispose() { Hive.Add(amount); Hive.WriteHiveLogEntry(hiveLog, amount + “mg of nectar was added”); The IDisposable interface only has one member: the Dispose() method. Whatever you put in this method will get executed at the end of the using statement. } } DaTanmihsdoipsuomnspuetas(rt)otfmihcaeunptleaphcretondac,r.osdoaedwdaelewdpa.uytIsti’ltsogiismn pttohhreetant, We can use multiple using statements now. First, let’s use a built-in object Stream, which implements IDisposable, . Then, we’ll work with our updated Nectar object, which also implements IDisposable: tYsliawokmueo’eltlIDbhslieiossecpwkonhseoaesfbtnleeycdooruduesefni.energeednstcteaots edimneectnlhaterse using (Stream Log = new File.Write(“log.txt”)) using (Nectar nect = new Nectar(16.3, hive, Log)) { } Bee.FlyTo(flower); Bee.Harvest(nect); Bee.FlyTo(hive); TwofhheicthNheewciotlluatcrelorosbeujseaicnutgtousmtseaastteitcmhaeellnyLta.otg stream, the end tTohbhejeenectntd,hweohfBicethehweoiblilnjenlocetgr uses the nect automatically at using statement. 472   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling Q: Can I only use objects that implement IDisposable with a using statement? A: Yes. IDisposable is tailor-made to work with using statements, and adding a using statement is just like creating a new instance of a class, except that it always calls its Dispose() method. Q: Can you put any statement inside a using block? A: Definitely. The whole idea with using is that it helps you make sure that every object you create with it is disposed. But what you do with those objects is entirely up to you. In fact, you can create an object with a using statement and never even use it inside the block. But that would be pretty useless, so we don’t recommend doing that. Q: Can you call Dispose() outside of a using statement? A: Yes. You don’t ever actually need to use a using statement. You can call Dispose() yourself when you’re done with the object. Or you can do whatever cleanup is necessary—like calling a stream’s Close() method manually. But if you use a using statement, it’ll make your code easier to understand and prevent problems that happen if you don’t dispose your objects. Q: You mentioned a “try/finally” block. Does that mean it’s okay to have a try and finally without a catch? A: Yes! You can definitely have a try block without a catch, and just a finally. It looks like this: try { DoSomethingRisky(); SomethingElseRisky(); } finally { AlwaysExecuteThis(); } If DoSomethingRisky() throws an exception, then the finally block will immediately run. Q: Does Dispose() only work with files and streams? A: No, there are a lot of classes that implement IDisposable, and when you’re using one you should always use a using statement. (You’ll see some of them in the next few chapters.) And if you write a class that has to be disposed in a certain way, then you can implement IDisposable, too. If try/catch is so great, why doesn’t the IDE just put it around everything? Then we wouldn’t have to write all these try/catch blocks on our own, right? You want to know what type of exception is thrown, so you can handle that exception. There’s more to exception handling than just printing out a generic error message. For instance, in the excuse finder, if we know we’ve got a FileNotFoundException, we might print an error that suggested where the right files should be located. If we have an exception related to databases, we might send an email to the database administrator. All that depends on you catching specific exception types. This is why there are so many from classes that inherit Exception, and why you may even want your own classes to from Exception. to write inherit More free ebooks : http://fast-file.blogspot.com you are here 4   473 the one that got away The worst catch block EVER: comments A catch block will let your program keep running if you want. An exception gets thrown, you catch the exception, and instead of shutting down and giving an error message, you keep going. But sometimes, that’s not such a good thing. Take a look at this Calculator class, which seems to be acting funny all the time. What’s going on? public class Calculator { ... public void try { Divide(float dividend, float divisor) { HiDseirzvede’resoBt,yhtZeheipsrrowoEbilxllecmcer.petIafitoend.iavisor this.quotient = dividend / divisor; } catch { But why atrheerwee’sstailclagtecthtibnlgocekr.rSoors? // Note from Jim: we need to figure out a way to prevent // people from entering in zero in a division problem. } } } You should handle your exceptions, not bury them Just because you can keep your program running doesn’t mean you’ve handled your exceptions. In the code above, the calculator won’t crash... at least, not in the Divide() method. But what if some other code calls that method, and tries to print the results? If the divisor was zero, then the method probably returned an incorrect (and unexpected) value. Instead of just adding a comment, and burying the exception, you need to handle the exception. And if you’re not able to handle the problem, don’t leave empty or commented catch blocks! That just makes it harder for someone else to track down what’s going on. It’s better to let the program continue to throw exceptions, because then it’s easy to figure out what’s going wrong. ihTcactaanohdulueaesltdemtpdeoprbrto.autgyrrrhyacaecamahktdimscadehecorxhwbcetlneohfpcpootkrur,igoobhbnwutlshetmobteyhshveaewutrsjitiunhshgte 474   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling Temporary solutions are okay (temporarily) Sometimes you find a problem, and know it’s a problem, but aren’t sure what to do about it. In these cases, you might want to log the problem, and note what’s going on. That’s not as good as handling the exception, but it’s better than doing nothing. Here’s a temporary solution to the calculator: public class Calculator { ... public void Divide(float dividend, float divisor) { try { this.quotient = dividend / divisor; } catch (Exception ex) { StreamWriter sw = new StreamWriter(@”C:\Logs\errors.txt”); sw.WriteLine(ex.getMessage()); sw.Close(); } } } Tswhhhoiesrrtset-ittllheernmepe,rdotsbhtliesommbaoekcfcesuixriertdedc, l.beuatr I get it. It’s sort of like using exception handling to place a marker in the problem area. Handling exceptions doesn’t always mean the same thing as FIXING exceptions. It’s never good to have your program bomb out. But it’s way worse to have no idea why it’s crashing or what it’s doing to users’ data. That’s why you need to be sure that you’re always dealing with the errors you can predict and logging the ones you can’t. More free ebooks : http://fast-file.blogspot.com you are here 4   475 some quick suggestions A few simple ideas for exception handling Design your code to handle failures GRACEFULLY. Give your users USEFUL error messages. Throw built-in .NET exceptions where you can. Only throw custom exceptions if you need to give custom information. Think about code in your try block that COULD get short‑circuited. ... and most of all ... Avoid unnecessary file system errors... ALWAYS USE A USING BLOCK ANY TIME YOU USE A STREAM! ALWAYS ALWAYS ALWAYS! 476   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling Use what you know about try/catch/finally to improve the exception handling in Brian’s excuse manager. 1 Add exception handling to the Open button’s Click event handler. Just make a simple try/catch block that pops up a message box. Here’s what it should pop up if you try to open up a file that’s not a real excuse file: YsgaYtoiovurreuree’alaymlmlolgeyuesisstsaamngtdoaehtlilfibsffaoeeixrlvxeea,csnlheibtdopuutteblirdoinarnaowbrrmoyigre(gks“fseToaerrghitmeeohnaweitenri.pt.w.uw”hit)lal.y. 3 You’re not done yet. Open up the excuse manager, select a folder, enter data into the “Description” and “Last Results” boxes, but don’t enter a Last Used date. Now select a folder and try saving the excuse. Did you get this ArgumentOutOfRange exception? Use the debugger to track down the exception. This particular exception is totally avoidable—you can fix the program and make sure that the exception never happens? (Hint: This has nothing to do with adding a try/catch block. You’ll need to figure out why the “Last Used” date is causing a problem. Look carefully at the exception message for clues.) 4 One last thing. Before the program threw the ArgumentOutOfRange exception, it saved out a file. Load that file in—you should get the same exception. And you’ll get a different exception if you try to open a file that’s not a valid excuse file. Add an exception handling block nested inside the one you added in step 2 to make sure it doesn’t fail when you try to load an invalid excuse file (which can happen in several situations). Here’s what to do: 1. Declare a boolean variable called clearForm above the try/catch block. You’ll set this to true if there’s an exception, and check it later to see if the form should be cleared. 2. Add another try/catch block inside the one you just added to the Open button. 3. Add a finally block to the outer try/catch to reset the form to its original empty state. Reset LastUsed.Value to DateTime.Now (which returns the current date) if the clearForm variable is set to true. More free ebooks : http://fast-file.blogspot.com you are here 4   477 exercise solution Use what you know about try/catch/finally to improve the exception handling to Brian’s excuse manager. private void open_Click(object sender, EventArgs e) { if (CheckChanged()) { openFileDialog1.InitialDirectory = selectedFolder; openFileDialog1.Filter = “Excuse files (*.excuse)|*.excuse|All files (*.*)|*.*”; openFileDialog1.FileName = description.Text + “.excuse”; Diifal(orbtgeorRsoyeulsl{utcllt=e=arreDFsiouarllmtog==RefosapulelsnteF.;iOlKe)Di{alog1.ShtHeorhererwoeDEr’si,xaticnlhuesoceagtsc(reoy)np/;srctoarbtulccehtmosbrlootccockulrotaowdchraeennatteexhceaufspeoo.rpmucpalls currentExcuse = new Excuse(openFileDialog1.FileName); try { UpdateForm(false); } catch { fdtHrhaeotarmtae’shitnahapeitpn.EeensTxtcihefudastett’hsrceoynno/fstcitlaerttuhgcceehtt.ossIrat.mloehaadanesddlperbsouebtxlehcmeaspstaiinrovinsasilnidg MessageBox.Show(“The excuse file ‘“ + openFileDialog1.FileName + “’ is invalid”, “Unable to open the excuse”); clearForm = true; } } Here’s catch the messagebox block. It prints tfhreomextcheeptoioutnemretssrayg/e. catch (Exception ex) { MessageBox.Show(“An error occurred while opening the excuse ‘“ + openFileDialog1.FileName + “’\n” + ex.Message, “Unable to open the excuse”, MessageBoxButtons.OK, MessageBoxIcon.Error); clearForm = true; }finalilfy({cdrlleeaesssacutrrlUFitsopsert.dmiT.)oeVnxa{.tlTue=ext“=”=;Da“t”e;Time.Now;Btsiknhhontoatotuehwlrdtacfchabttiiensscahfrlwleiynibstaelbholtllcyo.ykcIosbtkuls’sorsecwtfokikilcnlkalanyaelolalwytwraoFsbyolhstorahcmrvkauet,nt.scotionhtdcereeufyteoohrsuamot } } } } } 478   Chapter 10 More free ebooks : http://fast-file.blogspot.com exception handling Exceptioncross 1 3 2 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Across 5. The base class that DivideByZeroException and FormatException inherit from 8. An ____________Exception happens when you try to cast a value to a variable that can't hold it 10. If the next statement is a method, "Step _____" tells the debugger to execute all the statements in the method and break immediately afterwards 12. If you ____ your exceptions, it can make them hard to track down 13. This method is always called at the end of a using block 14. The field in the Exception object that contains a string with a description 15. One try block can have multiple _______ blocks 17. The ________ block contains any statements that absolutely must be run after an exception is handled 18. An __________Exception means you tried to cram a number that was too big into a variable that couldn't hold it Down 1. The window in the IDE that you can use to check your variables' values 2. You'll get an exception if you try to divide by this 3. Toggle this if you want the debugger to stop execution when it hits a specific line of code 4. "Step ____" tells the debugger to execute the rest of the statements in the current method and then break 6. What a reference contains if it doesn't point to anything 7. You can only declare a variable with a using statement if it implements this interface 9. When a statement has a problem, it ________ an exception 11. A program that handles errors well. 16. If the next statement is a method, "Step _____" tells the debugger to execute the first statement in that method More free ebooks : http://fast-file.blogspot.com you are here 4   479 get it? finally? yeah, we’re funny Exceptioncross Solution 1W 3B A 2Z 4O E R T U R 5E X C E P T I O 6N A H U 7I K 8 I N V A L I D C A S 9T P 10O V E 11R L I H S 12B U R Y I O P O N B 13D I S P O S E W T U S S 1M4 E S S A G E 15C A T C H T 16I B 17F I N A L L Y T E 18O V E R F L O W Across Down 5. The base class that DivideByZeroException and 1. The window in the IDE that you can use to check your FormatException inherit from [EXCEPTION] variables' values [WATCH] 8. An ____________Exception happens when you try to cast a 2. You'll get an exception if you try to divide by this [ZERO] value to a variable that can't hold it [INVALIDCAST] 3. Toggle this if you want the debugger to stop execution when it 10. If the next statement is a method, "Step _____" tells the hits a specific line of code [BREAKPOINT] debugger to execute all the statements in the method and break 4. "Step ____" tells the debugger to execute the rest of the immediately afterwards [OVER] statements in the current method and then break [OUT] 12. If you ____ your exceptions, it can make them hard to track 6. What a reference contains if it doesn't point to anything down [BURY] [NULL] 13. This method is always called at the end of a using block 7. You can only declare a variable with a using statement if it [DISPOSE] implements this interface [IDISPOSABLE] 14. The field in the Exception object that contains a string with a 9. When a statement has a problem, it ________ an exception description [MESSAGE] [THROWS] 48105. O neCtryhbalpoctkerca1n0have multiple _______ blocks [CATCH] 11. A program that handles errors well. [ROBUST] 17. The must be ________ block contains run after an exception is haanMnydosletradete[FmfIrNeenAetLsLteYhba] toaobskoslute:ly ht1dt6ep.b:uIf/g/tfghaeersntteo-xfetixsleetac.tubetmeloethgnetsifsiprsaot mstt.eacttheoommde,n"tSitnepth_a_t _m_e_t"htoedlls[INthTeO] 18. An __________Exception means you tried to cram a Brian finally gets his vacation... Now that Brian’s got a handle on his exceptions, his job’s going smoothly and he can take that well‑deserved (and boss‑approved!) vacation day. exception handling ...and things are looking up back home! Your exception handling skills did more than just prevent problems. They ensured that Brian’s boss has no idea anything went wrong in the first place! Good ol’ Brian. Never misses a day of work unless he’s got a real problem. Good exception handling is invisible to your users. The program never crashes, and if there are problems, they are handled gracefully, without confusing error messages. More free ebooks : http://fast-file.blogspot.com you are here 4   481 More free ebooks : http://fast-file.blogspot.com 11 events and delegates What your code does when you’re not looking I’d better subscribe to that TreePopsUpOutOfNowhere event, or I’ll have to call my OnBrokenLeg() method. 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’ve got too many objects responding to the same event. And that’s when callbacks will come in handy. this is a new chapter   483 More free ebooks : http://fast-file.blogspot.com publisher, meet subscriber Ever wish your objects could think for themselves? Suppose you’re writing a baseball simulator. You’re going to model a game, sell the software to the Yankees (they’ve got deep pockets, right?), and make a million bucks. You create your Ball, Pitcher, Umpire, and Fan objects, and a whole lot more. You even write code so that the Pitcher object can catch a ball. Now you just need to connect everything together. You add an OnBallInPlay() method to Ball, and now you want your Pitcher object to respond with its event handler method. Once the methods are written, you just need to tie the separate methods together: That’s a standard way of naming methods—we’ll talk more about it later. Pitc Ball Ball Whgiehtte,snOctnaBhlelaeldblI.anlPl lgaeyt()s Tgtorhianejgebctatolol rtwyraasfvreholitm8w2hiotfmheeepatla.7t0e, degree and it’s Ball.OnBallInPlay(70, 82) WcaetwchantthitshbeaPll.itcher to object her object ttTahhnhaegenledp8iitst2thca)eh.necbrealcl(a9wn0ashiashnigtdr,leeaanttdehre Pitcher.CatchBall(70, 90) But how does an object KNOW to respond? Here’s the problem. You really want your Ball object to only worry about getting hit, and your Pitcher to object only worry about catching balls that come its way. In other words, you really don’t want the Ball telling the Pitcher, “I’m coming to you.” object doTPfreiihetcmelicddhaBeeeyrdarbl,ewltooidTlrloShepmcisircaondkyo’tBbtietIaknsn(teu)ohmp.we.a..nwCmhawatihcychobheert,he TisTnhhthioseaurtldad’oscnet’nst.noI’tdttettmjhueeseratmnBminateelhla’asnwtshjoootbbh.fjaeitecltdassBcitaa.nll’t You want an object to worry about itself, not other objects. You’re separating the concerns of each object. 484   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates When an EVENT occurs... objects listen What you need to do when the ball is hit is use an event. An event is simply something that’s happened in your program. Then, other objects can respond to that event—like our Pitcher object. Even better, more than one object can listen for events. So the Pitcher could listen for a ball-being-hit event, as well as a Catcher, ThirdBaseman, an Umpire, even a Fan. And each object can respond to the event differently. event, noun. a thing that happens, especially something of importance. The solar eclipse was an amazing So what we want is a Ball object that can raise an event. Then, we want to have other objects to subscribe to that particular type of event... that event to behold. just means listen to it, and get notified when that event occurs. WhBihtae,llnIintaPrlBaayiasleelsvgeaentts. waAnhndayttoohbbejejecBctatlscl aoanbrejseucsbutsbcsdrcoirbeiesbnet’dto. this need event... to know BallInPlay event raised ~ If we subscribe to the BallInPlay event, we’ll always get notified when the ball’s in play. object Fan Um Pitc Ball Events look like lightning bolts in the IDE too. You’ll see a an icon like this next to events in IntelliSense and in the properties window. her object pire object object TpflhiaeeyldePritsthcwehaebnrtalalt.nodtortyhearnd aTtnohdesemuemoinpfiitroietr’scshwfeahciakrts oehrvaepfrpoyeunlb,sa.ll The Fan object gsuobesscirnitboestihnecsaesaetas. ball Want to DO SOMETHING with an event? You need an event handler Once your object “hears” about an event, you can set up some code to run. That code is called an event handler. An event handler gets information about the event, and runs every time that event occurs. Remember, all this happens without your intervention at runtime. So you write code to raise an event, and then you write code to handle those events, and fire up your application. Then, whenever an event is raised, your handler kicks into action... without you doing anything. And, best of all, your objects have separate concerns. They’re worrying about themselves, not other objects. Wayelyeoltvo’uvehauenalrcottlbniccegieokse.vdnerEaenadvtibreso.eureistnydpgt,otonatnidmnh,dsieastno More free ebooks : http://fast-file.blogspot.com you are here 4   485 if a tree falls in the woods... One object raises its event, others listen for it... Let’s take a look at how events, event handlers, and subscription works in C#: 1 First, other objects subscribe to the event Before the Ball can raise its BallInPlay event, other objects need to subscribe to it. That’s their way of saying, anytime a BallInPlay event occurs, we want to know about it. ~ epbteEvruhvevoteenegnttrretoysavn.emh1on_asbtnCj—tdeloclijecturlkiss(tatt)doeldtinkolsiefsityotyoersounurCofwaloidncrkd BallInPlay event Pitcher ob Umpire ob Fan objec ject ject t TtBhheaeslyleInwoPablnajetycttesoveaknrnteoiwssarayaniniysgteidm.e a 2 Something triggers an event The ball gets hit. It’s time for the Ball object to raise a new event. Ball object TrwhohelleinnBgai.tllItgo’ebstjjesocbhtitiss,ttaaorntdrsageiosveeesrayinnttheovinepgnlaty. Saotidtbrohi—omfifnufetgtietrh.riierenmPyangee’itorssiepitnnwl,egaaeolm’ljarlulentssitthneafevvluooekssrknaeitmnit,ge. 3 The ball raises an event A new event gets created (we’ll talk about exactly how that works in just a minute). That event also has some arguments, like the velocity of the ball, as well as its trajectory. Those arguments are attached to the event as an instance of an EventArgs object, and then the event is sent off, available to anyone listening for it. ~ BallInPlay event Ball object BallInPlay fired off is by an by event Ball. that gets 486   Chapter 11 Bal BojabfulElsojlvteIrnecPtanVt,leacAlByloaracsgrlisstleEfytvehearannettndAcdeTresgrfsaai,njenewcsehtwifocriheyl.diss More free ebooks : http://fast-file.blogspot.com events and delegates Then, the other objects handle the event Once an event is raised, all the objects subscribed to that event get notification, and can do something: 4 Subscribrs get notification Since the Pitcher, Umpire, and Fan object subscribed to the Ball object’s BallInPlay event, they all get notified—all of their event handler methods get called one after another. ~ ject ject t Bal Ball object BallInPlay event Pitcher ob lEventArgs rtAmahneiastteehdvoge.denttisnhrtaunhndelweshrubeinssctrjuihbseteretvohebenjtecits Umpire taoeAhnbvsedejensscdotuto,ibsntsiwtcaairtnscichbrteeethrasehsto’eebeistabvalaelcnllaBrt’snaaihtlsplaeEransasvdjseietlneicsttrtAsot.rroygs ob Fan objec Events are handled on a first-come, first-served basis—the object that subscribes first gets 5 Each object handles the event notified first. Now, Pitcher, Umpire, and Fan can all handle the BallInPlay event in their own way. But they don’t all run at the same time—their event handlers get called ~ one after another, with a reference to a BallEventArgs objeHecrveteerfaneest’rsietgwnsechpteasattrtoaeomatcwhehoetreookrb.bjwjeeictctth.ttIhhtaattalhsroaanigsdeeltdess the a the event. TBishaelcllEPovsiteecn, htiteArrfgoiesb,ljdeascntdthciefhebtcahkllse. ball BallInPlay event lEventArgs ttTBohhaeleclEabFtavacellhnn.itsoAbcrjlegocsstetseocnshoeeuecgkhifs Fan Bal Um Pitc her objecttToothhefeurUrtmehvpeeirnretrswe, aalitcktcehweBpshai.arltIleFthiemoalbdipgpejhedetncsoe.trveBnaslulTbshcrroiwben,to object you are here 4   487 More free ebooks : http://fast-file.blogspot.com i came here for an argument Connecting the dots Now that you’ve got a handle on what’s going on, let’s take a closer look at how the pieces fit together. Luckily, there are only a fewIfitmeno’mhsroepvayrtiioyntguogrcfolprdaeoasvsmeird—ntsetEi.atvae(hranagltstuAmhnroeogunsgtp.huTobnblhiojcatetcm’rtseesmqatunboierresd.) 1 We need an object for the event arguments Remember, our BallInPlay event has a few arguments that it IuotnephbevcamjeeaendnecsdtattltnetoysinoihttsuaechrtinaandsEtdepoviyateyeornosuttntu’oiAtccuaralngnasr. carries along. So we need a very simple object for those arguments. .NET has a standard class for it called EventArgs, but that class has no members. Its sole purpose is to allow your event arguments object to be passed to the event handlers that use it. Here’s the class declaration: The ball will use these public class BallEventArgs : EventArgs properties to pass information hit to the event handlers about where the ball’s been hit. EventArgs BallEventArgs Trajectory Distance 2 Next we’ll need to define the event in the class that’ll raise it The ball class will have a line with the event keyword—this is how it informs other objects about the event, so they can subscribe to it. This line can be anywhere in the class—it’s usually near the property declarations. But as long as it’s in the Ball class, other objects can subscribe to a ball’s event. It looks like this: public event EventHandler BallInPlay; Events are usually public. This event is defined in the Ball class, but we’ll want Pitcher, Umpire, etc., to be able to reference it. You could make it private if you only wanted other instances of the same class to subscribe to it. TteaAvhshfeeaptntateo’rrbshtjtneaocohnttfdesleea.NsrvuerEbmneTstsece.trrkTihvbeoeyihdndwegsoCrrste#hdoaosutcoklohndemeyylweoeosovouerkEndnvtle—ikeewidetn.h’tisattHdiaestfnhtiednoierltdeelrl . tontWhahbhemajeteenedvtceyhenotetu.i,rsnuaaseenmevndeeEnddetveserihsenaainntsddHraleeearfrrnseerfdnaeelennredceedenractt,neooyEtotaovuna’erktEeehnvettteewoAlnbolrijntegpgAcastroratrgtmhehsefeartetoremberrjnseae,cticseahtenod. ds 488   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates 3 The subscribing classes need event handler methods Every object that has to subscribe to the Ball’s BallInPlay event needs to have an event handler. You already know how event handlers work—every time you added a method to handle a Button’s Click event or a NumericUpDown’s ValueChanged event, the IDE added an event handler method to your class. The Ball’s BallInPlay event is no different, and an event handler for it should look pretty familiar: void ball_BallInPlay(object sender, EventArgs e) Ttnpferohheeleeldtorotewtb’yesojdesnctbobteaynCrndt#eaafhmreeerdrdunelnnaeaacmmetec,hienfaorgtoftlaclstooianwhnyeevswedaenyvytobe,uiynorbtnau:.entvteuhtnnehtdenerhareams’nscedoarloeefr,s TtsneeyhnepeddeesBaratslaolEInntdvPaelakanneytEteHwvveaeonnntptdaAdrlraegemcsrleact,raeawltrlhesidio—cnhaeln—mistoaeebnaddnjescihtttashvcaeeatvlneleiontdt return value. Thcsotaafhalnelrdettcdlhelsearbswesamivttleehnthltah“,tobbsdoaheiahlnistaglsst_hhBaa”ia,nsBldflpaIlonaelllPrdlotrl,waei“cyfeBuedlearavebrlenynlcetevtIehhvnneaatPrnnlidaalabmelyree”. 4 Each individual object subscribes to the event Once we’ve got the event handler set up, the various Pitcher, Umpire, ThirdBaseman, and Fan objects need to hook up their own event handlers. Each one of them will have its own specific ball_BallInPlay method that responds differently to the event. So if there’s a Ball object reference variable or field called ball, then the += operator will hook up the event handler: ball.BallInPlay += new EventHandler(ball_BallInPlay); TrehevahfeninesdtrlteenoerclfleuspwCisht#aoptoetitnvhoteerihnBogooabktljloeItn.cPhtelatyehveenbtall The += operator tells C# subscribe an event handler to an event. Tesuvhebisnsctpraihbraetndtsolpeertchimfeieetesvhewondhtic.tho T(moitrhaesttcpehhaveertnaphtmreoehgtoarennaredmsldeawernfodmnin’ertetedthcooubdrmyn’psEivlsevaie.glunneta)Htuahrnaeds lteor Turn the page, there’s a little more... More free ebooks : http://fast-file.blogspot.com you are here 4   489 Bal Pitc Ball the event of the season 5 A Ball object raises its event to notify subscribers that it’s in play Now that the events are all set up, the Ball can raise its event in response to something else that happens in the simulator. Raising an event is easy—it just calls the BallInPlay event. if (BallInPlay != null) e is a new BallEventArgs object. BallInPlay(this, e); The the ball Ball gets hit, and object goes into action... BallInPlay(this, e) object w.B..itbalyhlEctvrheeenattrAiingrghgtsaodnbaejtweac.t.. ...and ~ lEventArgs pietavsetsniontgtbheeing raised. Now the BallInPlay event event is active. Who’s TBevahelenlItnpPithlcaahnyederlevrehnottoo.ketdheupbaitlls’s subscribed? If you raise an event with no handlers, it’ll throw an exception. If no other objects have added their event handlers to an event, it’ll be null. So always check to make sure your event handler isn’t equal to null before you raise it. If you don’t, it’ll throw a NullReferenceException. ball_BallInPlay() her object Smwoaewintttadhhhneotctdsaphniegwtecdirtthoihsgehrwctt’ahshlaedletadetiv,tae,nt. Use a standard name when you add a method to raise an event Take a minute and go the code for any form and type the keyword override any place you’d declare a method. As soon as you press space, an IntelliSense window pops up: Notice how each of these methods takes They an all EventArgs as a parameter? pass that parameter on to the event when they raise it. There are a huge number of events that a Form object can raise, and every one of them has its own method that raises it. The form’s OnDoubleClick() raises the DoubleClick event, and that’s the whole reason it’s there. So the Ball event will follow the same convention: we’ll make sure it has a method called OnBallInPlay that takes a BallEventArgs object as a parameter. The baseball simulator will call that method any time it needs the ball to raise its BallInPlay event—so when the simulator detects that the bat hit the ball, it’ll create a new instance of BallEventArgs with the ball’s trajectory and distance and pass it to OnBallInPlay(). 490   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates Q: Why do I need to include the word EventHandler when I declare an event? I thought the event handler was what the other objects used to subscribe to the events. A: That’s true—when you need to subscribe to an event, you write a method called an event handler. But did you notice how we used EventHandler in the the event declaration (step #2) and the in line to subscribe the event handler to it (step #4)? What EventHandler does is it defines the signature of the event—it tells the objects subscribing to the event exactly how they need to define their event handler methods. Specifically, it says that if you want to subscribe a method to this event, it needs to take two parameters (an object and an EventArgs reference) and have a void return value. Q: What happens if I try to use a method that doesn’t match the ones that are defined by EventHandler? A: Then your program won’t compile. The compiler will make sure that you don’t ever accidentally subscribe an incompatible event handler method to an event. That’s why the standard event handler, EventHandler, is so useful—as soon as you see it, you know exactly what your event handler method needs to look like. Q:Wait, “standard” event handler? There are other kinds of event handlers? A:Yes! Your events don’t have to send an object and an EventArgs. In fact, they can send anything at all—or nothing at all! Look at the last line in the IntelliSense window on the bottom on the facing page. Notice how the OnDragDrop method takes a DragEventArgs reference instead of an EventArgs reference? DragEventArgs inherits from EventArgs, just like BallEventArgs does. The form’s DragDrop event doesn’t use EventHandler. It uses something else, DragEventArgs, and if you want to handle it, your event handler method needs to take an object and a DragEventArgs reference. The parameters of the event are defined by something called a delegate—EventHandler and DragEventArgs are two examples of delegates. But we’ll talk more about that in a minute. Q: So I can probably have my event handlers return something other than void, too, right? A: Well, you can, but it’s often a bad idea. If you don’t return void from your handler, you can’t chain event handlers. That means you can’t connect more than one handler to each event. Since chaining is a handy feature, you’d do best to always return void from your event handlers. Q:Chaining? What’s that? A: It’s how more than one object can subscribe to the same event—they chain their event handlers onto the event, one after another. We’ll talk a lot more about that in a minute, too. Q: Is that why I used += when when I added my event handler? Like I’m somehow adding a new handler to existing handlers? A: Exactly! Anytime you add an event handler, you want to use +=. That way, your handler doesn’t replace existing handlers. It just becomes one in what may be a very long chain of other event handlers, all of which are listening to the same event. Q:Why does the ball use “this” when it raises the BallInPlay() event? A:Because that’s the first parameter of the standard event handler. Have you noticed how every Click event handler method has a parameter “object sender”? That parameter is a reference to the object that’s raising the event. So if you’re handling a button click, sender points to the button that was clicked. And if you’re handling a BallInPlay event, sender will point to the Ball object that’s in play—and the ball sets that parameter to this when it raises the event. A SINGLE event is always raised by a SINGLE object. But a SINGLE event can be responded to by MULTIPLE objects. you are here 4   491 More free ebooks : http://fast-file.blogspot.com that’ll save you some typing The IDE creates event handlers for you automatically Most programmers follow the same convention for naming their event handlers. If there’s a Ball object that has a BallInPlay event, and the name of the reference holding the object is called ball, then the event handler would typically be named ball_BallInPlay(). That’s not a hard-and-fast rule, but if you write your code like that, it’ll be a lot easier for other programmers to read. Luckily, the IDE makes it really easy to name your event handlers properly. It has a feature that automatically adds event handler methods for you when you’re working with a class that raises an event. It shouldn’t be too surprising that the IDE can do this for you—after all, this is exactly what it does when you double-click on a button in your form. Do this 1 Start a new Windows application and add the Ball and BallEventArgs Here’s the Ball class: public class Ball { public event EventHandler BallInPlay; public void OnBallInPlay(BallEventArgs e) { if (BallInPlay != null) BallInPlay(this, e); } } And here’s the BallEventArgs class: public class BallEventArgs : EventArgs { public int Trajectory { get; private set; } public int Distance { get; private set; } public BallEventArgs(int Trajectory, int Distance) { this.Trajectory = Trajectory; this.Distance = Distance; } } 2 Start adding the Pitcher’s constructor Add a new Pitcher class to your project. Then give it a constructor that takes a Ball reference called ball as a parameter. There will be one line of code in the constructor to add its event handler to ball.BallInPlay. Start typing the statement, but don’t type += yet. public Pitcher(Ball ball) { ball.BallInPlay } 492   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates 3 Type += and the IDE will finish the statement for you As soon as you type += in the statement, the IDE displays a very useful little box: public Pitcher(Ball ball) { ball.BallInPlay += } As soon as you press the tab key, the IDE will finish the statement for you. It’ll look like this: public Pitcher(Ball ball) { ball.BallInPlay += new EventHandler(ball_BallInPlay); } DteWxheheasecignctnoyedsoraeu.mctsedooftutirlbheicleeki-n—fscotalriedcmakd’dsinooIgnfnaaijnubtseutivteatanodltndihiiznnagentdCihtleeortmfoaopurtotmhnoemedeaenntstdiigc(naoe)lflry,—mttheehetxehccoeIlDadpstEsintfdhtiolaheet.es the it adds Form1. 4 The IDE will add your event handler, too You’re not done—you still need to add a method to chain onto the event. Luckily, the IDE takes care of that for you, too. new EventHandler( Hit the tab key again to make the IDE add this event handler method to your Pitcher class. The IDE will always follow the objectName_HandlerName() convention: void ball_BallInPlay(object sender, EventArgs e) { } throw new NotImplementedException(); TNtssoohhomaetitfeIImtDtyhpoeEilneullgmsarleyiuwtnonatuyfetsidthllhEefeadixlctlcosiendypionetauiutiottshnt’oli(ilsm)lltaanthsericeoaadwlplytlaa.onceiemhxopclldeepmetreinotn 5 Finish the pitcher’s event handler Now that you’ve got the event handler’s skeleton added to your class, fill in the rest of its code. The pitcher should catch any low balls, otherwise he covers first base. Since BallEventArgs is a subclass of void ball_BallInPlay(object if (e is BallEventArgs) sender, { EventArgs e) {aEsveknetyAwrogrsd, we’ll downcast it so we can use its using the properties. BallEventArgs ballEventArgs = e as BallEventArgs; if ((ballEventArgs.Distance < 95) && (ballEventArgs.Trajectory < 60)) CatchBall(); else CoverFirstBase(); } You’ll add these in a minute. methods } More free ebooks : http://fast-file.blogspot.com you are here 4   493 put it all together 2 It’s time to put what you’ve learned so far into practice. Your job is to complete the Ball and Pitcher classes, add a Fan class, and make sure they all work together with a very basic version of your baseball simulator. 1 Complete the Pitcher class. Below is what we’ve got for Pitcher. Add the CatchBall() and CoverFirstBase() methods. Both should print out that the catcher has either caught the ball, or run to first base. public class Pitcher { public Pitcher(Ball ball) { ball.BallInPlay += new EventHandler(ball_BallInPlay); } void ball_BallInPlay(object sender, EventArgs e) { if (e is BallEventArgs){ BallEventArgs ballEventArgs = e as BallEventArgs; if ((ballEventArgs.Distance < 95) && (ballEventArgs.Trajectory < 60)) CatchBall(); else CoverFirstBase(); } } You’ll need to implement these two methods to write a line of output to the console. } Pitc her object 2 Write a Fan class. Create another class called Fan. Fan should also subscribe to the BallInPlay event in its constructor. The fan’s event handler should see if the distance is greater than 400 feet and the trajectory is greater than 30 (a home run), and grab for a glove to try and catch the ball if it is. If not, the fan should scream and yell. Write out what’s going on with the fan to the console. wtLhhoeaotkfaiatctinshtgohpuealdgoeuptrtpionutts.eweinedxoawctloyn Fan ? object 494   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates 4 Build a very simple simulator. Create a new application. The application should have two NumericUpDown controls: one for the ball’s distance, and one for its trajectory. Add a button, labeled “Play ball!” When “Play ball!” is clicked, a ball is hit with the values in the two NumericUpDowns. Your form should look something like this: Tc1pt0ahroneo01pr0,veaars0lnotugyeaseenfttfdoorrioV0tmtas,lruMM0aejiaenttxciootmimo2urum0ym. DVbeaofnlo’tureefyoporrugoeuptseerttotiehcseamstt.o the ints TdfrehofemauDl0tistvtaaonluc5ee0oc0fa,n1w0riat0nh.gea 5 Create the following output. See if you can make your simulator generate this output with three successive balls put into play. Write down the values you used to get the result below: Ball 1: Trajectory: Distance: Ball 2: Trajectory: Distance: Ball 3: Trajectory: Distance: More free ebooks : http://fast-file.blogspot.com you are here 4   495 exercise solution It’s time to put what you’ve learned so far into practice. Your job is to complete the Ball and Pitcher classes, add a Fan class, and make sure they all work together with a very basic version of your baseball simulator. public class Ball { public event EventHandler BallInPlay; public void OnBallInPlay(BallEventArgs e) { if (BallInPlay != null) BallInPlay(this, e); } } Titcthhh’leeelctBkOhanmrlBloaInwakPlelIalnasnluyareyeex(v)cietenmp’tste—tnioohbntou.dtnuijtluls,thoatrshateisorews ise Read-only automatic public class BallEventArgs : EventArgs { properties work { really well in event public int Trajectory { get; private set; } arguments because public int Distance { get; private set; } the event handlers public BallEventArgs(int Trajectory, int Distance) only read the data { passed to them. this.Trajectory = Trajectory; this.Distance = Distance; } } public class Fan { public Fan(Ball ball) TchhaeinFsaintsobejveecntt’shcaonndslterruoctnotro the BallInPlay event. { ball.BallInPlay += new EventHandler(ball_BallInPlay); } void ball_BallInPlay(object sender, EventArgs e) { The fan’s BallInPlay event handler looks for any ball that’s high and long. if (e is BallEventArgs) { BallEventArgs ballEventArgs = e as BallEventArgs; if (ballEventArgs.Distance > 400 && ballEventArgs.Trajectory > 30) Console.WriteLine(“Fan: Home run! I’m going for the ball!”); else Console.WriteLine(“Fan: Woo-hoo! Yeah!”); } } } 496   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates public class Pitcher { public Pitcher(Ball ball) { } ball.BallInPlay += new EventHandler(ball_BallInPlay); Ypoituchaelrre’asdByalhlIanvPelatyheevent void ball_BallInPlay(object sender, EventArgs e) { handler. It looks for any if (e is BallEventArgs) { low balls. BallEventArgs ballEventArgs = e as BallEventArgs; if ((ballEventArgs.Distance < 95) && (ballEventArgs.Trajectory < 60)) CatchBall(); else CoverFirstBase(); } } private void CatchBall() { Console.WriteLine(“Pitcher: I caught the ball”); } private void CoverFirstBase() { Console.WriteLine(“Pitcher: I covered first base”); } } public partial class Form1 : Form { Ball ball = new Ball(); Pitcher pitcher; Fan fan; public Form1() { ipTIottintshechechofofeoanorknsrst,umrtpaunhnctdeteoeofodrtan.shneeoapnbnietadclblhaeilnrl,. InitializeComponent(); pitcher = new Pitcher(ball); fan = new Fan(ball); } tWptihhtheecehnbeevatrellhntettoobhpufaittnirtcdeohlenort’fsshfceinliibtctakshlelBedta,politltIthncePhhelefaroybraaemtnvtdetenreft,la,lsnwwhtohihbiccejhhectcteasll.llss private void playBall_Click(object sender, EventArgs e) { BallEventArgs ballEventArgs = new BallEventArgs( (int)trajectory.Value, (int)distance.Value); ball.OnBallInPlay(ballEventArgs); } } Ball 1: Ball 2: Ball 3: bowHeueetarpueusleitatd.rteYlteootudhrgieseftfvmeaitrlguehhenetst. Trajectory: 75 Distance: 105 Trajectory: 48 Distance: 80 Trajectory: 40 Distance: 435 More free ebooks : http://fast-file.blogspot.com you are here 4   497 introducing the events page The forms you’ve been building all use events Every time you’ve created a button, double-clicked on it in the designer, and written code for a method like button1_Click(), you’ve been working with events. Do this 1 Create a new Windows Application project. Go to the Properties window for the form. There are icons at the top of the window—click on the one that’s got a lightning bolt icon on it. That will bring up the events page in the Properties window: You can see all of the events for a control: just click on it and then click on this events button in the properities window. YwcFolioiluclrkmcfsa1ir_noenCcelrtivecheakertynefeotaxrintmmeetbvosyeonCmsteleilcoteknchetaitinngthe events window. SyctctceolclhloiviuicrcaeckoFktnkdltolooegor,ndvenhmeottat1niwhsnt.htDden.eflehAeiItwrsDaronienogdEddurnCpdelielewtrivrct.“i’ecllkoCllrtslyaaoatitcddnhotykdddeoi”mhu.edaaorevWooelnukfiynhenbooteweltruen.hm-e 2 Double-click on the “Click” row in the events page. The IDE will automatically add an event handler method to your form called Form1_Click. Add this line of code to it: private void Form1_Click(object sender, EventArgs e) { MessageBox.Show(“You just clicked on the form”); } 3 Visual Studio did more than just write a little method declaration for you, though. It also hooked the event handler up to the Form objects Click event. Open up Form1.Designer.cs and use the Quick Find feature in the IDE to search for the text Form1_Click in the current project. You’ll find this line of code: this.Click += new System.EventHandler(this.Form1_Click); Now run the program and make sure your code works! 498   Chapter 11 Event handlers always need to be “hooked up”. If you drag a button onto your form and add a method called button1_Click(), that has the right parameters, but isn’t registered to listen to your button, the method won’t ever get called. Double-click on the button in the designer—the IDE will see the default event handler name is taken, so it’ll add an event handler for the button called button1_Click_1(). More free ebooks : http://fast-file.blogspot.com events and delegates One event, multiple handlers Here’s a really useful thing that you can do with events: you can chain them so that one event or delegate calls many methods, one after another. Let’s add a few buttons to your application to see how it works. Q: When I added a new event handler to the Pitcher object, why did the IDE make it throw an exception? 4 Add these two methods to your form: A: It added code to throw a private void SaySomething(object sender, EventArgs e) { MessageBox.Show(“Something”); } private void SaySomethingElse(object sender, EventArgs e) { MessageBox.Show(“Something else”); } NotImplementedException to remind you that you still need to implement code there. That’s a really useful exception, because you can use it as a placeholder just like the IDE did. For example, you’ll typically use it when you need to build the skeleton of a class but you don’t want to fill in all 5 Now add two buttons to your form. Double-click on each button to add its event handler. Here’s the code for both event handlers: the code yet. That way, if your program throws that exception, you know it’s because you still need to finish the code, private void button1_Click(object sender, EventArgs e) { and not because your program is broken. this.Click +=new EventHandler(SaySomething); } private void button2_Click(object sender, EventArgs e) { this.Click +=new EventHandler(SaySomethingElse); } 6 Now run your program and do this: ≥ Click the form—you’ll see a message box pop up that says, “You just clicked on the form”. ≥ Now click button1 and then click on the form again. You’ll see two message boxes pop up: “You just clicked on the form” and then “Something”. ≥ Click button2 twice and then click on the form again. You’ll see four message boxes: “You just clicked on the form”, “Something”, “Something else”, and “Something else”. ChtWahlihnecedyknleceyrhvsoeauniontnc.tdliocifkftehtreheenfstoerebmvu’etsnttons, So what happened? That means you won’t see Every time you clicked one of the buttons, you chained another method—either Something() or SomethingElse()—onto the form’s Click event. You can keep clicking the buttons, and they’ll keep chaining the same methods onto the event. The event doesn’t care how many methods are chained on, or even if the same method is in the chain more than once. It’ll just call them all every time the event fires, one after another, in the order they were added. anything when you click the buttons! You’ll need to click on the form, because the buttons change the form’s behavior by modifying its Click event. Form1_Click() For ~ m1 Click event object SaySomething() The same method SaySomethingElse() can be chained on to an event more than once. SaySomethingElse() you are here 4   499 More free ebooks : http://fast-file.blogspot.com givers and receivers Connecting event senders with event receivers One of the trickiest things about events is that the sender of the event has to know what kind of event to send—including the arguments to pass to the event. And the receiver of the event has to know about the return type and the arguments its handler methods must use. But—and here’s the tricky part—you can’t tie the sender and receiver together. You want the sender to send the event and not worry about who receives it. And the receiver cares about the event, not the object that raised the event. So both sender and receiver focus on the event, not each other. BabrbaeaolcilusaetnuestBeehdaiastltlItnneoPevelekadnnysto,w.to ~ BallInPlay event atBpoPpairttllohcIpnharPteilraaetynve,eeneseotdve,sintattnocdhakanbnnuordiwelldespraao.bnnodut Pitc Ball object BawFbahaolanlut,tdPtoPieytisptcehcNehoOrefT,r.UowbImtjapendicrttoee,twsoenot’rtwcko.scrarwryieth it: her object “My people will get in touch with your people.” You know what this code does: Ball currentBall; It creates a reference variable that can point to any Ball object. It’s not tied to a single Ball. Instead, it can point to any ball object—or it can be null, and not point to anything at all. An event needs a similar kind of reference—except instead of pointing to an object, it needs one that points to a method. Every event needs to keep track of a list of methods that are subscribed to it. You’ve already seen that they can be in other classes, and they can even be private. So how does it keep track of all of the event handler methods that it needs to call? 500   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates A delegate STANDS IN for an actual method One of the most useful aspects of events is that when an event fires, it has no idea whose event handler methods it’s calling. Anyone who happens to subscribe to an event gets his event handler called. So how does the event manage that? It uses a C# type called a delegate. A delegate lets you create a reference variable, but instead of referring to an instance of a class, it refers to a method inside a class. You’ve actually already been using delegates thoughout this chapter! When you created the BallInPlay event, you used EventHandler. Well, an EventHandler is just a delegate. If you right-click on EventHandler in the IDE and select “Go to definition”, this is what you’ll see (try it yourself): When you create a delegate, all you need to do is specify the signature of methods that it can point to. So this delegate can be used to reference any method that takes an object and an EventArgs and has no return value. public delegate void EventHandler(object sender, EventArgs e); Tspiohgiinnsattsputerocei—mfiewetshhitcohhdesmrweeiattnhusrvnaonivdaEluvreeentotufHrnatnhvdaelleudreeslc.eagnatoen’lsy TEvheentnaHmanedolefr.this delegate is A delegate adds a new type to your project Do this When you add a delegate to your project, you’re adding a delegate type. And when you use it to create a field or variable, you’re creating an instance of that delegate type. So create a new project. Then add a new class file to the project called ReturnsAString.cs. But instead of putting public delegate string ReturnsAString(); a cRplraeotsjsuericnntss.AidNSeotwirti,nyagoduidscaaandsieunslgeegleaittlietnoet:ydpeecltahraetvayroiua’bvelesadadndedftieoldyso.ur Go to the form code and add this field to the form: ReturnsAString someMethod; dsoemleegMateethtoydpeisRaentuirnnstsAanScterionfg.the Now build your program—it compiles! (It gets a warning because you never used that field—that’s okay.) As soon as you added your new delegate to the program, it created a new type called ReturnsAString. If you use that type to declare a variable, you can set that variable equal to any method that takes no parameters and returns a string. Try it out—add this method to your code: private string HiThere() { return “Hi there!”; } This method’s signature matches ReturnsAString. Add a button that has these three lines. Click it and see what happens: someMethod = new ReturnsAString(HiThere); sMtersisnaggemBeosxs.aSgheow=(mseosmseaMgeet)h;odY(aimto)neuy;ltickohaetondhaesriemttevhatsarhopiomapdbee,lMnesi,tetBtcohuatoplldoswinjwhutehsntattoyle.iokvueercall del-e-gate, noun. a person sent or authorized to represent others. The president sent a delegate to the summit. you are here 4   501 More free ebooks : http://fast-file.blogspot.com delegate your authority Delegates in action There’s nothing mysterious about delegates—in fact, they don’t take much code at all to use. Let’s use them to help a restaurant owner sort out his top chef ’s secret ingredients. Do this 1 Create a new Windows project and add a delegate Delegates usually appear outside of any other classes, so add a new class file to your project and call it GetSecretIngredient.cs. It will have exactly one line of code in it: public delegate string GetSecretIngredient(int amount); This delegate can be used to create a variable that can point to any method that takes one int parameter and returns a string. 2 Add a class for the first chef, Suzanne Suzanne.cs will hold a class that keeps track of the first chef ’s secret ingredient. It has a private method called SuzannesSecretIngredient() with a signature that matches GetSecretIngredient. But it also has a read-only property—and check out that property’s type. It returns a GetSecretIngredient. So other objects can use that property to get a reference to her SuzannesIngredientList() method. public class Suzanne { Suzanne’s secret ingredient method takes an int called amount and returns a string that describes her secret ingredient. public GetSecretIngredient MySecretIngredientMethod { get { return new GetSecretIngredient(SuzannesSecretIngredient); } } private string SuzannesSecretIngredient(int amount) { return amount.ToString() + “ ounces of cloves”; } } 3 Then add a class for the second chef, Amy Amy’s method works a lot like Suzanne’s: Amy’s GetSecretIngredient property GrpeoetitnuStreinncsgreattonInehgwerreindssietecnartnectde eionlefggratetdheeietnthamt’esthod. public class Amy { public GetSecretIngredient AmysSecretIngredientMethod { Amy’s secret get { ingredient method also takes an int } } return new GetSecretIngredient(AmysSecretIngredient); called amount and private string AmysSecretIngredient(int amount) { returns a string, but it returns a if (amount < 10) return amount.ToString() + “ cans of sardines -- you need more!”; different string else from Suzanne’s. } return amount.ToString() + “ cans of sardines”; } 502   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates 4 Create a new Windows project and add a delegate Build this form. Here’s the code for the form: GetSecretIngredient ingredientMethod = null; Suzanne suzanne = new Suzanne(); Amy amy = new Amy(); private void useIngredient_Click(object sender, EventArgs e) { if (ingredientMethod != null) Console.WriteLine(“I’ll add ” + ingredientMethod((int)amount.Value)); else Console.WriteLine(“I don’t have a secret ingredient!”); } private void getSuzanne_Click(object sender, EventArgs e) { ingredientMethod = new GetSecretIngredient(suzanne.MySecretIngredientMethod); } private void getAmy_Click(object sender, EventArgs e) { ingredientMethod = new GetSecretIngredient(amy.AmysSecretIngredientMethod); } 5 Use the debugger to explore how delegates work You’ve got a great tool—the IDE’s debugger—that really help you get a handle on how delegates work. Do the following steps: ≥ Start by running your program. First click the “Get the ingredient” button—it should write a line to the console that says, “I don’t have a secret ingredient.” ≥ Click the “Use Suzanne’s delegate” button—that takes the form’s ingredientMethod field (which is a GetSecretIngredient delegate) and set it equal to whatever Suzanne’s GetSecretIngredient property returns. That property returns a new instance of the GetSecretIngredient type that’s pointing to the SuzannesSecretIngredient() method. ≥ Click the “Get the ingredient” button again. Now that the form’s ingredientMethod field is pointing to SuzannesSecretIngredient(), it calls that, passing it the value in the numericUpDown control and writing its output to the console. ≥ Click the “Use Amy’s delegate” button. It uses the Amy.GetSecretIngredient property to set the form’s ingredientMethod field to point to the AmysSecretIngredient() method. ≥ Click the “Get the ingredient” method one more time. Now it calls Amy’s method. ≥ Now use the debugger to see exactly what’s going on. Place a breakpoint on the first line of each of the three methods in the form. Then restart the program (which resets the ingredientMethod so that it’s equal to null), and start over with the above five steps. Use the Step Into (F11) feature of the debugger to step through every line of code. Watch what happens when you click “Get the ingredient”. It steps right into the Suzanne and Amy classes, depending on which method the ingredientMethod field is pointing to. More free ebooks : http://fast-file.blogspot.com you are here 4   503 some events are too public Pool Puzzle Your job is to take snippets from the pool and place them into the blank lines in the code. You can use the same snippet more than once, and you won’t need to use all the snippets. Your goal is to complete the code for a form that writes this output to the console when its button1 button is clicked. Output Fingers is coming to get you! Note: each thing from the pool can be used more than once public Form1() { InitializeComponent(); this.______ += new EventHandler(Minivan); this.______ += new EventHandler(____________); } void Towtruck(object sender, EventArgs e) { Console.Write(“is coming ”); } void Motorcycle(object sender, EventArgs e) { button1.______ += new EventHandler(____________); } void Bicycle(object sender, EventArgs e) { Console.WriteLine(“to get you!”); } void ____________(object sender, EventArgs e) { button1.______ += new EventHandler(Dumptruck); button1.______ += new EventHandler(____________); } void ____________(object sender, EventArgs e) { Console.Write(“Fingers ”); } + ++ == Van -= Car != Minivan Motorcycle Tricycle Load Save Open Close Click Scroll event delegate int private public Airplane Bicycle Dumptruck Towtruck Flatbed 504   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates Any object can subscribe to a public event... Suppose we add a new class to our simulator, a Bat class, and that class adds a HitTheBall event into the mix. Here’s how it works: if the simulator detects that the player hit the ball, it calls the Bat object’s OnHitTheBall() method, which raises a HitTheBall event. So now we can add a bat_HitTheBall method to the Ball class that subscribes to the Bat object’s HitTheBall event. Then when the ball gets hit, its own event handler calls its OnBallInPlay() method to raise its own event, BallInPlay, and the chain reaction begins. Fielders field, fans scream, umpires yell... we’ve got a ball game. TtsOohhneeHitbistiacmTtauhlllcaesotBltolaihrdlele(d)dbeatmwteeicttothhbsojtedtchh.tea’tsball, Ball subscribed to the HitTheBall event. Now take its event handler can information about fhiogwurheaorudttthheeswdiisntganwcaes, and trajectory, and BallInPlay event. raise a Args bat.OnHitTheBall() object ~BatEvent HitTheBall event ...but that’s not always a good thing! There’s only ever going to be one ball in play at any time. But if the Bat object uses an event to announce to the ball that it’s been hit, then any Ball object can subscribe to it. And that means we’ve set ourself up for a nasty little bug—what happens if a programmer accidentally adds three more Ball objects? Then the batter will swing, hit, and four different balls will fly out into the field! bat_HitTheBall() object Usionuhupt-cpaooosshfee!dtTthhtheeoesfpbeiaerrbshktae.lllosdnweinewrreaessehritve Btetthvuhheetaenmtmta.at.fc.lhllaseertoweoplwieotthsuchsethenpeirrbntoathtgtoerh’sartbmehHawetmit,efThariilethlsleduftBb!ohasueclrlrbiobafelld bat_HitTheBall() bat_HitTheBall() Ball Bat Ball Ball ~BatEvent HitTheBall event Args object bat_HitTheBall() Ball object bat_HitTheBall() object Ball object More free ebooks : http://fast-file.blogspot.com you are here 4   505 callbacks to the rescue Five Minute Mystery The Case of the Golden Crustacean Henry “Flatfoot” Hodgkins is a TreasureHunter. He’s hot on the trail of one of the most prized possessions in the rare and unusual aquatic-themed jewelry markets: a jade‑encrusted translucent gold crab. But so are lots of other TreasureHunters. They all got a reference to the same crab in their constructor, but Henry wants to claim the prize first. In a stolen set of class diagrams, Henry discovers that the GoldenCrab class raises a RunForCover event every time anyone gets close to it. Even better, the event includes NewLocationArgs, which detail where the crab is moving to. But none of the other treasure hunters know about the event, so Henry figures he can cash in. Henry adds code to his constructor to register his treasure_RunForCover( ) method as an event handler for the RunForCover event, on the crab reference he’s got. Then, he sends a lowly underling after the crab, knowing it will run away, hide, and raise the RunForCover event—giving Henry’s treasure_RunForCover( ) method all the information he needs. Everything goes according to plan, until Henry gets the new location and rushes to grab the crab. He’s stunned to see three other TreasureHunters already there, fighting over the crab. How did the other treasure hunters beat Henry to the crab? Answers on page 511. TchTtoahhahfhsaenefeidtnycllshoaoeegasnrtedsswsfttooooreonrfuvnetmecivrotneeotindsrst. loaded. When the button is clicked, it calls the three event handlers that are chained to it. public Form1() { InitializeComponent(); this.Load += new EventHandler(Minivan); this.Load += new EventHandler(Motorcycle); } void Towtruck(object sender, EventArgs e) { Console.Write(“is coming ”); } void Motorcycle(object sender, EventArgs e) { button1.Click += new EventHandler(Bicycle); } void Bicycle(object sender, EventArgs e) { Console.WriteLine(“to get you!”); } void Minivan(object sender, EventArgs e) { button1.Click += new EventHandler(Dumptruck); button1.Click += new EventHandler(Towtruck); } void Dumptruck(object sender, EventArgs e) { Console.Write(“Fingers ”); } Pool Puzzle Solution ChThalohincoedkklteeuwrvpsoenttLthorohetaaedhnesdeelbvpeeuarntr.ttaothnea’snedvelenrts 506   Chapter 11 More free ebooks : http://fast-file.blogspot.com events and delegates Use a callback instead of an event to hook up exactly one object to a delegate Our system of events only works if we’ve got one Ball and one Bat. If you’ve got several Ball objects, and they all subscribe to the public event HitTheBall, then they’ll all go flying when the event is raised. But that doesn’t make any sense... it’s really only one Ball object that got hit. We need to let the one ball that’s being pitched hook itself up to the bat, but we need to do it in a way that doesn’t allow any other balls to hook themselves up. And that’s what a callback is—it’s a way of using a delegate so the object that’s calling it is guaranteed to only call the one method that it needs to call, and no other method can chain itself onto the delgate. Here’s how the callback will work: 1 The Bat will keep its delegate field private The easiest way to keep the wrong Ball objects from chaining themselves onto the Bat’s delegate is for the bat to make it private. That way, it has control over which Ball object’s method gets called. 2 The Bat’s constructor takes a delegate that points to a m