You are previewing Head First C#, 2nd Edition.

Head First C#, 2nd Edition

Cover of Head First C#, 2nd Edition by Andrew Stellman... Published by O'Reilly Media, Inc.
  1. Head First C#
  2. Dedication
  3. A Note Regarding Supplemental Files
  4. Advance Praise for Head First C#
  5. Praise for other Head First books
  6.  
  7. How to Use this Book: Intro
    1. Who is this book for?
      1. Who should probably back away from this book?
    2. We know what you’re thinking
    3. And we know what your brain is thinking
    4. Metacognition: thinking about thinking
    5. Here’s what WE did
    6. Here’s what YOU can do to bend your brain into submission
    7. What you need for this book
    8. Read me
    9. The technical review team
    10. Acknowledgments
    11. Safari® Books Online
  8. 1. Get Productive with C#: Visual Applications, in 10 minutes or less
    1. Why you should learn C#
      1. Here’s what the IDE automates for you...
      2. What you get with Visual Studio and 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...
    7. What Visual Studio does for you...
    8. Develop the user interface
    9. Visual Studio, behind the scenes
    10. Add to the auto-generated code
    11. You can already run your application
    12. Where are my files?
    13. Here’s what we’ve done so far
      1. .NET Visual Objects
    14. We need a database to store our information
    15. The IDE created a database
    16. SQL is its own language
    17. Creating the table for the Contact List
    18. The blanks on the contact card are columns in our People table
    19. Finish building the table
    20. Insert your card data into the database
    21. Connect your form to your database objects with a data source
    22. Add database-driven controls to your form
    23. Good programs are intuitive to use
    24. Test drive
      1. The IDE builds first, then runs
    25. How to turn YOUR application into EVERYONE’S application
    26. Give your users the application
    27. You’re NOT done: test your installation
    28. You’ve built a complete data-driven application
  9. 2. It’s All Just Code: Under the hood
    1. When you’re doing this...
    2. ...the IDE does this
    3. Where programs come from
      1. Every program starts out as source code files
      2. The .NET Framework gives you the right tools for the job
      3. Build the program to create an executable
      4. Your program runs inside the CLR
    4. The IDE helps you code
    5. When you change things in the IDE, you’re also changing your code
      1. Wait, wait! What did that say?
    6. Anatomy of a program
      1. Let’s take a closer look at your code
    7. Your program knows where to start
    8. You can change your program’s entry point
      1. So what happened?
    9. Two classes can be in the same namespace
    10. Your programs use variables to work with data
      1. Declare your variables
      2. Variables vary
      3. You have to assign values to variables before you use them
      4. A few useful types
    11. C# uses familiar math symbols
    12. Use the debugger to see your variables change
    13. Loops perform an action over and over
      1. Use a code snippet to write simple for loops
    14. Time to start coding
      1. Add statements to show a message
    15. if/else statements make decisions
    16. Set up conditions and see if they’re true
      1. Use logical operators to check conditions
      2. Set a variable and then check its value
      3. Add another conditional test
      4. Add loops to your program
  10. 3. Objects: Get Oriented!: Making code make sense
    1. How Mike thinks about his problems
    2. How Mike’s car navigation system thinks about his problems
    3. Mike’s Navigator class has methods to set and modify routes
      1. Some methods have a return value
    4. Use what you’ve learned to build a program that uses a class
      1. So what did you just build?
    5. Mike gets an idea
      1. He could create three different Navigator classes...
    6. Mike can use objects to solve his problem
    7. You use a class to build an object
      1. An object gets its methods from its class
    8. When you create a new object from a class, it’s called an instance of that class
    9. A better solution...brought to you by objects!
      1. Theory and practice
      2. A little advice for the code exercises
    10. An instance uses fields to keep track of things
      1. Methods are what an object does. Fields are what the object knows
    11. Let’s create some instances!
    12. Thanks for the memory
      1. Let’s take a closer look at what happened here
    13. What’s on your program’s mind
    14. You can use class and method names to make your code intuitive
    15. Give your classes a natural structure
      1. Let’s build a class diagram
    16. Class diagrams help you organize your classes so they make sense
    17. Build a class to work with some guys
    18. Create a project for your guys
    19. Build a form to interact with the guys
    20. There’s an easier way to initialize objects
  11. 4. Types and References: It’s 10:00. Do you know where your data is?
    1. The variable’s type determines what kind of data it can store
    2. A variable is like a data to-go cup
    3. 10 pounds of data in a 5 pound bag
    4. Even when a number is the right size, you can’t just assign it to any variable
      1. So what happened?
    5. When you cast a value that’s too big, C# will adjust it automatically
    6. C# does some casting automatically
    7. When you call a method, the arguments must be compatible with the types of the parameters
    8. Combining = with an operator
    9. Objects use variables, too
    10. Refer to your objects with reference variables
    11. References are like labels for your object
    12. If there aren’t any more references, your object gets garbage-collected
    13. Multiple references and their side effects
    14. Two references means TWO ways to change an object’s data
    15. A special case: arrays
      1. Use each element in an array like it is a normal variable
    16. Arrays can contain a bunch of reference variables, too
    17. Welcome to Sloppy Joe’s Budget House o’ Discount Sandwiches!
    18. Objects use references to talk to each other
    19. Where no object has gone before
    20. Build a typing game
  12. I. C# Lab: A Day at the Races
    1. 5. Encapsulation: Keep your privates... private
      1. Kathleen is an event planner
      2. What does the estimator do?
      3. Kathleen’s Test Drive
      4. Each option should be calculated individually
      5. It’s easy to accidentally misuse your objects
      6. Encapsulation means keeping some of the data in a class private
      7. Use encapsulation to control access to your class’s methods and fields
      8. But is the realName field REALLY protected?
      9. Private fields and methods can only be accessed from inside the class
      10. Encapsulation keeps your data pristine
      11. Properties make encapsulation easier
      12. Build an application to test the Farmer class
      13. Use automatic properties to finish the class
      14. What if we want to change the feed multiplier?
      15. Use a constructor to initialize private fields
    2. 6. Inheritance: Your object’s family tree
      1. Kathleen does birthday parties, too
      2. We need a BirthdayParty class
      3. Build the Party Planner version 2.0
      4. One more thing...can you add a $100 fee for parties over 12?
      5. When your classes use inheritance, you only need to write your code once
      6. Build up your class model by starting general and getting more specific
      7. How would you design a zoo simulator?
      8. Use inheritance to avoid duplicate code in subclasses
      9. Different animals make different noises
      10. Think about how to group the animals
      11. Create the class hierarchy
      12. Every subclass extends its base class
      13. Use a colon to inherit from a base class
      14. We know that inheritance adds the base class fields, properties, and methods to the subclass...
      15. A subclass can override methods to change or replace methods it inherited
      16. Any place where you can use a base class, you can use one of its subclasses instead
      17. A subclass can hide methods in the superclass
      18. Use the override and virtual keywords to inherit behavior
      19. A subclass can access its base class using the base keyword
      20. When a base class has a constructor, your subclass needs one, too
      21. Now you’re ready to finish the job for Kathleen!
      22. Build a beehive management system
      23. First you’ll build the basic system
      24. Use inheritance to extend the bee management system
    3. 7. Interfaces and Abstract Classes: Making classes keep their promises
      1. Let’s get back to bee-sics
      2. We can use inheritance to create classes for different types of bees
      3. An interface tells a class that it must implement certain methods and properties
      4. Use the interface keyword to define an interface
      5. Now you can create an instance of NectarStinger that does both jobs
      6. Classes that implement interfaces have to include ALL of the interface’s methods
      7. Get a little practice using interfaces
      8. You can’t instantiate an interface, but you can reference an interface
      9. Interface references work just like object references
      10. You can find out if a class implements a certain interface with “is”
      11. Interfaces can inherit from other interfaces
      12. The RoboBee 4000 can do a worker bee’s job without using valuable honey
      13. is tells you what an object implements, as tells the compiler how to treat your object
      14. A CoffeeMaker is also an Appliance
      15. Upcasting works with both objects and interfaces
      16. Downcasting lets you turn your appliance back into a coffee maker
      17. Upcasting and downcasting work with interfaces, too
      18. There’s more than just public and private
      19. Access modifiers change visibility
      20. Some classes should never be instantiated
      21. An abstract class is like a cross between a class and an interface
      22. Like we said, some classes should never be instantiated
      23. An abstract method doesn’t have a body
      24. Polymorphism means that one object can take many different forms
    4. 8. Enums and Collections; Storing lots of data
      1. Strings don’t always work for storing categories of data
      2. Enums let you work with a set of valid values
      3. Enums let you represent numbers with names
      4. We could use an array to create a deck of cards...
      5. Arrays are hard to work with
      6. Lists make it easy to store collections of...anything
      7. Lists are more flexible than arrays
      8. Lists shrink and grow dynamically
      9. Generics can store any type
      10. Collection initializers work just like object initializers
      11. Let’s create a List of Ducks
      12. Lists are easy, but SORTING can be tricky
      13. IComparable<Duck> helps your list sort its ducks
      14. Use IComparer to tell your List how to sort
      15. Create an instance of your comparer object
      16. IComparer can do complex comparisons
      17. Overriding a ToString() method lets an object describe itself
      18. Update your foreach loops to let your Ducks and Cards print themselves
      19. You can upcast an entire list using IEnumerable
      20. You can build your own overloaded methods
      21. Use a dictionary to store keys and values
      22. The Dictionary Functionality Rundown
      23. Build a program that uses a Dictionary
      24. And yet MORE collection types...
      25. A queue is FIFO—First In, First Out
      26. A stack is LIFO—Last In, First Out
  13. II. C# Lab: The Quest
    1. 9. Reading and Writing Files: Save the byte array, save the world
      1. .NET uses streams to read and write data
      2. Different streams read and write different things
      3. A FileStream reads and writes bytes to a file
      4. How to write text to a file in 3 simple steps
      5. The Swindler launches another diabolical plan
      6. Reading and writing using two objects
      7. Data can go through more than one stream
      8. Use built-in objects to pop up standard dialog boxes
      9. Dialog boxes are just another .NET control
      10. Dialog boxes are objects, too
      11. Use the built-in File and Directory classes to work with files and directories
      12. Use file dialogs to open and save files (all with just a few lines of code)
      13. IDisposable makes sure your objects are disposed of properly
      14. Avoid file system errors with using statements
      15. Trouble at work
      16. Writing files usually involves making a lot of decisions
      17. Use a switch statement to choose the right option
      18. Use a switch statement to let your deck of cards read from a file or write itself out to one
      19. Add an overloaded Deck() constructor that reads a deck of cards in from a file
      20. What happens to an object when it’s serialized?
      21. But what exactly IS an object’s state? What needs to be saved?
      22. When an object is serialized, all of the objects it refers to get serialized, too...
      23. Serialization lets you read or write a whole object all at once
      24. If you want your class to be serializable, mark it with the [Serializable] attribute
      25. Let’s serialize and deserialize a deck of cards
      26. .NET uses Unicode to store characters and text
      27. C# can use byte arrays to move data around
      28. Use a BinaryWriter to write binary data
      29. You can read and write serialized files manually, too
      30. Find where the files differ, and use that information to alter them
      31. Working with binary files can be tricky
      32. Use file streams to build a hex dumper
      33. StreamReader and StreamWriter will do just fine (for now)
      34. Use Stream.Read() to read bytes from a stream
    2. 10. Exception Handling: Putting out fires gets old
      1. Brian needs his excuses to be mobile
      2. When your program throws an exception, .NET generates an Exception object
      3. Brian’s code did something unexpected
      4. All exception objects inherit from Exception
      5. The debugger helps you track down and prevent exceptions in your code
      6. Use the IDE’s debugger to ferret out exactly what went wrong in the Excuse Manager
      7. Uh oh—the code’s still got problems...
      8. Handle exceptions with try and catch
      9. What happens when a method you want to call is risky?
      10. Use the debugger to follow the try/catch flow
      11. If you have code that ALWAYS should run, use a finally block
      12. Use the Exception object to get information about the problem
      13. Use more than one catch block to handle multiple types of exceptions
      14. One class throws an exception, another class catches the exception
      15. Bees need an OutOfHoney exception
      16. An easy way to avoid a lot of problems: using gives you try and finally for free
      17. Exception avoidance: implement IDisposable to do your own cleanup
      18. The worst catch block EVER: catch-all plus comments
      19. Temporary solutions are OK (temporarily)
      20. A few simple ideas for exception handling
      21. Brian finally gets his vacation...
    3. 11. Events and Delegates: What your code does when you’re not looking
      1. Ever wish your objects could think for themselves?
      2. But how does an object KNOW to respond?
      3. When an EVENT occurs...objects listen
      4. One object raises its event, others listen for it...
      5. Then, the other objects handle the event
      6. Connecting the dots
      7. The IDE creates event handlers for you automatically
      8. Generic EventHandlers let you define your own event types
      9. The forms you’ve been building all use events
      10. One event, multiple handlers
      11. Connecting event senders with event receivers
      12. A delegate STANDS IN for an actual method
      13. Delegates in action
      14. An object can subscribe to an event...
      15. Use a callback to control who’s listening
      16. A callback is just a way to use delegates
    4. 12. Review and Preview: Knowledge, power, and building cool stuff
      1. You’ve come a long way, baby
      2. We’ve also become beekeepers
      3. The beehive simulator architecture
      4. Building the beehive simulator
      5. Life and death of a flower
      6. Now we need a Bee class
      7. P. A. H. B. (Programmers Against Homeless Bees)
      8. The hive runs on honey
      9. Filling out the Hive class
      10. The hive’s Go() method
      11. We’re ready for the World
      12. We’re building a turn-based system
      13. Here’s the code for World
      14. Giving the bees behavior
      15. The main form tells the world to Go()
      16. We can use World to get statistics
      17. Timers fire events over and over again
      18. The timer’s using an event handler behind the scenes
      19. Add a timer to the simulator
      20. Test drive
      21. Let’s work with groups of bees
      22. A collection collects...DATA
      23. LINQ makes working with data in collections and databases easy
      24. Test drive (Part 2)
      25. One final challenge: Open and Save
    5. 13. Controls and Graphics: Make it pretty
      1. You’ve been using controls all along to interact with your programs
      2. Form controls are just objects
      3. Use controls to animate the beehive simulator
      4. Add a renderer to your architecture
      5. The renderer draws everything in the world on the two forms
      6. Controls are well suited for visual display elements
      7. Build your first animated control
      8. BeeControl is LIKE a PictureBox...so let’s start by INHERITING from PictureBox
      9. Create a button to add the BeeControl to your form
      10. Your controls need to dispose their controls, too!
      11. A UserControl is an easy way to build a control
      12. Your simulator’s renderer will use your BeeControl to draw animated bees on your forms
      13. Add the hive and field forms to the project
      14. Build the renderer
      15. Now connect the main form to your two new forms, HiveForm and FieldForm
      16. Test drive...ahem...buzz
      17. Looks great, but something’s not quite right...
      18. Let’s take a closer look at those performance issues
      19. You resized your Bitmaps using a Graphics object
      20. Your image resources are stored in Bitmap objects
      21. Use System.Drawing to TAKE CONTROL of graphics yourself
      22. A 30-second tour of GDI+ graphics
      23. Use graphics to draw a picture on a form
      24. Graphics can fix our transparency problem...
      25. Use the Paint event to make your graphics stick
      26. A closer look at how forms and controls repaint themselves
      27. Double buffering makes animation look a lot smoother
      28. Double buffering is built into forms and controls
      29. Use a Graphics object and an event handler for printing
      30. PrintDocument works with the print dialog and print preview window objects
    6. 14. Captain Amazing: The Death of the Object
      1. Your last chance to DO something... your object’s finalizer
      2. When EXACTLY does a finalizer run?
      3. Dispose() works with using, finalizers work with garbage collection
      4. Finalizers can’t depend on stability
      5. Make an object serialize itself in its Dispose()
      6. A struct looks like an object...
      7. ...but isn’t an object
      8. Values get copied; references get assigned
      9. Structs are value types; objects are reference types
      10. The stack vs. the heap: more on memory
      11. Use out parameters to make a method return more than one value
      12. Pass by reference using the ref modifier
      13. Use optional parameters to set default values
      14. Use nullable types when you need nonexistent values
      15. Nullable types help you make your programs more robust
      16. Captain Amazing...not so much
      17. Extension methods add new behavior to EXISTING classes
      18. Extending a fundamental type: string
    7. 15. LINQ: Get control of your data
      1. An easy project...
      2. ...but the data’s all over the place
      3. LINQ can pull data from multiple sources
      4. .NET collections are already set up for LINQ
      5. LINQ makes queries easy
      6. LINQ is simple, but your queries don’t have to be
      7. LINQ is versatile
      8. LINQ can combine your results into groups
      9. Combine Jimmy’s values into groups
      10. Use join to combine two collections into one query
      11. Jimmy saved a bunch of dough
      12. Connect LINQ to a SQL database
      13. Use a join query to connect Starbuzz and Objectville
  14. III. C# Lab: Invaders
    1. A. Leftovers: The top 11 things we wanted to include in this book
      1. #1. The Basics
      2. #2. Namespaces and assemblies
      3. #3. Use BackgroundWorker to make your UI responsive
      4. #4. The Type class and GetType()
      5. #5. Equality, IEquatable, and Equals()
      6. #6. Using yield return to create enumerable objects
      7. #7. Refactoring
      8. #8. Anonymous types, anonymous methods, and lambda expressions
      9. #9. Serializing data using DataContractSerializer
      10. #10. LINQ to XML
      11. #11. Windows Presentation Foundation
      12. Did you know that C# and the .NET Framework can...
  15. Index
  16. About the Authors
  17. Copyright
O'Reilly logo

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

image with no caption

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

The variable’s type determines what kind of data it can store

There are a bunch of types built into C#, and each one stores a different kind of data. You’ve already seen some of the most common ones, and you know how to use them. But there are a few that you haven’t seen, and they can really come in handy, too.

Types you’ll use all the time

It shouldn’t come as a surprise that int, string, bool, and double are the most common types.

  • int can store any whole number from –2,147,483,648 to 2,147,483,647.

    Note

    A whole number doesn’t have a decimal point.

  • string can hold text of any length (including the empty string "").

  • bool is a Boolean value—it’s either true or false.

  • double can store real numbers from ±5.0 × 10–324 to ±1.7 × 10308 with up to 16 significant figures. That range looks weird and complicated, but it’s actually pretty simple. The “significant figures” part means the precision of the number: 35,048,410,000,000, 1,743,059, 14.43857, and 0.00004374155 all have seven significant figures. The 10308 thing means that you can store any number as large as 10308 (or 1 followed by 308 zeroes)—as long as it only has 16 or fewer significant figures. On the other end of the range, 10-324 means that you can store any number as small as 10-324 (or a decimal point followed by 324 zeroes followed by 1)... but, you guessed it, as long as it only has 16 or fewer significant figures.

    Note

    “float” is short for “floating point”—as opposed to a “fixed point” number, which always has the same number of decimal places.

More types for whole numbers

Once upon a time, computer memory was really expensive, and processors were really slow. And, believe it or not, if you used the wrong type, it could seriously slow down your program. Luckily, times have changed, and most of the time if you need to store a whole number you can just use an int. But sometimes you really need something bigger... and once in a while, you need something smaller, too. That’s why C# gives you more options:

Note

A lot of times, if you’re using these types it’s because you’re solving a problem where it really helps to have the “wrapping around” effect that you’ll read about in a few minutes.

image with no caption

Types for storing really HUGE 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:

  • float can store any number from ±1.5. × 10-45 to ±3.4 × 1038 with 7 significant digits.

  • decimal can store any number from ±1.0 × 10-28 to ±7.9 × 1028 with 28–29 significant digits.

    Note

    When your program needs to deal with currency, you usually want to use a decimal to store the number.

    Note

    When you used the Value property in your numericUpDown control, you were using a decimal.

Note

A “literal” just means a number that you type into your code. So when you type “int i = 5;”, the 5 is a literal.

Literals have types, too

When you type a number directly into your C# program, you’re using a literal... and every literal is automatically assigned a type. You can see this for yourself—just enter this 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:

image with no caption

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.

Note

If you try to assign a float literal to a double or a decimal literal to a float, the IDE will give you a helpful message reminding you to add the right suffix. Cool!

Note

The “M” stands for “money”—seriously!

A few more useful built-in types

Sometimes you need to store a single character like Q or 7 or $, and when you do you’ll use the char type. Literal values for char are always inside single quotes ('x', '3'). You can include escape sequences in the quotes, too ('\n' is a line break, '\t' is a tab). You write an escape sequence in your C# code using two characters, but your program stores each escape sequence as a single character in memory.

Note

You’ll learn a lot more about how char and byte relate to each other in Chapter 9.

And finally, there’s one more important type: object. You’ve already seen how you can create objects by creating instances of classes. Well, every one of those objects can be assigned to an object variable. You’ll learn all about how objects and variables that refer to objects work later in this chapter.

Brain Power

Windows 7 has a really neat feature in Calculator called “Programmer” mode, where you can see binary and decimal at the same time!

You can use the Windows calculator to convert between decimal (normal, base-10) numbers and binary numbers (base-2 numbers written with only ones and zeroes)—put it in Scientific mode, enter a number, and click the Bin radio button to convert to binary. Then click Dec to convert it back. Now enter some of the upper and lower limits for the whole number types (like –32,768 and 255) and convert them to binary. Can you figure out why C# gives you those particular limits?

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.

Note

Not all data ends up on the heap. Value types usually keep their data in another part of memory called the stack. You’ll learn all about that in Chapter 14.

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.

image with no caption

Numbers that have decimal places are stored differently than whole numbers. You can handle most of your numbers that have decimal places using float, the smallest data type that stores decimals. If you need to be more precise, use a double. And if you’re writing a financial application where you’ll be storing currency values, you’ll want to use the decimal type.

image with no caption

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.

image with no caption

10 pounds of data in a 5 pound bag

image with no caption

When you declare your variable as one type, that’s how your compiler looks at it. Even if the value is nowhere near the upper boundary of the type you’ve declared, the compiler will see the cup it’s in, not the number inside. So this won’t work:

int leaguesUnderTheSea = 20000;

short smallerLeagues = leaguesUnderTheSea;

20,000 would fit into a short, no problem. But since leaguesUnderTheSea is declared as an int, the compiler sees it as int-sized and considers it too big to put in a short container. The compiler won’t make those translations for you on the fly. You need to make sure that you’re using the right type for the data you’re working with.

image with no caption

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.

Do this

  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:

    image with no caption
  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:

    image with no caption

So what happened?

The compiler won’t let you assign a value to a variable if it’s the wrong type—even if that variable can hold the value just fine—because that’s the underlying cause behind an enormous number of bugs. When you use casting, you’re essentially making a promise to the compiler that you know the types are different, and that in this particular instance it’s OK for C# to cram the data into the new variable.

Note

Take a minute to flip back to the beginning of the last chapter and check out how you used casting when you passed the NumericUpDown. Value to the Talker Tester form.

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

Wrap it yourself!

There’s no mystery to how casting “wraps” the numbers—you can do it yourself. Just pop up the Windows calculator, switch it to Scientific mode, and calculate 365 Mod 256 (using the “Mod” button, which does a modulo calculation). You’ll get 109.

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.

image with no caption

Yes! The + operator converts for you.

What you’ve been doing is using the + operator, which does a lot of converting for you automatically—but it’s especially smart about it. When you use + to add a number or Boolean to a string, then it’ll automatically convert that value to a string, too. If you use + (or *, /, or -) with two different types, it automatically converts the smaller type to the bigger one. Here’s an example:

image with no caption

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.

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:

image with no caption

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());

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

Note

A parameter is what you define in your method. An argument is what you pass to it. A method with an int parameter can take a byte argument.

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:

image with no caption

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.

Note

You can assign anything to a variable, parameter, or field with the type object.

if statements always test to see if something’s true

Did you notice how we wrote our if statement like this:

if (yesNo) {

We didn’t have to explicitly say “if (yesNo == true)”. That’s because an if statement always checks if something’s true. You check if something’s false using ! (an exclamation point, or the NOT operator). “if (!yesNo)” is the same thing as “if (yesNo == false)”. In our code examples from now on, you’ll usually just see us do “if (yesNo)” or “if (!yesNo)”, and not explicitly check to see if a Boolean is true or false.

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 *:

image with no caption

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:

image with no caption

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

  1. Write a statement to declare the integer.

    int myInt;
  2. Assign a value to the new variable.

    myInt = 3761;
  3. Use the integer in your code.

    while (i < myInt) {

Using an object

  1. Write a statement to declare the object.

    image with no caption
  2. Assign a value to the object.

    spot = new Dog();
  3. Check one of the object’s fields.

    while (spot.IsHappy) {
image with no caption

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.

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. Any time you want to use that particular guy, you can reference it with the reference variable called joe.

Note

That’s called instantiating the object.

So when you have a variable that is an object type, it’s a reference variable: a reference to a particular object. Take a look:

image with no caption

References are like labels for your object

In your kitchen, you probably have a container of salt and sugar. If you switched their labels, it would make for a pretty disgusting meal—even though the labels changed, the contents of the containers stayed the same. References are like labels. You can move labels around and point them at different things, but it’s the object that dictates what methods and data are available, not the reference itself.

When your code needs to work with an object in memory, it uses a reference, which is a variable whose type is a class of the object it’s going to point to. A reference is like a label that your code uses to talk about a specific object.

image with no caption

You never refer to your object directly. For example, you can’t write code like Guy.GiveCash() if Guy is your object type. The C# compiler doesn’t know which Guy you’re talking about, since you might have several instances of Guy on the heap. So you need a reference variable, like joe, that you assign to a specific instance, like Guy joe = new Guy().

Now you can call methods, like joe.GiveCash(). joe refers to a specific instance of the Guy class, and your C# compiler knows exactly which instance to use. And, as you saw above, you might have multiple labels pointing to the same instance. So you could say Guy dad = joe, and then call dad.GiveCash(). That’s OK, too—that’s what Joe’s kid does every day.

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

If all of the labels come off of an object, programs can no longer access that object. That means C# can mark the object for garbage collection. That’s when C# gets rid of any unreferenced objects, and reclaims the memory those objects took up for your program’s use.

  1. Here’s some code that creates an object.

    image with no caption

    For an object to stay in the heap, it has to be referenced. Some time after the last reference to the object disappears, so does the object.

  2. Now let’s create a second object.

    image with no caption
  3. Let’s take the reference to the first object, and change it to point at the second object.

    image with no caption

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";

    Objects:___1_______

    References:___1_______

    image with no caption
  2. Dog fido = new Dog();
    fido.Breed = "Beagle";
    Dog spot = rover;

    Objects:___2_______

    References:___3_______

    image with no caption
  3. Dog lucky = new Dog();
    lucky.Breed = "Dachshund";
    fido = rover;

    Objects:___2_______

    References:___4_______

    image with no caption

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:

Do this

image with no caption
  1. Add another button to your form.

  2. Add this code for the button. Can you guess what’s going to happen when you click it?

    image with no caption
  3. OK, go ahead and click the new button. Wait a second, that’s the Lucinda message box. Didn’t we call the WhoAmI() method from Lloyd?

    image with no caption

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:

image with no caption

Use each element in an array like it is a normal variable

When you use an array, first you need to declare a reference variable that points to the array. Then you need to create the array object using the new statement, specifying how big you want the array to be. Then you can set the elements in the array. Here’s an example of code that declares and fills up an array—and what’s happening on the heap when you do it. The first element in the array has an index of zero.

image with no caption

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 type of variable they store; it’s up to you. So you can have an array of ints, or an array of Duck objects, with no problem.

Here’s code that creates an array of 7 Dog variables. The line that initializes the array only creates reference variables. Since there are only two new Dog() lines, only two actual instances of the Dog class are created.

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.

image with no caption

An array’s length

You can find out how many elements are in an array using its Length property. So if you’ve got an array called heights, then you can use heights.Length to find out how long it is. If there are 7 elements in the array, that’ll give you 7—which means the array elements are numbered 0 to 6.

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?

MenuMaker

Randomizer

Meats

Condiments

Breads

GetMenuItem()

Do this

  1. Start a new project and add a MenuMaker class

    If you need to build a menu, you need ingredients. And arrays would be perfect for those lists. We’ll also need some way of choosing random ingredients to combine together into a sandwich. Luckily, the .NET Framework has a built-in class called Random that generates random numbers. So we’ll have four fields in our class: a Randomizer field that holds a reference to a Random object, and three arrays of strings to hold the meats, condiments, and breads.

    image with no caption
  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.

    image with no caption

Objects use references to talk to each other

So far, you’ve seen forms talk to objects by using reference variables to call their methods and check their fields. Objects can call one another’s methods using references, too. In fact, there’s nothing that a form can do that your objects can’t do, because your form is just another object. And when objects talk to each other, one useful keyword that they have is this. Any time an object uses the this keyword, it’s referring to itself—it’s a reference that points to the object that calls it.

Elephant

Name

EarSize

WhoAmI()

TellMe()

SpeakTo()

  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. You can add to button4_Click(), but add it before the statement that resets the references! (lloyd = lucinda;)

    lloyd.TellMe("Hi", lucinda);

    We called Lloyd’s TellMe() method, and passed it two parameters: “Hi” and a reference to Lucinda’s object. The method uses its whoSaidIt parameter to access the Name parameter of whatever elephant was passed into TellMe() using its second parameter.

  2. Here’s a method that calls another method

    Now let’s add this SpeakTo() method to the Elephant class. It uses a special keyword: this. That’s a reference that lets an object talk about itself.

    image with no caption

    Let’s take a closer look at how this works.

    lloyd.SpeakTo(lucinda, "Hello");

    When Lloyd’s SpeakTo() method is called, it uses its talkTo parameter (which has a reference to Lucinda) to call Lucinda’s TellMe() method.

    image with no caption

    So Lucinda acts as if she was called with ("Hello", lloyd), and shows this message:

    image with no caption

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.

image with no caption

Build a typing game

You’ve reached a milestone...you know enough to build a game! Here’s how your game will work. The form will display random letters. If the player types one of them, it disappears and the accuracy rate goes up. If the player types an incorrect letter, the accuracy rate goes down. As the player keeps typing letters, the game goes faster and faster, getting more difficult with each correct letter. If the form fills up with letters, the game is over!

Do this

image with no caption
  1. Build the form.

    Here’s what the form will look like in the form designer:

    image with no caption

    You’ll need to:

    • Turn off the minimize box and maximize box. Then set the form’s FormBorderStyle property to Fixed3D. That way, the player won’t be able to accidentally drag and resize it. Then resize it so that it’s much wider than it is tall (we set our form’s size to 876, 174).

    • Drag a ListBox out of the Toolbox onto the form. Set its Dock property to Fill, and its MultiColumn property to True. Set its Font to 72 point bold.

    • In the Toolbox, expand the “All Windows Forms” group at the top. This will display many controls. Find the Timer control and double-click on it to add it to your form.

    • Find the StatusStrip in the “All Windows Forms” group in the Toolbox and double-click on it to add a status bar to your form. You should now see the StatusStrip and Timer icons in the gray area at the bottom of the form designer:

    image with no caption

    See how you can use a Timer to make your form do more than one thing at once? Take a minute and flip to #3 in the “Leftovers” appendix to learn about another way to do that.

  2. Set up the StatusStrip control.

    Take a closer look at the status bar at the bottom of the screenshot. On one side, it’s got a series of labels:

    image with no caption

    Relax

    You’ll be using three new controls, but they’re easy to work with!

    Even though you haven’t seen a ListBox, StatusStrip, or Timer before, you already know how to set their properties and work with them in your code. You’ll learn a lot more about them in the next few chapters.

    And on the other side, it’s got a label and a progress bar:

    image with no caption

    Add a StatusLabel to your StatusStrip by clicking its drop-down and selecting StatusLabel:

    image with no caption
    • Set the StatusStrip’s SizingGrip property to False.

    • Use the Properties window to set its (Name) to correctLabel and its Text to “Correct: 0”. Add three more StatusLabels: missedLabel, totalLabel, and accuracyLabel.

    • Add one more StatusLabel. Set its Spring to True, TextAlign to MiddleRight, and Text to “Difficulty”. Finally, add a ProgressBar and name it difficultyProgressBar.

  3. Set up the Timer control.

    Did you notice how your Timer control didn’t show up on your form? That’s because the Timer is a non-visual control. It doesn’t actually change the look and feel of the form. It does exactly one thing: it calls a method over and over again. Set the Timer control’s Interval property to 800, so that it calls its method every 800 milliseconds. Then double-click on the timer1 icon in the designer. The IDE will do what it always does when you double-click on a control: it will add a method to your form. This time, it’ll add one called timer1_Tick. Here’s the code for it:

    image with no caption
  4. Add a class to keep track of the player stats.

    If the form is going to display the total number of keys the player pressed, the number that were missed and the number that were correct, and the player’s accuracy, then we’ll need a way to keep track of all that data. Sounds like a job for a new class! Add a class called Stats to your project. It’ll have four int fields called Total, Missed, Correct, and Accuracy, and a method called Update with one bool parameter: true if the player typed a correct letter that was in the ListBox, or false if the player missed one.

    Stats

    Total

    Missed

    Correct

    Accuracy

    Update()

    image with no caption
  5. Add fields to your form to hold a Stats object and a Random object.

    You’ll need an instance of your new Stats class to actually store the information, so add a field called stats to store it. And you already saw that you’ll need a field called random—it’ll contain a Random object.

    Add the two fields to the top of your form:

    public partial class Form1 : Form
    {
        Random random = new Random();
        Stats stats = new Stats();
        ...
  6. Handle the keystrokes.

    There’s one last thing your game needs to do: any time the player hits a key, it needs to check if that key is correct (and remove the letter from the ListBox if it is), and update the stats on the StatusStrip.

    Go back to the form designer and select the form. Then go to the Properties window and click on the lightning bolt button. Scroll to the KeyDown row and double-click on it. This tells the IDE to add a method called Form1_KeyDown() that gets called every time the user presses a key. Here’s the code for the method:

    image with no caption
    image with no caption
  7. Run your game.

    Your game’s done! Give it a shot and see how well you do. You may need to adjust the font size of the ListBox to make sure it holds exactly 7 letters, and you can change the difficulty by adjusting the values that are subtracted from timer1.Interval in the Form1_KeyDown() method.

The best content for your career. Discover unlimited learning on demand for around $1/day.