C# 3.0 Practical Learning I

  • July 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View C# 3.0 Practical Learning I as PDF for free.

More details

  • Words: 185,020
  • Pages: 955
Visual C# 3.0 Application Design

FunctionX Press

C# 3.0 Practical Learning

2

INDEX 1 - INTRODUCTION TO C#.................................................................................15 INTRODUCTION.....................................................................................................15 C# is a Sharp C...........................................................................................15 Console Applications..................................................................................15 WRITING CODE....................................................................................................17 Practical Learning: Creating a Program......................................................17 Comments..................................................................................................17 Practical Learning: Creating Comments......................................................17 Code Colors................................................................................................18 Indentation ...............................................................................................19 SOLUTION AND PROJECT MANAGEMENT..........................................................................19 A Project ...................................................................................................19 Saving a Project ........................................................................................20 A Solution...................................................................................................20 Executing a Project....................................................................................22 Practical Learning: Executing an Application..............................................23 Adding a Project ........................................................................................23 2 - INTRODUCTION TO VARIABLES...................................................................26 VARIABLES..........................................................................................................26 Practical Learning: Introducing Variables..................................................26 Names in C#...............................................................................................26 Values and Variables on the Console..........................................................28 THE NUMERIC SYSTEMS...........................................................................................28 The Binary System.....................................................................................29 The Decimal System...................................................................................29 The Hexadecimal System...........................................................................30 Signed and Unsigned..................................................................................31 Data Types.................................................................................................31 REPRESENTING NUMBERS.........................................................................................33 A Bit...........................................................................................................33 The Four-Bit Combination...........................................................................33 A BYTE.............................................................................................................36 Characters..................................................................................................38 Escape Sequences......................................................................................38 The Byte Data Type....................................................................................39 Practical Learning: Using Bytes..................................................................41 Signed Byte................................................................................................42 A WORD...........................................................................................................42 Short Integers............................................................................................43 Unsigned Short Integers............................................................................44 Practical Learning: Using Unsigned Short Integers....................................45 3 – USING VARIABLES......................................................................................47 A DOUBLE-WORD.................................................................................................47 Practical Learning: Using Unsigned Integers..............................................49 Signed Integers..........................................................................................50 Unsigned Integers......................................................................................51 Practical Learning: Using Unsigned Integers..............................................52 A QUAD-WORD...................................................................................................53 Long Integers.............................................................................................54 Unsigned Long Integers.............................................................................56 REAL NUMBERS....................................................................................................56 Floating-Point Numbers.............................................................................57 Double-Precision Numbers.........................................................................57 Practical Learning: Using a Double-Precision Variable...............................59 Decimal......................................................................................................60

C# 3.0 Practical Learning

3

Practical Learning: Using Decimal Values...................................................63 ACCESSORY DATA TYPES..........................................................................................64 Strings.......................................................................................................64 Practical Learning: Using Strings...............................................................65 Dates and Times.........................................................................................67 Objects.......................................................................................................67 CONSTANTS.........................................................................................................69 Custom Constants......................................................................................69 Built-in Constants.......................................................................................71 4 - INTRODUCTION TO CLASSES.......................................................................73 FUNDAMENTALS OF CLASSES......................................................................................73 Practical Learning: Introducing Classes.....................................................73 Creating a Class.........................................................................................73 Practical Learning: Introducing Classes.....................................................75 Visually Managing Classes..........................................................................75 Declaring a Variable of a Class Type...........................................................76 Sharing a Class...........................................................................................78 Garbage Collection.....................................................................................78 CLASS' FIELDS.....................................................................................................79 Practical Learning: Introducing Class Members..........................................79 ACCESSING CLASS MEMBERS.....................................................................................81 Private Members........................................................................................81 Internal Members.......................................................................................82 INITIALIZING AN OBJECT..........................................................................................82 Practical Learning: Using a Class' Fields.....................................................84 Using an Anonymous Type.........................................................................85 THE METHODS OF A CLASS.......................................................................................86 The Solution Explorer.................................................................................88 Practical Learning: Creating the Methods of a Class...................................89 Accessing a Method....................................................................................91 THE STATIC MEMBERS OF A CLASS..............................................................................92 Static Fields................................................................................................92 Static Methods...........................................................................................96 Static Classes.............................................................................................97 CHARACTERISTICS OF MEMBERS OF A CLASS....................................................................98 Constants...................................................................................................98 this Instance..............................................................................................98 Practical Learning: Using this.....................................................................99 5 - C# AND CODE ORGANIZATION...................................................................101 NAMESPACES......................................................................................................101 Practical Learning: Creating a Namespacep> ..........................................101 Accessing Members of a Namespace........................................................102 Namespace Nesting..................................................................................103 THE SYSTEM NAMESPACE.......................................................................................104 Using a Namespace..................................................................................105 Practical Learning: Using the Keyword.....................................................105 .NET SUPPORT OF DATA TYPES...............................................................................105 C# LANGUAGE ACCESSORIES...................................................................................106 Command Line Options.............................................................................106 Unsafe Code.............................................................................................107 Code Editor Region Delimiter...................................................................109 6 - DATA READING AND FORMATTING............................................................114 DATA READING..................................................................................................114 Practical Learning: Introducing Data Reading..........................................114 String Value Request ...............................................................................114 Practical Learning: Reading String Values................................................115

C# 3.0 Practical Learning

4

Number Request.......................................................................................116 Practical Learning: Reading Numeric Values............................................117 Requesting Dates and Times....................................................................119 Practical Learning: Requesting Date and Time Values..............................120 FORMATTING DATA DISPLAY....................................................................................123 Practical Learning: Displaying Data With Placeholders.............................124 Conversion To String................................................................................126 Practical Learning: Converting to String...................................................127 Number Formatting..................................................................................127 Practical Learning: Formatting Data Display............................................129 Line Formatting........................................................................................132 Data and Time Formatting........................................................................132 Practical Learning: Controlling Date/Time Formatting.............................133 DETAILS ON THE METHODS OF A CLASS..........................................................136 METHODS AND LOCAL VARIABLES..............................................................................136 Practical Learning: Using a Method's Local Variables...............................136 A Method that Returns a Value ................................................................138 Practical Learning: Returning a Value From a Method .............................139 The Main Method of an Application...........................................................140 METHODS' ARGUMENTS..........................................................................................141 Practical Learning: Passing Arguments....................................................142 TECHNIQUES OF PASSING ARGUMENTS.........................................................................144 Passing an Argument by Value.................................................................144 Passing an Argument by Reference..........................................................144 Practical Learning: Passing Arguments By Reference...............................147 Method Overloading.................................................................................148 Practical Learning: Overloading a Method................................................149 CLASS CONSTRUCTION AND DESTRUCTION.....................................................................153 Method Initializer.....................................................................................153 Default Constructor..................................................................................156 The Constructor Initializer.......................................................................157 Constructor Overloading..........................................................................158 The Destructor of a Class.........................................................................160 COMBINATIONS OF CLASSES..........................................................................162 CLASSES COMBINATIONS........................................................................................162 Class Nesting............................................................................................162 A Class as a Field......................................................................................166 Practical Learning: Using a Class as a Field..............................................167 RETURNING A CLASS OR PASSING A CLASS...................................................................169 Returning a Class From a Method.............................................................169 Passing a Class as Argument....................................................................170 Practical Learning: Return a Class or Passing One as Argument...............173 INVOLVING A CLASS AND ITS OWN METHODS................................................................176 Passing a Class as its Own Argument.......................................................176 Returning a Class From its Own Method...................................................180 INTRODUCTION TO CONDITIONS....................................................................184 BOOLEAN VARIABLES............................................................................................184 Practical Learning: Introducing Boolean Variables...................................184 Declaring a Boolean Variable....................................................................188 Retrieving the Value of a Boolean Variable...............................................190 Creating a Boolean Field...........................................................................190 Boolean Arguments..................................................................................192 ENUMERATIONS...................................................................................................192 Declaring an Enumeration Variable..........................................................194 Initializing an Enumeration Variable........................................................194 Enumerations Visibility............................................................................196

C# 3.0 Practical Learning

5

An Enumeration as a Member Variable.....................................................196 Practical Learning: Creating and Using Enumerations..............................198 LOGICAL OPERATORS............................................................................................202 The Equality Operator ==.........................................................................203 The Logical Not Operator !........................................................................204 The Inequality Operator !=......................................................................205 The Comparison for a Lower Value <........................................................206 Combining Equality and Lower Value <=..................................................207 The Comparison for a Greater Value >.....................................................208 The Greater Than or Equal Operator >=...................................................208 LOGICALLY INCREMENTING OR DECREMENTING A VALUE.....................................................209 Incrementing a Variable...........................................................................209 Pre and Post-Increment...........................................................................211 Decrementing a Value..............................................................................212 Pre Decrementing a Value........................................................................214 Techniques of Incrementing and Decrementing a Variable......................215 CONDITIONAL STATEMENTS...........................................................................218 CONDITION IS TRUE.......................................................................................218 Practical Learning: Introducing Conditional Expressions..........................218 if..............................................................................................................219 Practical Learning: Using the Simple if Condition.....................................224 if…else.....................................................................................................226 Practical Learning: Using the if...else Condition.......................................228 LOGICAL CONJUNCTION: AND.................................................................................231 Combining Conjunctions...........................................................................238 LOGICAL DISJUNCTION: OR....................................................................................241 Combinations of Disjunctions...................................................................245 IF A

CONDITIONAL SWITCHES...............................................................................246 SWITCHES.....................................................................................................246 The Ternary Operator (?:)........................................................................246 Practical Learning: Introducing Conditional Switches..............................247 if…else if and if…else if…else...................................................................248 CASE SWITCHES..................................................................................................251 Practical Learning: Using Conditional Switches........................................256 Combining Cases......................................................................................260 Using Enumerations.................................................................................262 IF

COUNTING AND LOOPING...............................................................................264 CONDITIONAL LOOPING.........................................................................................264 while a Condition is True..........................................................................264 do This while a Condition is True..............................................................265 Practical Learning: Introducing Counting and Looping.............................267 for............................................................................................................273 CONTROLLING THE CONDITIONAL STATEMENTS................................................................274 Nesting a Conditional Statement..............................................................274 Practical Learning: Nesting Conditions.....................................................276 Breaking the Flow of a Conditional Statement..........................................281 Continuing a Conditional Statement.........................................................282 Going to a Designated Label.....................................................................283 Conditional Return...................................................................................283 RECURSION.......................................................................................................285 Creating a Recursive Methods..................................................................286 Using Recursive Methods.........................................................................287 THE PROPERTIES OF A CLASS.........................................................................289 OVERVIEW OF PROPERTIES......................................................................................289 Accessories for Properties........................................................................289 Practical Learning: Introducing Properties...............................................290

C# 3.0 Practical Learning

6

TYPES OF PROPERTIES...........................................................................................291 Property Readers.....................................................................................291 Practical Learning: Creating Property Readers.........................................294 Property Writers......................................................................................297 Read/Write Properties.............................................................................299 Practical Learning: Creating Property Writers..........................................299 A Boolean Property..................................................................................302 PROPERTIES OF EXTERNAL CLASSES............................................................................303 Properties and Enumerations...................................................................303 Practical Learning: Creating an Enumeration Property.............................303 A Class as a Property................................................................................306 Practical Learning: Creating a Property of a Class Type...........................307 INHERITANCE.................................................................................................313 INTRODUCTION TO INHERITANCE...............................................................................313 Practical Learning: Introducing Inheritance.............................................313 Class Derivation.......................................................................................319 Practical Learning: Inheriting...................................................................324 Implementation of Derived Members ......................................................330 The new Modifier......................................................................................334 POLYMORPHISM AND ABSTRACTION..............................................................336 CHARACTERISTICS OF INHERITANCE............................................................................336 Namespaces and Inheritance...................................................................336 Practical Learning: Using Inheritance With Namespaces..........................338 Protected Members..................................................................................339 Virtual Members.......................................................................................341 Practical Learning: Using Virtual Members...............................................342 Abstract Classes.......................................................................................345 Practical Learning: Creating an Abstract Class.........................................345 Abstract Properties and Methods.............................................................346 Practical Learning: Creating an Abstract Property....................................346 Sealed Classes..........................................................................................349 INTERFACES.......................................................................................................350 Practical Learning: Introducing Interfaces...............................................350 The Members of an Interface...................................................................350 Practical Learning: Creating Members of an Interface..............................351 AN INTERFACE AS A BASE CLASS..............................................................................352 Practical Learning: Inheriting From an Interface.....................................352 Implementation of Derived Classes of an Interface..................................353 Practical Learning: Implementing Derived Members of an Interface........356 Class Partial Implementation...................................................................360 Practical Learning: Partially Implementing a Class..................................365 DELEGATES AND EVENTS.................................................................................371 FUNDAMENTALS OF DELEGATES.................................................................................371 Practical Learning: Introducing Delegates...............................................371 Creating a Delegate..................................................................................376 ACCESSING A DELEGATE.........................................................................................377 A Static Method for a Delegate.................................................................378 An Anonymous Delegate..........................................................................379 The Lambda Operator...............................................................................380 A Delegate that Returns a Value...............................................................381 Delegates Compositions...........................................................................382 DELEGATES AND ARGUMENTS...................................................................................382 Using an Argumentative Delegate............................................................383 A Lambda Expression...............................................................................384 A Delegate With Many Arguments............................................................386 Practical Learning: Passing Arguments to a Delegate..............................387

C# 3.0 Practical Learning

7

A Delegate Passed as Argument...............................................................391 DELEGATES AND CLASSES.......................................................................................394 A Delegate that Returns an Object...........................................................395 A Delegate that Takes an Object as Argument.........................................397 EVENTS............................................................................................................398 Event Creation..........................................................................................399 STRUCTURES...................................................................................................402 FUNDAMENTALS OF STRUCTURES................................................................................402 Structure Declaration...............................................................................403 TECHNIQUES OF USING STRUCTURES...........................................................................404 A Structure as a Property.........................................................................404 Returning a Structure From a Method......................................................406 Passing a Structure as Argument.............................................................407 BUILT-IN STRUCTURES: THE INTEGRAL DATA TYPES.......................................................411 Conversion to a String..............................................................................411 Parsing a String........................................................................................411 The Minimum and Maximum Values of a Primitive Type...........................414 Value Comparisons...................................................................................417 BUILT-IN STRUCTURES: THE BOOLEAN TYPE.................................................................420 Parsing a Boolean Variable.......................................................................420 Comparisons of Boolean Variables...........................................................422 FLOATING-POINT NUMBERS....................................................................................424 Operations on Floating-Point Numbers.....................................................425 Comparison Operations............................................................................426 BUILT-IN CLASSES..........................................................................................428 THE OBJECT CLASS..............................................................................................428 Practical Learning: Introducing Ancestor Classes.....................................428 Equality of Two Class Variables................................................................430 Practical Learning: Implementing Equality...............................................431 Stringing a Class......................................................................................432 Practical Learning: Converting to String...................................................433 Boxing and Un-Boxing..............................................................................435 Finalizing a Variable.................................................................................437 Other Built-In Classes..............................................................................437 RANDOM NUMBERS...............................................................................................437 Getting a Random Number.......................................................................437 The Seed of a Random Number................................................................439 Generating Random Numbers in a Range of Numbers..............................440 BUILT-IN ASSEMBLIES AND LIBRARIES........................................................................442 Microsoft Visual Basic Functions..............................................................442 C# CUSTOM LIBRARIES.........................................................................................443 Creating a Library.....................................................................................443 Practical Learning: Creating a Library......................................................444 A LIBRARY CREATED IN ANOTHER LANGUAGE................................................................447 Using a Visual C++/CLI Library................................................................447 Creating a Library.....................................................................................447 Using the Library......................................................................................448 Using the Win32 Library...........................................................................449 INTRODUCTION TO EXCEPTION HANDLING....................................................450 INTRODUCTION TO EXCEPTIONS.................................................................................450 Overview..................................................................................................450 Practical Learning: Introducing Exception Handling.................................451 Exceptional Behaviors..............................................................................454 Practical Learning: Introducing Vague Exceptions...................................456 Exceptions and Custom Messages............................................................457 Practical Learning: Displaying Custom Messages.....................................458

C# 3.0 Practical Learning

8

EXCEPTIONS IN THE .NET FRAMEWORK.......................................................................460 The Exception Class..................................................................................460 The Exception's Message..........................................................................461 Custom Error Messages............................................................................462 A REVIEW OF .NET EXCEPTION CLASSES....................................................................463 The FormatException Exception...............................................................464 Practical Learning: Using the FormatException Class...............................465 The OverflowException Exception............................................................469 The ArgumentOutOfRangeException Exception........................................469 The DivideByZeroException Exception......................................................470 USING EXCEPTION HANDLING........................................................................472 TECHNIQUES OF USING EXCEPTIONS...........................................................................472 Practical Learning: Using Exceptions........................................................472 Throwing an Exception.............................................................................481 Practical Learning: Throwing an Exception...............................................482 Catching Various Exceptions....................................................................485 Practical Learning: Catching Various Exceptions......................................488 Exception Nesting....................................................................................495 Exceptions and Methods...........................................................................497 CUSTOM EXCEPTIONS............................................................................................502 Creating an Exceptional Class..................................................................502 INTRODUCTION TO ARRAYS............................................................................506 A SERIES OF SIMILAR ITEMS..................................................................................506 Practical Learning: Introducing Arrays.....................................................507 Array Creation..........................................................................................507 Practical Learning: Creating an Array.......................................................508 Introduction to Initializing an Array.........................................................508 Practical Learning: Initializing Some Arrays.............................................510 Other Techniques of Initializing an Array.................................................511 ACCESSING THE MEMBERS OF AN ARRAY......................................................................513 Practical Learning: Using the Members of an Array..................................514 For an Indexed Member of the Array........................................................515 Practical Learning: Using a for Loop.........................................................518 For Each Member in the Array..................................................................520 ANONYMOUS ARRAYS............................................................................................521 Creating an Anonymous Array..................................................................521 Accessing the Members of an Anonymous Array......................................523 SELECTING A VALUE FROM AN ARRAY.........................................................................525 Using for and foreach...............................................................................525 Practical Learning: Checking a Value From an Array................................526 ARRAYS AND CLASSES....................................................................................529 AN ARRAY OF A PRIMITIVE TYPE AS A FIELD................................................................529 Practical Learning: Introducing Arrays and Classes.................................530 Presenting the Array................................................................................531 Practical Learning: Presenting an Array...................................................532 ARRAYS AND METHODS..........................................................................................533 An Array Passed as Argument..................................................................534 Returning an Array From a Method..........................................................536 MAIN()'S ARGUMENT...........................................................................................538 Command Request from Main()................................................................539 AN ARRAY OF OBJECTS.........................................................................................541 Practical Learning: Introducing Arrays of Objects....................................542 Creating an Array of Objects....................................................................543 Initializing an Array of Objects.................................................................544 Accessing the Members of the Array........................................................546 Practical Learning: Using an Array of Objects..........................................548

C# 3.0 Practical Learning

9

A CLASS ARRAY AS A FIELD...................................................................................550 Using the Array........................................................................................551 ARRAYS OF OBJECTS AND METHODS...........................................................................554 Passing an Array of Objects as Argument.................................................554 Returning an Array of Objects..................................................................555 Practical Learning: Using Array of Objects With Methods.........................557 ARRAYS AND DELEGATES........................................................................................559 An Array of Delegates..............................................................................560 MULTIDIMENSIONAL ARRAYS.........................................................................562 FUNDAMENTALS OF MULTIDIMENSIONAL ARRAYS.............................................................562 Practical Learning: Introducing Multidimensional Arrays.........................562 Creating a Two-Dimensional Array...........................................................563 Practical Learning: Creating a Two-Dimensional Array.............................565 Accessing the Members of a Two-Dimensional Array...............................566 Practical Learning: Accessing the Members..............................................569 MULTIDIMENSIONAL ARRAYS....................................................................................571 Creating a Multidimensional Array...........................................................571 Initializing a Multidimensional Array........................................................572 Access to Members of a Multidimensional Array.......................................572 MULTIDIMENSIONAL ARRAYS AND CLASSES...................................................................577 A Multidimensional Array as Argument....................................................579 Returning a Multi-Dimensional Array.......................................................580 A MULTIDIMENSIONAL ARRAY OF OBJECTS...................................................................582 A Variable of a Multidimensional Array of Objects....................................582 Accessing the Members of a Multidimensional Array of Objects...............585 MULTIDIMENSIONAL ARRAYS OF OBJECTS AND CLASSES.....................................................586 Passing a Multidimensional Array of Objects............................................588 Returning a Multidimensional Array of Objects........................................589 INTRODUCTION TO JAGGED ARRAYS............................................................................591 Practical Learning: Introducing Jagged Arrays.........................................591 Initialization of a Jagged Array................................................................592 Practical Learning: Initializing a Jagged Array.........................................593 Access to Members of a Jagged Array......................................................595 Practical Learning: Using a Jagged Array.................................................597 THE ARRAY CLASS...........................................................................................601 INTRODUCTION TO THE ARRAY CLASS..........................................................................601 Overview..................................................................................................601 The Length of an Array.............................................................................602 The Rank of an Array................................................................................603 FUNDAMENTAL OPERATIONS ON AN ARRAY....................................................................603 Adding Items to an Array.........................................................................603 Accessing the Members of an Array..........................................................604 MULTIDIMENSIONAL ARRAYS....................................................................................605 Two-Dimensional Arrays..........................................................................606 Three-Dimensional Arrays........................................................................608 Multidimensional Arrays...........................................................................613 ARRANGING THE LIST...........................................................................................614 Arranging the Items in Alphabetical or Numerical Order..........................614 Reversing the Arrangement.....................................................................615 LOCATING AN ELEMENT IN AN ARRAY..........................................................................615 Locating the Index of an Element.............................................................615 The Bounds of an Array............................................................................616 STRINGS.........................................................................................................618 THE CHARACTERS OF A STRING................................................................................618 Practical Learning: Introducing Strings....................................................619 The String: An Array of Characters ..........................................................628

C# 3.0 Practical Learning

10

Converting Characters to the Opposite Case............................................629 Replacing a Character..............................................................................631 WORKING WITH STRINGS......................................................................................632 The Length of a String..............................................................................632 Practical Learning: Using Characters of a String......................................633 Replacing a Sub-String.............................................................................637 Formatting a String..................................................................................637 Copying a String.......................................................................................638 OPERATIONS ON STRINGS.......................................................................................639 String Concatenation................................................................................639 STRINGS COMPARISONS.........................................................................................641 String Equality..........................................................................................642 WORKING WITH SUB-STRINGS................................................................................643 Sub-String Creation..................................................................................643 INTRODUCTION TO INDEXERS........................................................................644 A PROPERTY CAN BE INDEXED................................................................................644 Practical Learning: Introducing Indexed Properties.................................645 An Indexer...............................................................................................649 Indexed Properties of Other Primitive Types............................................650 Using a Non-Integer-Based Index............................................................652 Practical Learning: Creating an Indexer...................................................655 TOPICS ON INDEXED PROPERTIES..............................................................................657 Multi-Parameterized Indexed Properties..................................................657 Overloading an Indexed Property.............................................................661 READ/WRITE INDEXED PROPERTIES..........................................................................664 A Read/Write Property of a Primitive Type..............................................665 CLASSES AND INDEXERS.................................................................................668 FUNDAMENTALS OF INDEXED PROPERTIES AND CLASSES.....................................................668 Practical Learning: Introducing Indexers and Classes..............................668 An Integer-Based Indexed Property.........................................................672 Practical Learning: Using an Integer-Based Indexer................................675 An Indexed Property Using Another Primitive Type.................................676 TOPICS ON INDEXED PROPERTIES AND CLASSES..............................................................680 A Class as Index.......................................................................................680 Overloading a Class-Based Indexed Property...........................................684 Practical Learning: Overloading an Indexer.............................................693 Read/Write Indexed Properties...............................................................694 INTRODUCTION TO COLLECTIONS..................................................................697 ARRAY-BASED LISTS............................................................................................697 Setting Up a Collection.............................................................................697 The Number of Items in a Collection........................................................698 ROUTINE OPERATIONS ON AN ARRAY-BASED LIST...........................................................700 Adding an Item........................................................................................700 Getting an Item From a List.....................................................................701 Inserting an Item in the List....................................................................703 Removing an Item From the List..............................................................706 A COLLECTION OF ITEMS........................................................................................709 Practical Learning: Introducing Collections..............................................709 Implementing a Collection.......................................................................716 Practical Learning: Creating a Class Collection.........................................718 The Beginning of a Collection...................................................................718 Linking the Items of a Collection..............................................................719 Practical Learning: Creating a List's Monitor............................................720 OPERATIONS ON A COLLECTION.................................................................................721 Adding an Item........................................................................................721 Practical Learning: Adding Items to a Collection......................................722

C# 3.0 Practical Learning

11

Retrieving an Item...................................................................................723 Practical Learning: Retrieving the Items of a Collection...........................724 Removing an Item....................................................................................727 Practical Learning: Retrieving the Items of a Collection...........................728 Locating an Item......................................................................................732 ITERATING THROUGH A COLLECTION.............................................................736 ENUMERATING THE MEMBERS OF A COLLECTION..............................................................736 Introduction to System Collections..........................................................736 Practical Learning: Introducing Built-In Collections.................................736 Introduction to the IEnumerator Interface..............................................739 Practical Learning: Introducing Enumerations.........................................740 The Current Item of an Enumeration........................................................741 Practical Learning: Getting to the Current Item.......................................741 Resetting the Tag of the Current Item......................................................742 Practical Learning: Resetting the Tag of the Current Item.......................743 Moving to the Next Item in the Enumerator.............................................744 Practical Learning: Moving to the Next Item in the Enumerator...............745 AN ENUMERABLE COLLECTION..................................................................................746 Getting the Enumerator............................................................................746 Practical Learning: Getting the Enumerator.............................................747 Using foreach...........................................................................................748 Practical Learning: Using foreach on an Enumerator................................750 INTRODUCTION TO BUILT-IN COLLECTION CLASSES......................................753 OVERVIEW OF .NET COLLECTIONS............................................................................753 The ICollection Interface..........................................................................753 Introduction to the ArrayList Class...........................................................753 Practical Learning: Introducing the ArrayList Class..................................753 The Capacity of a List...............................................................................757 A Read-Only List.......................................................................................758 Item Addition...........................................................................................758 Practical Learning: Adding Items to an ArrayList List...............................759 The Number of Items in the List...............................................................771 Item Retrieval..........................................................................................771 Practical Learning: Retrieving Items From an ArrayList List.....................772 Item Location...........................................................................................794 Item Deletion...........................................................................................795 GENERICS.......................................................................................................796 GENERIC METHODS..............................................................................................796 Practical Learning: Introducing Generics.................................................797 Generic Method Creation..........................................................................800 Practical Learning: Creating a Generic Method.........................................800 Calling a Generic Method..........................................................................801 Practical Learning: Calling a Generic Method............................................802 A GENERIC METHOD WITH VARIOUS PARAMETERS..........................................................803 Practical Learning: Using a Method With Various Parameters..................804 A Generic Method With Various Parameter Types.....................................805 Calling a Generic Method With Various Parameter Types.........................806 GENERIC CLASSES...............................................................................................807 Practical Learning: Introducing Generic Classes......................................808 Using a Generic Class...............................................................................810 Passing a Parameter Type to a Method.....................................................812 Returning a Parameter Type.....................................................................812 Practical Learning: Returning a Parameter Type......................................813 A Property of the Parameter Type............................................................815 A GENERIC CLASS WITH MULTIPLE PARAMETERS...........................................................816 Using Multiple Type Parameters...............................................................816

C# 3.0 Practical Learning

12

A Class as a Parameter Type....................................................................818 GENERIC CLASSES AND INHERITANCE..........................................................................820 Generic Classes and Interfaces................................................................825 Constraining a Generic Class....................................................................826 INTRODUCTION TO FILE PROCESSING............................................................831 OVERVIEW OF FILE PROCESSING AND DEFINITIONS..........................................................831 Files.........................................................................................................831 Streams....................................................................................................831 STREAMING PREREQUISITES.....................................................................................832 Practical Learning: Introducing Streaming...............................................832 The Name of a File....................................................................................838 Practical Learning: Specifying the Name of a File.....................................839 The Path to a File.....................................................................................840 THE .NET SUPPORT FOR FILES...............................................................................842 File Existence...........................................................................................842 Practical Learning: Checking the Existence of a File.................................842 File Creation.............................................................................................844 Access to a File.........................................................................................845 File Sharing..............................................................................................845 The Mode of a File....................................................................................845 FUNDAMENTALS OF FILE STREAMING...........................................................................846 Practical Learning: Creating a Stream......................................................847 Stream Writing.........................................................................................848 Stream Closing.........................................................................................849 Practical Learning: Writing to a Stream....................................................849 Stream Reading........................................................................................852 Practical Learning: Reading From a Stream..............................................854 DETAILS ON FILE PROCESSING.......................................................................864 EXCEPTION HANDLING IN FILE PROCESSING..................................................................864 Finally......................................................................................................864 Practical Learning: Finally Releasing Resources.......................................866 .NET Framework Exception Handling for File Processing..........................876 Practical Learning: Handling File Processing Exceptions..........................878 FILE INFORMATION..............................................................................................886 Practical Learning: Introducing File Information......................................886 File Initialization......................................................................................889 File Creation.............................................................................................889 File Existence...........................................................................................890 Writing to a File........................................................................................891 Practical Learning: Writing to a File.........................................................891 Appending to a File...................................................................................892 Practical Learning: Appending to a File....................................................892 FILES OPERATIONS.........................................................................................895 ROUTINE OPERATIONS ON FILES...............................................................................895 Opening a File..........................................................................................895 Deleting a File..........................................................................................895 Copying a File...........................................................................................895 Moving a File............................................................................................896 CHARACTERISTICS OF A FILE....................................................................................897 The Date and Time a File Was Created ....................................................897 The Date and Time a File Was Last Accessed ...........................................898 The Name of a File....................................................................................898 The Extension of a File.............................................................................898 The Size of a File......................................................................................899 The Path to a File.....................................................................................900 The Attributes of a File.............................................................................900

C# 3.0 Practical Learning

13

DIRECTORIES.....................................................................................................900 Practical Learning: Introducing Directories..............................................901 Directory Creation....................................................................................902 Checking for a Directory Existence...........................................................903 Locating a File..........................................................................................903 Practical Learning: Using Directories and Files.........................................903 SERIALIZATION..............................................................................................916 OBJECT SERIALIZATION AND DE-SERIALIZATION.............................................................916 Practical Learning: Introducing Serialization...........................................919 Serialization.............................................................................................922 Practical Learning: Serializing an Object..................................................924 De-Serialization........................................................................................936 Practical Learning: De-Serializing an Object.............................................938 SOAP SERIALIZATION.........................................................................................941 Practical Learning: Introducing SOAP Serialization..................................941 Serialization With SOAP...........................................................................943 Practical Learning: Serializing With SOAP................................................945 De-Serialization With SOAP......................................................................947 Practical Learning: Deserializing With SOAP............................................948 DETAILS ON SERIALIZATION....................................................................................951 Partial Serialization..................................................................................951 Implementing a Custom Serialized Class..................................................954 .NET Built-In Serialized Classes................................................................954

C# 3.0 Practical Learning

14

1 - Introduction to C# Introduction C# is a Sharp C C#, pronounced c sharp, is a computer language used to give instructions that tell the computer what to do, how to do it, and when to do it. This is a universal language that is used on many operating systems, including Microsoft Windows. C# is one of the languages used in the Microsoft .NET Framework. The Microsoft .NET Framework is a library of objects that create or draw things on the computer.

Console Applications The C# language is used to create applications that display on a black window referred to as the DOS prompt or DOS window. Those are the types of applications we will create in our lessons. To study the C# language, we will use Microsoft Visual C# 2008 Express Edition or Microsoft Visual C# 2008 Professional. To get Microsoft Visual C# 2008 Express Edition, you can download it free from the Microsoft web site. After downloading it, you can install it. To launch Microsoft Visual C# 2008 Express Edition, you can click Start -> (All) Programs -> Microsoft Visual C# 2008 Expression Edition:

To launch Microsoft Visual C# 2008 Professional, you can click Start -> (All) Programs -> Microsoft Visual Studio 2008. To create the type of applications we will study in our lessons, on the main menu, you can click File -> New Project... In the Templates section of the New Project dialog box, you can click Console Application, accept the default name or change it:

After clicking OK, a skeleton code would be created for you. Right now, we will not review every part of the code. Everything will be introduced and explained as we move on. C# 3.0 Practical Learning

16

Writing Code Introduction The programs we will write are meant to give instructions to the computer about what to do, when to do something, and how to do it. You write these instructions in an easy to understand English format, using words we will study. This means that a regular instruction uses normal text with alphabetic characters, numbers, and non-readable symbols. Normally, you can write your instructions using any text editor such as Notepad, WordPad, WordPerfect, or Microsoft Word, etc. When writing your instructions, there are rules your must follow and suggestions you should observe. We sill study each one of them as we move on. The group of instructions used by your program is also referred to as code. To assist you with writing code, Microsoft Visual C# 2008 includes a text editor referred to as the Code Editor. This is the window that displays when you have just created a console application. Besides the Code Editor, the integrated development interface (IDE) of the Microsoft Visual C# 2008 is made of various parts, which we will review when necessary.

Practical Learning: Creating a Program 1. Start Microsoft Visual C# 2008 Express Edition or Microsoft Visual C# 2008 Professional 2. To create a new application, on the Start Page, on the right side of Create, click Project 3. In the Templates section, click Console Application 4. Change the Name to GeorgetownCleaningServices1 and click OK

Comments A comment is a line or paragraph of text that will not be considered as part of your code of a program. There are two types of comments recognized by C#. To display a comment on a line of text, start the line with two forward slashes //. Anything on the right side of // would be ignored. Here is an example: // This line will be ignored. I can write in it anything I want

The above type of comment is used on only one line. You can also start a comment with /*. This type of comment ends with */. Anything between this combination of /* and */ would not be read. Therefore, you can use this technique to span a comment on more than one line.

Practical Learning: Creating Comments

C# 3.0 Practical Learning

17

1. To create comments, change the file as follows: using System; // using System.Collections.Generic; // using System.Linq; // using System.Text; /* namespace GeorgetownCleaningServices1 {*/ class Program { static void Main(/* string[] args */) { } } //}

2. To save the project, on the Standard toolbar, click the Save All button

3. Accept the name as GeorgetownCleaningServices1 and click Save

Code Colors Code is written in a wide area with a white background. This is the area you use the keyboard to insert code with common readable characters. The Code Editor uses some colors to differentiate categories of words or lines of text. The colors used are highly customizable. To change the colors, on the main menu, you can click Tools -> Options... In the Options dialog box, in the Environment section, click Fonts and Colors. To set the color of a category, in the Display Items section, click the category. In the Item Foreground combo box, select the desired color. If you want the words of the category to have a colored background, click the arrow of the Item Background combo box and select one:

C# 3.0 Practical Learning

18

In both cases, the combo boxes display a fixed list of colors. If you want more colors, you can click a Custom button to display the Color dialog box that allows you to "create" a color.

Indentation Indentation is another feature that makes your program easy to read. Indentation is a technique of grouping lines of code by category. To delimit the items of your code, you should indent them by two empty spaces or one tab. Indentation should be incremental. That is, when a line of code appears to be a child of the previous line, the new line should be indented.

Solution and Project Management A Project We have seen how to create a console application. Microsoft Visual C# allows you to create various other types of applications. This is why you should first display the New Project dialog box to select your option. Besides console applications, in future lessons, we will start some applications with the Empty Project. We will also learn how to create a library using the Class Library option. We will ignore the other three options in this book. To control the indentation of your code, on the main menu, click Tools -> Options... In the left list, expand C#, followed by Formatting and click Indentation. Then change the options on the right side:

C# 3.0 Practical Learning

19

After making the changes, click OK to validate or Cancel to ignore.

Saving a Project In previous versions of Microsoft Visual C# (namely 2002 and 2003), you always had to formally create a project in order to use one and you always had to save it. After realizing that many of the projects that developers or students create are for experimental purposes, Microsoft provided the ability to only temporarily create a project, then to save it or not. Saving a project allows you to keep on a medium so you can refer to it later. When Microsoft Visual Studio 2008 (any edition) is installed, it creates a folder named Visual Studio 2008 in your My Documents folder. The My Documents folder is called your personal drive or your personal directory. Inside of the Visual Studio 2008 folder, it creates a sub-folder named Projects. By default, this is where it would save your projects, each with its own folder. To save a project, on the Standard toolbar, you can click the Save All button . Alternatively, on the main menu, you can click File -> Save All. If the project had already been saved but you want to save it under a different name, on the main menu, you can click File -> Save project name As...

A Solution A solution is used to coordinate the different aspects of an application that is being created. When you create a project, it represents one detail of the application you have in mind. Besides the code you are writing, you may want to add other items. Instead of one project, in the next sections, we will see that a solution can contain more than one project. When creating a project, the solution holds the same name as the project. You can see their names in the Solution Explorer: 20 C# 3.0 Practical Learning

The solution and a project can have different names. While working on a project, to rename the solution, in the Solution Explorer, you can click the first node, which is the name of the solution starting with Solution. Then, in the Properties window, click (Name) and type the name of your choice:

This name is temporary, especially if you have not yet saved the project. If you want to permanently save a solution for later use, there are two techniques you can use. If you start saving a project for the first time, it would bring the Save Project dialog box. By default, Microsoft Visual Studio selects your personal directory as the path to the solution. This is called the location. In the location, Microsoft Visual Studio creates a folder as the solution of the project. The solution must have, or must be stored, in its own folder. As mentioned earlier, Microsoft Visual Studio uses the name of the project as the name of the solution. To rename the solution, you can change the string in the Solution Name text box. Remember that you can enter the name of the project in the Name text box. Here is an example:

C# 3.0 Practical Learning

21

When you save a project (for the first time), by default, Microsoft Visual C# creates a new folder for it in the My Documents\Visual Studio 2008\Projects folder. It uses the name of the solution to name the folder. It creates some files and stores them in that new folder. Then, it creates a sub-folder, using the name of the project, inside of the folder of the solution. Besides the sub-folder with the name as the project, it creates another folder named debug. It also creates another folder named Debug in the sub-folder of the name of the project. In each folder and some other folders, it creates some files that we will not pay attention to for now. If the project had already been saved but you want to change the name of the solution, on the main menu, you can click File -> Save solution-name.sln As... This would bring the Save File As dialog box where you can specify the name of the solution and click Save.

Executing a Project After creating a project and writing code, you may want to see the result. To do this, you must execute the application. This would create an executable that you can use on other computers and that you can distribute to other people. To execute an application, on the main menu, you can click Debug -> Start Without Debugging. Instead of going through the main menu every time, you can add the Start Without Debugging button to a toolbar. To do this, you can right-click any toolbar and click Customize... In the Commands property page of the Customize dialog box, you can click Debug in the Categories click, then drag Start Without Debugging, and drop it on a toolbar. Here is an example:

C# 3.0 Practical Learning

22

After adding the button(s), you can click Close. The next time you want to execute an application, you can just click this button.

Practical Learning: Executing an Application 1. To execute the application, on the main menu, click Debug -> Start Without Debugging 2. After viewing the result in a DOS window, press Enter to close it

Adding a Project One of the most valuable features of Microsoft Visual Studio 2005 is that it allows you to work on more than one project without launching more than one instance of the studio. This means that you can add a project to another project you are working on and treat each as a separate entity.

C# 3.0 Practical Learning

23

Before adding one project to another, you must save, or you must have saved, the current project. To add a project, in the Solution Explorer, you can rightclick the most top node (it starts with Solution) and position the mouse on Add:

If you have a project that was previously saved but you don't want to open a separate instance of Microsoft Visual Studio for it, you can click Existing Project... This would bring the Add Existing Project dialog box that allows you to select a project from a folder. To add a new project, after right-clicking, you can click New Project... If you add a new project, and if you want to keep it for future references, you must save it. To save the new project, you can click the Save All button on the Standard toolbar. After saving the new project, a folder with its name would be created inside of the folder of the solution. On the right side of the name of the solution in Solution, the number of its projects is specified in parentheses, as 1 project, or 2 projects, etc. After adding a project, each would be represented by its own node in the Solution Explorer and in the Class View. Here is an example:

C# 3.0 Practical Learning

24

Also, a sub-folder for each project is created in the folder of the solution:

In the Solution, the name of one of the projects, if there is more than one, is in bold characters. This project is called the StartUp Project. If, on the main menu, you click Debug -> Start Without Debugging, the project in bold characters would be executed. If you want to change the start up project, you can rightclick its node and click Set As StartUp Project.

C# 3.0 Practical Learning

25

2 - INTRODUCTION TO VARIABLES Variables Definition A computer receives information from different applications in various forms. Sometimes a person types it using the keyboard. Sometimes the user clicks the mouse. Sometimes information comes from another, more complicated source. The idea is that the computer spends a great deal of its time with various pieces of information. Information provided to the computer through a program is called datum and the plural is data. Sometimes the word data is used both for singular and plural items.

Data used by the computer comes and goes regularly as this information changes. For this reason, such information is called a variable. When the user enters data in a program, the computer receives it and must store it somewhere to eventually make it available to the program as needed. For a program used to process employment applications, the types of information a user would enter into the program are the name, the residence, the desired salary, years of experience, education level, etc. Because there can be so much information for the same program, you must specify to the computer what information you are referring to and when. To do this, each category of piece of information must have a name.

Practical Learning: Introducing Variables 1. Start Microsoft Visual C# 2008 Express Edition or Microsoft Visual C# 2008 Professional From now on, we will only refer to Microsoft Visual C# 2. To create a new application, on the Start Page, on the right side of Create, click Project 3. In the Templates section, click Console Application 4. Change the Name to GeorgetownCleaningServices2 and click OK

Names in C# C# 3.0 Practical Learning

26

To name the variables of your program, you must follow strict rules. In fact, everything else in your program must have a name. C# uses a series of words, called keywords, for its internal use. This means that you must avoid naming your objects using one of these keywords. They are: abstract const

extern

int

out

short

typeof uint

as

continue false

interface

override

sizeof

base

decimal

finally

internal

params

stackalloc ulong

bool

default

fixed

is

private

static

break

delegate float

lock

protected string

unsafe

byte

do

for

long

public

struct

ushort

case

double

foreach

namespace

readonly

switch

using

catch

else

goto

new

ref

this

virtual

char

enum

if

null

return

throw

void

implicit

object

sbyte

true

volatile

in

operator

sealed

try

while

checked event class

explicit

unchecked

Besides these keywords, C# has other words that should be reserved only depending on how and where they are used. These are referred to as contextual keywords and they are: get

partial

set

value

where

yield

Once you avoid these words, there are rules you must follow when naming your objects. On this site, here are the rules we will follow: •

The name must start with a letter or an underscore



After the first letter or underscore, the name can have letters, digits, and/or underscores



The name must not have any special characters other than the underscore C# 3.0 Practical Learning

27



The name cannot have a space

Besides these rules, you can also create your own but that abide by the above. C# is case-sensitive. This means that the names Case, case, and CASE are completely different. For example, main is always written Main.

Values and Variables on the Console As mentioned already, the applications we will create display in a dark object called the DOS window. Here is an example showing some values:

To display a value in this window, you can enter it in the parentheses of the Console.Write() or Console.WriteLine(). Here are two examples: using System; class Program { static void Main() { Console.WriteLine(248); Console.Write(1); } }

If you write Console.WriteLine() with empty parentheses, an empty line would be displayed. In future lessons, we will learn what the meanings of Console, Write(), and WriteLine().

The Numeric Systems Introduction When a computer boots, it “loads” the operating system. If you want to use a program, you must find it either on the Start menu or from its directory and take the necessary action to open it. Such a program uses numbers, characters, meaningful words, pictures, graphics, etc, that are part of the program. As these things are numerous, so is the size of the program, and so is C# 3.0 Practical Learning

28

the length of time needed to come up. Your job as a programmer is to create such programs and make them available to the computer, then to people who want to interact with the machine. To write your programs, you will be using alphabetic letters that are a, b, c, d, e, f, g, h, I, j, k, l, m, n, o, p, q, r, s, t, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z. You will also use numeric symbols 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Additionally, you will use characters that are not easily readable but are part of the common language; they are ` ~ ! @ # $ % ^ & * ( ) _ + - = : “ < > ; ‘ , . /. Some of these symbols are used in the C# language while some others are not. When creating your programs, you will be combining letters and/or symbols to create English words or language instructions. Some of the instructions you will give to the computer could consist of counting the number of oranges, converting water to soup, or making sure that a date occurs after January 15. After typing an instruction, the compiler would translate it to machine language. The computer represents any of your instructions as a group of numbers. Even if you ask the computer to use an orange, it would translate it into a set of numbers. As you give more instructions or create more words, the computer stores them in its memory using a certain amount of space for each instruction or each item you use. There are three numeric systems that will be involved in your programs, with or without your intervention.

The Binary System When dealing with assignments, the computer considers a piece of information to be true or to be false. To evaluate such a piece, it uses two symbols: 0 and 1. When a piece of information is true, the computer gives it a value of 1; otherwise, its value is 0. Therefore, the system that the computer recognizes and uses is made of two symbols: 0 and 1. As the information in your computer is greater than a simple piece, the computer combines 0s and 1s to produce all sorts of numbers. Examples of such numbers are 1, 100, 1011, or 1101111011. Therefore, because this technique uses only two symbols, it is called the binary system. When reading a binary number such as 1101, you should not pronounce "One Thousand One Hundred And 1", because such a reading is not accurate. Instead, you should pronounce 1 as One and 0 as zero or o. 1101 should be pronounced One One Zero One, or One One o One. The sequence of the symbols of the binary system depends on the number that needs to be represented.

The Decimal System The numeric system that we are familiar with uses ten symbols that are 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9. Each of these symbols is called a digit. Using a combination of these digits, you can display numeric values of any kind, such as 240, 3826 or 234523. This system of representing numeric values is called the decimal system because it is based on 10 digits. C# 3.0 Practical Learning

29

When a number starts with 0, a calculator or a computer ignores the 0. Consequently, 0248 is the same as 248; 030426 is the same as 30426. From now on, we will represent a numeric value in the decimal system without starting with 0: this will reduce, if not eliminate, any confusion. Decimal Values: 3849, 279, 917293, 39473 Non- Decimal Values: 0237, 0276382, k2783, R3273 The decimal system is said to use a base 10. This allows you to recognize and be able to read any number. The system works in increments of 0, 10, 100, 1000, 10000, and up. In the decimal system, 0 is 0*100 (= 0*1, which is 0); 1 is 1*100 (=1*1, which is 1); 2 is 2*100 (=2*1, which is 2), and 9 is 9*100 (= 9*1, which is 9). Between 10 and 99, a number is represented by left-digit * 10 1 + right-digit * 100. For example, 32 = 3*101 + 2*100 = 3*10 + 2*1 = 30 + 2 = 32. In the same way, 85 = 8*101 + 5*100 = 8*10 + 5*1 = 80 + 5 = 85. Using the same logic, you can get any number in the decimal system. Examples are: 2751 = 2*103 + 7*102 + 5*101 + 1*100 = 2*1000 + 7*100 + 5*10 + 1 = 2000 + 700 + 50 + 1 = 2751 67048 = 6*104 + 7*103 + 0*102 + 4*101 + 8*100 = 6*10000 + 7*1000+0*100+4*10+8*1 = 67048 Another way you can represent this is by using the following table:

etc

Add 0 to the preceding 100000 10000 1000 1000 100 10 0 value 0 0 0

When these numbers get large, they become difficult to read; an example is 279174394327. To make this easier to read, you can separate each thousand fraction with a comma. Our number would become 279,174,394,327. You can do this only on paper, never in a program: the compiler would not understand the comma(s).

The Hexadecimal System While the decimal system uses 10 digits (they are all numeric), the hexadecimal system uses sixteen (16) symbols to represent a number. Since the family of Latin languages consists of only 10 digits, we cannot make up new ones. To compensate for this, the hexadecimal system uses alphabetic characters. After counting from 0 to 9, the system uses letters until it gets 16 different values. The letters used are a, b, c, d, e, and f, or their uppercase equivalents A, B, C, D, E, and F. The hexadecimal system counts as follows: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f; or 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F. To produce a hexadecimal number, you use a combination of these sixteen symbols. Examples of hexadecimal numbers are 293, 0, df, a37, c23b34, or ffed54. At first glance, the decimal representation of 8024 and the hexadecimal representation of 8024 are the same. Also, when you see fed, is it a name of a federal agency or a hexadecimal number? Does CAB represent a taxi, a social organization, or a hexadecimal number? C# 3.0 Practical Learning

30

From now on, to express the difference between a decimal number and a hexadecimal one, each hexadecimal number will start with 0x or 0X. The number will be followed by a valid hexadecimal combination. The letter can be in uppercase or lowercase. Legal Hexadecimals: 0x273, 0xfeaa, 0Xfe3, 0x35FD, 0x32F4e Non-Hex Numbers: 0686, ffekj, 87fe6y, 312 There is also the octal system but we will not use it anywhere in our applications.

Signed and Unsigned The numbers we have used so far were counting from 0, then 1, then 2, and up to any number desired, in incrementing values. Such a number that increments from 0, 1, 2, and up is qualified as positive. By convention, you do not need to let the computer or someone else know that such a number is positive: by just displaying or saying it, the number is considered positive. This is the basis of our counting items. In real life, there are numbers counted in decrement values. Such numbers start at –1 and move down to -2, -3, -4 etc. These numbers are qualified as negative. When you write a number “normally”, such as 42, 502, or 1250, the number is positive. If you want to express the number as negative, you use the – on the left side of the number. The – symbol is called a sign. Therefore, if the number does not have the – symbol, C++ (or the compiler) considers such a number as unsigned. In C++, if you declare a variable that would represent a numeric value and you do not initialize (assign a value to) such a variable, the compiler will consider that the variable can hold either a signed or an unsigned value. If you want to let the compiler know that the variable should hold only a positive value, you will declare such a variable as unsigned.

Data Types In order to use a variable in your program, the compiler must be aware of it. Once the compiler knows about a variable, it would reserve an amount of memory space for that variable

Using its name, you can refer to a particular variable when necessary. Because there are various types of variables a program can use, such as the employee's name, his home address, the desired salary, years of experience, education level, etc for our employment application analogy, the compiler needs a second piece of information for each variable you intend to use. This piece of information specifies the amount of space that a variable needs. You can see that, to store a character, such as an employee's gender (M or F) or an answer as Y or N to a question, the compiler would certainly not need the same amount of space to store the name of the last school attended by an employee. 31 C# 3.0 Practical Learning

A data type is an amount of space needed to store the information related to a particular variable. The name of a variable allows you and the compiler to refer to a particular category of information in your program. The data type allows the compiler to reserve an adequate amount of memory space for a variable. Because you are the one who writes a program, you also tell the compiler the amount of memory space each particular variable will need. Based on this, the C# language provides categories of data types used to specify this amount of space needed for a variable. As stated already, before using a variable, you must communicate your intentions to the compiler. Making the compiler aware is referred to as declaring the variable. To declare a variable, you have two options: •

If you know the type of variable you want to use, you can provide it followed by the name of the variable. Based on this, one syntax used to declare a variable is: DataType VariableName;



As an alternative, you can provide only a name for the variable but let the compiler specify its data type. To declare such a variable, you use the var keyword followed by the name of the variable. This certainly would not be enough. For the compiler to know how much space is necessary, you must provide a value for the variable

Providing a value for a variable is referred to as initializing it. This can be done for declared with either a data type or the var keyword: •

If you declare a variable using data type, the initialization could be optional (depending on how you will access the variable)



If you declare a variable using the var keyword, you must initialize it

To initialize a variable, on the right side of its name, type the assignment operation, which is =, followed by a value: •

If you declare a variable using a data type, you must initialize it with an appropriate value. When we study the data type, we will see what value is appropriate for what data type



If you declare a variable using the var keyword, you can initialize it with almost any type of value (of course there are exceptions). The purpose of using the var keyword is to let the compiler decides what type the variable is. To make this decision, the compiler refers to the type of value the variable was assigned with. For illustrative purposes, in many lessons, we will use the var keyword to declare variables. In practicality, don't abuse or overuse the var keyword. It can be confusing. The beauty of var, which is one of its rules, is that you MUST initialize its variable. This makes it possible to know the type of variable you are using. On the other hand, if you declare too many variables with var and initialize them with the same types of values, you C# 3.0 Practical Learning

32

could get confused with the type of data that each of those variables is holding. So, use the var keyword sparingly: It can be a beauty but, if overused, it can be confusing. The good news is that the compiler knows exactly what it is doing and what it is asked to do.

Representing Numbers A Bit The computer (or an Intel computer, or a computer that runs on an Intel microprocessor) uses the binary system to represent its information. It represents data using only a 0 or 1 value:

0

1

You can represent a piece of information with one of two states. This technique of representing values is the same as the binary system. In the computer, it uses values 0 and/or 1, which themselves are called digits. The entity used to represent such a value is called a binary digit; in its abbreviated form, it is called a bit (for binary digit). The bit (binary digit) is the most fundamental representation of the computer's counting system. Although the C# compiler recognizes a bit, you cannot store a variable in a bit. However, eventually, you will be able to manipulate the information stored in a bit.

The Four-Bit Combination The single bit is used only to represent a tinny piece of information. To get effective numbers, the computer combines the bits. The first combination of bits consists of grouping four consecutive bits.

To count the bits, we number them starting at 0, followed by 1, 2, and 3. The count starts with the most right bit:

C# 3.0 Practical Learning

33

The first bit, on the right side of the group, is called the Low Order bit or LO bit. This is also called the least significant bit. The last bit, on the left side of the group, is called the High Order bit or HI bit; it is also called the most significant bit. The bit on the right side is counted as bit 0. The bit on the left side is counted as bit 3. The other bits are called by their positions: bit 1 and bit 2. Once again, each bit can have one of two states. Continuing with our illustration, when a cup is empty, it receives a value of 0. Otherwise, it has a value of 1. On a group of four consecutive bits, we can have the following combinations:

This produces the following binary combinations: 0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111 = 16 combinations. When using the decimal system, these combinations can be represented as 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, and 15. This combination is also a system that the computer uses to count bits internally. Sometimes, in your program or in the help files, you will encounter a number that is less than four bits, such as 10 or 01 or 101. The technique used to complete and fill out the group of 4 bits consists of displaying 0 for each non-represented bit. The binary number 10 will be the same as 0010. The number 01 is the same as 0001. The number 101 is the same as 0101. This technique is valuable and allows you to always identify a binary number as a divider of 4. When all bits of a group of 4 are 0, the combination has the lowest value, which is 0000. Any of the other combinations has at least one 0 bit, except for the last one. When all bits are 1, this provides the highest value possible for a group of 4 bits. The lowest value, also considered the minimum value, can be represented in the decimal system as 0. The highest value, also considered the maximum, can be expressed in decimal value as 24 (2 represents the fact that there are two possible states: 0 and 1; 4 represents the fact that there are four possible combinations), which is 16. This produces 16 because 24 = 16. C# 3.0 Practical Learning

34

As you can see, the binary system can appear difficult to read when a value combines various bit representations. To make it easier, the computer recognizes the hexadecimal representation of bits. Following the box combinations above, we can represent each 4-bit of the sixteen combinations using the decimal, hexadecimal, and binary systems as follows: Decimal

Binary

Hexadecimal

0

0000

0

1

0001

1

2

0010

2

3

0011

3

4

0100

4

5

0101

5

6

0110

6

7

0111

7

8

1000

8

9

1001

9

10

1010

A

11

1011

B

12

1100

C

13

1101

D

14

1110

E

15

1111

F

Table of Numeric Conversions

C# 3.0 Practical Learning

35

When looking at a binary value represented by 4 bits, you can get its decimal or hexadecimal values by referring to the table above. A group of four consecutive bits has a minimum and maximum values on each system as follows: Decimal

Hexadecimal

Binary

Minimum

0

0x0

0000

Maximum

15

0xf

1111

Although the C# compiler recognizes a group of four consecutive bits, you cannot store any variable in it. You can, however, manipulate the bits of the group.

A Byte Introduction A byte is a group or eight consecutive bits. The bits are counted from right to left starting at 0:

The most right bit is bit 0; it is called the least significant bit. It is also referred to as the Low Order bit, the LO bit, or LOBIT. The most left bit is bit 7; it is called the most significant bit. It is also referred to as the High Order bit, the HI bit, or HIBIT. The other bits are referred to following their positions:

Using the binary system, you can represent the byte using a combination of 0s and 1s. When all bits have a value of 0, the byte is represented as 00000000. On the other hand, when all bits have a value of 1, the byte is represented as 11111111. When the number grows very large, it becomes difficult to read. Therefore, you can represent bits in groups of four. Instead of writing 00000000, you can write 0000 0000. This makes the number easier to read.

C# 3.0 Practical Learning

36

If you have the patience to create combinations of bits using the boxes as we did for the group of 4, you would find out that there are 256 possible combinations. Another way to find it out is by using the base 2 technique: 27 + 26 + 25 + 24 + 23 + 22 + 21 + 20 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255 Therefore, the maximum decimal value you can store in a byte is 255. Remember that the byte with all bits having a value of 0 has its value set to 0. Since this byte also holds a valid value, the number of combinations = 255 + 1 = 256. When a byte is completely represented with 0s, it provides the minimum value it can hold; this is 0000 0000, which is also 0. When all bits have a value of 1, which is 1111 1111, a byte holds its maximum value that we calculated as 255 in the decimal system. As done with the group of 4 bits, we get the following table: Decimal

Hexadecimal

Binary

Minimum

0

0x0

0000

Maximum

255

0xff

1111 1111

The minimum storage area offered by the (Intel) computer is the byte. As you know already, a byte is a group of 8 consecutive bits. The amount of memory space offered by a byte can be used to store just a single symbol, such as those you see on your keyboard. These symbols, also called characters, have been organized by the American Standard Code for Information Exchange (ASCII) in a set list. But, ASCII uses only 128 decimal numbers (based on a 7-bit format) to represent symbols counted from 0 to 127. To compensate for the remaining 1 bit, IBM used it to organize special characters, foreign language characters, mathematical symbols, small graphics, etc. Each one of these characters has a decimal, a hexadecimal, and a binary equivalents. Each one of the characters you see on your keyboard is represented as a numeric value, but whether it appears as a number, a letter, or a symbol, each one of these is considered a character. To display any character on your screen, you can pass it to Write() or WriteLine() and include the character between single-quotes, as follows: using System; class Exercise { static void Main() { Console.WriteLine('n'); } }

C# 3.0 Practical Learning

37

Characters In the English alphabet, a character is one of the following symbols: a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, and Z. Besides these readable characters, the following symbols are called digits and they are used to represent numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. In addition, some symbols on the (US QWERTY) keyboard are also called characters or symbols. They are ` ~ ! @ # $ %^&*()-_=+[{]}\|;:'" Besides the English language, other languages use other or additional characters that represent verbal or written expressions. C# recognizes that everything that can be displayed as a symbol is called a character. To declare a variable whose value would be a character, you can use the var keyword and initialize the variable with a character in single-quotes. Here is an example: using System; class Exercise { static void Main() { var Gender = 'F';

}

Console.Write("Student Gender: "); Console.WriteLine(Gender);

}

Alternatively, you can use the char keyword. Here is an example: using System; class Exercise { static void Main() { char Gender = 'M'; Console.Write("Student Gender: "); Console.WriteLine(Gender); }

}

This would produce: Student Gender: M

Escape Sequences An escape sequence is a special character that displays non-visibly. For example, you can use this type of character to indicate the end of line, that is, to ask the program to continue on the next line. An escape sequence is represented by a backslash character, \, followed by another character or symbol. For example, the escape sequence that moves to the next line is \n. 38 C# 3.0 Practical Learning

An escape can be included in single-quotes as in '\n'. It can also be provided in double-quotes as "\n". The C# language recognizes other escape sequences. Escape Sequence

Name

Description

\a

Bell (alert)

Makes a sound from the computer

\b

Backspace

Takes the cursor back

\t

Horizontal Tab

Takes the cursor to the next tab stop

\n

New line

Takes the cursor to the beginning of the next line

\v

Vertical Tab Performs a vertical tab

\f

Form feed

\r

Carriage return

Causes a carriage return

\"

Double Quote

Displays a quotation mark (")

\'

Apostrophe Displays an apostrophe (')

\?

Question mark

Displays a question mark

\\

Backslash

Displays a backslash (\)

\0

Null

Displays a null character

To use an escape sequence, you can also first declare a char variable and initialize it with the desired escape sequence in single-quotes.

The Byte Data Type A byte is an unsigned number whose value can range from 0 to 255 and therefore can be stored in one byte. You can use it when you know a variable 39 C# 3.0 Practical Learning

would hold a relatively small value such as people's age, the number of children of one mother, etc. To declare a variable that would hold a small natural number, use the byte keyword. Here is an example: byte Age;

You can initialize a byte variable when declaring it or afterwards. Here is an example that uses the byte data type: using System; class ObjectName { static void Main() { Byte Age = 14; Console.Write("Student Age: "); Console.WriteLine(Age); Age = 12; Console.Write("Student Age: "); Console.WriteLine(Age); }

}

Make sure you do not use a value that is higher than 255 for a byte variable, you would receive an error. When in doubt, or when you think that there is a possibility a variable would hold a bigger value, don't use the byte data type as it doesn't like exceeding the 255 value limit. Alternatively, you can also use the var keyword to declare the variable and initialize it with a small number. Here is an example: using System; class Exercise { static void Main() { var Age = 14; Console.Write("Student Age: "); Console.WriteLine(Age);

}

Age = 12; Console.Write("Student Age: "); Console.WriteLine(Age);

}

Instead of a decimal number, you can also initialize an integral variable with a hexadecimal value. When doing this, make sure the decimal equivalent is less than 255. Here is an example: using System; class Exercise { static void Main() {

C# 3.0 Practical Learning

40

var Number = 0xFE; Console.Write("Number: "); Console.WriteLine(Number);

} }

This would produce: Number: 254 Press any key to continue . . .

Practical Learning: Using Bytes 1. Change the Program.cs file as follows: using using using using

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

namespace GeorgetownCleaningServices2 { class Program { static void Main(string[] args) { byte Shirts; byte Pants; Shirts = 4; Pants = 1; Console.WriteLine("-/- Georgetown Cleaning Services -/-");

}

Console.WriteLine("========================"); Console.WriteLine("Item Type Qty"); Console.WriteLine("------------------------"); Console.Write("Shirts "); Console.WriteLine(Shirts); Console.Write("Pants "); Console.WriteLine(Pants); Console.WriteLine("========================"); Console.WriteLine(); }

}

2. Execute the program. This would produce: -/- Georgetown Cleaning Services -/======================== Item Type Qty -----------------------Shirts 4 Pants 1 ========================

C# 3.0 Practical Learning

41

3. Close the DOS window

Signed Byte A byte number is referred to as signed if it can hold a negative of a positive value that ranges from -128 to 127, which can therefore fit in a byte. To declare a variable for that kind of value, use the sbyte keyword. Here is an example: using System; class NumericRepresentation { static void Main() { sbyte RoomTemperature = -88; Console.Write("When we entered, the room temperature was "); Console.WriteLine(RoomTemperature); Console.WriteLine(); }

}

This would produce: When we entered, the room temperature was -88

A Word Introduction A word is a group of 16 consecutive bits. The bits are counted from right to left starting at 0:

Considered as a group of 16 bits, the most right bit of a word, bit 0, is called the least significant bit or Low Order bit or LO bit or LOBIT. The most left bit, bit 15, is called the most significant bit or High Order bit or HI bit or HIBIT. The other bits are referred to using their positions: bit 1, bit 2, bit 3, etc. Considering that a word is made of two bytes, the group of the right 8 bits is called the least significant byte or Low Order byte or LO byte or LOBYTE. The other group is called the most significant byte or High Order byte or HI byte or HIBYTE. The representation of a word in binary format is 0000000000000000. To make it easier to read, you can group bits by 4, like this: 0000 0000 0000 0000. Therefore, the minimum binary value represented by a word is 0000 0000 0000 0000. The minimum decimal value of a word is 0. The minimum hexadecimal 42 C# 3.0 Practical Learning

value you can store in a word is 0x0000000000000000. This is also represented as 0x00000000, or 0x0000, or 0x0. All these numbers produce the same value, which is 0x0. The maximum binary value represented by a word is 1111 1111 1111 1111. To find out the maximum decimal value of a word, you can use the base 2 formula, filling out each bit with 1: 1*215+1*214+1*213 + 1*212 + 1*211 + 1*210 + 1*29 + 1*28 + 1*27 + 1*26 + 1*25 + 1*24 + 1*23 + 1*22 + 1*21 + 1*20 = 32768 + 16384 + 8192 + 4096 + 2048 + 1024 + 512 + 256 + 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 65535 To find out the maximum hexadecimal number you can store in a word, replace every group of 4 bits with an f or F: 1111 1111 1111 1111 f

f

f

f

= 0xffff = 0xFFFF = 0Xffff = 0XFFFF

Short Integers A word, which is a group of 16 contiguous bits or 2 bytes, can be used to hold a natural number. As we have studied, the maximum numeric value that can fit in a word is 65535. To declare a variable for such a value, you can use the var keyword and initialize the variable with a value between –32768 to 32767. Here is an example: using System; class Exercise { static void Main() { var SchoolEffective = 1400; // Number of Students Console.Write("School Effective: "); Console.WriteLine(SchoolEffective);

C# 3.0 Practical Learning

43

} }

This would produce: School Effective: 1400 Press any key to continue . . .

Since the byte is used for characters and very small numbers, whenever you plan to use a number in your program, the minimum representation you should use is a word. A natural number is also called an integer. If you want to declare the variable using a data type, the smallest integer you can store in a word is declared with the short keyword. Because a short integer is signed by default, it can store a value that ranges from –32768 to 32767. Here is an example program that uses two short integers: using System; class Exercise { static void Main() { short NumberOfPages; short Temperature; NumberOfPages = 842; Temperature = -1544; Console.Write("Number of Pages of the book: "); Console.WriteLine(NumberOfPages); Console.Write("Temperature to reach during the experiment: "); Console.Write(Temperature); Console.WriteLine(" degrees\n"); }

}

This would produce: Number of Pages of the book: 842 Temperature to reach during the experiment: -1544 degrees

Because a short integer handles numbers that are larger than the signed byte, any variable you can declare for a signed byte can also be declared for a short variable.

Unsigned Short Integers If a variable must hold positive and relatively small numbers, it is referred as an unsigned short integer. Such a variable can be declared using either the var of the ushort keyword. An unsigned short integer can hold numbers that range from 0 to 65535 and therefore can fit in 16 bits. Here is an example: using System; class NumericRepresentation {

C# 3.0 Practical Learning

44

static void Main() { // These variables must hold only positive integers ushort NumberOfTracks; ushort MusicCategory; NumberOfTracks = 16; MusicCategory = 2; Console.Write("This music album contains "); Console.Write(NumberOfTracks); Console.WriteLine(" tracks"); Console.Write("Music Category: "); Console.Write(MusicCategory); Console.WriteLine(); }

}

This would produce: This music album contains 16 tracks Music Category: 2

Practical Learning: Using Unsigned Short Integers 1. To use unsigned short integers, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices2 { class Program { static void Main(string[] args) { byte Shirts; byte Pants; ushort OtherItems; Shirts = 4; Pants = 1; OtherItems = 3; Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("========================"); Console.WriteLine("Item Type Qty"); Console.WriteLine("------------------------"); Console.Write("Shirts "); Console.WriteLine(Shirts); Console.Write("Pants "); Console.WriteLine(Pants); Console.Write("Other Items "); Console.WriteLine(OtherItems); Console.WriteLine("========================"); Console.WriteLine();

C# 3.0 Practical Learning

45

} }

}

2. Execute the program. This would produce: -/- Georgetown Cleaning Services -/======================== Order Date: 7/15/2002 -----------------------Item Type Qty -----------------------Shirts 4 Pants 1 Other Items 3 ======================== Press any key to continue . . .

3. Close the DOS window

C# 3.0 Practical Learning

46

3 – USING VARIABLES A Double-Word Introduction A double-word is a group of two consecutive Words. This means that a doubleword combines 4 bytes or 32 bits. The bits, counted from right to left, start at 0 and end at 31. The most right bit, bit 0, is called the Low Order bit or LO bit or LOBIT. The most left bit, bit 31, is called the High Order bit or HI bit or HIBIT. The other bits are called using their positions. The group of the first 8 bits (from bit 0 to bit 7), which is the right byte, is called the Low Order Byte, or LO Byte. It is sometimes referred to as LOBYTE. The group of the last 8 bits (from bit 24 to bit 31), which is the left byte, is called the High Order Byte, or HI Byte or HIBYTE. The other bytes are called by their positions.

The group of the right 16 bits, or the right Word, is called the Low Order Word, or LO Word, or LOWORD. The group of the left 16 bits, or the left Word, is called the High Order Word, or HI Word, or HIWORD. The minimum binary number you can represent with a double-word is 0. The minimum decimal value of a double-word is 0. To find out the maximum decimal value of a word, you can use the base 2 formula giving a 1 value to each bit:

2n1

230

229

228

227

226

225

224

et 1,073,741,8 536,870,9 268,435,4 134,217,7 67,108,86 33,554,43 16,777,21 c 24 12 56 28 4 2 6

223

222

221

220

219

C# 3.0 Practical Learning

218

217

216 47

8,388,60 4,194,30 2,097,15 1,048,57 524,288 262,144 131,072 8 4 2 6

215 32,768

214 16,384

27 128

213

212

211

210

8,192

4,096

2,048

1,024

25

24

23

22

26 64

32

16

8

4

29 512

65,536

28 256

21 2

20 1

1*231+1*230+1*229 + 1*228 + 1*227 + 1*226 + 1*225 + 1*224 + 1*223 + 1*222 + 1*221 + 1*220 + 1*219 + 1*218 + 1*217 + 1*216 + 1*215 + 1*214 + 1*213 + 1*212 + 1*211 + 1*210 + 1*29 + 1*28 + 1*27 + 1*26 + 1*25 + 1*24 + 1*23 + 1*22 + 1*21 + 1*20 = 2,147,483,648 + 1,073,741,824 + 536,870,912 + 268,435,456 + 134,217,728 + 67,108,864 + 33,554,432 + 16,777,216 + 8,388,608 + 4,194,304 + 2,097,152 + 1,048,576 + 524,288 + 262,144 + 131,072 + 65,536 + 32,768 + 16,384 + 8,192 + 4,096 + 2,048 + 1,024 + 512 + 256 + 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 4,286,578,708 The minimum hexadecimal value you can store in a double-word is 0x00000000000000000000000000000000 which is the same as 0x0. To find out the maximum hexadecimal number you can represent with a word, replace every group of 4-bits with an f or F: 1111 1111 1111 1111 1111 1111 1111 1111 f

f

f

f

f

f

f

f

= 0xffffffff = 0Xffffffff = 0XFFFFFFFF = 0xFFFFFFFF

C# 3.0 Practical Learning

48

To declare a variable that can hold large values, you can use the var keyword and initialize the variable with the desired value. Here is an example: using System; class Exercise { static void Main() { var Population = 72394475; Console.Write("Country Population: "); Console.WriteLine(Population); }

}

This would produce: Country Population: 72394475 Press any key to continue . . .

Practical Learning: Using Unsigned Integers 1. Start Microsoft Visual C# 2. To create a new application, on the main menu, click File -> New -> Project... 3. In the Templates section, click Console Application 4. Change the Name to GeorgetownCleaningServices3 and click OK 5. Change the file as follows: using using using using

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

namespace GeorgetownCleaningServices3 { class Program { static void Main(string[] args) { byte Shirts; byte Pants; ushort OtherItems; Shirts = 4; Pants = 0; OtherItems = 3; Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("========================"); Console.WriteLine("------------------------"); Console.WriteLine("Item Type Qty");

C# 3.0 Practical Learning

49

Console.WriteLine("------------------------"); Console.Write("Shirts "); Console.WriteLine(Shirts); Console.Write("Pants "); Console.WriteLine(Pants); Console.Write("Other Items "); Console.WriteLine(OtherItems); Console.WriteLine("========================"); Console.WriteLine(); }

}

}

6. Execute the program to see the result 7. Close the DOS window

Signed Integers A double-word is large enough to contain double the amount of data that can be stored in a word. This is equivalent to 32 bits or 4 bytes or 4,294,967,295. Therefore, a double-word is used for large numbers that would not fit in a word. To use a variable that would hold quite large numbers, besides the var keyword, you can declare it using the int keyword. A variable declared as int can store values between –2,147,483,648 and 2,147,484,647 negative or positive, that can fit in 32 bits. Here is an example: using System; class Exercise { static void Main() { int CoordX; int CoordY; CoordX = 12; CoordY = -8;

}

Console.Write("Cartesian Coordinate System: "); Console.Write("P("); Console.Write(CoordX); Console.Write(", "); Console.Write(CoordY); Console.WriteLine(")\n");

}

When executed, the program would produce: Cartesian Coordinate System: P(12, -8)

If you declare an integer variable using the var keyword and initialize it with a value lower than 2,147,484,647, the compiler concludes that the memory needed to store that variable is 32 bits: C# 3.0 Practical Learning

50

When initializing an integral variable, instead of a decimal number, you can also initialize it with a hexadecimal value whose decimal equivalent is less than 2,147,484,647. Here is an example: using System; class Exercise { static void Main() { var Number = 0xF0488EA; Console.Write("Number: "); Console.WriteLine(Number); }

}

This would produce: Number: 251955434 Press any key to continue . . .

Unsigned Integers If the variable must hold only positive natural numbers, you can declared it using the uint keyword. The uint keyword is used to identify a 32-bit positive integer whose value would range from 0 to 2,147,484,647. Here is an example: using System; class Exercise { static void Main() {

C# 3.0 Practical Learning

51

uint DayOfBirth; uint MonthOfBirth; uint YearOfBirth; DayOfBirth = 8; MonthOfBirth = 11; YearOfBirth = 1996; Console.WriteLine("Red Oak High School"); Console.Write("Student Date of Birth: ");

}

Console.Write(MonthOfBirth); Console.Write("/"); Console.Write(DayOfBirth); Console.Write("/"); Console.Write(YearOfBirth); Console.WriteLine();

}

This would produce: Red Oak High School Student Date of Birth: 11/8/1996

Practical Learning: Using Unsigned Integers 1. To use unsigned variables, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices3 { class Program { static void Main(string[] args) { byte Shirts; byte Pants; ushort OtherItems; uint OrderDay; uint OrderMonth; uint OrderYear; Shirts = 4; Pants = 0; OtherItems = 3; OrderDay = 15; OrderMonth = 7; OrderYear = 2002; Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("========================");

C# 3.0 Practical Learning

52

Console.Write("Order Date: "); Console.Write(OrderMonth); Console.Write('/'); Console.Write(OrderDay); Console.Write('/'); Console.WriteLine(OrderYear); Console.WriteLine("------------------------"); Console.WriteLine("Item Type Qty"); Console.WriteLine("------------------------"); Console.Write("Shirts "); Console.WriteLine(Shirts); Console.Write("Pants "); Console.WriteLine(Pants); Console.Write("Other Items "); Console.WriteLine(OtherItems); Console.WriteLine("========================"); Console.WriteLine(); }

}

}

2. Execute the program. This would produce: -/- Georgetown Cleaning Services -/======================== Order Date: 7/15/2002 -----------------------Item Type Qty -----------------------Shirts 4 Pants 0 Other Items 3 ======================== Press any key to continue . . .

3. Close the DOS window

A Quad-Word Introduction Sometimes you may want to store values that a double-word cannot handle. To store a very large number in a variable, you can consider a combination of 64 bits. The group can also be referred to as a quad-word. A quad-word is so large it can store numbers in the range of –9,223,372,036,854,775,808 and 9,223,372,036,854,775,807. If you declare an integer variable using the var keyword and initialize it with a value between 2,147,484,647 and 9,223,372,036,854,775,807, the compiler concludes that the memory needed to store that variable is 64 bits:

C# 3.0 Practical Learning

53

Long Integers If you want to use a variable that can hold very large numbers that would require up to 64 bits, you can declare it using either the var or the long keyword. In C++, the long data type is 32 bits while in C#, the long data type is 64 bits. As stated previously, if you initialize the variable with a value lower than 2,147,484,647, the compiler would allocate 32 bits of memory for it. If you initialize the variable with a value between 2,147,484,647 and 9,223,372,036,854,775,807, the compiler would allocate 64 bits of memory for it. If the value is higher than 9,223,372,036,854,775,807, which is too large, the compiler would present an error:

C# 3.0 Practical Learning

54

This means that you should limit the values assigned to integral variables to 64 bits, which is very significant. Here is an example that uses the long data type: using System; class Exercise { static void Main() { var CountryArea = 5638648; Console.Write("Country Area: "); Console.Write(CountryArea); Console.Write("km2\n"); }

}

This would produce: Country Area: 5638648km2 Press any key to continue . . .

As mentioned for other integral types, you can initialize a long variable with a hexadecimal value. Although the long data type is used for large number, it mainly indicates the amount of space available but you do not have to use the whole space. For example, you can use the long keyword to declare a variable that would hold the same range of numbers as the short, the int, or the uint data types. If you declare a variable as long but use it for small numbers that don't require 64 bits, the compiler would allocate the appropriate amount of space to accommodate the values of the variable. Consequently, the amount of space C# 3.0 Practical Learning

55

made available may not be as large as 64 bits. If you insist and want the compiler to reserve 64 bits, when assigning a value to the variable, add an L suffix to it. Here is an example that uses space of a long data type to store a number that would fit in 32 bits: using System; class NumericRepresentation { static void Main() { long CountryArea; CountryArea = 5638648L;

}

Console.Write("Country Area: "); Console.Write(CountryArea); Console.Write("km2\n");

}

Therefore, keep in mind that an int, a uint, a short, or a ushort can fit in a long variable.

Unsigned Long Integers You can use a combination of 64 bits to store positive or negative integers. In some cases, you will need a variable to hold only positive, though large, numbers. To declare such a variable, you can use the ulong data type. A variable declared as ulong can handle extremely positive numbers that range from 0 to 18,446,744,073,709,551,615 to fit in 64 bits.

Real Numbers Introduction A real number is a number that displays a decimal part. This means that the number can be made of two sections separated by a symbol that is referred to as the Decimal Separator or Decimal Symbol. This symbol is different by language, country, group of languages, or group of countries. In US English, this symbol is the period as can be verified from the Regional (and Language) Settings of the Control Panel:

C# 3.0 Practical Learning

56

On both sides of the Decimal Symbol, digits are used to specify the value of the number. The number of digits on the right side of the symbol determines how much precision the number offers.

Floating-Point Numbers The integers we have used so far have the main limitation of not allowing decimal values. C# provides floating values that would solve this problem. The most fundamental floating variable is declared with the float keyword. A variable declared a float can store real numbers that range from ±1.5 × 10−45 to ±3.4 × 1038 with a precision of 7 digits in 32 bits. Here is an example: using System; class NumericRepresentation { static void Main() { float Distance; } }

Double-Precision Numbers

C# 3.0 Practical Learning

57

When a variable is larger than the float can handle and requires more precision, you should declare it using either the var or the the double keyword. Here is an example: using System; class Exercise { static void Main() { var Number = 62834.9023;

}

Console.Write("Number: "); Console.WriteLine(Number);

}

This would produce: Number: 62834.9023 Press any key to continue . . .

A variable declared as double uses 64 bits to store very large numbers ranging from ±5.0 × 10−324 to ±1.7 × 10308 with a precision of 15 or 16 digits. Because the double data type provides a better result with a better precision than the float, whenever you declare a variable using either the var or the float keyword and assign it a value, the compiler allocates 64 bits to store the values of the variable. If you insist on the variable being treated as float, when assigning it a value, add an F suffix to the value. Here is an example: using System; class NumericRepresentation { static void Main() { float Distance; Distance = 248.38F;

}

Console.Write("Distance = "); Console.Write(Distance); Console.WriteLine("km\n");

}

This would produce: Distance = 248.38km

Remember that if you declare the variable as var and want to treat it as a value with single precision, add an F suffix to the value assigned to it. Here is an example: using System; class Exercise { static void Main()

C# 3.0 Practical Learning

58

{ var

Number = 62834.9023F;

Console.Write("Number: "); Console.WriteLine(Number); }

}

On the other hand, if you want a value to be treated with double-precision, add a D suffix to it. Here is an example: using System; class Exercise { static void Main() { var Number = 62834.9023D; Console.Write("Number: "); Console.WriteLine(Number); }

}

Practical Learning: Using a Double-Precision Variable 1. To use a double-precision value, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices3 { class Program { static void Main(string[] args) { byte Shirts; byte Pants; ushort OtherItems; uint OrderDay; uint OrderMonth; uint OrderYear; double MondayDiscount; Shirts = 4; Pants = 0; OtherItems = 3; OrderDay = 15; OrderMonth = 7; OrderYear = 2002; MondayDiscount = 0.25D; // 25% Console.WriteLine("-/- Georgetown Cleaning Services -/-");

C# 3.0 Practical Learning

59

} }

Console.WriteLine("========================"); Console.Write("Order Date: "); Console.Write(OrderMonth); Console.Write('/'); Console.Write(OrderDay); Console.Write('/'); Console.WriteLine(OrderYear); Console.WriteLine("------------------------"); Console.WriteLine("Item Type Qty"); Console.WriteLine("------------------------"); Console.Write("Shirts "); Console.WriteLine(Shirts); Console.Write("Pants "); Console.WriteLine(Pants); Console.Write("Other Items "); Console.WriteLine(OtherItems); Console.WriteLine("------------------------"); Console.Write("Monday Discount: "); Console.Write(MondayDiscount); Console.WriteLine('%'); Console.WriteLine("========================"); Console.WriteLine();

}

2. Execute the application to see the result: -/- Georgetown Cleaning Services -/======================== Order Date: 7/15/2002 -----------------------Item Type Qty -----------------------Shirts 4 Pants 0 Other Items 3 -----------------------Monday Discount: 0.25% ======================== Press any key to continue . . .

3. Close the DOS window

Decimal The decimal data type can be used to declare a variable that would hold significantly large values that can be stored in a combination of 128 bits. You declare such a variable using the decimal keyword. The values stored in a decimal variable can range from ±1.0 × 10−28 to ±7.9 × 1028 with a precision of 28 to 29 digits. Because of this high level of precision, the decimal data type is suitable for currency values. After declaring a decimal variable, you can initialize it with a natural number. To indicate that the variable holds a decimal value, when initializing it, add an M suffix to its value. Here is an example: C# 3.0 Practical Learning

60

using System; class NumericRepresentation { static void Main() { decimal HourlySalary; HourlySalary = 24.25M; Console.Write("Hourly Salary = "); Console.WriteLine(HourlySalary); Console.WriteLine(); }

}

This would produce: Hourly Salary = 24

As seen in previous sections and this one, when declaring and initializing a real variable, the suffix you give to its assigned value indicates to the compiler the actual type of value and the type of memory that would be allocated for the variable: •

If the value receives an F suffix, it is considered a floating point number with single precision



If the value receives a D suffix, it is considered a floating point number with double precision C# 3.0 Practical Learning

61



If the value receives an M suffix, it is considered a large decimal number

C# 3.0 Practical Learning

62

Practical Learning: Using Decimal Values 1. To use decimal variables, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices3 { class Program { static void Main(string[] args) { byte Shirts; decimal PriceOneShirt; byte Pants; decimal PriceAPairOfPants; ushort OtherItems; decimal PriceOtherItems; uint OrderDay; uint OrderMonth; uint OrderYear; double MondayDiscount; Shirts = 5; PriceOneShirt = 0.95M; Pants = 2; PriceAPairOfPants = 1.95M; OtherItems = 3; PriceOtherItems = 4.55M; OrderDay = 15; OrderMonth = 7; OrderYear = 2002; MondayDiscount = 0.25D; // 25% Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("========================"); Console.Write("Order Date: "); Console.Write(OrderMonth); Console.Write('/'); Console.Write(OrderDay); Console.Write('/'); Console.WriteLine(OrderYear); Console.WriteLine("------------------------"); Console.WriteLine("Item Type Qty Unit Price"); Console.WriteLine("------------------------"); Console.Write("Shirts "); Console.Write(Shirts); Console.Write(" "); Console.WriteLine(PriceOneShirt); Console.Write("Pants "); Console.Write(Pants);

C# 3.0 Practical Learning

63

} }

Console.Write(" "); Console.WriteLine(PriceAPairOfPants); Console.Write("Other Items "); Console.Write(OtherItems); Console.Write(" "); Console.WriteLine(PriceOtherItems); Console.WriteLine("------------------------"); Console.Write("Monday Discount: "); Console.Write(MondayDiscount); Console.WriteLine('%'); Console.WriteLine("========================"); Console.WriteLine();

}

2. Execute the program. This would produce: -/- Georgetown Cleaning Services -/======================== Order Date: 7/15/2002 -----------------------Item Type Qty Unit Price -----------------------Shirts 5 0.95 Pants 2 1.95 Other Items 3 4.55 -----------------------Monday Discount: 0.25% ======================== Press any key to continue . . .

3. Close the DOS window

Accessory Data Types Strings A string is an empty space, a character, a word, or a group of words that you want the compiler to consider "as is", that is, not to pay too much attention to what the string is made of, unless you explicitly ask it to. This means that, in the strict sense, you can put in a string anything you want. Primarily, the value of a string starts with a double quote and ends with a double-quote. An example of a string is "Welcome to the World of C# Programming!". You can include such a string in Console.Write() to display it on the console. Here is an example: using System; class Exercise { static void Main()

C# 3.0 Practical Learning

64

{ }

Console.WriteLine("Welcome to the World of C# Programming!");

}

This would produce: Welcome to the World of C# Programming! Press any key to continue . . .

Sometimes, you will need to use a string whose value is not known in advance. Therefore, you can first declare a string variable. To do this, use either the var or the string keyword followed by a name for the variable. The name will follow the rules we defined above. When declaring a string variable, you can initialize it with an empty space, a character, a symbol, a word, or a group of words. The value given to a string must be included in double-quotes. Here are two examples: using System; class Exercise { static void Main() { var Team = "Real Madrid"; string Country = "Guinée Equatoriale"; Console.WriteLine("Welcome to the World of C# Programming!"); Console.Write("Team: "); Console.WriteLine(Team); Console.Write("Country: "); Console.WriteLine(Country); Console.WriteLine(); }

}

This would produce: Welcome to the World of C# Programming! Team: Real Madrid Country: Guinée Equatoriale Press any key to continue . . .

Practical Learning: Using Strings 1. To use strings, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices3 { class Program { static void Main(string[] args)

C# 3.0 Practical Learning

65

{ string CustomerName; string CustomerHomePhone; byte Shirts; decimal PriceOneShirt; byte Pants; decimal PriceAPairOfPants; ushort OtherItems; decimal PriceOtherItems; uint OrderDay; uint OrderMonth; uint OrderYear; double MondayDiscount; CustomerName = "Gregory Almas"; CustomerHomePhone = "(301) 723-4425"; Shirts = 5; PriceOneShirt = 0.95M; Pants = 2; PriceAPairOfPants = 1.95M; OtherItems = 3; PriceOtherItems = 4.55M; OrderDay = 15; OrderMonth = 7; OrderYear = 2002; MondayDiscount = 0.25D; // 25% Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("========================"); Console.Write("Customer: "); Console.WriteLine(CustomerName); Console.Write("Home Phone: "); Console.WriteLine(CustomerHomePhone); Console.Write("Order Date: "); Console.Write(OrderMonth); Console.Write('/'); Console.Write(OrderDay); Console.Write('/'); Console.WriteLine(OrderYear); Console.WriteLine("------------------------"); Console.WriteLine("Item Type Qty Unit Price"); Console.WriteLine("------------------------"); Console.Write("Shirts "); Console.Write(Shirts); Console.Write(" "); Console.WriteLine(PriceOneShirt); Console.Write("Pants "); Console.Write(Pants); Console.Write(" "); Console.WriteLine(PriceAPairOfPants); Console.Write("Other Items "); Console.Write(OtherItems); Console.Write(" "); Console.WriteLine(PriceOtherItems); Console.WriteLine("------------------------"); Console.Write("Monday Discount: "); Console.Write(MondayDiscount);

C# 3.0 Practical Learning

66

Console.WriteLine('%'); Console.WriteLine("========================"); Console.WriteLine(); }

}

}

2. Execute the program. This would produce: -/- Georgetown Cleaning Services -/======================== Customer: Gregory Almas Home Phone: (301) 723-4425 Order Date: 7/15/2002 -----------------------Item Type Qty Unit Price -----------------------Shirts 5 0.95 Pants 2 1.95 Other Items 3 4.55 -----------------------Monday Discount: 0.25% ======================== Press any key to continue . . .

3. Close the DOS window

Dates and Times A date is a unit that measures the number of years, months, or days elapsed in a specific period. A time is a unit that counts the number of seconds that have elapsed since midnight of the day considered. Although dates and times are large subjects that would require a detailed study, at this time, we will consider them in simple terms. To declare a variable that would hold date or time values, use the DateTime data type. using System; class NumericRepresentation { static void Main() { DateTime DateHired; } }

The .NET Framework sets its starting periodic date to January 1, 0001 at midnight (12:00:00 or 0:00 AM). If not assigned a specific value (in future lessons, we will learn that this is equivalent to declaring a variable using the default constructor), the variable is initialized to 1/1/0001 at midnight.

Objects C# 3.0 Practical Learning

67

The object data type is used to declare a variable whose type is not primarily defined and can be any of the other data types we have introduced. After creating an object variable, you can use its value as you see fit. For example, you can enter the variable in the parentheses of Console.Write() or Console.WriteLine() to display it in the console window. Here is an example: using System; class Exercise { static void Main() { var EmployeeName = "Ernestine Lamb"; object Address = "10244 Lockwood Drive"; Console.Write("Employee Name: "); Console.WriteLine(EmployeeName); Console.Write("Home Address: "); Console.WriteLine(Address); Console.WriteLine(); }

}

This would produce: Employee Name: Ernestine Lamb Home Address: 10244 Lockwood Drive Press any key to continue . . .

A variable declared with object can embrace almost any value. This means that, when initializing the variable, you can use any of the types of values we have seen so far. Here are examples: using System; class Program { static void Main() { object PropertyNumber = "293749"; object PropertyType = 'S'; object Stories = 3; object Bedrooms = 4; object Value = 425880; Console.WriteLine("=//= Altair Realty =//="); Console.WriteLine("Properties Inventory"); Console.Write("Property #: "); Console.WriteLine(PropertyNumber); Console.Write("Property Type: "); Console.WriteLine(PropertyType); Console.Write("Stories: "); Console.WriteLine(Stories); Console.Write("Bedrooms: "); Console.WriteLine(Bedrooms); Console.Write("Market Value: "); Console.WriteLine(Value); }

}

C# 3.0 Practical Learning

68

This would produce: =//= Altair Realty =//= Properties Inventory Property #: 293749 Property Type: S Stories: 3 Bedrooms: 4 Market Value: 425880 Press any key to continue . . .

Constants Custom Constants Suppose you intend to use a number such as 39.37 over and over again. Here is an example: using System; class Exercise { static void Main() { double Meter, Inch;

}

Meter = 12.52D; Inch = Meter * 39.37D; Console.Write(Meter); Console.Write("m = "); Console.Write(Inch); Console.WriteLine("in\n");

}

Here is an example of running the program: 12.52m = 492.9124in

If you use this 39.37 many times in your program, at one time, you may make a mistake and type it as 3937 or 3.937 or else. Consider the following program: using System; class Exercise { static void Main() { double Meter, Inch; Meter = 12.52D; Inch = Meter * 39.37; Console.Write(Meter); Console.Write("m = "); Console.Write(Inch); Console.WriteLine("in\n");

C# 3.0 Practical Learning

69

Meter = 12.52D; Inch = Meter * 3.937; Console.Write(Meter); Console.Write("m = "); Console.Write(Inch); Console.WriteLine("in\n");

}

Meter = 12.52D; Inch = Meter * 393.7; Console.Write(Meter); Console.Write("m = "); Console.Write(Inch); Console.WriteLine("in\n");

}

This would produce: 12.52m = 492.9124in 12.52m = 49.29124in 12.52m = 4929.124in

Because of mistakes in the way to represent the number, the same calculation produces different results. To make sure that this is unlikely, you can instead use a variable that holds the value. Then, when you need that value, you can access the variable instead of the value itself. A number such as 39.37 is called a constant. A constant is a value that never changes such as 244, "ASEC Mimosa", 39.37, or True. These are constant values you can use in your program any time. You can also declare a variable and make it a constant; that is, use it so that its value is always the same. To create a constant, type the const keyword to its left. When declaring a constant, you must initialize it with an appropriate value. Here is an example: const double ConversionFactor = 39.37D;

Once a constant has been created and it has been appropriately initialized, you can use its name where the desired constant would be used. Here is an example of a constant variable used various times: using System; class Exercise { static void Main() { const double ConversionFactor = 39.37D; double Meter, Inch; Meter = 12.52D; Inch = Meter * ConversionFactor; Console.Write(Meter); Console.Write("m = "); Console.Write(Inch);

C# 3.0 Practical Learning

70

Console.WriteLine("in\n"); Meter = 12.52D; Inch = Meter * ConversionFactor; Console.Write(Meter); Console.Write("m = "); Console.Write(Inch); Console.WriteLine("in\n"); Meter = 12.52D; Inch = Meter * ConversionFactor; Console.Write(Meter); Console.Write("m = "); Console.Write(Inch); Console.WriteLine("in\n"); }

}

This would produce: 12.52m = 492.9124in 12.52m = 492.9124in 12.52m = 492.9124in

Notice that, this time, the calculation is more accurate. Also, this time, if you mistype the name of the variable in an operation, you would receive a compiler error, giving you the time to fix it. To initialize a constant variable, the value on the right side of the assignment operator "=" must be a constant or a value that the compiler can determine as constant. Instead of using a known constant, you can also assign it another variable that has already been declared as constant.

Built-in Constants There are two main categories of constants you will use in your programs. You can create your own constant as we saw above. The C# language also provides various constants. Some constants are part of the C# language. Some other constants are part of the .NET Framework. Before using a constant, of course, you must first know that it exists. Second, you must know how to access it. A constant that is part of the C# language can be accessed anywhere in your code. Those constant are normally defined in the System namespace. Other constant are defined in various appropriate namespaces. null: The null keyword is a constant used to indicate that a variable doesn't

hold a known value

PI: PI is a constant used as the ratio of the circumference of a circle to its diameter. PI is defined in Math. To use it, you would type Math.PI.

C# 3.0 Practical Learning

71

C# 3.0 Practical Learning

72

4 - INTRODUCTION TO CLASSES Fundamentals of Classes Introduction In the previous two lessons, to use a variable, we were declaring it using either var or a known and simple data type. For example, we could use an integer to declare a variable that represented the number of bedrooms of a house. Here is an example: using System; class Program { static void Main() { int bedrooms = 3; } }

As opposed to a simple variable, in C#, you can use one or more variables to create a more complete or complex object. Instead of only one file, you can create a program with many of them. Each file can contain different instructions that, when put together, can create an application as complete as possible. To create a code file, on the main menu, you can click Project -> Add New Item... In the Templates list, click Code File, accept or change the name of the file. You can omit the .cs extension. If you do, a file with the extension .cs would be added.

Practical Learning: Introducing Classes 1. Start Microsoft Visual C# 2. Create a Console Application named DepartmentStore1 3. Execute the application to see the result 4. Close the DOS window

Creating a Class C# 3.0 Practical Learning

73

A class is a technique of using one or a group of variables to be used as a foundation for a more detailed variable. To create a class, you start with the class keyword followed by a name and its body delimited by curly brackets. Here is an example of a class called House: class House { }

A class is created in a code file. As such, you can include it in the first file of your project. Here is an example: using System; class House { } class Program { static void Main() { int bedrooms = 3; } }

You can also create a class in its own file. To assist you with this, Microsoft Visual C# provides a wizard. To use it, on the main menu, you can click Project -> Add Class... or Project -> Add New Item... In the Templates list, click Class. In the Name text box, accept or change the default name and click Add. A new file named after the class with the .cs extension would be added to your project. When a project is made of various files, each file is represented by a tab in the top section of the Code Editor:

C# 3.0 Practical Learning

74

To access a file, you can click its tab.

Practical Learning: Introducing Classes 1. To create a new class, on the main menu, click Project -> Add Class... 2. In the Add New Item dialog box, change the name to DepartmentStore and click Add

Visually Managing Classes To assist you with managing the various classes of a project, Microsoft Visual C# includes various tools and windows. One of the windows you can use is called the Class View. To display it, on the main menu, you can click View -> Class View:

C# 3.0 Practical Learning

75

The Class View is made of four sections. The toolbar under the title bar includes four buttons. To identify a button, you can position the mouse on it and a tool tip would appear. Under the toolbar, another bar made of a combo box and a button allow you to search. The main top section of the Class View is made of various nodes. To expand a node, you can click its + button. To collapse a node, you can click its - button. The top node displays the name of the project. Under the project node, the names of classes display. The bottom section of the Class View is used to display the members of a class. To see the members of a class, you can click it in the top window. Here is an example:

To add a new class, besides the main menu, you can right-click the name of the project in the Class View, position the mouse on Add, and click Class...

Declaring a Variable of a Class Type Like any normal variable, to use a class in your program, you can first declare a variable for it. Like the variables we introduced in the previous lesson, to declare a variable of a class, you can use the var keyword. Alternatively, you C# 3.0 Practical Learning

76

can type its name followed by a name for the variable. For example, to declare a variable of the above House class, you could type the following: using System; class House { } class Program { static void Main() { var property . . . } }

Or the following: using System; class House { } class Program { static void Main() { House property; } }

The variables we have declared so far are called value variables. This is because such variables of primitive types hold their value. The C# language supports another type of variable. This time, when you declare the variable, its name does not hold the value of the variable; it holds a reference to the address where the actual variable is stored in memory. This reference type is the kind used to declare a variable for a class. To use a variable as reference, you must initialize it using an operator called new. Here is an example: using System; class House { } class Program { static void Main() { var Property = new House(); } }

C# 3.0 Practical Learning

77

If you are using the name of the class instead of var to declare the variable, you can first declare it. Then, on another line, you can allocate memory for it using the new operator. Here is an example: using System; class House { } class Program { static void Main() { House Property; // You can do something here }

Property = new House();

}

In C#, as well as Visual Basic, if you create a class in any of the files that belong to the same project, the class is made available to all other files of the same project.

Sharing a Class Unlike its sisters the C and the C++ languages, C# was developed with the idea of working complementarily with other languages such as C++/CLI, Visual Basic, and J#. In other words, code from these other languages should be able to "read" or access code written in a C# application. To make this possible, a C# class can be created as a public object. If you want your class to be accessible to code written in other languages, precede the class keyword with public when creating it. Here is an example: using System; public class Exercise { static void Main() { var Number = 244; var Thing = "Vehicle";

}

Console.WriteLine(Number); Console.WriteLine(Thing);

}

Garbage Collection When you initialize a variable using the new operator, you are in fact reserving some space in the heap memory. The memory is "allocated" for the variable. 78 C# 3.0 Practical Learning

When that variable is no longer needed, such as when your program closes, it (the variable) must be removed from memory and the space it was using can be made available to other variables or other programs. This is referred to as garbage collection. In the past, namely in C/C++, this was a concern for programmers because they usually had to remember to manually delete such a variable (a pointer) and free its memory. The .NET Framework solves the problem of garbage collection by "cleaning" the memory after you. This is done automatically when necessary so that the programmer doesn't need to worry about this issue.

Class' Fields Introduction Consider a class named House: public class House { }

The section between the curly brackets, { and }, of a class is referred to as its body. In the body of a class, you can create a list of the parts that make up the class. Each of these parts must be a complete variable with a name and a data type. For example, here are the characteristics that make up a house, declared as the parts of the above Book class and each declared as a variable: public class House { string PropertyNumber; char PropertyType; byte Stories; uint bedrooms; decimal Value; }

The variables declared in the body of a class are referred to as its member variables and each member variable is referred to as a field. The fields can be any type we have seen in the previous lesson. When creating a class, it is your job to decide what your object is made of.

Practical Learning: Introducing Class Members Imagine you want to write a (console-based) program for a department store and the customer has given you a preliminary catalog as follows:

C# 3.0 Practical Learning

79

Stock #: 437876 Stock #: 792475 Women Scoop Neck Dress Men Lightweight Jacket Unit Price: $148.00 Unit Price: $185

Stock: Women Leather $75.00

681432 Stock #: Python Print Men Escalade Bag Shoes $89.85

759470 Slip-On

Stock #: 740797 Girls Velour Active Skirt Unit Price: $22.85

Stock #: 482746 Boys Leather Bomber Jacket $255.50

Each item in this catalog is represented by its Stock number, its name or description, and its price. Based on this, you can create a class that represents each item. 1. Change the DepartmentStore class as follows: using using using using

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

namespace DepartmentStore1 { class DepartmentStore { long StockNumber; char Category; string ItemName;

C# 3.0 Practical Learning

80

decimal UnitPrice; }

}

2. Save the file

Accessing Class Members Private Members The parts of an object fall into two main categories: those you can touch and those you don't have access to. For example, for a car parked at the mall, you can see or touch its doors and its tires but you don't see its engine or its spare tire, you don't even know if it has one. The parts of an object that you have access to are referred to as public. Those you can't see or touch are referred to as private. A C# class also recognizes that some parts of a class can be made available to other classes and some other parts can be hidden from other classes. A part that must be hidden from other classes is private and it can be declared starting with the private keyword. If you declare a member variable and want to make it available to other classes, you must start its name with the public keyword. The public and private keywords are referred to as access level. By default, if you declare a member variable (or anything else) in a class but don't specify its access level, the member is considered private and cannot be accessed from outside, that is by a non-member, of that class. Therefore, to make a member accessible by other classes, you must declare it as public. You can use a mix of public and private members in a class and there is no rule on which access level should be listed first or last. Here are examples: public class House { string PropertyNumber; public char PropertyType; byte Stories; public uint bedrooms; private decimal Value; }

Just keep in mind that if you omit or forget the access level of a member of a class, the member is automatically made private. To reduce confusion as to what member is public or private, you should always specify the access level of a member variable. public class House { public string PropertyNumber; public char PropertyType; public byte Stories; public uint Bedrooms;

C# 3.0 Practical Learning

81

public decimal Value; }

After creating a member of a class, to access it from another class, first declare a variable from its class as we saw earlier. To actually access the member, use the period operator ".".

Internal Members We have seen that the public keyword is used to let objects of the same program and objects of other programs access the public member. The private keyword is used to let only members of a class access the (private) member of the class. If you want to create a member of a class so that only objects of the same program can access that member, you can mark it with the internal keyword. The differences between these keywords can be resumed as follows: If a class member is marked as public

private internal

Members of its class can Yes access this member

Yes

Yes

Members of this program, including outside of the Yes class, can access this member

No

Yes

Objects outside of this program can access this Yes member

No

No

Initializing an Object Introduction After declaring an instance of a class, you can access each of its members and assign it the desired value. Here is an example: using System; public class House {

C# 3.0 Practical Learning

82

}

internal internal internal internal

long PropertyNumber; string PropertyType; uint Bedrooms; double Value;

public class Exercise { static void Main() { var Property = new House();

}

Property.PropertyNumber = 283795; Property.PropertyType = "Single Family"; Property.Bedrooms = 4; Property.Value = 652880;

}

Once a member variable has been initialized, you can use the period operator to access it and retrieve its value: using System; public class { internal internal internal internal }

House long PropertyNumber; string PropertyType; uint Bedrooms; double Value;

public class Exercise { static void Main() { var Property = new House(); Property.PropertyNumber = 283795; Property.PropertyType = "Single Family"; Property.Bedrooms = 4; Property.Value = 652880; Console.WriteLine("=//= Altair Realty =//="); Console.WriteLine("Properties Inventory"); ; Console.Write("Property #: "); Console.WriteLine(Property.PropertyNumber); Console.Write("Property Type: "); Console.WriteLine(Property.PropertyType); Console.Write("Bedrooms: "); Console.WriteLine(Property.Bedrooms); Console.Write("Market Value: "); Console.WriteLine(Property.Value); }

}

This would produce: =//= Altair Realty =//= Properties Inventory

C# 3.0 Practical Learning

83

Property #: 283795 Property Type: Single Family Bedrooms: 4 Market Value: 652880 Press any key to continue . . .

Practical Learning: Using a Class' Fields 1. To make public the members of the DepartmentStore class, type the public keyword to their left: using using using using

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

namespace DepartmentStore1 { class DepartmentStore { public long StockNumber; public char Category; public string ItemName; public double UnitPrice; } }

2. To access the Program.cs file, click its tab above the Code Editor 3. Change using using using using

Main()

as

follows:

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

namespace DepartmentStore1 { class Program { static void Main(string[] args) { DepartmentStore dptStore = new DepartmentStore(); dptStore.StockNumber = 437876; dptStore.Category = 'W'; dptStore.ItemName = "Scoop Neck Dress"; dptStore.UnitPrice = 148.00D; Console.WriteLine("Department Store"); Console.Write("Stock #: "); Console.WriteLine(dptStore.StockNumber); Console.Write("Category: "); Console.WriteLine(dptStore.Category); Console.Write("Name: "); Console.WriteLine(dptStore.ItemName); Console.Write("Unit Price: ");

C# 3.0 Practical Learning

84

} }

Console.WriteLine(dptStore.UnitPrice); Console.WriteLine();

}

4. Execute the application. This would produce: Department Store Stock #: 437876 Category: W Name: Scoop Neck Dress Unit Price: 148.00 Press any key to continue . . .

5. Close the DOS window

Using an Anonymous Type We saw that, to use a class, you could first declare a variable for it and initialize it. Fortunately, you don't have to use a class to initialize an object. You can declare a variable that resembles an instance of a class and initialize it as you see fit. This is referred to as an anonymous type. To use it, declare the variable using the var keyword and use the new operator to allocate memory for it. Instead of using the name of a class, type an opening and a closing curly brackets after the new operator. In the curly brackets, state a name for each member as if it were the member of the class and initialize each member variable with the desired value. After the closing curly bracket, end the declaration with a semi-colon. Here is an example: using System; public class Exercise { static void Main() { var BookInformation = new { Title = "Calculus 6e Edition", Pages = 1074, Cover = "Hard Back" }

};

}

After initializing the anonymous type, you can access each one of its members using the name of the variable followed by the period operator, and followed by the member variable. Here is an example: using System; public class Exercise { static void Main()

C# 3.0 Practical Learning

85

{ var BookInformation = new { Title = "Calculus 6e Edition", Pages = 1074, Cover = "Hard Back" }; Console.WriteLine("=//= BookInformation =//="); Console.Write("Title: "); Console.WriteLine(BookInformation.Title); Console.Write("Nbr of Pages: "); Console.WriteLine(BookInformation.Pages); Console.Write("Type of Cover: "); Console.WriteLine(BookInformation.Cover); }

}

This would produce: =//= BookInformation =//= Title: Calculus 6e Edition Nbr of Pages: 1074 Type of Cover: Hard Back Press any key to continue . . .

Remember that spreading the declaration on many lines only makes it easy to read. Otherwise, you can as well include everything on the same line. using System; public class Exercise { static void Main() { var Book = new { Title = "Calculus 6e Edition", Pages = 1074 }; Console.WriteLine("=//= BookInformation =//="); Console.Write("Title: "); Console.WriteLine(BookInformation.Title); Console.Write("Nbr of Pages: "); Console.WriteLine(BookInformation.Pages); }

}

The Methods of a Class Introduction When you create a class, the fields are meant to describe it. For a class named House, such aspects as the number of bedrooms, the property type, or its value, are used to describe it: public class House { public char PropertyType; public uint Bedrooms;

C# 3.0 Practical Learning

86

}

Besides the characteristics used to describe it, an object can also perform actions or assignments. An action performed by a class is called a method. A method is simply a section of code that takes care of a particular detail for the functionality of the class. To create a method, you specify its name, which follows the rules we defined for variables. The name of a method is followed by parentheses. A method's job is to carry a specific assignment within a program. As such, it could provide a value once the assignment has been carried. In some cases, a method must produce a result. If it doesn't, then it is considered void. The type of value that a method can provide (or return) is written on the left side of the method name. If the method doesn't produce a result, type void to its left. The assignment that a method carries is included between an opening curly bracket "{" and a closing curly bracket "}". Here is an example: public class House { public char PropertyType; public uint Bedrooms; void Display() { }

}

The most regularly used method of a C# program is called Main. Like a member variable: •

If the method will be accessed only by members of the same class, you can mark it as private or not mark it with an access keyword



If the method will be accessed by members of the class and other parts of the same program but not outside of the program, mark it with the internal keyword



In the method can be accessed by the members of the same class, other parts of the same program, and other parts of other programs, mark it as public

After creating a method, in its body delimited by its curly brackets, you can define the desired behavior. For example, you can write the member variables in the parentheses of Console.Write() or Console.WriteLine(). Here are examples: public class House { public char PropertyType; public uint Bedrooms; internal void Display() { Console.WriteLine("=//= Altair Realty =//="); Console.WriteLine("Properties Inventory"); ; Console.Write("Property Type: "); Console.WriteLine(PropertyType);

C# 3.0 Practical Learning

87

}

Console.Write("Bedrooms: Console.WriteLine(Bedrooms);

");

}

In the same way, you can create as many methods as you want in a class. To assist you with managing the methods of a class, the Code Editor is equipped with two combo boxes.

The left combo box, called Types, displays the classes that are part of the project. The right combo box, named Members, displays the members of the class that is selected in the Types combo box:

If you select an item from the Members combo box, the caret would be displayed on its declaration in the file.

The Solution Explorer C# 3.0 Practical Learning

88

The Solution Explorer is a window that displays the file names and other items used in your project. The items of this window display in a tree. To expand a node, you can click its + button. To collapse it, click its - button. To explore an item, you can double-click it. The result depends on the item you doubleclicked. The Solution Explorer can be used to create and add a new class or a new item to the current project. It can also be used to add a another project to the current project. To perform any of these operations, you can right-click a folder node such as the name of the project and position the mouse on Add to select the desired operation:

Remember that you can also perform any of these operations from the Project category of the main menu. Besides adding new items to the project, you can also use the Solution Explorer to build the project or change its properties. If you add one or more other project(s) to the current one, one of the project must be set as the default. That project would be the first to come up when the user executes the application. By default, the first project created is set as the default. If you have more than one project, to set the default, right-click the name of the desired project in Solution Explorer and click Set As StartUp Project. The Solution Explorer also allows you to rename or delete some of the items that belong to your project.

Practical Learning: Creating the Methods of a Class 1. Access the DepartmentStore.cs file 2. To add some methods to the DepartmentStore class, change it as follows: C# 3.0 Practical Learning

89

using using using using

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

namespace DepartmentStore1 { class DepartmentStore { public long StockNumber; public char Category; public string ItemName; public double UnitPrice; public void CreateItem() { StockNumber = 792475; Category = 'M'; ItemName = "Lightweight Jacket"; UnitPrice = 185.00D; } public void ShowItem() { Console.WriteLine("Department Store"); Console.Write("Stock #: "); Console.WriteLine(StockNumber); Console.Write("Category: "); Console.WriteLine(Category); Console.Write("Name: "); Console.WriteLine(ItemName); Console.Write("Unit Price: "); Console.WriteLine(UnitPrice); Console.WriteLine(); }

}

}

3. Access using using using using

the

Program.cs

file

and

change

Main()

as

follows:

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

namespace DepartmentStore1 { class Program { static void Main(string[] args) { DepartmentStore dptStore = new DepartmentStore(); dptStore.CreateItem(); dptStore.ShowItem(); }

}

}

C# 3.0 Practical Learning

90

4. Execute the application. This would produce: Department Store Stock #: 792475 Category: M Name: Lightweight R4 Jacket Unit Price: $185.00 Press any key to continue . . .

5. Close the DOS window

Accessing a Method After creating a method, you can access it outside of its class. You do this following the same rules used to access a field, using the period operator. Unlike a field, the name of a class must be followed by parentheses. Here is an example: using System; public class House { public char PropertyType; public uint Bedrooms; internal void Display() { Console.WriteLine("=//= Altair Realty =//="); Console.WriteLine("Properties Inventory"); ; Console.Write("Property Type: "); Console.WriteLine(PropertyType); Console.Write("Bedrooms: "); Console.WriteLine(Bedrooms); } } public class Program { static void Main() { var Property= new House(); Property.PropertyType = 'S'; Property.Bedrooms = 4; Property.Display(); }

}

This would produce: =//= Altair Realty =//= Properties Inventory Property Type: S Bedrooms: 4 Press any key to continue . . .

C# 3.0 Practical Learning

91

The Static Members of a Class Static Fields Imagine you create a class called Book. To access it in the Main() method, you can declare its variable, as we have done so far. A variable you have declared of a class is also called an instance of the class. In the same way, you can declare various instances of the same class as necessary: using System; public class Book { public string public string public short public int public char }

Title; Author; YearPublished; NumberOfPages; CoverType;

public class Exercise { static void Main() { var written = new Book(); var bought = new Book(); } }

Each one of these instances gives you access to the members of the class but each instance holds the particular values of the members of its instance. Consider the results of the following program: using System; public class Book { public string Title; public string Author; public short YearPublished; public int NumberOfPages; public char CoverType; } public class Exercise { static void Main() { var First = new Book(); First.Title = "Psychology and Human Evolution"; First.Author = "Jeannot Lamm"; First.YearPublished = 1996; First.NumberOfPages = 872; First.CoverType = 'H';

C# 3.0 Practical Learning

92

Console.WriteLine("Book Characteristics"); Console.Write("Title: "); Console.WriteLine(First.Title); Console.Write("Author: "); Console.WriteLine(First.Author); Console.Write("Year: "); Console.WriteLine(First.YearPublished); Console.Write("Pages: "); Console.WriteLine(First.NumberOfPages); Console.Write("Cover: "); Console.WriteLine(First.CoverType); var Second = new Book(); Second.Title = "C# First Step"; Second.Author = "Alexandra Nyango"; Second.YearPublished = 2004; Second.NumberOfPages = 604; Second.CoverType = 'P'; Console.WriteLine("Book Characteristics"); Console.Write("Title: "); Console.WriteLine(Second.Title); Console.Write("Author: "); Console.WriteLine(Second.Author); Console.Write("Year: "); Console.WriteLine(Second.YearPublished); Console.Write("Pages: "); Console.WriteLine(Second.NumberOfPages); Console.Write("Cover: "); Console.WriteLine(Second.CoverType); Console.WriteLine(); }

}

This would produce: Book Characteristics Title: Psychology and Human Evolution Author: Jeannot Lamm Year: 1996 Pages: 872 Cover: H Book Characteristics Title: C# First Step Author: Alexandra Nyango Year: 2004 Pages: 604 Cover: P

All of the member variables and methods of classes we have used so far are referred to as instance members because, in order to access them, you must have an instance of a class declared in another class in which you want to access them. C# allows you to declare a class member and refer to it regardless of which instance of an object you are using. Such a member variable is called static. To declare a member variable of a class as static, type the static keyword on its 93 C# 3.0 Practical Learning

left. Whenever you have a static member, in order to refer to it, you must "qualify" it in the class in which you want to call it. Qualifying a member means you must specify its class. Here is an example: using System; public class Book { public static string Title; public static string Author; public short YearPublished; public int Pages; public char CoverType; } public class Exercise { static void Main() { var First = new Book(); Book.Title = "Psychology and Human Evolution"; Book.Author = "Jeannot Lamm"; First.YearPublished = 1996; First.Pages = 872; First.CoverType = 'H'; Console.WriteLine("Book Characteristics"); Console.Write("Title: "); Console.WriteLine(Book.Title); Console.Write("Author: "); Console.WriteLine(Book.Author); Console.Write("Year: "); Console.WriteLine(First.YearPublished); Console.Write("Pages: "); Console.WriteLine(First.Pages); Console.Write("Cover: "); Console.WriteLine(First.CoverType); var Second = new Book(); Book.Title = "C# First Step"; Book.Author = "Alexandra Nyango"; Second.YearPublished = 2004; Second.Pages = 604; Second.CoverType = 'P'; Console.WriteLine("Book Characteristics"); Console.Write("Title: "); Console.WriteLine(Book.Title); Console.Write("Author: "); Console.WriteLine(Book.Author); Console.Write("Year: "); Console.WriteLine(Second.YearPublished); Console.Write("Pages: "); Console.WriteLine(Second.Pages); Console.Write("Cover: "); Console.WriteLine(Second.CoverType); Console.WriteLine();

C# 3.0 Practical Learning

94

} }

Notice that when a member variable has been declared as static, you don't need an instance of the class to access that member variable outside of the class. Based on this, if you declare all members of a class as static, you don't need to declare a variable of their class in order to access them. In the following example, the Title and Author fields of the Book class are accessed from the Program class without using an instance of the Book class: using System; public class Book { public static string Title; public static string Author; } public class Exercise { static void Main() { Book.Title = "Psychology and Human Evolution"; Book.Author = "Jeannot Lamm"; Console.WriteLine("Book Characteristics"); Console.WriteLine("Title: "); Console.WriteLine(Book.Title); Console.WriteLine("Author: "); Console.WriteLine(Book.Author); Book.Title = "C# First Step"; Book.Author = "Alexandra Miles"; Console.WriteLine("Book Characteristics"); Console.WriteLine("Title: "); Console.WriteLine(Book.Title); Console.WriteLine("Author: "); Console.WriteLine(Book.Author); Console.ReadLine(); }

}

You can also declare member variables of the main class as static. If you are referring to a static member variable in the same class in which it was declared, you don't have to qualify it. Here is an example: using System; public class Exercise { static double Length; static double Width; static void Main() { Console.WriteLine("Rectangles Characteristics");

C# 3.0 Practical Learning

95

Length = 22.55; Width = 20.25; Console.WriteLine("\nRectangle 1"); Console.Write("Length: "); Console.WriteLine(Length); Console.Write("Width: "); Console.WriteLine(Width); Length = 254.04; Width = 408.62; Console.WriteLine("\nRectangle 2"); Console.Write("Length: "); Console.WriteLine(Length); Console.Write("Width: "); Console.WriteLine(Width); Console.WriteLine(); }

}

Static Methods Like a member variable, a method of a class can be defined as static. Consequently, this particular method can access any member of the class regardless of the instance if there are many instances of the class declared. To define a method as static, type the static keyword to its left. Here is an example: using System; public class Book { private static static private private static static private static public { Title Author Pages Price }

string string int double

Title; Author; Pages; Price;

void CreateBook() = = = =

"Psychology and Human Evolution"; "Jeannot Lamm"; 472; 24.95;

static public void ShowBook() { Console.WriteLine("Book Characteristics"); Console.Write("Title: "); Console.WriteLine(Book.Title); Console.Write("Author: "); Console.WriteLine(Book.Author); Console.Write("Pages: "); Console.WriteLine(Pages); Console.Write("Price: ");

C# 3.0 Practical Learning

96

Console.WriteLine(Price); }

}

public class Exercise { static void Main() { Book.CreateBook(); Book.ShowBook(); } }

This would produce: Book Characteristics Title: Psychology and Human Evolution Author: Jeannot Lamm Pages: 472 Price: 24.95

The ReadLine(), the Write(), and the WriteLine() methods of the Console class that we have used so far are examples of static methods.

Static Classes A static class: 1. Is a class whose members must be accessed without an instance of the class. In other words, the members of a static class must be accessed directly from (using the name of) the class, using the period operator 2. Is a class whose members must be created as static. In other words, you cannot add a non-static member to a static class: all members, except for constants, must be static To create a static class, precede the class keyword with the static keyword. Based on the above two rules, here is an example: using System; namespace Staticity { public static class Square { public static double Side; public static double Perimeter() { return Side * 4; }

}

public static double Area() { return Side * Side; }

public class Exercise

C# 3.0 Practical Learning

97

{ static void Main(string[] args) { Square.Side = 36.84;

} }

Console.WriteLine("Square Characteristics"); Console.Write("Side: "); Console.WriteLine(Square.Side); Console.Write("Perimeter: "); Console.WriteLine(Square.Perimeter()); Console.Write("Area: "); Console.WriteLine(Square.Area());

}

This would produce: Square Characteristics Side: 36.84 Perimeter: 147.36 Area: 1357.1856 Press any key to continue . . .

Characteristics of Members of a Class Constants Unlike C/C++, in C#, you can create a constant variable in a class. As done in Lesson 2 when studying variables, to declare a constant variable, type the const keyword to the left of the variable. Once again, when declaring a constant, you must initialize it with an appropriate constant value.

this Instance If a class contains fields and methods, the (non-static) field members are automatically available to the method(s) of the class, even fields that are private. When accessing a field or a method from another method of the class, to indicate that the member you are accessing belongs to the same class, you can precede it with the this member and the period operator. Here are examples: public class House { internal char PropertyType; internal uint Bedrooms; internal void Display() { Console.WriteLine("=//= Altair Realty =//="); Console.WriteLine("Properties Inventory"); ; Console.Write("Property Type: "); Console.WriteLine(this.PropertyType); Console.Write("Bedrooms: ");

C# 3.0 Practical Learning

98

Console.WriteLine(this.Bedrooms); }

}

When using the this member variable (in C/C++, it is a pointer), you can access any member of a class within any method of the same class. There are rules you must observe when using this: •

The this member can never be declared: it is automatically implied when you create a class



this cannot be used in a class A to access a member of class B. The

following

will

cause

an

error:

public class Exercise { static void Main() { House property = new House(); property.PropertyType = 'S'; property.Bedrooms = 4; this.property.Display(); }

} •

this cannot be used in a static method

Practical Learning: Using this 1. Access the DepartmentStore.cs file and, to use this, change the class as follows: using using using using

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

namespace DepartmentStore1 { class DepartmentStore { public long StockNumber; public char Category; public string ItemName; public double UnitPrice; public void CreateItem() { this.StockNumber = 792475; this.Category = 'M'; this.ItemName = "Lightweight Jacket"; this.UnitPrice = 185.00D; }

C# 3.0 Practical Learning

99

public void ShowItem() { Console.WriteLine("Department Store"); Console.Write("Stock #: "); Console.WriteLine(this.StockNumber); Console.Write("Category: "); Console.WriteLine(this.Category); Console.Write("Name: "); Console.WriteLine(this.ItemName); Console.Write("Unit Price: "); Console.WriteLine(this.UnitPrice); Console.WriteLine(); }

}

}

2. Execute the application to see the result 3. Close the DOS window

C# 3.0 Practical Learning

100

5 - C# AND CODE ORGANIZATION Namespaces Introduction A namespace is a section of code that is identified with a specific name. The name could be anything such as somebody's name, the name of the company's department, or a city. To create a namespace, you start with the namespace keyword followed by the name of the section. Like a class, the section that is part of a namespace starts with an opening curly bracket "{" and ends with a closing curly bracket "}". Here is an example: namespace Business { }

Between the curly brackets, you can type anything that is part of the namespace. For example, you can create a class inside of a namespace. Here is an example: namespace Business { class House { } }

Practical Learning: Creating a Namespacep> 1. Start Microsoft Visual C# 2005 and create a new Console Application named RealEstate1 2. To create a new class, in the Class View, right-click the name of the project, position the mouse on Add and click Class... 3. Change the name to House and press Enter 4. Change the class as follows: using System;

C# 3.0 Practical Learning

101

using System.Collections.Generic; using System.Linq; using System.Text; namespace RealEstate1 { public class House { public string PropertyNumber; public char PropertyType; public uint Stories; public uint Bedrooms; public float Bathrooms; public double Value; } }

5. Save the file

Accessing Members of a Namespace After creating the necessary members of a namespace, you can use the period operator to access an item that is part of the namespace. To do this, in the desired location, type the name of the namespace, followed by a period, followed by the desired member of the namespace. Here is an example: using System; namespace Business { public class House { public string PropertyNumber; public decimal Price; } } public class Exercise { static void Main() { Business.House property = new Business.House(); property.PropertyNumber = "D294FF"; property.Price = 425880; Console.WriteLine("=//= Altair Realty =//="); Console.WriteLine("Properties Inventory"); Console.Write("Property #: "); Console.WriteLine(property.PropertyNumber); Console.Write("Market Value: "); Console.WriteLine(property.Price); Console.WriteLine(); }

}

This would produce: =//= Altair Realty =//=

C# 3.0 Practical Learning

102

Properties Inventory Property #: D294FF Market Value: 425880 Press any key to continue . . .

Namespace Nesting You can create one namespace inside of another namespace. Creating a namespace inside of another is referred to as nesting the namespace. The namespace inside of another namespace is nested. To create a namespace inside of another, simply type it as you would create another namespace. Here is an example: namespace Business { public class House { public string PropertyNumber; public decimal Price; }

}

namespace Dealer { }

In the example above, the Dealer namespace is nested inside of the Business namespace. After creating the desired namespaces, nested or not, you can create the necessary class(es) inside of the desired namespace. To access anything that is included in a nested namespace, you use the period operator before calling a member of a namespace or before calling the next nested namespace. Here is an example: using System; namespace Business { public class House { public string PropertyNumber; public decimal Price; }

}

namespace Dealer { public class Car { public decimal Price; } }

public class Exercise { static void Main() { Business.House property = new Business.House();

C# 3.0 Practical Learning

103

property.PropertyNumber = "D294FF"; property.Price = 425880; Console.WriteLine("=//= Altair Realty =//="); Console.WriteLine("Properties Inventory"); Console.Write("Property #: "); Console.WriteLine(property.PropertyNumber); Console.Write("Market Value: "); Console.WriteLine(property.Price); Console.WriteLine(); Business.Dealer.Car vehicle = new Business.Dealer.Car(); vehicle.Price = 38425.50M; Console.Write("Car Value: "); Console.WriteLine(vehicle.Price); }

}

This would produce: =//= Altair Realty =//= Properties Inventory Property #: D294FF Market Value: 425880 Car Value: 38425.50 Press any key to continue . . .

In the same way, you can nest as many namespaces inside of other namespaces as you judge necessary.

The System Namespace Introduction To make programming in C# a little easier, many classes ship with it and they are created in various namespaces of the .NET Framework. Each namespace in C# is used to provide a specific set of classes. The most regularly used namespace in the C# language is called System. Inside of the System namespace is a class called Console. The Console class is used to display things on the console screen also called the DOS window. The Console class contains static methods to display information on the screen or to retrieve information from the user who types it in the DOS window. The method that is used to display text on the screen is called Write. To use the Write() method, inside of the parentheses, type the sentence between doublequotes. Here is an example: public class Exercise { static void Main() { System.Console.Write("The Wonderful World of C# Programming");

C# 3.0 Practical Learning

104

} }

Besides the Write() method, the Console class also provides another static method named WriteLine(). The difference is that, after displaying something on the screen, the Write() method keeps the caret on the same line but WriteLine() transfers the caret to the next line. We will see various examples of this behavior throughout our lessons.

Using a Namespace We saw that, to call an object or a method that is part of a namespace, you must "qualify" that method or object using the period operator. Instead of using this approach, if you already know the name of a namespace that exists or has been created in another file, you can use a special keyword to indicate that you are using a namespace that is defined somewhere. This is done with the using keyword. To do this, on top of the file (preferably), type using followed by the name of the namespace. With the using keyword, you can include as many external namespaces as necessary.

Practical Learning: Using the Keyword •

Access the Program.cs file and notice that it has a using declaration

.NET Support of Data Types Introduction In C# (unlike many other languages such as C/C++, Pascal, etc), all of the data types we have used so far are in fact complete classes. This means that they are equipped with methods. These classes are defined in the System namespace. The classes of these data types are defined as: C# Data Type

Equivalent .NET Class

C# Data Type

Equivalent . NET Class

bool

Boolean

char

Char

byte

Byte

sbyte

SByte

short

Int16

ushort

UInt16

int

Int32

uint

UInt32

long

Int64

ulong

UInt64

C# 3.0 Practical Learning

105

float

Single

decimal

Decimal

double

Double

This means that, if you don't want to use the data types we have reviewed so far, you can use the class that is defined in the System namespace. To use one of these types, type the System namespace followed by a period. Then type the equivalent class you want to use. Here is an example: class Operations {

public double Addition() { System.Double a; System.Double b; System.Double c; a = 128.76; b = 5044.52; c = a + b; return c;

}

}

Because the regular names of data types we introduced in the previous lessons are more known and familiar, we will mostly use them. Because the data types are defined as classes, they are equipped with methods. One of the methods that each one of them has is called ToString. As its name implies, it is used to convert a value to a string.

C# Language Accessories Command Line Options In Lesson 1, we saw that, to see the result of an application, you must execute it. To make this possible,, Microsoft Visual C# ships with an internal program called a compiler. A compiler is a computer program made of internal other sub-programs. One of the sub-programs, in fact probably the first, of a compiler is called a parser. A parser "scans" a file that contains (part of) the program. It checks for syntax, keywords, unknown words, and some other routines. If the parser finds a problem, which could be anything, either it stops or it continues making a list of the mistakes it found. Then it displays this list to you to fix. Sometimes it would point to the exact line where the/a problem was found. Sometimes it would point to the line where the problem showed its impact although the problem may be found somewhere else. With experience, C# 3.0 Practical Learning

106

you will know how to fix the programs or troubleshoot these problems. In this ebook, we will address as many issues as possible. If the parser doesn't find any problem, or after you have fixed the problems, it (the parser) passes its result(s) to the compiler. The compiler calls another program called a linker. If the program contains just one file, the linker considers it. If the program contains more than one file, the linker considers them. The linker gathers some of the files that the C# compiler shipped with (those files that your program needs in order to work, since your program doesn't need all possible files that C# ships with), puts them together ("links" them) with your file(s) to get your instructions in a manner that can produce a suitable result. If there is no significant problem, the compiler creates the program. This doesn't mean that everything is alright, it only means that the compiler thinks that everything is alright: it is still possible that the result may not be what you would expect. To make your life easier, all of the subprograms (parser, linker, debugger, etc) that ship with C# are grouped in one large program: the compiler. Therefore, from now on, we will use the word "compiler" to refer to the program you use to "translate" your English-based instructions into a computer-based language. The compiler that ships with the C# version we will use, that is, the compiler of the Microsoft .NET Framework is a program called csc. Like most other programs, it has the extension .exe. This csc name is not standard. This means that another C# compiler may have another name; csc.exe is just the name of the compiler we will use. The csc compiler is freely available if you download the .NET Framework from the Microsoft web site. In this book, we will create our program using Microsoft Visual C# but if you didn't have it, you would still be able to create and execute applications. To do this, at the Command Prompt, you would type csc, followed by the name of the file that contains the code with its extension. An example would be: csc Filename.cs

When you do this, an executable with the same name as the file is created. If you want, you can ask the compiler to produce an executable using the name of your choice. To do this, you would compile the project using the following formula: csc /out:NameOfExecutate.exe Filename.cs

The NameOfExecutate factor in our formula represents the name you want the executable to have. If the name you want is in one word, you can just type it. If you want a name made of various words, you can include those words in double-quotes The FileName factor is one we are familiar with.

Unsafe Code When C# was invented, one of its biggest goals was to avoid some of the difficulties of C/C++. Among them was the use of pointers. C/C++ uses pointers to refer to the area in memory where a value is located. C# highly C# 3.0 Practical Learning

107

avoids pointers and takes over memory management as opposed to letting the programmer take care of that aspect of an application. You can still use pointers in C# in extreme cases when you judge them necessary. Because the C# compiler is in charge of managing the memory used by the values of an application, pointers are said to be unsafe. If you want to use a pointer in your application, you must precede the name of every method that uses unsafe code with the unsafe keyword. Here is an example: using System; class Exercise { unsafe static void Main() { int Length = 224; int *Len = &Length; Console.Write("Length "); Console.WriteLine(Length); Console.Write("Length "); Console.WriteLine(*Len); Console.WriteLine(); Length = 804; Console.Write("Length "); Console.WriteLine(Length); Console.Write("Length "); Console.WriteLine(*Len); }

}

To compile the application, you must indicate that you are using unsafe code. To do that, use the /unsafe modifier. Here is an example: csc /unsafe Exercise.cs

To apply this option in Microsoft Visual C#, on the main menu, you can click Project -> Project Properties... In the Build section, click the Allow Unsafe Code check box:

C# 3.0 Practical Learning

108

Code Editor

Region Delimiter

Microsoft Visual C# provides various techniques to assist you with code writing and management. The characteristics include color-coded words, intuitive indentation, delimitation of sections of code, etc. Consider the following contents of the Code Editor based on what we have reviewed so far:

C# 3.0 Practical Learning

109

Notice that there are - buttons on the left side of some lines of code. These allow you to collapse a section of code if you think you don't need to see it. To do this, you can click the - button. If you click that - button, it changes into a + button. Here is an example:

C# 3.0 Practical Learning

110

The + button allows you to expand a hidden code section. This behavior of creating + and - buttons is part of the Code Editor of Microsoft Visual Studio (yes, many other programming environments use that behavior also). To create these sections, the Code Editor follows some rules. For example, it looks for the start and end of such items as directives, namespaces, classes, methods, etc. Besides, or instead of, the sections of code created by the Code Editor, if you want, you can create your own sections. To do this, start the section with #region Whatever

and end it with #endregion Whatever

When and where you start, the #region expression is required. On the right side of this expression, you can type anything you want on the line. To end the section, type #endregion, followed by anything you want. Consider the following example: using System; class House { void Create() { } } #region These are classes used for Student Registration

C# 3.0 Practical Learning

111

class Car { void Build() { } } class Student { void Register() { } } #endregion We can just stop it here class Program { static void Main() { } }

You don't have to type anything on the right side of #endregion. After creating the region, the Code Editor would display a - button to the left side of #region with a line from there to the left of #endregion:

This then allows you to expand and collapse that section at will: C# 3.0 Practical Learning

112

We mentioned that you didn't have to type anything on the right side of #endregion and you could leave it empty. In our example, notice that there is a rectangle with gray lines around the string that follows #region. This rectangle doesn't cover the string that follows #endregion. This means that if you don't type anything on the right side of #endregion, that section on the right side the #region line would not show.

C# 3.0 Practical Learning

113

6 - DATA READING AND FORMATTING Data Reading Introduction In previous lessons, we saw that the Console class allows using the Write() and the WriteLine() methods to display things on the screen. While the Console.Write() method is used to display something on the screen, the Console class provides the Read() method to get a value from the user. To use it, the name of a variable can be assigned to it. The syntax used is: VariableName = Console.Read();

This simply means that, when the user types something and presses Enter, what the user had typed would be given (the word is assigned) to the variable specified on the left side of the assignment operator.

Read() doesn't always have to assign its value to a variable. For example, it can

be used on its own line, which simply means that the user is expected to type something but the value typed by the user would not be used for any significant purpose. For example some versions of C# (even including Microsoft's C# and Borland C#Builder) would display the DOS window briefly and disappear. You can use the Read() function to wait for the user to press any key in order to close the DOS window. Besides Read(), the Console class also provides the ReadLine() method. Like the WriteLine() member function, after performing its assignment, the ReadLine() method sends the caret to the next line. Otherwise, it plays the same role as the Read() function.

Practical Learning: Introducing Data Reading •

Start Microsoft Visual C# and create a Console Application named GeorgetownCleaningServices4

String Value Request In most assignments of your programs, you will not know the value of a string when writing your application. For example, you may want the user to provide such a string. To request a string (or any of the variables we will see in this C# 3.0 Practical Learning

114

lesson), you can call the Console.Read() or the Console.ReadLine() function and assign it to the name of the variable whose value you want to retrieve. Here is an example: using System; public class Exercise { public static void Main() { string FirstName; Console.Write("Enter First Name: "); FirstName = Console.ReadLine(); }

}

Practical Learning: Reading String Values 1. To request strings from the user, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices4 { class Program { static void Main(string[] args) { string CustomerName, HomePhone; Console.WriteLine("-/- Georgetown Cleaning Services -/-"); // Request customer information from the user Console.Write("Enter Customer Name: "); CustomerName = Console.ReadLine(); Console.Write("Enter Customer Phone: "); HomePhone = Console.ReadLine(); Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.Write("Customer: "); Console.WriteLine(CustomerName); Console.Write("Home Phone: "); Console.WriteLine(HomePhone); Console.WriteLine("====================================\n"); }

}

}

C# 3.0 Practical Learning

115

2. Execute the program. This would produce: -/- Georgetown Cleaning Services -/Enter Customer Name: James Watson Enter Customer Phone: (410) 493-2005 ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: James Watson Home Phone: (410) 493-2005 ====================================

3. Close the DOS window

Number Request In C#, everything the user types is a string and the compiler would hardly analyze it without your explicit asking it to do so. Therefore, if you want to get a number from the user, first request a string. Here is an example: using System; public class Exercise { public static void Main() { int Number; string strNumber; }

strNumber = Console.ReadLine();

}

After getting the string, you must convert it to a number. To perform this conversion, each data type of the .NET Framework provides a mechanism called Parse. To use Parse(), type the data type, followed by a period, followed by Parse, and followed by parentheses. In the parentheses of Parse, type the string that you requested from the user. Here is an example: using System; public class Exercise { public static void Main() { int Number; string strNumber;

}

strNumber = Console.ReadLine(); Number = int.Parse(strNumber);

}

An advanced but faster way to do this is to type Console.ReadLine() in the parentheses of Parse. This has the same effect. Here is an example: C# 3.0 Practical Learning

116

using System; public class Exercise { public static int Main() { int Number; Number = int.Parse(Console.ReadLine()); return 0; }

}

Practical Learning: Reading Numeric Values 1. To retrieve various numbers from the user, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices4 { class Program { static void Main(string[] args) { // Price of items const double PriceOneShirt = 0.95; const double PriceAPairOfPants = 2.95; const double PriceOneDress = 4.55; const double TaxRate = 0.0575; // 5.75% // Customer personal infoirmation string CustomerName, HomePhone; // Unsigned numbers to represent cleaning items uint NumberOfShirts, NumberOfPants, NumberOfDresses; // Each of these sub totals will be used for cleaning items double SubTotalShirts, SubTotalPants, SubTotalDresses; // Values used to process an order double TotalOrder, TaxAmount, SalesTotal; double AmountTended, Difference; Console.WriteLine("-/- Georgetown Cleaning Services -/-"); // Request customer information from the user Console.Write("Enter Customer Name: "); CustomerName = Console.ReadLine(); Console.Write("Enter Customer Phone: "); HomePhone = Console.ReadLine(); // Request the quantity of each category of items Console.Write("Number of Shirts: "); string strShirts = Console.ReadLine(); NumberOfShirts = uint.Parse(strShirts); Console.Write("Number of Pants:

C# 3.0 Practical Learning

"); 117

string strPants = Console.ReadLine(); NumberOfPants = uint.Parse(strPants); Console.Write("Number of Dresses: "); string strDresses = Console.ReadLine(); NumberOfDresses = uint.Parse(strDresses); // Perform the necessary calculations SubTotalShirts = NumberOfShirts * PriceOneShirt; SubTotalPants = NumberOfPants * PriceAPairOfPants; SubTotalDresses = NumberOfDresses * PriceOneDress; // Calculate the "temporary" total of the order TotalOrder = SubTotalShirts + SubTotalPants + SubTotalDresses; // Calculate the tax amount using a constant rate TaxAmount = TotalOrder * TaxRate; // Add the tax amount to the total order SalesTotal = TotalOrder + TaxAmount; // Communicate the total to the user... Console.Write("\nThe Total order is: "); Console.WriteLine(SalesTotal); // and request money for the order Console.Write("Amount Tended? "); AmountTended = double.Parse(Console.ReadLine()); // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - SalesTotal; Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.Write("Customer: "); Console.WriteLine(CustomerName); Console.Write("Home Phone: "); Console.WriteLine(HomePhone); Console.WriteLine("------------------------------------"); Console.WriteLine("Item Type Qty Unit/Price Sub-Total"); Console.WriteLine("------------------------------------"); Console.Write("Shirts "); Console.Write(NumberOfShirts); Console.Write(" "); Console.Write(PriceOneShirt); Console.Write(" "); Console.WriteLine(SubTotalShirts); Console.Write("Pants "); Console.Write(NumberOfPants); Console.Write(" "); Console.Write(PriceAPairOfPants); Console.Write(" "); Console.WriteLine(SubTotalPants); Console.Write("Dresses "); Console.Write(NumberOfDresses); Console.Write(" "); Console.Write(PriceOneDress);

C# 3.0 Practical Learning

118

} }

Console.Write(" "); Console.WriteLine(SubTotalDresses); Console.WriteLine("------------------------------------"); Console.Write("Total Order: "); Console.WriteLine(TotalOrder); Console.Write("Tax Rate: "); Console.Write(TaxRate * 100); Console.WriteLine('%'); Console.Write("Tax Amount: "); Console.WriteLine(TaxAmount); Console.Write("Net Price: "); Console.WriteLine(SalesTotal); Console.WriteLine("------------------------------------"); Console.Write("Amount Tended: "); Console.WriteLine(AmountTended); Console.Write("Difference: "); Console.WriteLine(Difference); Console.WriteLine("====================================");

}

2. Execute the program and test it. Here is an example: -/- Georgetown Cleaning Services -/Enter Customer Name: Genevieve Alton Enter Customer Phone: (202) 974-8244 Number of Shirts: 8 Number of Pants: 2 Number of Dresses: 3 The Total order is: 28.711125 Amount Tended? 30 ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Genevieve Alton Home Phone: (202) 974-8244 -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 8 0.95 7.60 Pants 2 2.95 5.90 Dresses 3 4.55 13.65 -----------------------------------Total Order: 27.15 Tax Rate: 5.7500% Tax Amount: 1.561125 Net Price: 28.711125 -----------------------------------Amount Tended: 30 Difference: 1.288875 ====================================

3. Close the DOS window

Requesting Dates and Times C# 3.0 Practical Learning

119

As done with the regular numbers, you can request a date value from the user. This is also done by requesting a string from the user. Here is an example: using System; namespace ValueRequests { class Exercise { static void Main() { string strDateHired; strDateHired = Console.ReadLine(); }

}

}

After the user has entered the string you can then convert it to a DateTime value. Just like any value you request from the user, a date or time value that the user types must be valid, otherwise, the program would produce an error. Because dates and times follow some rules for their formats, you should strive to let the user know how you expect the value to be entered. By default, if you request only a date from the user and the user enters a valid date, the compiler would add the midnight value to the date. If you request only the time from the user and the user enters a valid time, the compiler would add the current date to the value. Later on, we will learn how to isolate either only the date or only the time.

Practical Learning: Requesting Date and Time Values 1. To deal with new dates and times, change the program as follows: using using using using

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

namespace GeorgetownCleaningServices4 { class OrderProcessing { static void Main() { // Price of items const double PriceOneShirt const double PriceAPairOfPants const double PriceOneDress const double TaxRate

= = = =

0.95; 2.95; 4.55; 0.0575;

// 5.75%

// Basic information about an order string CustomerName, HomePhone; DateTime OrderDate; // Unsigned numbers to represent cleaning items uint NumberOfShirts, NumberOfPants, NumberOfDresses; // Each of these sub totals will be used for cleaning items

C# 3.0 Practical Learning

120

double SubTotalShirts, SubTotalPants, SubTotalDresses; // Values used to process an order double TotalOrder, TaxAmount, SalesTotal; double AmountTended, Difference; Console.WriteLine("-/- Georgetown Cleaning Services -/-"); // Request order information from the user Console.Write("Enter Customer Name: "); CustomerName = Console.ReadLine(); Console.Write("Enter Customer Phone: "); HomePhone = Console.ReadLine(); Console.WriteLine("Enter the order date and " + "time (mm/dd/yyyy hh:mm AM/PM)"); OrderDate = DateTime.Parse(Console.ReadLine()); // Request the quantity of each category of items Console.Write("Number of Shirts: "); string strShirts = Console.ReadLine(); NumberOfShirts = uint.Parse(strShirts); Console.Write("Number of Pants: "); string strPants = Console.ReadLine(); NumberOfPants = uint.Parse(strPants); Console.Write("Number of Dresses: "); string strDresses = Console.ReadLine(); NumberOfDresses = uint.Parse(strDresses); // Perform the necessary calculations SubTotalShirts = NumberOfShirts * PriceOneShirt; SubTotalPants = NumberOfPants * PriceAPairOfPants; SubTotalDresses = NumberOfDresses * PriceOneDress; // Calculate the "temporary" total of the order TotalOrder = SubTotalShirts + SubTotalPants + SubTotalDresses; // Calculate the tax amount using a constant rate TaxAmount = TotalOrder * TaxRate; // Add the tax amount to the total order SalesTotal = TotalOrder + TaxAmount; // Communicate the total to the user... Console.Write("\nThe Total order is: "); Console.WriteLine(SalesTotal); // and request money for the order Console.Write("Amount Tended? "); AmountTended = double.Parse(Console.ReadLine()); // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - SalesTotal; Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.Write("Customer: "); Console.WriteLine(CustomerName);

C# 3.0 Practical Learning

121

Console.Write("Home Phone: "); Console.WriteLine(HomePhone); Console.Write("Date & Time: "); Console.WriteLine(OrderDate); Console.WriteLine("------------------------------------"); Console.WriteLine("Item Type Qty Unit/Price Sub-Total"); Console.WriteLine("------------------------------------"); Console.Write("Shirts "); Console.Write(NumberOfShirts); Console.Write(" "); Console.Write(PriceOneShirt); Console.Write(" "); Console.WriteLine(SubTotalShirts); Console.Write("Pants "); Console.Write(NumberOfPants); Console.Write(" "); Console.Write(PriceAPairOfPants); Console.Write(" "); Console.WriteLine(SubTotalPants); Console.Write("Dresses "); Console.Write(NumberOfDresses); Console.Write(" "); Console.Write(PriceOneDress); Console.Write(" "); Console.WriteLine(SubTotalDresses); Console.WriteLine("------------------------------------"); Console.Write("Total Order: "); Console.WriteLine(TotalOrder); Console.Write("Tax Rate: "); Console.Write(TaxRate * 100); Console.WriteLine('%'); Console.Write("Tax Amount: "); Console.WriteLine(TaxAmount); Console.Write("Net Price: "); Console.WriteLine(SalesTotal); Console.WriteLine("------------------------------------"); Console.Write("Amount Tended: "); Console.WriteLine(AmountTended); Console.Write("Difference: "); Console.WriteLine(Difference); Console.WriteLine("===================================="); }

}

}

2. Execute the program and test it. Here is an example: -/- Georgetown Cleaning Services -/Enter Customer Name: Alexander Pappas Enter Customer Phone: (301) 397-9764 Enter the order date and time (mm/dd/yyyy hh:mm AM/PM) 06/22/98 08:26 AM Number of Shirts: 2 Number of Pants: 6 Number of Dresses: 0 The Total order is: 20.727000 Amount Tended? 50

C# 3.0 Practical Learning

122

==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Alexander Pappas Home Phone: (301) 397-9764 Date & Time: 6/22/1998 8:26:00 AM -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 2 0.95 1.90 Pants 6 2.95 17.70 Dresses 0 4.55 0 -----------------------------------Total Order: 19.60 Tax Rate: 5.7500% Tax Amount: 1.127000 Net Price: 20.727000 -----------------------------------Amount Tended: 50 Difference: 29.273000 ====================================

3. Return to Notepad

Formatting Data Display Introduction Instead of using two Write() or a combination of Write() and WriteLine() to display data, you can convert a value to a string and display it directly. To do this, you can provide two strings to the Write() or WriteLine() and separate them with a comma: 1. The first part of the string provided to Write() or WriteLine() is the complete string that would display to the user. This first string itself can be made of different sections: a. One section is a string in any way you want it to display b. Another section is a number included between an opening curly bracket "{" and a closing curly bracket "}". This combination of "{" and "}" is referred to as a placeholder You can put the placeholder anywhere inside of the string. The first placeholder must have number 0. The second must have number 1, etc. With this technique, you can create the string anyway you like and use the placeholders anywhere inside of the string 2. The second part of the string provided to Write() or WriteLine() is the value that you want to display. It can be one value if you used only one placeholder with 0 in the first string. If you used different placeholders, you can then provide a different value for each one of them in this second part, separating the values with a comma Here are examples: C# 3.0 Practical Learning

123

using System; public class Exercise { public static void Main() { var FullName = "Anselme Bogos"; var Age = 15; var HSalary = 22.74; Console.WriteLine("Full Name: {0}", FullName); Console.WriteLine("Age: {0}", Age); Console.WriteLine("Distance: {0}", HSalary); Console.WriteLine(); }

}

This would produce: Full Name: Anselme Bogos Age: 15 Distance: 22.74

As mentioned already, the numeric value typed in the curly brackets of the first part is an ordered number. If you want to display more than one value, provide each incremental value in its curly brackets. The syntax used is: Write("To Display {0} {1} {2} {n}", First, Second, Third, nth);

You can use the sections between a closing curly bracket and an opening curly bracket to create a meaningful sentence.

Practical Learning: Displaying Data With Placeholders 1. To use curly brackets to display data, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices4 { class OrderProcessing { static void Main() { // Price of items const double PriceOneShirt const double PriceAPairOfPants const double PriceOneDress const double TaxRate

= = = =

0.95; 2.95; 4.55; 0.0575;

// 5.75%

// Basic information about an order string CustomerName, HomePhone; DateTime OrderDate; // Unsigned numbers to represent cleaning items

C# 3.0 Practical Learning

124

uint NumberOfShirts, NumberOfPants, NumberOfDresses; // Each of these sub totals will be used for cleaning items double SubTotalShirts, SubTotalPants, SubTotalDresses; // Values used to process an order double TotalOrder, TaxAmount, SalesTotal; double AmountTended, Difference; Console.WriteLine("-/- Georgetown Cleaning Services -/-"); // Request order information from the user Console.Write("Enter Customer Name: "); CustomerName = Console.ReadLine(); Console.Write("Enter Customer Phone: "); HomePhone = Console.ReadLine(); Console.WriteLine("Enter the order date and " + "time (mm/dd/yyyy hh:mm AM/PM)"); OrderDate = DateTime.Parse(Console.ReadLine()); // Request the quantity of each category of items Console.Write("Number of Shirts: "); NumberOfShirts = uint.Parse(Console.ReadLine()); Console.Write("Number of Pants: "); NumberOfPants = uint.Parse(Console.ReadLine()); Console.Write("Number of Dresses: "); NumberOfDresses = uint.Parse(Console.ReadLine()); // Perform the necessary calculations SubTotalShirts = NumberOfShirts * PriceOneShirt; SubTotalPants = NumberOfPants * PriceAPairOfPants; SubTotalDresses = NumberOfDresses * PriceOneDress; // Calculate the "temporary" total of the order TotalOrder = SubTotalShirts + SubTotalPants + SubTotalDresses; // Calculate the tax amount using a constant rate TaxAmount = TotalOrder * TaxRate; // Add the tax amount to the total order SalesTotal = TotalOrder + TaxAmount; // Communicate the total to the user... Console.Write("\nThe Total order is: "); Console.WriteLine(SalesTotal); // and request money for the order Console.Write("Amount Tended? "); AmountTended = double.Parse(Console.ReadLine()); // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - SalesTotal; Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.WriteLine("Customer: {0}", CustomerName); Console.WriteLine("Home Phone: {0}", HomePhone); Console.WriteLine("Date & Time: {0}", OrderDate);

C# 3.0 Practical Learning

125

Console.WriteLine("------------------------------------"); Console.WriteLine("Item Type Qty Unit/Price Sub-Total"); Console.WriteLine("------------------------------------"); Console.WriteLine("Shirts {0} {1} {2}", NumberOfShirts, PriceOneShirt, SubTotalShirts); Console.WriteLine("Pants {0} {1} {2}", NumberOfPants, PriceAPairOfPants, SubTotalPants); Console.WriteLine("Dresses {0} {1} {2}", NumberOfDresses, PriceOneDress, SubTotalDresses); Console.WriteLine("------------------------------------"); Console.WriteLine("Total Order: {0}", TotalOrder); Console.WriteLine("Tax Rate: {0}%", TaxRate * 100); Console.WriteLine("Tax Amount: {0}", TaxAmount); Console.WriteLine("Net Price: {0}", SalesTotal); Console.WriteLine("------------------------------------"); Console.WriteLine("Amount Tended: {0}", AmountTended); Console.WriteLine("Difference: {0}", Difference); Console.WriteLine("===================================="); }

}

}

2. Execute the program and test it 3. Close the DOS window

Conversion To String We mentioned earlier that everything the user types using the keyboard is primarily a string and it's your job to convert it to the appropriate type. In reverse, if you have a value that is not a string, you can easily convert it to a string. To support this, each .NET Framework data type provides a mechanism called ToString. Normally, in C#, as we mentioned with boxing, and as we have done so far, this conversion is automatically or transparently done by the compiler. In some cases, you will need to perform the conversion yourself. To convert a value of a primitive data type to a string, type the name of the variable, followed by a period, followed by ToString(). Here is an example: using System; public class Exercise { public static void Main() { var FullName = "Anselme Bogos"; var Age = 15; var HSalary = 22.74; Console.WriteLine("Full Name: {0}", FullName); Console.WriteLine("Age: {0}", Age.ToString()); Console.WriteLine("Distance: {0}", HSalary.ToString()); Console.WriteLine(); }

C# 3.0 Practical Learning

126

}

In some cases, you will type something in the parentheses of ToString().

Practical Learning: Converting to String 1. To convert some values to string, change the program as follows: using using using using

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

namespace GeorgetownCleaningServices4 { class OrderProcessing { static void Main() { // Price of items const double PriceOneShirt const double PriceAPairOfPants const double PriceOneDress const double TaxRate

= = = =

0.95; 2.95; 4.55; 0.0575;

// 5.75%

. . . No Change

} }

Console.WriteLine("------------------------------------"); Console.WriteLine("Shirts {0} {1} {2}", NumberOfShirts.ToString(), PriceOneShirt, SubTotalShirts.ToString()); Console.WriteLine("Pants {0} {1} {2}", NumberOfPants, PriceAPairOfPants, SubTotalPants); Console.WriteLine("Dresses {0} {1} {2}", NumberOfDresses, PriceOneDress, SubTotalDresses); Console.WriteLine("------------------------------------"); Console.WriteLine("Total Order: {0}", TotalOrder); Console.WriteLine("Tax Rate: {0}%", TaxRate * 100); Console.WriteLine("Tax Amount: {0}", TaxAmount.ToString()); Console.WriteLine("Net Price: {0}", SalesTotal); Console.WriteLine("------------------------------------"); Console.WriteLine("Amount Tended: {0}", AmountTended); Console.WriteLine("Difference: {0}", Difference); Console.WriteLine("====================================");

}

2. Execute the program and test it 3. Close the DOS window

Number Formatting C# 3.0 Practical Learning

127

To properly display data in a friendly and most familiar way, you can format it. Formatting tells the compiler what kind of data you are using and how you want the compiler to display it to the user. As it happens, you can display a natural number in a common value or, depending on the circumstance, you may prefer to show it as a hexadecimal value. When it comes to doubleprecision numbers, you may want to display a distance with three values on the right side of the decimal separator and in some cases, you may want to display a salary with only 2 decimal places. The System namespace provides a specific letter that you can use in the Write() or WriteLine()'s placeholder for each category of data to display. To format a value, in the placeholder of the variable or value, after the number, type a colon and one of the appropriate letters from the following table. If you are using ToString(), then, in the parentheses of ToString(), you can include a specific letter or combination inside of double-quotes. The letters and their meanings are: Character Used For

c

C

Currency values

d

D

Decimal numbers

e

E

Scientific numeric display such as 1.45e5

f

F

Fixed decimal numbers

g

G

General and most common type of numbers

n

N

Natural numbers

r

R

Roundtrip formatting

x

X

Hexadecimal formatting

p

P

Percentages

Here are examples: using System; public class Exercise { public static void Main() { var Distance = 248.38782;

C# 3.0 Practical Learning

128

var var var var var

Age = 15; NewColor = 3478; HSalary = 22.74; HoursWorked = 35.5018473; WeeklySalary = HSalary * HoursWorked;

Console.WriteLine("Distance: {0}", Distance.ToString("E")); Console.WriteLine("Age: {0}", Age.ToString()); Console.WriteLine("Color: {0}", NewColor.ToString("X")); Console.WriteLine("Weekly Salary: {0} for {1} hours", WeeklySalary.ToString("c"), HoursWorked.ToString("F")); }

Console.WriteLine();

}

This would produce: Distance: 2.483878E+002 Age: 15 Color: D96 Weekly Salary: $807.31 for 35.50 hours

As you may have noticed, if you leave the parentheses of ToString() empty, the compiler would use a default formatting to display the value. As opposed to calling ToString(), you can use the above letters in the curly brackets of the first part of Write() or WriteLine(). In this case, after the number in the curly brackets, type the colon operator followed by the letter.

Practical Learning: Formatting Data Display 1. To format data display, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices4 { class OrderProcessing { static void Main() { // Price of items const double PriceOneShirt const double PriceAPairOfPants const double PriceOneDress const double TaxRate

= = = =

0.95; 2.95; 4.55; 0.0575;

// 5.75%

// Basic information about an order string CustomerName, HomePhone; DateTime OrderDate; // Unsigned numbers to represent cleaning items

C# 3.0 Practical Learning

129

uint NumberOfShirts, NumberOfPants, NumberOfDresses; // Each of these sub totals will be used for cleaning items double SubTotalShirts, SubTotalPants, SubTotalDresses; // Values used to process an order double TotalOrder, TaxAmount, SalesTotal; double AmountTended, Difference; Console.WriteLine("-/- Georgetown Cleaning Services -/-"); // Request order information from the user Console.Write("Enter Customer Name: "); CustomerName = Console.ReadLine(); Console.Write("Enter Customer Phone: "); HomePhone = Console.ReadLine(); Console.WriteLine("Enter the order date and " + "time (mm/dd/yyyy hh:mm AM/PM)"); OrderDate = DateTime.Parse(Console.ReadLine()); // Request the quantity of each category of items Console.Write("Number of Shirts: "); NumberOfShirts = uint.Parse(Console.ReadLine()); Console.Write("Number of Pants: "); NumberOfPants = uint.Parse(Console.ReadLine()); Console.Write("Number of Dresses: "); NumberOfDresses = uint.Parse(Console.ReadLine()); // Perform the necessary calculations SubTotalShirts = NumberOfShirts * PriceOneShirt; SubTotalPants = NumberOfPants * PriceAPairOfPants; SubTotalDresses = NumberOfDresses * PriceOneDress; // Calculate the "temporary" total of the order TotalOrder = SubTotalShirts + SubTotalPants + SubTotalDresses; // Calculate the tax amount using a constant rate TaxAmount = TotalOrder * TaxRate; // Add the tax amount to the total order SalesTotal = TotalOrder + TaxAmount; // Communicate the total to the user... Console.Write("\nThe Total order is: "); Console.WriteLine(SalesTotal); // and request money for the order Console.Write("Amount Tended? "); AmountTended = double.Parse(Console.ReadLine()); // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - SalesTotal; Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.WriteLine("Customer: {0}", CustomerName); Console.WriteLine("Home Phone: {0}", HomePhone); Console.WriteLine("Date & Time: {0}", OrderDate); Console.WriteLine("------------------------------------");

C# 3.0 Practical Learning

130

Console.WriteLine("Item Type Qty Unit/Price Sub-Total"); Console.WriteLine("------------------------------------"); Console.WriteLine("Shirts {0} {1:C} {2}", NumberOfShirts.ToString(), PriceOneShirt, SubTotalShirts.ToString("C")); Console.WriteLine("Pants {0} {1:C} {2:C}", NumberOfPants, PriceAPairOfPants, SubTotalPants); Console.WriteLine("Dresses {0} {1:C} {2:C}", NumberOfDresses, PriceOneDress, SubTotalDresses); Console.WriteLine("------------------------------------"); Console.WriteLine("Total Order: {0:C}", TotalOrder); Console.WriteLine("Tax Rate: {0:P}", TaxRate); Console.WriteLine("Tax Amount: {0}", TaxAmount.ToString("C")); Console.WriteLine("Net Price: {0:F}", SalesTotal); Console.WriteLine("------------------------------------"); Console.WriteLine("Amount Tended: {0:C}", AmountTended); Console.WriteLine("Difference: {0:C}", Difference); Console.WriteLine("===================================="); }

}

}

2. Execute the application. Here is an example: -/- Georgetown Cleaning Services -/Enter Customer Name: Gretchen McCormack Enter Customer Phone: (410) 739-2884 Enter the order date and time (mm/dd/yyyy hh:mm AM/PM) 04/09/2001 10:25 AM Number of Shirts: 5 Number of Pants: 12 Number of Dresses: 8 The Total order is: 80.951625 Amount Tended? 100 ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Gretchen McCormack Home Phone: (410) 739-2884 Date & Time: 4/9/2001 10:25:00 AM -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 5 $0.95 $4.75 Pants 12 $2.95 $35.40 Dresses 8 $4.55 $36.40 -----------------------------------Total Order: $76.55 Tax Rate: 5.75 % Tax Amount: $4.40 Net Price: 80.95 -----------------------------------Amount Tended: $100.00 Difference: $19.05

C# 3.0 Practical Learning

131

====================================

3. Close the DOS window

Line Formatting In the above programs, to display a line of text, we easily used Write() or WriteLine(). To position text of different lengths one above the other, we had to "corrupt" a string by including extra-empty spaces. Such a technique is uncertain and less professional. Fortunately, you can highly format how a string or a line of text should display. The .NET Framework provides mechanisms to control the amount of space used to display a string of text and how to align that string on its line. To specify the amount of space used to display a string, you can use its placeholder in Write() or WriteLine(). To do this, in the placeholder, type the 0 or the incrementing number of the placer and its formatting character if necessary and if any. Then, type a comma followed by the number of characters equivalent to the desired width. Here are examples: using System; public class Exercise { public static void Main() { var FullName = "Anselme Bogos"; var Age = 15; var HSalary = 22.74; Console.WriteLine("Full Name: {0,20}", FullName); Console.WriteLine("Age:{0,14}", Age.ToString()); Console.WriteLine("Distance: {0:C,8}", HSalary.ToString()); Console.WriteLine(); }

}

This would produce: Full Name: Anselme Bogos Age: 15 Distance: 22.74

The sign you provide for the width is very important. If it is positive, the line of text is aligned to the right. This should be your preferred alignment for numeric values. If the number is negative, then the text is aligned to the left. Data and Time Formatting

As mentioned earlier, when the user enters a date value for a DateTime variable, the compiler adds a time part to the value. Fortunately, if you want to consider only the date or only the time part, you can specify this to the compiler. To support this, the DateTime data type provides a series of letters you can use to format how its value should be displayed to the user. The C# 3.0 Practical Learning

132

character is entered in the placeholder of the DateTime variable after the 0 or the incremental numeric value.

Practical Learning: Controlling Date/Time Formatting 1. To control formatting of date and time, change the file as follows: using using using using

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

namespace GeorgetownCleaningServices4 { class OrderProcessing { static void Main() { // Price of items const double PriceOneShirt const double PriceAPairOfPants const double PriceOneDress const double TaxRate

= = = =

0.95; 2.95; 4.55; 0.0575;

// 5.75%

// Basic information about an order string CustomerName, HomePhone; DateTime OrderDate, OrderTime; // Unsigned numbers to represent cleaning items uint NumberOfShirts, NumberOfPants, NumberOfDresses; // Each of these sub totals will be used for cleaning items double SubTotalShirts, SubTotalPants, SubTotalDresses; // Values used to process an order double TotalOrder, TaxAmount, SalesTotal; double AmountTended, Difference; Console.WriteLine("-/- Georgetown Cleaning Services -/-"); // Request order information from the user Console.Write("Enter Customer Name: "); CustomerName = Console.ReadLine(); Console.Write("Enter Customer Phone: "); HomePhone = Console.ReadLine(); Console.Write("Enter the order date(mm/dd/yyyy): "); OrderDate = DateTime.Parse(Console.ReadLine()); Console.Write("Enter the order time(hh:mm AM/PM): "); OrderTime = DateTime.Parse(Console.ReadLine()); // Request the quantity of each category of items Console.Write("Number of Shirts: "); NumberOfShirts = uint.Parse(Console.ReadLine()); Console.Write("Number of Pants: "); NumberOfPants = uint.Parse(Console.ReadLine()); Console.Write("Number of Dresses: "); NumberOfDresses = uint.Parse(Console.ReadLine()); // Perform the necessary calculations

C# 3.0 Practical Learning

133

SubTotalShirts = NumberOfShirts * PriceOneShirt; SubTotalPants = NumberOfPants * PriceAPairOfPants; SubTotalDresses = NumberOfDresses * PriceOneDress; // Calculate the "temporary" total of the order TotalOrder = SubTotalShirts + SubTotalPants + SubTotalDresses; // Calculate the tax amount using a constant rate TaxAmount = TotalOrder * TaxRate; // Add the tax amount to the total order SalesTotal = TotalOrder + TaxAmount; // Communicate the total to the user... Console.WriteLine("\nThe Total order is: {0:C}", SalesTotal); // and request money for the order Console.Write("Amount Tended? "); AmountTended = double.Parse(Console.ReadLine()); // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - SalesTotal; Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.WriteLine("Customer: {0}", CustomerName); Console.WriteLine("Home Phone: {0}", HomePhone); Console.WriteLine("Order Date: {0:D}", OrderDate); Console.WriteLine("Order Time: {0:t}", OrderTime); Console.WriteLine("------------------------------------"); Console.WriteLine("Item Type Qty Unit/Price Sub-Total"); Console.WriteLine("------------------------------------"); Console.WriteLine("Shirts {0} {1} {2}", NumberOfShirts.ToString(), PriceOneShirt.ToString("C"), SubTotalShirts.ToString("C")); Console.WriteLine("Pants {0} {1} {2}", NumberOfPants.ToString(), PriceAPairOfPants.ToString("C"), SubTotalPants.ToString("C")); Console.WriteLine("Dresses {0} {1} {2}", NumberOfDresses.ToString(), PriceOneDress.ToString("C"), SubTotalDresses.ToString("C")); Console.WriteLine("------------------------------------"); Console.WriteLine("Total Order: {0}", TotalOrder.ToString("C")); Console.WriteLine("Tax Rate: {0}", TaxRate.ToString("P")); Console.WriteLine("Tax Amount: {0}", TaxAmount.ToString("C")); Console.WriteLine("Net Price: {0}", SalesTotal.ToString("C")); Console.WriteLine("------------------------------------"); Console.WriteLine("Amount Tended: {0}", AmountTended.ToString("C"));

C# 3.0 Practical Learning

134

Console.WriteLine("Difference: {0}", Difference.ToString("C")); Console.WriteLine("===================================="); }

}

}

2. Execute the program. Here is an example: -/- Georgetown Cleaning Services -/Enter Customer Name: Antoinette Calhoun Enter Customer Phone: (703) 797-1135 Enter the order date(mm/dd/yyyy): 04/12/2002 Enter the order time(hh:mm AM/PM): 2:12 PM Number of Shirts: 5 Number of Pants: 2 Number of Dresses: 1 The Total order is: $16.07 Amount Tended? 20 ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Antoinette Calhoun Home Phone: (703) 797-1135 Order Date: Friday, April 12, 2002 Order Time: 2:12 PM -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 5 $0.95 $4.75 Pants 2 $2.95 $5.90 Dresses 1 $4.55 $4.55 -----------------------------------Total Order: $15.20 Tax Rate: 5.75 % Tax Amount: $0.87 Net Price: $16.07 -----------------------------------Amount Tended: $20.00 Difference: $3.93 ====================================

3. Close the DOS window

C# 3.0 Practical Learning

135

DETAILS ON THE METHODS OF A CLASS Methods and Local Variables Introduction In the body of a method, you can declare one or more variables that would be used only by the method. A variable declared in the body of a method is referred to as a local variable. The variable cannot be accessed outside of the method it belongs to. After declaring a local variable, it is made available to the method and you can use it as you see fit, for example, you can assign it a value prior to using it.

Practical Learning: Using a Method's Local Variables 1. Start Microsoft Visual C# and create a Console Application named Geometry1

2. To create a new class, on the main menu, click Project -> Add Class... 3. Set the Name to Cylinder and click Add 4. To declare and use local variables of a method, change the file as follows: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Geometry1 { public class Cylinder { public void Process() { double Radius, Height; double BaseArea, LateralArea, TotalArea; double Volume; Console.WriteLine("Enter the dimensions of the cylinder");

C# 3.0 Practical Learning

136

Console.Write("Radius: "); Radius = double.Parse(Console.ReadLine()); Console.Write("Height: "); Height = double.Parse(Console.ReadLine()); BaseArea = Radius * Radius * Math.PI; LateralArea = 2 * Math.PI * Radius * Height; TotalArea = 2 * Math.PI * Radius * (Height + Radius); Volume = Math.PI * Radius * Radius * Height; Console.WriteLine("\nCylinder Characteristics"); Console.WriteLine("Radius: {0}", Radius); Console.WriteLine("Height: {0}", Height); Console.WriteLine("Base: {0:F}", BaseArea); Console.WriteLine("Lateral: {0:F}", LateralArea); Console.WriteLine("Total: {0:F}", TotalArea); Console.WriteLine("Volume: {0:F}", Volume); }

} }

5. Access the Program.cs file and change it as follows: using using using using

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

namespace Geometry1 { public class Program { static void Main() { Cylinder cyl = new Cylinder(); cyl.Process(); Console.WriteLine(); }

} }

6. Execute the application to test it. Here is an example: Enter the dimensions of the cylinder Radius: 38.64 Height: 22.48 Cylinder Radius: Height: Base: Lateral: Total: Volume:

Characteristics 38.64 22.48 4690.55 5457.75 14838.85 105443.65

C# 3.0 Practical Learning

137

7. Close the DOS window

A Method that Returns a Value If a method has carried an assignment and must make its result available to other methods or other classes, the method must return a value and cannot be void. To declare a method that returns a value, provide its return type to the left of its name. Here is an example: using System; class Exercise { static double Operation() { }

}

static void Main() { }

After a method has performed its assignment, it must clearly demonstrate that it is returning a value. To do this, you use the return keyword followed by the value that the method is returning. The value returned must be of the same type specified as the return type of the method. Here is an example: using System; class Exercise { static double Operation() { return 24.55; }

}

static void Main() { }

A method can also return an expression, provided the expression produces a value that is conform to the return type. Here is an example: using System; class Exercise { static double Operation() { return 24.55 * 4.16; } static void Main() { } }

C# 3.0 Practical Learning

138

When a method returns a value, the compiler considers such a method as were a regular value. This means that you can use the Console.Write() or Console.WriteLine() method to display its value. To do this, simply type name of the method and its parentheses in the Console.Write() of Console.WriteLine() methods' parentheses. Here is an example:

if it the the the

using System; class Exercise { static double Operation() { return 24.55; } static void Main() { Console.WriteLine(Operation()); } }

In the same way, a method that returns a value can be assigned to a variable of the same type.

Practical Learning: Returning a Value From a Method 1. Access the Cylinder.cs file 2. To create methods that return values, change the file as follows: using using using using

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

namespace Geometry1 { class Cylinder { public double GetRadius() { double rad; Console.Write("Radius: "); rad = double.Parse(Console.ReadLine()); return rad; } public double GetHeight() { double h; Console.Write("Height: "); h = double.Parse(Console.ReadLine()); return h;

C# 3.0 Practical Learning

139

} public void Process() { double Radius, Height; double BaseArea, LateralArea, TotalArea; double Volume; Console.WriteLine("Enter the dimensions of the cylinder"); Radius = GetRadius(); Height = GetHeight(); BaseArea = Radius * Radius * Math.PI; LateralArea = 2 * Math.PI * Radius * Height; TotalArea = 2 * Math.PI * Radius * (Height + Radius); Volume = Math.PI * Radius * Radius * Height;

}

Console.WriteLine("\nCylinder Characteristics"); Console.WriteLine("Radius: {0}", Radius); Console.WriteLine("Height: {0}", Height); Console.WriteLine("Base: {0:F}", BaseArea); Console.WriteLine("Lateral: {0:F}", LateralArea); Console.WriteLine("Total: {0:F}", TotalArea); Console.WriteLine("Volume: {0:F}", Volume);

}

}

3. Execute the application. Here is an example: Enter the dimensions of the cylinder Radius: 52.08 Height: 36.44 Cylinder Radius: Height: Base: Lateral: Total: Volume:

Characteristics 52.08 36.44 8521.02 11924.20 28966.25 310506.14

4. Close the DOS window

The Main Method of an Application So far, we have used the Main() method as it is defined by default when you create an application using using New Project dialog box. This default implementation of the Main() method is of type void. Another way to implement the Main() method is to make it return an integer. The rule is the same as for any method of type int. The Main() method can return any type of integer as long as it is a valid integer. Here is an example: using System; class Exercise {

C# 3.0 Practical Learning

140

static char HaveCharacter() { return 'G'; } static int Main() { Console.Write("Character: "); Console.WriteLine(HaveCharacter()); return 244006; }

}

This would produce: Character: G Press any key to continue . . .

Methods' Arguments Introduction A method performs an assignment that completes the operations of a class. The methods we used in the previous sections relied on local variables to exchange information with other sections of the program. Sometimes, a method would need one or more values in order to carry its assignment. The particularity of such a value or such values is that another method that calls this one must supply the needed value(s). When a method needs a value to complete its assignment, such a value is called an argument. Like a variable, an argument is represented by its type of value. For example, one method may need a character while another would need a string. Yet another method may require a decimal number. This means that the method or class that calls a method is responsible for supplying the right value, even though a method may have an internal mechanism of checking the validity of such a value. The value supplied to a method is typed in the parentheses of the method and it's called an argument. In order to declare a method that takes an argument, you must specify its name and the argument between its parentheses. Because a method must specify the type of value it would need, the argument is represented by its data type and a name. Suppose you want to define a method that displays the side length of a square. Since you would have to supply the length, you can define such a method as follows: using System; public class Exercise { static void DisplaySide(double Length) { }

C# 3.0 Practical Learning

141

static int Main() { return 0; } }

In the body of the method, you may or may not use the value of the argument. Otherwise, you can manipulate the supplied value as you see fit. In this example, you can display the value of the argument as follows: using System; public class Exercise { static void DisplaySide(double Length) { Console.Write("Length: "); Console.WriteLine(Length); }

}

static int Main() { return 0; }

When calling a method that takes an argument, you must supply a value for the argument; otherwise you would receive an error. Also, you should/must supply the right value; otherwise, the method may not work as expected and it may produce an unreliable result. Here is an example: using System; public class Exercise { static void DisplaySide(double Length) { Console.Write("Length: "); Console.WriteLine(Length); } static int Main() { DisplaySide(35.55); }

return 0;

}

As mentioned already, a method that takes an argument can also declare its own local variable(s). A method can take more than one argument. When defining such a method, provide each argument with its data type and a name. The arguments are separated by a comma.

Practical Learning: Passing Arguments

C# 3.0 Practical Learning

142

1. Access the Cylinder.cs file and change it as follows: using using using using

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

namespace Geometry1 { public class Cylinder { public double GetRadius() { double rad; Console.Write("Radius: "); rad = double.Parse(Console.ReadLine()); return rad; } public double GetHeight() { double h; Console.Write("Height: "); h = double.Parse(Console.ReadLine()); return h; } public double CalculateBaseArea(double rad) { return rad * rad * Math.PI; } public double CalculateLateralArea(double rad, double hgt) { return 2 * Math.PI * rad * hgt; } public double CalculateTotalArea(double rad, double hgt) { return 2 * Math.PI * rad * (hgt + rad); } public double CalculateVolume(double rad, double hgt) { return Math.PI * rad * rad * hgt; } public void Process() { double Radius; double Height; double BaseArea; double LateralArea; double TotalArea; double Volume;

C# 3.0 Practical Learning

143

Console.WriteLine("Enter the dimensions of the cylinder"); Radius = GetRadius(); Height = GetHeight(); BaseArea = CalculateBaseArea(Radius); LateralArea = CalculateLateralArea(Radius, Height); TotalArea = CalculateTotalArea(Radius, Height); Volume = CalculateVolume(Radius, Height); Console.WriteLine("\nCylinder Characteristics"); Console.WriteLine("Radius: {0}", Radius); Console.WriteLine("Height: {0}", Height); Console.WriteLine("Base: {0:F}", BaseArea); Console.WriteLine("Lateral: {0:F}", LateralArea); Console.WriteLine("Total: {0:F}", TotalArea); Console.WriteLine("Volume: {0:F}", Volume); }

} }

2. Execute the program: Enter the dimensions of the cylinder Radius: 35.96 Height: 30.28 Cylinder Radius: Height: Base: Lateral: Total: Volume:

Characteristics 35.96 30.28 4062.46 6841.56 14966.49 123011.33

3. Close the DOS window

Techniques of Passing Arguments Passing an Argument by Value When calling a methods that takes one or more arguments, we made sure we provided the necessary value. This is because an argument is always required and the calling method must provide a valid value when calling such a method.

Passing an Argument by Reference Consider the following program: using System; public class Payroll { static void Earnings(double ThisWeek, double Salary)

C# 3.0 Practical Learning

144

{ ThisWeek = 42.50;

}

Console.WriteLine("\nIn the Earnings() function,"); Console.Write("Weekly Hours = "); Console.WriteLine(ThisWeek); Console.Write("Salary = "); Console.WriteLine(Salary); Console.Write("Weekly Salary: = "); Console.WriteLine(ThisWeek * Salary);

static int Main() { double Hours, Rate; Rate = 15.58; Hours = 26.00; Console.WriteLine("In the Main() method,"); Console.Write("\nWeekly Hours = "); Console.Write(Hours); Console.Write("\nSalary = "); Console.WriteLine(Rate); Console.Write("Weekly Salary = "); Console.WriteLine(Hours * Rate); Console.WriteLine("\nCalling the Earnings() method"); Earnings(Hours, Rate); Console.Write("\nAfter calling the Earnings() method, "); Console.WriteLine("\nin the Main() function,"); Console.Write("\nWeekly Hours = "); Console.Write(Hours); Console.Write("\nSalary = "); Console.WriteLine(Rate); Console.Write("Weekly Salary = "); Console.WriteLine(Hours * Rate);

}

Console.Write("\n"); return 0;

}

This would produce: In the Main() method, Weekly Hours Salary Weekly Salary

= 26 = 15.58 = 405.08

Calling the Earnings() method In the Earnings() function, Weekly Hours = 42.5 Salary = 15.58 Weekly Salary: = 662.15

C# 3.0 Practical Learning

145

After calling the Earnings() method, in the Main() function, Weekly Hours Salary Weekly Salary

= 26 = 15.58 = 405.08

Press any key to continue

Notice that the weekly hours and salary values are the same before and after calling the Earnings() method. When you declare a variable in a program, the compiler reserves an amount of space for that variable. If you need to use that variable somewhere in your program, you call it and make use of its value. There are two major issues related to a variable: its value and its location in the memory. The location of a variable in memory is referred to as its address. If you supply the argument using its name, the compiler only makes a copy of the argument’s value and gives it to the calling method. Although the calling method receives the argument’s value and can use it in any way, it cannot (permanently) alter it. C# allows a calling method to modify the value of a passed argument if you find it necessary. If you want the calling method to modify the value of a supplied argument and return the modified value, you should pass the argument using its reference. To pass an argument as a reference, when defining and when calling the method, precede the argument's data type with the ref keyword. You can pass 0, one, or more arguments as reference in the program or pass all arguments as reference. The decision as to which argument(s) should be passed by value or by reference is based on whether or not you want the called method to modify the argument and permanently change its value. Another option consists of passing an argument using the out keyword. Here is an example: using System; class Exercise { static void Initializer(out double n) { n = 128.44; } public static int Main() { double Number = 15.25; Console.WriteLine("Number = {0}", Number); return 0; }

}

If you pass an argument with out, any modification made on the argument would be kept when the method ends. When calling a method that takes an out argument, precede the argument with the out keyword. Here is an example: C# 3.0 Practical Learning

146

using System; class Exercise { static void Initializer(out double n) { n = 128.44; } public static int Main() { double Number = 15.25; Console.WriteLine("Number = {0}", Number); Initializer(out Number); Console.WriteLine("Number = {0}", Number); return 0; }

}

This would produce: Number = 15.25 Number = 128.44

Practical Learning: Passing Arguments By Reference 1. To pass arguments by reference, change the Cylinder.cs file as follows: using using using using

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

namespace Geometry1 { class Cylinder { public void GetRadius(ref double rad) { Console.Write("Radius: "); rad = double.Parse(Console.ReadLine()); } public void GetHeight(out double h) { Console.Write("Height: "); h = double.Parse(Console.ReadLine()); } public double CalculateBaseArea(double rad) { return rad * rad * Math.PI; } public double CalculateLateralArea(double rad, double hgt) { return 2 * Math.PI * rad * hgt;

C# 3.0 Practical Learning

147

} public double CalculateTotalArea(double rad, double hgt) { return 2 * Math.PI * rad * (hgt + rad); } public double CalculateVolume(double rad, double hgt) { return Math.PI * rad * rad * hgt; } public void Process() { double Radius = 0.00; double Height = 0.00; double BaseArea; double LateralArea; double TotalArea; double Volume; Console.WriteLine("Enter the dimensions of the cylinder"); GetRadius(ref Radius); GetHeight(out Height); BaseArea = CalculateBaseArea(Radius); LateralArea = CalculateLateralArea(Radius, Height); TotalArea = CalculateTotalArea(Radius, Height); Volume = CalculateVolume(Radius, Height); Console.WriteLine("\nCylinder Characteristics"); Console.WriteLine("Radius: {0}", Radius); Console.WriteLine("Height: {0}", Height); Console.WriteLine("Base: {0:F}", BaseArea); Console.WriteLine("Lateral: {0:F}", LateralArea); Console.WriteLine("Total: {0:F}", TotalArea); Console.WriteLine("Volume: {0:F}", Volume); }

} }

2. Execute the application to test it. Here is an example: Enter the dimensions of the cylinder Radius: 24.55 Height: 20.85 Cylinder Radius: Height: Base: Lateral: Total: Volume:

Characteristics 24.55 20.85 1893.45 3216.16 7003.05 39478.34

3. Close the DOS window

Method Overloading C# 3.0 Practical Learning

148

A typical program involves a great deal of names that represent variables and methods of various kinds. The compiler does not allow two variables to have the same name in the same method. Although two methods should have unique names in the same program, a class can have different methods with the same name if you follow some rules. The ability to have various methods with the same name in the same program is referred to as method overloading. To perform overloading, the methods must have different numbers or different type(s) of arguments. The moment of inertia is the ability of a beam to resist bending. It is calculated with regard to the cross section of the beam. Because it depends on the type of section of the beam, its calculation also depends on the type of section of the beam. In this exercise, we will review different formulas used to calculate the moment of inertia. Since this exercise is for demonstration purposes, you do not need to be a Science Engineering major to understand it.

Practical Learning: Overloading a Method 1. Create

a

new

Console

Application

named

MomentOfInertia1

2. Change the file as follows: using using using using

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

public class Exercise { // Rectangle static double MomentOfInertia(double b, double h) { return b * h * h * h / 3; } static int Main() { double Base, Height; Console.WriteLine("Enter the dimensions of the Rectangle"); Console.Write("Base: ");

C# 3.0 Practical Learning

149

Base = double.Parse(Console.ReadLine()); Console.Write("Height: "); Height = double.Parse(Console.ReadLine()); Console.WriteLine("\nMoment of inertia with " + "regard to the X axis: "); Console.WriteLine("I = {0}mm", MomentOfInertia(Base, Height)); Console.WriteLine(); return 0; }

}

3. Execute the application. Here is an example of running the program: Enter the dimensions of the Rectangle Base: 2.44 Height: 3.58 Moment of inertia with regard to the X axis: I = 37.3179390933333mm

4. Close the DOS window 5. A circle, and thus a semi-circle, requires only a radius. Since the other version of the MomentOfInertia() function requires two arguments, we can overload it by providing only one argument, the radius. To overload the above MomentOfInertia() method, type the following in the file:

using using using using

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

public class Exercise { // Rectangle static double MomentOfInertia(double b, double h) { return b * h * h * h / 3; } // Semi-Circle static double MomentOfInertia(double R) { const double PI = 3.14159; return R * R * R * R * PI/ 8; }

C# 3.0 Practical Learning

150

static int Main() { double Base, Height; double Radius; Console.WriteLine("Enter the dimensions of the Rectangle"); Console.Write("Base: "); Base = double.Parse(Console.ReadLine()); Console.Write("Height: "); Height = double.Parse(Console.ReadLine()); Console.WriteLine("\nMoment of inertia with regard to the X axis: ");

Console.WriteLine("I = {0}mm", MomentOfInertia(Base, Height)); Console.Write("\nEnter the radius: "); Radius = double.Parse(Console.ReadLine()); Console.WriteLine("Moment of inertia of a semi-circle " + "with regard to the X axis: "); Console.WriteLine("I = {0}mm", MomentOfInertia(Radius)); Console.WriteLine(); return 0;

}

}

6. Execute the program. Here is an example: Enter the dimensions of the Rectangle Base: 4.25 Height: 2.55 Moment of inertia with regard to the X axis: I = 23.49028125mm Enter the radius: 5.35 Moment of inertia of a semi-circle with regard to the X axis: I = 321.717471644992mm

7. Close the DOS window 8. Here are the formulas considered for a triangle:

9. As you can see, the rectangle and the triangle are using the same dimension types. This means that we can provide only the same kinds of arguments, the base and the height, to calculate the moment of inertia. C# 3.0 Practical Learning

151

This also means that the compiler will not allow us to write two methods that have the same name, the same number of arguments, and the same types of arguments because that would violate the rule of function overloading. 10. In order to overload the MomentOfInertia() function, we will add an argument that will never be used; this argument will serve only as a “witness” to set the difference between both versions of the function. This “witness” argument can be anything: an integer, a character, a string, a float, etc. For our example, we will make it a simple integer. To use the version applied to the triangle, we will provide this argument to overload the MomentOfInertia() function. When called with only two arguments, the rectangle version will apply. Change the file as follows: using using using using

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

public class Exercise { // Rectangle static double MomentOfInertia(double b, double h) { return b * h * h * h / 3; } // Semi-Circle static double MomentOfInertia(double R) { const double PI = 3.14159; }

return R * R * R * R * PI/ 8;

// Triangle static double MomentOfInertia(double b, double h, int i) { return b * h * h * h / 12; } static int Main() { double Base = 7.74, Height = 14.38, Radius = 12.42; Console.WriteLine( "Rectangle - Moment of inertia with regard to the X axis: "); Console.WriteLine("I = {0}mm", MomentOfInertia(Base, Height)); Console.WriteLine("\nSemi-Circle - Moment of inertia of a " + "semi-circle with regard to the X axis: "); Console.WriteLine("I = {0}mm", MomentOfInertia(Radius)); Console.WriteLine("\nEnter the dimensions of the triangle"); Console.Write("Base: "); Base = double.Parse(Console.ReadLine());

C# 3.0 Practical Learning

152

Console.Write("Height: "); Height = double.Parse(Console.ReadLine()); Console.WriteLine( "\nTriangle - Moment of inertia with regard to the X axis: "); Console.WriteLine("I = {0}mm", MomentOfInertia(Base, Height, 1)); Console.WriteLine(); return 0; }

}

11.

Execute the program. Here is an example:

Rectangle - Moment of inertia with regard to the X axis: I = 7671.78395376mm Semi-Circle - Moment of inertia of a semi-circle with regard to the X axis: I = 9344.28126291881mm Enter the dimensions of the triangle Base: 5.52 Height: 3.84 Triangle - Moment of inertia with regard to the X axis: I = 26.04662784mm

12.

Close the DOS window

Class Construction and Destruction Method Initializer Imagine you are writing a program for a business that sells flowers:

Flower

Type

Daisies

Lilies

Roses

Live Plants

Color

White

Mixed

Red

Green

Pink

Vase

Bouquet

Basket

Vase

Arrangement Vase

C# 3.0 Practical Learning

Orchids

153

Price

37.15

29.95

85.95

60.95

55.95

Consider the following program: using System; public class Flower { public int Type; public int Color;

}

public char Arrangement; public double UnitPrice;

public class Exercise { static int Main() { var flr = new Flower();

}

Console.WriteLine("Flower Type: Console.WriteLine("Flower Color: Console.WriteLine("Arrangement: Console.WriteLine("Price: Console.WriteLine(""); return 0;

{0}", flr.Type); {0}", flr.Color); {0}", flr.Arrangement); {0:C}", flr.UnitPrice);

}

This would produce: Flower Type: 0 Flower Color: 0 Arrangement: Price: $0.00 Press any key to continue . . .

If you declare a variable of a class in your program, when the program comes up, the compiler reserves enough memory space for each member of the class. The memory space reserved for each member variable is filled with an initial value based on its type. For a string object, the space would be left empty. For an integer type, the space would be filled with 0. A better way to take care of this type is to provide a value whose role would be to initialize the member variables with the values of your choice. A method that initializes an object can return any value but it is preferable to be of type void because its primary purpose is to reset the values. Since this method would give a starting value to all member variables that need to be initialized, it should have an equivalent argument for each of the member variables that it would initialize. Here is an example: public class Flower { public int Type; public int Color;

C# 3.0 Practical Learning

154

public char Arrangement; public double UnitPrice;

}

public void Initializer(int tp, int clr, char arng, double price) { }

The method initializer does not have to initialize all members of the class. For example, the previous execution of the program shows that the member variables that are of type string are initialized with empty strings. In such a case, you may not have to initialize such variables. To implement a method initializer, simply assign its argument to the corresponding member variable of the class. Here are examples: public class Flower { public int Type; public int Color; public char Arrangement; public double UnitPrice;

}

public void Initializer(int tp, int clr, char arng, double price) { Type = tp; Color = clr; Arrangement = arng; UnitPrice = price; }

You can call a method initializer after declaring the instance of the class to give it initial values. Here is an example: using System; public class Flower { public int Type; public int Color; public char Arrangement; public double UnitPrice; public void Initializer(int tp, int clr, char arng, double price) { Type = tp; Color = clr; Arrangement = arng; UnitPrice = price; } } public class Exercise { static int Main() { var flr = new Flower(); flr.Initializer(3, 7, 'V', 37.15D);

C# 3.0 Practical Learning

155

Console.WriteLine("Flower Type: Console.WriteLine("Flower Color: Console.WriteLine("Arrangement: flr.Arrangement); Console.WriteLine("Price: flr.UnitPrice); Console.WriteLine(""); return 0; } }

{0}", flr.Type); {0}", flr.Color); {0}", {0:C}",

This would produce: Flower Type: Flower Color: Arrangement: Price:

3 7 V $37.15

Press any key to continue . . .

Using a method initializer, after initializing the object, you can use the values it holds as you see fit.

Default Constructor A constructor is a special method that is created when the object comes to life. This particular method holds the same name as the class and it initializes the object whenever that object is created. When you create a class, if you don't declare a constructor, the compiler creates one for you; this is useful because it lets all other objects of the program know that the object exists. This compilercreated constructor is called the default constructor. If you want, you can create your own constructor. To create a constructor, declare a method that holds the same name as the class. Remember that the method must not return any value. Here is an example: namespace FlowerShop { public class Flower { Flower() { } } }

When you declare an instance of the class, whether you use that object or not, a constructor for the object is created. When an instance of a class has been declared, the default constructor is called, whether the object is used or not. This is illustrated in the following program: using System; namespace FlowerShop {

C# 3.0 Practical Learning

156

public class Flower { public int Type; public int Color; public char Arrangement; public decimal UnitPrice; public Flower() { Console.WriteLine("New Flower Order"); } } public class Exercise { static int Main() { var flr = new Flower(); return 0; } } }

This would produce: New Flower Order Press any key to continue...

As you can see, even though the flr variable was not used, just its declaration was enough to signal it. You might find it sometimes convenient to create your own constructor because, whether you create an empty constructor or not, this does not negatively impact your program.

The Constructor Initializer A constructor can be used to initialize the member variables of a class. As such, a constructor provides a valuable alternative to a method initializer, the type of method we saw earlier. To use a constructor to initialize the member variables of a class, provide as arguments the necessary variables that you intend to initialize. You don't have to initialize all member variables in the constructor, only those that need to be initialized. In fact, you should initialize only those members that you think the other objects would need when using this object. This means that your object may have fields that, either the external objects don't need to modify (or access) or the member variable(s) will be initialized later when called from the needed object(s). To implement a default constructor, you can just initialize the desired members of the class. For a member variable of a numeric type, you can just assign the desired constant to each. If the variable is a character, assign a single-quoted symbol to it. If the variable is a string, then assign a double-quoted value to the variable. Here are examples: using System; namespace FlowerShop {

C# 3.0 Practical Learning

157

public class Flower { public int Type; public int Color; public char Arrangement; public decimal UnitPrice;

}

public Flower() { Type Color Arrangement UnitPrice }

= = = =

1; 1; 'V'; 0M;

public class Program { static int Main() { var flr = new Flower();

} }

Console.WriteLine("Flower Type: {0}", flr.Type); Console.WriteLine("Flower Color: {0}", flr.Color); Console.WriteLine("Arrangement: {0}", flr.Arrangement); Console.WriteLine("Price: {0:C}", flr.UnitPrice); Console.WriteLine(""); return 0;

}

Constructor Overloading The default constructor is the favorite place to provide default values to the members of a class. Besides the default constructor, you can add as many constructors as you judge necessary. This feature of C# allows you to create various constructors for different reasons. This also means that the methods or constructors of a class can be overloaded. One of the rules of method overloading consists of having methods with different types of arguments. The most basic constructor you would create can use a single argument. When implementing a constructor that takes one argument, you should initialize the member that corresponds to the unique argument and initialize the other members with default values. Here is an example: using System; namespace FlowerShop

C# 3.0 Practical Learning

158

{ public class Flower { public int Type; public int Color; public char Arrangement; public decimal UnitPrice; public Flower() { Type Color Arrangement UnitPrice }

= = = =

public Flower(int { Type = Color = Arrangement = UnitPrice = } }

1; 1; 'V'; 0M; tp) tp; 1; 'V'; 0M;

}

If you create a class with only one constructor as in the current example, when declaring an instance of the class, you must use that constructor: you cannot use the default constructor that doesn't take an argument. When declaring the variable, initialize it with a constructor with parentheses and provide the value(s) in the parentheses of the constructor. Here is an example: using System; namespace FlowerShop { public class Flower { public string Type; public string Color; public string Arrangement; public double UnitPrice; public Flower() { Type Color Arrangement UnitPrice }

}

= = = =

""; "Red"; "Basket"; 35.95D;

public Flower(string tp) { Type = tp; Color = "Red"; Arrangement = "Basket"; UnitPrice = 35.95D;

}

C# 3.0 Practical Learning

159

public class Exercise { static int Main() { var flr = new Flower("Tulips");

}

Console.WriteLine("Flower Type: Console.WriteLine("Flower Color: Console.WriteLine("Arrangement: Console.WriteLine("Price: Console.WriteLine(""); return 0;

{0}", flr.Type); {0}", flr.Color); {0}", flr.Arrangement); {0:C}", flr.UnitPrice);

}

}

This would produce: Flower Type: Flower Color: Arrangement: Price:

Tulips Red Basket $35.95

Press any key to continue . . .

In the same way, you can create different constructors for different initializations, although it would not be realistic to create a different constructor for each variable. If you create different constructors with different arguments to initialize (remember the rules of method overloading), when declaring the classes, make sure you initialize each instance with the right number of arguments; otherwise, the compiler would complain. If you create a class with only one constructor and that constructor has at least one argument, the default constructor would not be available anymore. If you want to access a default constructor of an object, you have two alternatives: •

If you don't create any constructor at all on a class, the default constructor would always be available whenever you invoke that class



If you create at least one constructor on a class and supply at least one argument to that constructor, you must explicitly create a default constructor for your class.

The Destructor of a Class As opposed to a constructor, a destructor is called when a program has finished using an object. A destructor does the cleaning behind the scenes. Like the default constructor, the compiler always creates a default destructor if you don't create one. Unlike the constructor, the destructor cannot be overloaded. This means that, if you decide to create a destructor, you can have only one. Like the default constructor, a destructor also has the same name as its class. This time, the name of the destructor starts with a tilde "~". To create a destructor, type ~ followed by the name of the class. Here is an example:

C# 3.0 Practical Learning

160

namespace FlowerShop { public class Flower { public string Type; public string Color; public string Arrangement; public decimal UnitPrice; public Flower() { Type = ""; Color = "Red"; Arrangement = "Basket"; UnitPrice = 35.95M; } public Flower(string tp) { Type = tp; Color = "Red"; Arrangement = "Basket"; UnitPrice = 35.95M; } ~Flower() { } }

}

C# 3.0 Practical Learning

161

COMBINATIONS OF CLASSES Classes

Combinations

Class Nesting A class can be created inside of another class. A class created inside of another is referred to as nested. To nest a class, simply create it as you would any other. Here is an example of a class called Inside that is nested in a class called Outside: public class Outside { public class Inside { } }

In the same way, you can nest as many classes as you wish in another class and you can nest as many classes inside of other nested classes if you judge it necessary. Just as you would manage any other class so can you exercise control on a nested class. For example, you can declare all necessary fields, properties, or methods in the nested class or in the nesting class. When you create one class inside of another, there is no special programmatic relationship between both classes: just because a class is nested does not mean that the nested class has immediate access to the members of the nesting class. They are two different classes and they can be used separately as you judge it necessary. The name of a nested class is not "visible" outside of the nesting class. To access a nested class outside of the nesting class, you must qualify the name of the nested class anywhere you want to use it. For example, if you want to declare an Inside variable somewhere in the program but outside of Outside, you must qualify its name. Here is an example: using System; public class Outside { public class Inside { public Inside() {

C# 3.0 Practical Learning

162

Console.WriteLine(" -= Inside =-"); }

}

}

public Outside() { Console.WriteLine(" =- Outside -="); }

public class Exercise { static int Main() { Outside Recto = new Outside(); Outside.Inside Ins = new Outside.Inside(); }

return 0;

}

This would produce: =- Outside -= -= Inside =-

Because there is no programmatically privileged relationship between a nested class and its "container" class, if you want to access the nested class in the nesting class, you can use its static members. In other words, if you want, you can declare static all members of the nested class that you want to access in the nesting class. Here is an example: using System; public class Outside { public class Inside { public static string InMessage; public Inside() { Console.WriteLine(" -= Insider =-"); InMessage = "Sitting inside while it's raining"; } public static void Show() { Console.WriteLine("Show me the wonderful world of C# Programming"); } } public Outside() { Console.WriteLine(" =- The Parent -="); } public void Display() {

C# 3.0 Practical Learning

163

}

Console.WriteLine(Inside.InMessage); Inside.Show();

} class Exercise { static int Main() { Outside Recto = new Outside(); Outside.Inside Ins = new Outside.Inside();

}

Recto.Display(); return 0;

}

In the same way, if you want to access the nesting class in the nested class, you can go through the static members of the nesting class. To do this, you can declare static all members of the nesting class that you want to access in the nested class. Here is an example: using System; public class Outside { public class Inside { public static string InMessage; public Inside() { Console.WriteLine(" -= Insider =-"); InMessage = "Sitting inside while it's raining"; } public static void Show() { Console.WriteLine("Show me the wonderful world of C# Programming"); }

}

public void FieldFromOutside() { Console.WriteLine(Outside.OutMessage); }

private static string OutMessage; public Outside() { Console.WriteLine(" =- The Parent -="); OutMessage = "Standing outside! It's cold and raining!!"; } public void Display() { Console.WriteLine(Inside.InMessage); Inside.Show();

C# 3.0 Practical Learning

164

} } public class Exercise { static int Main() { Outside Recto = new Outside(); Outside.Inside Ins = new Outside.Inside();

}

Recto.Display(); Console.WriteLine(); Ins.FieldFromOutside(); return 0;

}

This would produce: =- The Parent -= -= Insider =Sitting inside while it's raining Show me the wonderful world of C# Programming Standing outside! It's cold and raining!!

Instead of static members, if you want to access members of a nested class in the nesting class, you can first declare a variable of the nested class in the nesting class. In the same way, if you want to access members of a nesting class in the nested class, you can first declare a variable of the nesting class in the nested class. Here is an example: using System; public class Outside { // A member of the nesting class private string OutMessage; // The nested class public class Inside { // A field in the nested class public string InMessage;

raining";

// A constructor of the nested class public Inside() { Console.WriteLine(" -= Insider =-"); this.InMessage = "Sitting inside while it's } // A method of the nested class public void Show() { // Declare a variable to access the nesting class Outside outsider = new Outside(); Console.WriteLine(outsider.OutMessage); }

C# 3.0 Practical Learning

165

} // End of the nested class // A constructor of the nesting class public Outside() { this.OutMessage = "Standing outside! It's cold and raining!!"; Console.WriteLine(" =- The Parent -="); } // A method of the nesting class public void Display() { Console.WriteLine(insider.InMessage); } // Declare a variable to access the nested class Inside insider = new Inside(); } public class Exercise { static int Main() { Outside Recto = new Outside(); Outside.Inside Ins = new Outside.Inside(); Ins.Show(); Recto.Display(); return 0; }

}

This would produce: -= Insider ==- The Parent -= -= Insider =-= Insider ==- The Parent -= Standing outside! It's cold and raining!! Sitting inside while it's raining

A Class as a Field Just like any of the variables we have used so far, you can make a class or a structure a member variable of another class. To use a class in your own class, of course you must have that class. You can use one of the classes already available in C# or you can first create your own class. Here is an example of a class: public class Point { internal short x; internal short y; }

C# 3.0 Practical Learning

166

A field is a member variable created from another class instead of a primitive type. To use one class as a member variable of another class, simply declare its variable as you would proceed with any of the member variables we have declared so far. Here is an example: public class Point { internal short x; internal short y; } public class CoordinateSystem { public Point Start; }

After a class has been declared as a member variable of another class, it can be used regularly. Because the member is a class, declared as a reference, there are some rules you must follow to use it. After declaring the member variable, you must make sure you have allocated memory for it. You must also make sure that the variable is initialized appropriately before it can be used; otherwise you would receive an error when compiling the program.

Practical Learning: Using a Class as a Field 1. Start a new Console Application and name it ElectonicStore1 2. To create a new class, in the Solution Explorer, right-click the name of the project, position the mouse on Add and click Class... 3. Set the Name to StoreItem and click Add 4. Complete the file as follows: using using using using

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

namespace ElectronicStore1 { public class StoreItem { private long nbr; private char cat; private string mk; private string mdl; private double price; public long GetItemNumber() { return nbr; } public void SetItemNumber(long number) { this.nbr = number;

C# 3.0 Practical Learning

167

} public char GetCategory() { return cat; } public void SetCategory(char category) { this.cat = category; } public string GetMake() { return mk; } public void SetMake(string make) { this.mk = make; } public string GetModel() { return mdl; } public void SetModel(string model) { this.mdl = model; } public double GetUnitPrice() { return price; } public void SetUnitPrice(double unitPrice) { this.price = unitPrice; } }

}

5. Access the Program.cs file and change it as follows: using using using using

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

namespace ElectronicStore1 { class Program { static void Main() { string strTitle1 = "=-= Nearson Electonics =-=\n"; string strTitle2 = "******* Store Items ******";

C# 3.0 Practical Learning

168

} }

Console.WriteLine();

}

6. Save all

Returning a Class or Passing a Class Returning a Class From a Method Like a value from a regular type, you can return a class value from a method of a class. To do this, you can first declare the method and specify the class as the return type. Here is an example: public class Point { internal short x; internal short y; } public class CoordinateSystem { private Point Start; private Point End; public Point GetThePoint() { } }

After implementing the method, you must return a value that is conform to the class, otherwise you would receive an error when compiling the application. You can proceed by declaring a variable of the class in the body of the method, initializing the variable, and then returning it. Here is an example: public class Point { internal short x; internal short y; } public class CoordinateSystem { private Point Start; private Point End; public Point GetThePoint() { Point pt = new Point(); Console.Write("Enter the x coordinate of the point: "); pt.x = short.Parse(Console.ReadLine()); Console.Write("Enter the y coordinate of the point: "); pt.y = short.Parse(Console.ReadLine());

C# 3.0 Practical Learning

169

return pt; }

}

Once a method has returned a value of a class, the value can be used as normally as possible.

Passing a Class as Argument Once a class has been created, it can be used like any other variable. For example, its variable can be passed as argument to a method of another class. When a class is passed as argument, its public members are available to the method that uses it. As done for the arguments of primitive types, you can pass more than one class as argument to a method. Here are different examples: using System; namespace Geometry { public class Point { internal short x; internal short y; } public class CoordinateSystem { public Point Start; public Point End; public Point GetThePoint() { Point pt = new Point(); Console.Write("Enter the x coordinate of the point: "); pt.x = short.Parse(Console.ReadLine()); Console.Write("Enter the y coordinate of the point: "); pt.y = short.Parse(Console.ReadLine()); return pt; } public double DistanceFromOrigin(Point pt) { double sqr1 = Math.Pow(pt.x, 2); double sqr2 = Math.Pow(pt.y, 2); double distance = Math.Sqrt(sqr1 + sqr2); return distance; }

}

public double DistanceBetween2Points(Point pt1, Point pt2) { double sqr1 = Math.Pow(pt2.x - pt1.x, 2); double sqr2 = Math.Pow(pt2.y - pt1.y, 2); double distance = Math.Sqrt(sqr1 + sqr2); return distance; }

C# 3.0 Practical Learning

170

public class Program { private static CoordinateSystem IdentifyCoordinates() { CoordinateSystem coord = new CoordinateSystem(); Console.WriteLine("Start Point"); coord.Start = coord.GetThePoint(); Console.WriteLine("End Point"); coord.End = coord.GetThePoint(); return coord; } private static void Show(CoordinateSystem c) { Console.WriteLine("Coordinate System"); Console.WriteLine("Starting Point: P({0}, {1})", c.Start.x, c.Start.y); Console.WriteLine("Ending Point: Q({0}, {1})", c.End.x, c.End.y); Console.WriteLine("Distance Between Both Points: {0:F}", c.DistanceBetween2Points(c.Start, c.End)); } static int Main() { CoordinateSystem coord = IdentifyCoordinates(); Console.WriteLine(); Show(coord); return 0; }

}

}

Here is an example of running the program: Start Point Enter the x Enter the y End Point Enter the x Enter the y

coordinate of the point: -2 coordinate of the point: 2 coordinate of the point: 3 coordinate of the point: -6

Coordinate System Starting Point: P(-2, 2) Ending Point: Q(3, -6) Distance Between Both Points: 9.43 Press any key to continue . . .

Because classes are always used as references, when passing a class as argument, it is implied to be passed by reference. To reinforce this, you can type the ref keyword to the left of the argument. Here is an example: using System; namespace ConsoleApplication1 {

C# 3.0 Practical Learning

171

public class Point { internal short x; internal short y; } public class CoordinateSystem { public Point Start; public Point End; public Point GetThePoint() { Point pt = new Point();

}

Console.Write("Enter the x coordinate of the point: "); pt.x = short.Parse(Console.ReadLine()); Console.Write("Enter the y coordinate of the point: "); pt.y = short.Parse(Console.ReadLine()); return pt;

public double DistanceFromOrigin(ref Point pt) { double sqr1 = Math.Pow(pt.x, 2); double sqr2 = Math.Pow(pt.y, 2); double distance = Math.Sqrt(sqr1 + sqr2); return distance; } public double DistanceBetween2Points(ref Point pt1, ref Point pt2)

{ double double double return }

sqr1 = Math.Pow(pt2.x - pt1.x, 2); sqr2 = Math.Pow(pt2.y - pt1.y, 2); distance = Math.Sqrt(sqr1 + sqr2); distance;

}

public class Program { private static CoordinateSystem IdentifyCoordinates() { CoordinateSystem coord = new CoordinateSystem(); Console.WriteLine("Start Point"); coord.Start = coord.GetThePoint(); Console.WriteLine("End Point"); coord.End = coord.GetThePoint(); }

return coord;

private static void Show(CoordinateSystem c) { Console.WriteLine("Coordinate System"); Console.WriteLine("Starting Point: P({0}, {1})", c.Start.x, c.Start.y);

C# 3.0 Practical Learning

172

Console.WriteLine("Ending Point: c.End.y); c.End));

Q({0}, {1})", c.End.x,

Console.WriteLine("Distance Between Both Points: {0:F}", c.DistanceBetween2Points(ref c.Start, ref

} static int Main() { CoordinateSystem coord = IdentifyCoordinates();

} }

Console.WriteLine(); Show(coord); return 0;

}

Practical Learning: Return a Class or Passing One as Argument 1. To return a class or pass it as argument, change the Program.cs file as follows: using using using using

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

namespace ElectronicStore1 { public class SaleItem { double DiscountAmount; double NetPrice; int Quantity; double SaleTotal; public double GetDiscountRate() { Console.Write( "Discount Applied (Enter 0 to 100, 0 if no discount): "); double discount = double.Parse(Console.ReadLine()); return discount; } public int GetQuantity() { Console.Write("Enter Quantity: "); int q = int.Parse(Console.ReadLine()); return q; } public StoreItem Create() { long itemNumber; char category; string make; string model;

C# 3.0 Practical Learning

173

double discount; double price; StoreItem saleItem = new StoreItem(); Console.Write("Enter the Item #: "); itemNumber = long.Parse(Console.ReadLine()); Console.WriteLine("Category"); Console.WriteLine("A - Audio Cables"); Console.WriteLine("B - Instructional and Tutorials (Books)"); Console.WriteLine("C - Cell Phones and Accessories"); Console.WriteLine("D - Bags and Cases"); Console.WriteLine("E - Headphones"); Console.WriteLine("F - Instructional and Tutorials (VHS & DVD)");

Console.WriteLine("G - Digital Cameras"); Console.WriteLine("H - Cables and Connectors"); Console.WriteLine("I - PDAs and Accessories"); Console.WriteLine("J - Telephones and Accessories"); Console.WriteLine("K - Surge Protector"); Console.WriteLine("L - TVs and Videos"); Console.WriteLine("U - Unknown"); Console.Write("Your Choice? "); category = char.Parse(Console.ReadLine()); Console.Write("Make: "); make = Console.ReadLine(); Console.Write("Model: "); model = Console.ReadLine(); Console.Write("Unit Price: "); price = double.Parse(Console.ReadLine()); saleItem.SetItemNumber(itemNumber); saleItem.SetCategory(category); saleItem.SetMake(make); saleItem.SetModel(model); saleItem.SetUnitPrice(price); return saleItem; } public void ShowSaleItem(StoreItem item) { double discountRate = GetDiscountRate(); int quantity = GetQuantity(); DiscountAmount = item.GetUnitPrice() * discountRate / 100; NetPrice = item.GetUnitPrice() - DiscountAmount; SaleTotal = NetPrice * quantity;

Console.WriteLine("\nStore Item Description"); Console.WriteLine("Item Number: {0}", item.GetItemNumber()); Console.WriteLine("Category: {0}", item.GetCategory()); Console.WriteLine("Make {0}", item.GetMake()); Console.WriteLine("Model: {0}", item.GetModel()); Console.WriteLine("Unit Price: {0:C}", item.GetUnitPrice()); Console.WriteLine("Discount Rate: {0:P}", discountRate/100); Console.WriteLine("Discount Amount: {0:C}", DiscountAmount); Console.WriteLine("Price/Item: {0:C}", NetPrice);

C# 3.0 Practical Learning

174

}

Console.WriteLine("Quantity: Console.WriteLine("Sale Total:

{0}", quantity); {0:C}", SaleTotal);

} public class Program { static void Main() { StoreItem item = new StoreItem(); SaleItem sale = new SaleItem(); string strTitle1 = "=-= Nearson Electonics =-=\n"; string strTitle2 = "******* Store Items ******"; Console.WriteLine(strTitle1); Console.WriteLine(strTitle2); item = sale.Create(); sale.ShowSaleItem(item); Console.WriteLine(); }

}

}

2. Execute the application. Here is an example: =-= Nearson Electonics =-= ******* Store Items ****** Enter the Item #: 927374 Category A - Audio Cables B - Instructional and Tutorials (Books) C - Cell Phones and Accessories D - Bags and Cases E - Headphones F - Instructional and Tutorials (VHS & DVD) G - Digital Cameras H - Cables and Connectors I - PDAs and Accessories J - Telephones and Accessories K - Surge Protector L - TVs and Videos U - Unknown Your Choice? L Make: NEC Model: VT48 Video Projector Unit Price: 705.95 Discount Applied (Enter 0 to 100, 0 if no discount): 15 Enter Quantity: 1 Store Item Description Item Number: 927374 Category: L Make NEC Model: VT48 Video Projector

C# 3.0 Practical Learning

175

Unit Price: Discount Rate: Discount Amount: Price/Item: Quantity: Sale Total:

$705.95 15.00 % $105.89 $600.06 1 $600.06

Press any key to continue . . .

3. Return to your programming environment

Involving a Class and its Own Methods Passing a Class as its Own Argument An instance of a class can be passed as an argument to one of its own methods (if you have programmed in C++, an example of this implementation is the copy constructor; although you can legitimately create a copy constructor in C#, it does not have the exact same concept as in C++, probably because C# has the Equals() method, which is actually a concept of the .NET Framework). To do this, you primarily pass the argument as if it were any class. Here is an example: public class Point { internal int x; internal int y; public void Equivalent(Point Same) { } }

Then, in the body of the method, do whatever you want. You can, or you may not, use the argument. Still, if you decide to use the argument, know that all of the other members of the class are available through the argument. Probably the simplest way to use the argument is the assign each of of its values to the equivalent member of the class. Here is an example: public class Point { internal int x; internal int y;

}

public void Equivalent(Point Same) { this.x = Same.x; this.y = Same.y; }

When calling the method, make sure you pass an instance of the class to it. You can first create and define the class, then pass it. Here is an example: using System;

C# 3.0 Practical Learning

176

public class Point { internal int x; internal int y; public void Equivalent(Point Same) { this.x = Same.x; this.y = Same.y; } } public class Program { private static void ShowPoint(Point pt) { Console.Write("Point Coordinates: "); Console.WriteLine("A({0}, {1})", pt.x, pt.y); } static int Main(string[] args) { Point pt = new Point(); pt.x = 4; pt.y = 6; ShowPoint(pt); Point One = new Point(); One.Equivalent(pt); ShowPoint(One); }

return 0;

}

This would produce: Point Coordinates: A(4, 6) Point Coordinates: A(4, 6) Press any key to continue . . .

Instead of first declaring a variable of the class and initializing it, you can create an instance of the class in the parentheses of the calling method. To do this, you may need a constructor that can specify the values of the fields of the class so the argument can be rightfully initialized. Here is an example: using System; public class Point { internal int x; internal int y; public Point() { } public Point(int XCoord, int YCoord)

C# 3.0 Practical Learning

177

{ this.x = XCoord; this.y = YCoord; }

}

public void Equivalent(Point Same) { this.x = Same.x; this.y = Same.y; }

public class Program { private static void ShowPoint(Point pt) { Console.Write("Point Coordinates: "); Console.WriteLine("A({0}, {1})", pt.x, pt.y); } static int Main(string[] args) { Point pt = new Point(); pt.x = 4; pt.y = 6; ShowPoint(pt); Point One = new Point(); One.Equivalent(new Point(-3, 2)); ShowPoint(One); return 0; }

}

Instead of a formal method, you can use a constructor of the class to pass an instance of the same class. Then, in the constructor, use the argument as you see fit, knowing that all the members of the class are available. Here is an example: public class Point { internal int x; internal int y; public Point() { } public Point(int XCoord, int YCoord) { this.x = XCoord; this.y = YCoord; } public Point(Point Same) { this.x = Same.x; this.y = Same.y;

C# 3.0 Practical Learning

178

} }

Obviously the purpose of passing a class to one of its own methods is not to find its equivalent. The C# language (actually the .NET Framework) can also take care of that (through the Equals() built-in method). Instead, you can create a method that takes an instance of the same class but modifies that instance. For example, for our Point class, we may want to create a new point that is distanced by one unit from the current Point object. Here is an example of doing that: using System; public class Point { internal int x; internal int y; public Point() { } public Point(int XCoord, int YCoord) { this.x = XCoord; this.y = YCoord; } public void Equivalent(Point Same) { this.x = Same.x; this.y = Same.y; } public void CreatePointOneUnitAway(Point AddUnit) { this.x = AddUnit.x + 1; this.y = AddUnit.y + 1; } } public class Program { private static void ShowPoint(Point pt) { Console.Write("Point Coordinates: "); Console.WriteLine("A({0}, {1})", pt.x, pt.y); } static int Main(string[] args) { Point pt = new Point(); pt.x = 4; pt.y = 6; ShowPoint(pt); Point One = new Point(); One.CreatePointOneUnitAway(pt);

C# 3.0 Practical Learning

179

ShowPoint(One); One.CreatePointOneUnitAway(new Point(-8, -3)); ShowPoint(One); return 0; }

}

This would produce: Point Point Point Press

Coordinates: A(4, 6) Coordinates: A(5, 7) Coordinates: A(-7, -2) any key to continue . . .

Returning a Class From its Own Method You can create a method in a class that returns an instance of the class. To start, on the left side of the method, enter the name of the class. Here is an example: public class Point { public Point MethodName() { } }

There are various ways you can deal with the method. If you want to return a new value of the class, you can declare an instance of the class, initialize it, and then return it. Here is an example: using System; public class Point { internal int x; internal int y; public Point() { } public Point(int XCoord, int YCoord) { this.x = XCoord; this.y = YCoord; } public Point(Point Same) { this.x = Same.x; this.x = Same.x; } public Point AdvanceBy5() { Point Some = new Point(); Some.x = 5;

C# 3.0 Practical Learning

180

}

Some.y = 5; return Some;

} public class Program { private static void ShowPoint(Point pt) { Console.Write("Point Coordinates: "); Console.WriteLine("A({0}, {1})", pt.x, pt.y); } static int Main(string[] args) { Point pt = new Point(); pt.x = 4; pt.y = 6; ShowPoint(pt); Point Away5 = pt.AdvanceBy5(); ShowPoint(Away5); return 0; }

}

This would produce: Point Coordinates: A(4, 6) Point Coordinates: A(5, 5) Press any key to continue . . .

Alternatively, you can declare an instance of the class, use the current values of the class combined with the those of the instance to get new values, and then return the instance. Here is an example: using System; public class Point { internal int x; internal int y; public Point() { } public Point(int XCoord, int YCoord) { this.x = XCoord; this.y = YCoord; } public Point(Point Same) { this.x = Same.x; this.x = Same.x; }

C# 3.0 Practical Learning

181

}

public Point AdvanceBy5() { Point Some = new Point(); Some.x = this.x + 5; Some.y = this.y + 5; return Some; }

public class Program { private static void ShowPoint(Point pt) { Console.Write("Point Coordinates: "); Console.WriteLine("A({0}, {1})", pt.x, pt.y); } static int Main(string[] args) { Point pt = new Point(); pt.x = 4; pt.y = 6; ShowPoint(pt); Point Away5 = pt.AdvanceBy5(); ShowPoint(Away5); }

return 0;

}

This would produce: Point Coordinates: A(4, 6) Point Coordinates: A(9, 11) Press any key to continue . . .

Remember that, to call the method, if it is not static, you will need to declare an instance of the class from where you are calling the method. The second type of implementation consists of modifying the instance of the class that is calling the method. For example, you can add values to its fields or you can perform any other operation you want on the members of the calling instance. is an example: using System; public class Point { internal int x; internal int y; public Point() { } public Point(int XCoord, int YCoord) { this.x = XCoord;

C# 3.0 Practical Learning

182

this.y = YCoord; } public Point(Point Same) { this.x = Same.x; this.x = Same.x; } // This method adds 1 to each field of the class // to get a new point away North-East of the current point public Point CreatePointOneUnitAway() { this.x = this.x + 1; this.y = this.y + 1; return this; }

}

public class Program { private static void ShowPoint(Point pt) { Console.Write("Point Coordinates: "); Console.WriteLine("A({0}, {1})", pt.x, pt.y); } static int Main(string[] args) { Point pt = new Point(); pt.x = 4; pt.y = 6; ShowPoint(pt); Point One = new Point(-8, 5); Point Another = One.CreatePointOneUnitAway(); ShowPoint(Another); return 0; }

}

This would produce: Point Coordinates: A(4, 6) Point Coordinates: A(-7, 6) Press any key to continue . . .

As we have learned now, you can create a method that takes an argument that is the same type as its parent class. In the method, you can access any member of the class, including calling the other methods of the class.

C# 3.0 Practical Learning

183

INTRODUCTION TO CONDITIONS Boolean Variables Introduction When interacting with a computer, a user submits values to a running application. Some of these values are valid. Some other values must be rejected or changed. To take care of these, the values must be checked, examined, re-examined, etc. The validity of a value is checked against its type. For example, a number can be checked as being equal to another. A condition can be checked as being true. A measure can be checked as to whether it is higher than a certain threshold. To perform the necessary validations of values, the C# language provides some symbols, referred to as Boolean operators.

Practical Learning: Introducing Boolean Variables 1. Start Microsoft Visual C# 2. Create a new Console Application named FlowerShop1 3. To create a new class, on the main menu, click Project -> Add Class... 4. Set the Name of the class to Flower and click Add 5. Complete the Flower.cs file as follows:

C# 3.0 Practical Learning

184

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace FlowerShop1 { public class Flower { public int Type; public int Color; public char Arrangement; public decimal UnitPrice; public Flower() { Type = 0; Color = 0; Arrangement = 'B'; UnitPrice = 0.00M; } public Flower(int type) { Type = type; Color = 0; Arrangement = 'B'; UnitPrice = 0.00M; } color,

public Flower(int type, int char argn, decimal price)

{

Type = type; Color = color; Arrangement = argn; UnitPrice = price; }

}

}

6. To create a new class, in the Solution Explorer, right-click the project name, position the mouse on Add and click Class... 7. Set the Name of the class to OrderProcessing and click Add 8. Complete the OrderProcessing.cs file as follows: using using using using

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

namespace FlowerShop1

C# 3.0 Practical Learning

185

{ public class OrderProcessing { public OrderProcessing() { FlowerOrder = new Flower(); } public Flower FlowerOrder; public int Quantity; public decimal GetTotalPrice() { return Quantity * FlowerOrder.UnitPrice; } }

}

9. Access the Program.cs file and complete it as follows: using using using using

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

namespace FlowerShop1 { public class Program { private static OrderProcessing CreateFlowerOrder() { OrderProcessing order = new OrderProcessing(); int type, color, qty; char arrangement; decimal price; Console.WriteLine("======================="); Console.WriteLine("==-=-=Flower Shop=-=-=="); Console.WriteLine("-----------------------"); Console.WriteLine("Enter the Type of Flower Order"); Console.WriteLine("1. Roses"); Console.WriteLine("2. Lilies"); Console.WriteLine("3. Daisies"); Console.WriteLine("4. Carnations"); Console.WriteLine("5. Live Plant"); Console.WriteLine("6. Mixed"); Console.Write("Your Choice: "); type = int.Parse(Console.ReadLine()); Console.WriteLine("Enter the Color"); Console.WriteLine("1. Red"); Console.WriteLine("2. White"); Console.WriteLine("3. Yellow"); Console.WriteLine("4. Pink"); Console.WriteLine("5. Orange"); Console.WriteLine("6. Blue"); Console.WriteLine("7. Lavender"); Console.WriteLine("8. Mixed");

C# 3.0 Practical Learning

186

Console.Write("Your Choice: "); color = int.Parse(Console.ReadLine()); Console.WriteLine("Enter the Type of Arrangement"); Console.WriteLine("U. Bouquet"); Console.WriteLine("V. Vase"); Console.WriteLine("B. Basket"); Console.WriteLine("M. Mixed"); Console.Write("Your Choice: "); arrangement = char.Parse(Console.ReadLine()); Console.Write("Enter the Unit Price: "); price = decimal.Parse(Console.ReadLine()); Console.Write("Enter Quantity: "); qty = int.Parse(Console.ReadLine()); Flower flr = new Flower(type, color, arrangement, price); order.FlowerOrder = flr; order.Quantity = qty; }

return order;

private static void ShowFlowerOrder(OrderProcessing order) { Console.WriteLine("======================="); Console.WriteLine("==-=-=Flower Shop=-=-=="); Console.WriteLine("-----------------------"); Console.WriteLine("Flower Type: {0}", order.FlowerOrder.Type); Console.WriteLine("Flower Color: {0}", order.FlowerOrder.Color); Console.WriteLine("Arrangement: {0}", order.FlowerOrder.Arrangement); Console.WriteLine("Price: {0:C}", order.FlowerOrder.UnitPrice); Console.WriteLine("Quantity: {0}", order.Quantity); Console.WriteLine("Total Price: {0:C}", order.GetTotalPrice()); Console.WriteLine("======================="); } static void Main(string[] args) { OrderProcessing flower = CreateFlowerOrder(); Console.WriteLine();

} }

ShowFlowerOrder(flower); Console.WriteLine();

}

10.

Execute the application and test it. Here is an example:

======================= ==-=-=Flower Shop=-=-== -----------------------

C# 3.0 Practical Learning

187

Enter the Type of Flower Order 1. Roses 2. Lilies 3. Daisies 4. Carnations 5. Live Plant 6. Mixed Your Choice: 4 Enter the Color 1. Red 2. White 3. Yellow 4. Pink 5. Orange 6. Blue 7. Lavender 8. Mixed Your Choice: 6 Enter the Type of Arrangement U. Bouquet V. Vase B. Basket M. Mixed Your Choice: V Enter the Unit Price: 37.95 Enter Quantity: 2 ======================= ==-=-=Flower Shop=-=-== ----------------------Flower Type: 4 Flower Color: 6 Arrangement: V Price: $37.95 Quantity: 2 Total Price: $75.90 ======================= Press any key to continue . . .

11.

Close the DOS window

Declaring a Boolean Variable A variable is referred to as Boolean if it can hold a value that is either true or false. To declare a Boolean variable, you can use either the var or the bool keyword. Here is an example: using System; public class Exercise { static int Main() { bool DrinkingUnderAge; }

return 0;

}

C# 3.0 Practical Learning

188

Alternatively, you can declare a Boolean variable using the Boolean data type. The Boolean data type is part of the System namespace. Here is an example: using System; public class Exercise { static int Main() { bool DrinkingUnderAge; Boolean TheFloorIsCoveredWithCarpet; }

return 0

}

After the variable has been declared, you must initialize it with a true or a false value. In fact, if you declare it as var, you must initialize it. Here is an example: using System; public class Exercise { static int Main() { var DrinkingUnderAge = true; return 0; }

}

To display the value of a Boolean variable on the console, you can type its name in the parentheses of the Write() or the WriteLine() methods of the Console class. Here is an example: using System; public class Exercise { static int Main() { var DrinkingUnderAge = true; Console.WriteLine("Drinking Under Age: {0}", DrinkingUnderAge); return 0; }

}

This would produce: Drinking Under Age: True Press any key to continue . . .

At any time and when you judge it necessary, you can change the value of the Boolean variable by assigning it a true or false value. Here is an example: using System; public class Exercise

C# 3.0 Practical Learning

189

{ static int Main() { var DrinkingUnderAge = true; Console.WriteLine("Drinking Under Age: {0}", DrinkingUnderAge);

}

DrinkingUnderAge = false; Console.WriteLine("Drinking Under Age: {0}", DrinkingUnderAge); return 0;

}

This would produce: Drinking Under Age: True Drinking Under Age: False Press any key to continue . . .

Retrieving the Value of a Boolean Variable As reviewed for the other data types, you can request the value of a Boolean variable from the user. In this case, the user must type either True (or true) or False (or false) and you can retrieve it using the Read() or the ReadLine() methods of the Console class. Here is an example: using System; public class Exercise { static int Main() { var DrivingUnderAge = false; Console.WriteLine("Were you driving under age?"); Console.Write("If Yes, enter True. Otherwise enter False: "); DrivingUnderAge = bool.Parse(Console.ReadLine()); Console.WriteLine("\nWas Driving Under Age: {0}\n", DrivingUnderAge); return 0; } }

Here is an example of running the program: Were you driving under age? If Yes, enter True. Otherwise enter False: true Was Driving Under Age: True Press any key to continue . . .

Creating a Boolean Field

C# 3.0 Practical Learning

190

Like the other types of variables we used in previous lessons, a Boolean variable can be made a field of a class. You declare it like any other variable, using the bool keyword or the Boolean data type. Here is an example: public class House {

}

public public public public public public public

char TypeOfHome; int Bedrooms; float Bathrooms; byte Stories; bool HasCarGarage; int YearBuilt; double Value;

When initializing an object that has a Boolean variable as a member, simply assign true or false to the variable. In the same way, you can retrieve or check the value that a Boolean member variable is holding by simply accessing it. Here are examples: using System; public class House { public char TypeOfHome; public int Bedrooms; public float Bathrooms; public byte Stories; public bool HasCarGarage; public int YearBuilt; public double Value; } public class Program { static int Main() { var Condominium = new { HasCarGarage = false, YearBuilt = 2002, Bathrooms = 1.5F, Stories = 18, Value = 155825, Bedrooms = 2, TypeOfHome = 'C' }; Console.WriteLine("=//= Altair Realty =//="); Console.WriteLine("=== Property Listing ==="); Console.WriteLine("Type of Home: {0}", Condominium.TypeOfHome); Console.WriteLine("Number of Bedrooms: {0}", Condominium.Bedrooms); Console.WriteLine("Number of Bathrooms: {0}", Condominium.Bathrooms); Console.WriteLine("Number of Stories: {0}", Condominium.Stories);

C# 3.0 Practical Learning

191

Console.WriteLine("Year Built: Condominium.YearBuilt); Console.WriteLine("Has Car Garage: Condominium.HasCarGarage); Console.WriteLine("Monetary Value: Condominium.Value); }

{0}", {0}", {0}\n",

return 0;

}

This would produce: =//= Altair Realty =//= === Property Listing === Type of Home: C Number of Bedrooms: 2 Number of Bathrooms: 1.5 Number of Stories: 18 Year Built: 2002 Has Car Garage: False Monetary Value: 155825 Press any key to continue . . .

Boolean Arguments Like parameters of the other types, you can pass an argument of type bool or Boolean to a method. Such an argument would be treated as holding a true or false value.

Enumerations Introduction Consider that, when creating a program for a real estate company that sells houses, you want the program to ask a customer the type of house that he or she wants to purchase and/or the type of garage that the desired house should have. Here is an example: using System; public class Exercise { static int Main() { int TypeOfHouse = 0; int TypeOfGarage = 0; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1 - Single Family"); Console.WriteLine("2 - Townhouse"); Console.WriteLine("3 - Condominium"); Console.Write("Your Choice: ");

C# 3.0 Practical Learning

192

TypeOfHouse = int.Parse(Console.ReadLine()); Console.WriteLine("Enter the type of garage you want"); Console.WriteLine("0 - Doesn't matter"); Console.WriteLine("1 - Interior"); Console.WriteLine("2 - Exterior"); Console.Write("Your Choice: "); TypeOfGarage = int.Parse(Console.ReadLine()); Console.WriteLine("\nHouse Type: {0}", TypeOfHouse); Console.WriteLine("Garage Type: {0}", TypeOfGarage); return 0; }

}

Here is an example of running the program: Enter the type of house you want to purchase 1 - Single Family 2 - Townhouse 3 - Condominium Your Choice: 3 Enter the type of garage you want 0 - Doesn't matter 1 - Interior 2 - Exterior Your Choice: 1 House Type: 3 Garage Type: 1 Press any key to continue . . .

For such a program, the numbers can be vague. 1 can be considered a general number but, in our program, it can represent a Single Family house or an Interior type of garage. At the same time, our program uses the constant 1 in particular meaningful ways. To make it possible to give more meaning to a constant number, when the number can be made part of a series, C# allows you to create a type of list. An enumeration is a series of constant integers that each has a specific position in the list and can be recognized by a meaningful name. Based on this, instead of just remembering that the constant 1 represents Single Family, you can create a list that has that type of house. In another list, instead of using 1 again, you can give it a name. Consequently, in each list, although the constant 1 would still be considered, at least it would mean something precise. To create an enumeration, you use the enum keyword, followed by the name of the enumeration, followed by a name for each item of the list. The name of the enumerator and the name of each item of the list follows the rules we reviewed for names. The formula of creating an enumeration is: enum Series_Name {Item1, Item2, Item_n};

Here is an example: using System; public class Exercise

C# 3.0 Practical Learning

193

{ enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } static int Main() { return 0; } }

Declaring an Enumeration Variable After creating an enumeration, each member of the enumeration holds a value of a natural number, such as 0, 4, 12, 25, etc. In C#, an enumeration cannot hold character values (of type char). After creating an enumeration, you can declare a variable from it. Here is an example: using System; public class Exercise { enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } static int Main() { HouseType propType; }

return 0;

}

Just as done with the other types, you can use the var keyword to declare a variable of an enumeration type.

Initializing an Enumeration Variable After declaring a variable for an enumeration, to initialize it, specify which member of the enumeration would be assigned to the variable. You should only assign a known member of the enumeration. To do this, on the right side of the assignment operator, type the name of the enumeration, followed by the period operator, and followed by the member whose value you want to assign. Here is an example: using System; public class Exercise { enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } static int Main() { var propType = HouseType.SingleFamily; }

return 0;

}

C# 3.0 Practical Learning

194

You can also find out what value the declared variable is currently holding. For example, you can display it on the console using Write() or WriteLine(). Here is an example: using System; public class Exercise { enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } static int Main() { var propType = HouseType.SingleFamily; Console.WriteLine("House Type: }

{0}", propType);

return 0;

}

This would produce: House Type: SingleFamily Press any key to continue . . .

An enumeration is in fact a list of numbers where each member of the list is identified with a name. By default, the first item of the list has a value of 0, the second has a value of 1, and so on. For example, on the HouseType enumeration, Unknown has a value of 0 while Townhouse has a value of 2. These are the default values. If you don't want these values, you can specify the value of one or each member of the list. Suppose you want the Unknown member in the above enumeration to have a value of 5. To do this, use the assignment operator "=" to give the desired value. The enumerator would be: using System; public class Exercise { enum HouseType { Unknown = 5, SingleFamily, TownHouse, Condominium }

}

static int Main() { return 0; }

In this case, Unknown now would have a value of 5, SingleFamily would have a value of 6 because it follows a member whose value is 1 (thus 5 + 1 = 6). Townhouse would have a value of 7, and Condominium would have a value of 8. You can also assign a value to more than one member of an enumeration. Here is an example: using System; public class Exercise { enum HouseType { Unknown = 3, SingleFamily = 12, TownHouse, Condominium = 8 }

C# 3.0 Practical Learning

195

}

static int Main() { return 0; }

In this case, Townhouse would have a value of 13 because it follows SingleFamily that has a value of 12.

Enumerations Visibility By default, if you create an enumeration the way we have proceeded so far, it would be available only in the project it belongs to. As done for a class, you can control an enumeration's accessibility outside of its project. This means that you can hide or make it visible outside of its project. To do this, you can precede it with the private or the public keyword. Here is an example: using System; public class Exercise { public enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } static int Main() { HouseType propType = HouseType.SingleFamily;

}

Console.WriteLine("House Type: return 0;

{0}", propType);

}

An Enumeration as a Member Variable After creating an enumeration, you can use it as a data type to declare a variable. To create a field that is of an enumeration type, follow the same rules as done for the primitive types: the name of the enumeration, followed by the name of the variable, and followed by a semi-colon. Here is an example: public enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } public class House { HouseType PropertyType; }

C# 3.0 Practical Learning

196

In the same way, you can declare as many enumeration variables as you want. After declaring the variable, to initialize it, assign it the desired member of the enumeration. Here is an example: public enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } public class House { HouseType PropertyType;

}

public House() { PropertyType = HouseType.Unknown; }

Once the member variable has been initialized, you can use it as you see fit as we will learn and practice in future sections and lessons. At a minimum, you can pass it to Write() or WriteLine() to display its value. Here is an example: using System; public enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } public class House { public HouseType PropertyType; public House() { PropertyType = HouseType.Unknown; } public void Display() { Console.WriteLine("Property Type: {0}", PropertyType); } } public class Exercise { static int Main() { var propType = new House(); propType.Display(); Console.WriteLine(); propType.PropertyType = HouseType.SingleFamily;

C# 3.0 Practical Learning

197

propType.Display(); Console.WriteLine(); }

return 0;

}

This would produce: Property Type: Unknown Property Type: SingleFamily Press any key to continue . . .

Using it as normal data type, you can create a method that returns an enumeration. You can also pass an enumeration to a method as argument.

Practical Learning: Creating and Using Enumerations 1. Access the Flower.cs file 2. To create some enumerations, change the file as follows: using using using using

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

namespace FlowerShop1 { public enum FlowerType { Roses = 1, Lilies, Daisies, Carnations, LivePlant, Mixed } public enum FlowerColor { Red = 1, White, Yellow, Pink, Orange, Blue, Lavender, Mixed } public enum FlowerArrangement { Bouquet = 1, Vase, Basket,

C# 3.0 Practical Learning

198

Mixed } public class Flower { public FlowerType Type; public FlowerColor Color; public FlowerArrangement Arrangement; public decimal UnitPrice;

}

public Flower() { Type = FlowerType.Mixed; Color = FlowerColor.Mixed; Arrangement = FlowerArrangement.Vase; UnitPrice = 0.00M; } public Flower(FlowerType type) { Type = type; Color = FlowerColor.Mixed; Arrangement = FlowerArrangement.Vase; UnitPrice = 0.00M; } public Flower(FlowerType type, FlowerColor color, FlowerArrangement argn, decimal price) { Type = type; Color = color; Arrangement = argn; UnitPrice = price; }

}

3. Access the Program.cs file 4. To use the enumerations, change the file as follows: using using using using

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

namespace FlowerShop1 { public class Program { private static OrderProcessing CreateFlowerOrder() { OrderProcessing order = new OrderProcessing(); int type, color, qty; int arrangement; decimal price; Console.WriteLine("======================="); Console.WriteLine("==-=-=Flower Shop=-=-=="); Console.WriteLine("-----------------------");

C# 3.0 Practical Learning

199

Console.WriteLine("Enter the Type of Flower Order"); Console.WriteLine("1. Roses"); Console.WriteLine("2. Lilies"); Console.WriteLine("3. Daisies"); Console.WriteLine("4. Carnations"); Console.WriteLine("5. Live Plant"); Console.WriteLine("6. Mixed"); Console.Write("Your Choice: "); type = int.Parse(Console.ReadLine()); Console.WriteLine("Enter the Color"); Console.WriteLine("1. Red"); Console.WriteLine("2. White"); Console.WriteLine("3. Yellow"); Console.WriteLine("4. Pink"); Console.WriteLine("5. Orange"); Console.WriteLine("6. Blue"); Console.WriteLine("7. Lavender"); Console.WriteLine("8. Mixed"); Console.Write("Your Choice: "); color = int.Parse(Console.ReadLine()); Console.WriteLine("Enter the Type of Arrangement"); Console.WriteLine("1. Bouquet"); Console.WriteLine("2. Vase"); Console.WriteLine("3. Basket"); Console.WriteLine("4. Mixed"); Console.Write("Your Choice: "); arrangement = int.Parse(Console.ReadLine()); Console.Write("Enter the Unit Price: "); price = decimal.Parse(Console.ReadLine()); Console.Write("Enter Quantity: "); qty = int.Parse(Console.ReadLine()); Flower flr = new Flower((FlowerType)type, (FlowerColor)color, (FlowerArrangement)arrangement, price); order.FlowerOrder = flr; order.Quantity = qty; }

return order;

private static void ShowFlowerOrder(OrderProcessing order) { Console.WriteLine("======================="); Console.WriteLine("==-=-=Flower Shop=-=-=="); Console.WriteLine("-----------------------"); Console.WriteLine("Flower Type: {0}", order.FlowerOrder.Type); Console.WriteLine("Flower Color: {0}", order.FlowerOrder.Color); Console.WriteLine("Arrangement: {0}", order.FlowerOrder.Arrangement); Console.WriteLine("Price: {0:C}", order.FlowerOrder.UnitPrice); Console.WriteLine("Quantity: {0}", order.Quantity);

C# 3.0 Practical Learning

200

Console.WriteLine("Total Price: {0:C}", order.GetTotalPrice()); Console.WriteLine("======================="); } static void Main(string[] args) { OrderProcessing flower = CreateFlowerOrder(); Console.WriteLine();

} }

ShowFlowerOrder(flower); Console.WriteLine();

}

5. Execute the application and process an order. Here is an example: ======================= ==-=-=Flower Shop=-=-== ----------------------Enter the Type of Flower Order 1. Roses 2. Lilies 3. Daisies 4. Carnations 5. Live Plant 6. Mixed Your Choice: 5 Enter the Color 1. Red 2. White 3. Yellow 4. Pink 5. Orange 6. Blue 7. Lavender 8. Mixed Your Choice: 7 Enter the Type of Arrangement 1. Bouquet 2. Vase 3. Basket 4. Mixed Your Choice: 3 Enter the Unit Price: 35.95 Enter Quantity: 4 ======================= ==-=-=Flower Shop=-=-== ----------------------Flower Type: LivePlant Flower Color: Lavender Arrangement: Basket Price: $35.95 Quantity: 4 Total Price: $143.80 =======================

C# 3.0 Practical Learning

201

Press any key to continue . . .

6. Close the DOS window

Logical Operators Introduction A program is a series of instructions that ask the computer (actually the compiler) to check some situations and to act accordingly. To check such situations, the computer spends a great deal of its time performing comparisons between values. A comparison is a Boolean operation that produces a true or a false result, depending on the values on which the comparison is performed. A comparison is performed between two values of the same type; for example, you can compare two numbers, two characters, or the names of two cities. On the other hand, a comparison between two disparate values doesn't bear any meaning. For example, it is difficult to compare a telephone number and somebody's age, or a music category and the distance between two points. Like the binary arithmetic operations, the comparison operations are performed on two values. Unlike arithmetic operations where results are varied, a comparison produces only one of two results. The result can be a logical true or a logical false. When a comparison is true, it has an integral value of 1 or positive; that is, a value greater than 0. If the comparison is not true, it is considered false and carries an integral value of 0. The C# language is equipped with various operators used to perform any type of comparison between similar values. The values could be numeric, strings, or objects (operations on objects are customized in a process referred to as Operator Overloading). There are primary assumptions you should make when writing statements used in conditions: •

Simplicity and Clarity: A statement should be clear enough and possibly simple but as complete as possible. When a statement becomes long, it can lead to being segmented in short parts, which deceives its clarity and may create other issues.



Factual: The statement must be presented as fact and not as opinion. This means that you don't have to like the statement but the majority, including you, must agree that it is true or it is false. In fact, the statement doesn't have to be correct but it must be agreed upon to be true. Based on this, a statement such as "An hour contains 45 minutes" doesn't have to fit your way of thinking but it must be considered as true or as false. A statement such as "This job applicant is attractive" is an opinion and therefore must not be considered in a conditional statement.



Circumstantial Truthfulness: At the time the statement is made, it must be considered as true or as false even if it can change at another time. For example, suppose that, in a certain year, a statement is formulated as "This year, the month of February has 28 days". Although allowed, you C# 3.0 Practical Learning

202

should refrain from regularly using circumstantial truthfulness, unless you have to. •

Inverse: A statement must be able to find its reverse. This means that, when a statement is made and decided upon to be true or false, an inverse statement must be found to make it false or true. For example, if you have a statement such as "This job applicant is 18 years old", you must be able to state that "This job applicant is not 18 years old" or "This job applicant is younger than 18".

In your programs, make sure you clearly formulate your statements. This would make your programs easy to read and troubleshoot when problems occur (not if, but when).

The Equality Operator == To compare two variables for equality, C# uses the == operator. The formula used is: Value1 == Value2

The equality operation is used to find out whether two variables (or one variable and a constant) hold the same value. From our syntax, the compiler would compare the value of Value1 with that of Value2. If Value1 and Value2 hold the same value, the comparison produces a true result. If they are different, the comparison renders false.

Most of the comparisons performed in C# will be applied to conditional statements. The result of a comparison can also be assigned to a variable. To store the result of a comparison, you should include the comparison operation between parentheses. Here is an example: using System; public class Exercise { static int Main() { var Value1 = 15; var Value2 = 24;

C# 3.0 Practical Learning

203

Console.Write("Value 1 = "); Console.WriteLine(Value1); Console.Write("Value 2 = "); Console.WriteLine(Value2); Console.Write("Comparison of Value1 == 15 produces "); Console.WriteLine(Value1 == 15); }

return 0;

}

This would produce: Value 1 = 15 Value 2 = 24 Comparison of Value1 == 15 produces True

It is important to make a distinction between the assignment "=" and the logical equality operator "==". The first is used to give a new value to a variable, as in Number = 244. The operand on the left side of = must always be a variable and never a constant. The == operator is never used to assign a value; this would cause an error. The == operator is used only to compare to values. The operands on both sides of == can be variables, constants, or one can be a variable while the other is a constant. If you use one operator in place of the other, you would receive an error when you compile the program.

The Logical Not Operator ! When a variable is declared and receives a value (this could be done through initialization or a change of value) in a program, it becomes alive. It can then participate in any necessary operation. The compiler keeps track of every variable that exists in the program being processed. When a variable is not being used or is not available for processing (in visual programming, it would be considered as disabled) to make a variable (temporarily) unusable, you can nullify its value. C# considers that a variable whose value is null is stern. To render a variable unavailable during the evolution of a program, apply the logical not operator which is !. Its syntax is: !Value

There are two main ways you can use the logical not operator. As we will learn when studying conditional statements, the most classic way of using the logical not operator is to check the state of a variable. To nullify a variable, you can write the exclamation point to its left. Here is an example: using System; public class Exercise { static int Main() { bool HasAirCondition = true; bool DoesIt; Console.Write("HasAirCondition = ");

C# 3.0 Practical Learning

204

Console.WriteLine(HasAirCondition); DoesIt = !HasAirCondition; Console.Write("DoesIt = "); Console.WriteLine(DoesIt); }

return 0;

}

This would produce: HasAirCondition = True DoesIt = False

When a variable holds a value, it is "alive". To make it not available, you can "not" it. When a variable has been "notted", its logical value has changed. If the logical value was true, which is 1, it would be changed to false, which is 0. Therefore, you can inverse the logical value of a variable by "notting" or not "notting" it.

The Inequality Operator != As opposed to Equality, C# provides another operator used to compare two values for inequality. This operation uses a combination of equality and logical not operators. It combines the logical not ! and a simplified == to produce !=. Its syntax is: Value1 != Value2

The != is a binary operator (like all logical operator except the logical not, which is a unary operator) that is used to compare two values. The values can come from two variables as in Variable1 != Variable2. Upon comparing the values, if both variables hold different values, the comparison produces a true or positive value. Otherwise, the comparison renders false or a null value:

Here is an example: using System; public class Exercise {

C# 3.0 Practical Learning

205

static { var var var

int Main() Value1 = 212; Value2 = -46; Value3 = (Value1 != Value2);

Console.Write("Value1 = "); Console.WriteLine(Value1); Console.Write("Value2 = "); Console.WriteLine(Value2); Console.Write("Value3 = "); Console.Write(Value3); Console.WriteLine(); return 0; }

}

The inequality is obviously the opposite of the equality.

The Comparison for a Lower Value < To find out whether one value is lower than another, use the < operator. Its syntax is: Value1 < Value2

The value held by Value1 is compared to that of Value2. As it would be done with other operations, the comparison can be made between two variables, as in Variable1 < Variable2. If the value held by Variable1 is lower than that of Variable2, the comparison produces a true or positive result.

Here is an example: using System; public class Exercise { static int Main() { var Value1 = 15; var Value2 = (Value1 < 24);

C# 3.0 Practical Learning

206

Console.Write("Value 1 = "); Console.WriteLine(Value1); Console.Write("Value 2 = "); Console.WriteLine(Value2); Console.WriteLine(); }

return 0;

}

This would produce: Value 1 = 15 Value 2 = True

Combining Equality and Lower Value <= The previous two operations can be combined to compare two values. This allows you to know if two values are the same or if the first is less than the second. The operator used is <= and its syntax is: Value1 <= Value2

The <= operation performs a comparison as any of the last two. If both Value1 and VBalue2 hold the same value, result is true or positive. If the left operand, in this case Value1, holds a value lower than the second operand, in this case Value2, the result is still true.

Here is an example: using System; public class Exercise { static int Main() { var Value1 = 15; var Value2 = (Value1 <= 24); Console.Write("Value 1 = "); Console.WriteLine(Value1);

C# 3.0 Practical Learning

207

Console.Write("Value 2 = "); Console.WriteLine(Value2); Console.WriteLine(); return 0; }

}

This would produce: Value 1 = 15 Value 2 = True

The Comparison for a Greater Value > When two values of the same type are distinct, one of them is usually higher than the other. C# provides a logical operator that allows you to find out if one of two values is greater than the other. The operator used for this operation uses the > symbol. Its syntax is: Value1 > Value2

Both operands, in this case Value1 and Value2, can be variables or the left operand can be a variable while the right operand is a constant. If the value on the left of the > operator is greater than the value on the right side or a constant, the comparison produces a true or positive value . Otherwise, the comparison renders false or null:

The Greater Than or Equal Operator >= The greater than or the equality operators can be combined to produce an operator as follows: >=. This is the "greater than or equal to" operator. Its syntax is: Value1 >= Value2

A comparison is performed on both operands: Value1 and Value2. If the value of Value1 and that of Value2 are the same, the comparison produces a true or C# 3.0 Practical Learning

208

positive value. If the value of the left operand is greater than that of the right operand,, the comparison produces true or positive also. If the value of the left operand is strictly less than the value of the right operand, the comparison produces a false or null result:

Here is a summary table of the logical operators we have studied:

Operator

Meaning

Example

Opposite

==

Equality to

a == b

!=

!=

Not equal to

12 != 7

==

<

Less than

25 < 84

>=

<=

Less than or equal to

Cab <= Tab

>

>

Greater than

248 > 55

<=

>=

Greater than or equal to

Val1 >= Val2

<

Logically Incrementing or Decrementing a Value Incrementing a Variable C# 3.0 Practical Learning

209

We are used to counting numbers such as 1, 2, 3, 4, etc. In reality, when counting such numbers, we are simply adding 1 to a number in order to get the next number in the range. The simplest technique of incrementing a value consists of adding 1 to it. After adding 1, the value or the variable is (permanently) modified and the variable would hold the new value. This is illustrated in the following example: // This program studies value incrementing using System; public class Exercise { static int Main() { var Value = 12; Console.WriteLine("Techniques of incrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Value = Value + 1; Console.Write("Value = "); Console.WriteLine(Value); return 0; }

}

This would produce: Techniques of incrementing a value Value = 12 Value = 13

C# provides a special operator that takes care of this operation. The operator is called the increment operator and is represented by ++. Instead of writing Value = Value + 1, you can write Value++ and you would get the same result. The above program can be re-written as follows: // This program studies value incrementing using System; public class Exercise { static int Main() { var Value = 12; Console.WriteLine("Techniques of incrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Value++; Console.Write("Value = "); Console.WriteLine(Value); return 0;

C# 3.0 Practical Learning

210

} }

The ++ is a unary operator because it operates on only one variable. It is used to modify the value of the variable by adding 1 to it. Every time the Value++ is executed, the compiler takes the previous value of the variable, adds 1 to it, and the variable holds the incremented value: // This program studies value incrementing using System; public class Exercise { static int Main() { var Value = 12; Console.WriteLine("Techniques of incrementing a value"); Value++; Console.Write("Value = "); Console.WriteLine(Value); Value++; Console.Write("Value = "); Console.WriteLine(Value); Value++; Console.Write("Value = "); Console.WriteLine(Value); }

return 0;

}

This would produce: Techniques of incrementing a value Value = 13 Value = 14 Value = 15

Pre and Post-Increment When using the ++ operator, the position of the operator with regard to the variable it is modifying can be significant. To increment the value of the variable before re-using it, you should position the operator on the left of the variable: // This program studies value incrementing using System; public class Exercise { static int Main() { var Value = 12;

C# 3.0 Practical Learning

211

Console.WriteLine("Techniques of incrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Console.Write("Value = "); Console.WriteLine(++Value); Console.Write("Value = "); Console.WriteLine(Value); }

return 0;

}

This would produce: Techniques of incrementing a value Value = 12 Value = 13 Value = 13

When writing ++Value, the value of the variable is incremented before being called. On the other hand, if you want to first use a variable, then increment it, in other words, if you want to increment the variable after calling it, position the increment operator on the right side of the variable: // This program studies value incrementing using System; public class Exercise { static int Main() { var Value = 12; Console.WriteLine("Techniques of incrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Console.Write("Value = "); Console.WriteLine(Value++); Console.Write("Value = "); Console.WriteLine(Value); return 0; }

}

This would produce: Techniques of incrementing a value Value = 12 Value = 12 Value = 13

Decrementing a Value C# 3.0 Practical Learning

212

When counting numbers backward, such as 8, 7, 6, 5, etc, we are in fact subtracting 1 from a value in order to get the lesser value. This operation is referred to as decrementing a value. This operation works as if a value is decremented by 1, as in Value = Value – 1: // This program studies value decrementing using System; public class Exercise { static int Main() { var Value = 12; Console.WriteLine("Techniques of decrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Value = Value - 1; Console.Write("Value = "); Console.WriteLine(Value); return 0; }

}

This would produce: Techniques of decrementing a value Value = 12 Value = 11

As done to increment, C# provides a quicker way of subtracting 1 from a value. This is done using the decrement operator, that is --. To use the decrement operator, type –- on the left or the right side of the variable when this operation is desired. Using the decrement operator, the above program could be written: // This program studies value decrementing using System; public class Exercise { static int Main() { var Value = 12; Console.WriteLine("Techniques of decrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Value--; Console.Write("Value = "); Console.WriteLine(Value); return 0; }

}

C# 3.0 Practical Learning

213

Pre Decrementing a Value Once again, the position of the operator can be important. If you want to decrement the variable before calling it, position the decrement operator on the left side of the operand. This is illustrated in the following program: // This program studies value decrementing using System; public class Exercise { static int Main() { var Value = 12; Console.WriteLine("Techniques of decrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Console.Write("Value = "); Console.WriteLine(--Value); Console.Write("Value = "); Console.WriteLine(Value); }

return 0;

}

This would produce: Techniques of decrementing a value Value = 12 Value = 11 Value = 11

If you plan to decrement a variable only after it has been accessed, position the operator on the right side of the variable. Here is an example: // This program studies value decrementing using System; public class Exercise { static int Main() { var Value = 12; Console.WriteLine("Techniques of decrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Console.Write("Value = "); Console.WriteLine(Value--); Console.Write("Value = "); Console.WriteLine(Value); return 0;

C# 3.0 Practical Learning

214

} }

This would produce: Techniques of decrementing a value Value = 12 Value = 12 Value = 11

Techniques of Incrementing and Decrementing a Variable It is not unusual to add or subtract a constant value to or from a variable. All you have to do is to declare another variable that would hold the new value. Here is an example: // This program studies value incrementing and decrementing using System; public class Exercise { static int Main() { double Value = 12.75; double NewValue; Console.WriteLine("Techniques of incrementing and decrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); NewValue = Value + 2.42; Console.Write("Value = "); Console.WriteLine(NewValue); return 0; }

}

This would produce: Techniques of incrementing and decrementing a value Value = 12.75 Value = 15.17

The above technique requires that you use an extra variable in your application. The advantage is that each value can hold its own value although the value of the second variable depends on whatever would happen to the original or source variable. Sometimes in your program you will not need to keep the original value of the source variable. You may want to permanently modify the value that a variable is holding. In this case you can perform the addition operation directly on the variable by adding the desired value to the variable. This operation modifies whatever value a variable is holding and does not need an additional variable.

C# 3.0 Practical Learning

215

To add a value to a variable and change the value that the variable is holding, you can combine the assignment “=” and the addition “+” operators to produce a new operator as += Here is an example: // This program studies value incrementing and decrementing using System; public class Exercise { static int Main() { var Value = 12.75; Console.WriteLine("Techniques of incrementing and decrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Value += 2.42; Console.Write("Value = "); Console.WriteLine(Value); }

return 0;

}

This program produces the same result as the previous. To decrement the value of a variable, instead of the addition, use the subtraction and apply the same technique. In the above program, the variable can have its value decremented by combining the assignment and the subtraction operations on the variable. This is done with the -= operator. Here is an example: // This program studies value incrementing and decrementing using System; public class Exercise { static int Main() { var Value = 12.75; Console.WriteLine("Techniques of incrementing and decrementing a value"); Console.Write("Value = "); Console.WriteLine(Value); Value -= 2.42; Console.Write("Value = "); Console.WriteLine(Value); }

return 0;

}

This would produce: C# 3.0 Practical Learning

216

Techniques of incrementing and decrementing a value Value = 12.75 Value = 10.33

C# 3.0 Practical Learning

217

CONDITIONAL STATEMENTS if a Condition is True Introduction A conditional statement is an expression that produces a true or false result. You can use that result as you see fit. To create the expression, you use the Boolean operators we studied in the previous lesson. In the previous lesson, we saw only how to perform the operations and how to get the results, not how to use them. To use the result of a Boolean operation, the C# programming language provides some specific conditional operators.

Practical Learning: Introducing Conditional Expressions 1. Start Microsoft Visual C# and create a Console Application named ElectronicStore2

2. To create a new class, on the main menu, click Project -> Add Class... 3. Set the Name of the class to StoreItem and click Add 4. Complete the StoreItem.cs file as follows:

using using using using

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

namespace ElectronicStore2 { public enum ItemsCategories { Unknown, CablesAndConnectors, CellPhonesAndAccessories, Headphones, DigitalCameras, PDAsAndAccessories, TelephonesAndAccessories, TVsAndVideos, SurgeProtectors, Instructional } public class StoreItem

C# 3.0 Practical Learning

218

{ public public public public public public

long ItemNumber; ItemsCategories Category; string Make; string Model; string Name; double UnitPrice;

// An item whose characteristics are not (yet) defined public StoreItem() { ItemNumber = 0; Category = ItemsCategories.Unknown; Make = "Unknown"; Model = "Unspecified"; Name = "N/A"; UnitPrice = 0.00D; } // An item that is known by its make, model, and unit price public StoreItem(long itmNbr, String make, String model, double price) { ItemNumber = itmNbr; Category = ItemsCategories.Unknown; Make = make; Model = model; Name = "N/A"; UnitPrice = price; } // An item that is known by its name and unit price public StoreItem(long itmNbr, String name, double price) { ItemNumber = itmNbr; Category = ItemsCategories.Unknown; Make = "Unknown"; Model = "Unspecified"; Name = name; UnitPrice = price; } // An item completely defined public StoreItem(long itmNbr, ItemsCategories category, String make, String model, double price) { ItemNumber = itmNbr; Category = category; Make = make; Model = model; UnitPrice = price; } }

}

5. Save the file

if Consider the following program: C# 3.0 Practical Learning

219

using System; public enum HouseType { Unknown, SingleFamily, TownHouse,

Condominium }

public class Exercise { static int Main() { var type = HouseType.Unknown; var choice = 0; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine());

}

Console.WriteLine("\nDesired House Type: {0}", type); return 0;

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. TownHouse 3. Condominium You Choice? 3 Desired House Type: Unknown Press any key to continue . . .

C# 3.0 Practical Learning

220

To check if an expression is true and use its Boolean result, you can use the if operator. Its formula is: if(Condition) Statement;

The Condition can be the type of Boolean operation we studied in the previous lesson. That is, it can have the following formula: Operand1 BooleanOperator Operand2

If the Condition produces a true result, then the compiler executes the Statement. If the statement to execute is short, you can write it on the same line with the condition that is being checked. Here is an example: using System; public enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } public class Exercise { static int Main() { var type = HouseType.Unknown; var choice = 0; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); if (choice == 1) type = HouseType.SingleFamily; Console.WriteLine("\nDesired House Type: {0}", type); return 0; }

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1 Desired House Type: SingleFamily Press any key to continue . . .

If the Statement is too long, you can write it on a different line than the if condition. Here is an example: C# 3.0 Practical Learning

221

using System; public enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } public class Exercise { static int Main() { var type = HouseType.Unknown; var choice = 0; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); if (choice == 1) type = HouseType.SingleFamily;

}

Console.WriteLine("\nDesired House Type: {0}", type); return 0;

}

You can also write the Statement on its own line even if the statement is short enough to fit on the same line with the Condition. Although the (simple) if statement is used to check one condition, it can lead to executing multiple dependent statements. If that is the case, enclose the group of statements between an opening curly bracket “{“ and a closing curly bracket “}”. Here is an example: using System; public enum HouseType { Unknown, SingleFamily, TownHouse, Condominium } public class Exercise { static int Main() { var type = HouseType.Unknown; var choice = 0; Console.WriteLine("Enter the type of house you want to purchase");

C# 3.0 Practical Learning

222

Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine());

}

if (choice == 1) { type = HouseType.SingleFamily; Console.WriteLine("\nDesired House Type: {0}", type); } return 0;

}

If you omit the brackets, only the statement that immediately follows the condition would be executed. Just as you can write one if condition, you can write more than one. Here are examples: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Exercise { static int Main() { var type = HouseType.Unknown; var choice = 0; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); if (choice type = if (choice type = if (choice type =

== 1) HouseType.SingleFamily; == 2) HouseType.Townhouse; == 3) HouseType.Condominium;

Console.WriteLine("\nDesired House Type: {0}", type); return 0; }

}

Here is an example of running the program: C# 3.0 Practical Learning

223

Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 3 Desired House Type: Condominium Press any key to continue . . .

Practical Learning: Using the Simple if Condition 1. Access the Program.cs file and change it as follows: using using using using

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

namespace ElectronicStore2 { public class Program { private static StoreItem CreateStoreItem() { StoreItem sItem = new StoreItem(); int Category;

Videos");

Console.WriteLine( "To create a store item, enter its information"); Console.Write("Item Number: "); sItem.ItemNumber = long.Parse(Console.ReadLine()); Console.WriteLine("Category"); Console.WriteLine("1. Unknown/Miscellaneous"); Console.WriteLine("2. Cables and Connectors"); Console.WriteLine("3. Cell Phones and Accessories"); Console.WriteLine("4. Headphones"); Console.WriteLine("5. Digital Cameras"); Console.WriteLine("6. PDAs and Accessories"); Console.WriteLine("7. Telephones and Accessories"); Console.WriteLine("8. TVs and Videos - Plasma / LCD"); Console.WriteLine("9. Surge Protector"); Console.WriteLine( "10. Instructional and Tutorials (VHS & DVD)TVs and Console.Write("Your Choice? "); category = int.Parse(Console.ReadLine());

if (Category == 1) sItem.Category = ItemsCategories.Unknown; if (Category == 2) sItem.Category = ItemsCategories.CablesAndConnectors; if (Category == 3) sItem.Category = ItemsCategories.CellPhonesAndAccessories; if (Category == 4) sItem.Category = ItemsCategories.Headphones; if (Category == 5) sItem.Category = ItemsCategories.DigitalCameras;

C# 3.0 Practical Learning

224

if (Category == 6) sItem.Category = ItemsCategories.PDAsAndAccessories; if (Category == 7) sItem.Category = ItemsCategories.TelephonesAndAccessories; if (Category == 8) sItem.Category = ItemsCategories.TVsAndVideos; if (Category == 9) sItem.Category = ItemsCategories.SurgeProtectors; if (Category == 10) sItem.Category = ItemsCategories.Instructional; Console.Write("Make: "); sItem.Make = Console.ReadLine(); Console.Write("Model: "); sItem.Model = Console.ReadLine(); Console.Write("Unit Price: "); sItem.UnitPrice = decimal.Parse(Console.ReadLine()); }

return sItem;

static void DescribeStoreItem(StoreItem item) { Console.WriteLine("Store Item Description"); Console.WriteLine("Item Number: {0}", item.ItemNumber); Console.WriteLine("Category: {0}", item.Category); Console.WriteLine("Make: {0}", item.Make); Console.WriteLine("Model: {0}", item.Model); Console.WriteLine("Unit Price: {0:C}", item.UnitPrice); } static void Main() { string strTitle1 = "=-= Nearson Electonics =-="; string strTitle2 = "******* Store Items ******"; StoreItem saleItem = CreateStoreItem(); Console.WriteLine(""); DescribeStoreItem(saleItem); }

}

}

2. Execute the application to see the result. Here is an example:

To create a store item, enter its information Item Number: 868264 Category

C# 3.0 Practical Learning

225

1. Unknown/Miscellaneous 2. Cables and Connectors 3. Cell Phones and Accessories 4. Headphones 5. Digital Cameras 6. PDAs and Accessories 7. Telephones and Accessories 8. TVs and Videos - Plasma / LCD 9. Surge Protector 10. Instructional and Tutorials (VHS & DVD)TVs and Videos Your Choice? 1 Make: Altec Lansing Model: VS4221 Computer Speakers Unit Price: 85.95 Store Item Description Item Number: 868264 Category: Unknown Make: Altec Lansing Model: VS4221 Computer Speakers Unit Price: $85.95 Press any key to continue . . .

3. Close the DOS window

if…else Here is an example of what we learned in the previous section:

using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium }

public class Exercise { static int Main() { var type = HouseType.Unknown;

C# 3.0 Practical Learning

226

var choice = 0; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); if (choice type = if (choice type = if (choice type =

== 1) HouseType.SingleFamily; == 2) HouseType.Townhouse; == 3) HouseType.Condominium;

Console.WriteLine("\nDesired House Type: {0}", type); if (type == HouseType.SingleFamily) Console.WriteLine("\nDesired House Matched"); return 0; }

}

If you use an if condition to perform an operation and if the result is true, we saw that you could execute the statement. As we saw in the previous section, any other result would be ignored. To address an alternative to an if condition, you can use the else condition. The formula to follow is: if(Condition) Statement1; else Statement2;

Once again, the Condition can be a Boolean operation like those we studied in the previous lesson. If the Condition is true, then the compiler would execute Statement1. If the Condition is false, then the compiler would execute Statement2. Here is an example: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Program { static int Main() { var type = HouseType.Unknown; var choice = 0;

C# 3.0 Practical Learning

227

Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); if (choice type = if (choice type = if (choice type =

== 1) HouseType.SingleFamily; == 2) HouseType.Townhouse; == 3) HouseType.Condominium;

Console.WriteLine("\nDesired House Type: {0}", type); if (type == HouseType.SingleFamily) Console.WriteLine("Desired House Matched"); else Console.WriteLine("No House Desired"); return 0; }

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1 Desired House Type: SingleFamily Desired House Matched Press any key to continue . . .

Here is another example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 2 Desired House Type: Townhouse No House Desired Press any key to continue . . .

Practical Learning: Using the if...else Condition 1. Access the Program.cs file and, to use the if...else condition, change the file as follows: using System; using System.Collections.Generic; using System.Linq;

C# 3.0 Practical Learning

228

using System.Text; namespace ElectronicStore2 { class Program { static StoreItem CreateStoreItem() { StoreItem sItem = new StoreItem(); int Category; double ItemPrice = 0D;

Videos");

Console.WriteLine( "To create a store item, enter its information"); Console.Write("Item Number: "); sItem.ItemNumber = long.Parse(Console.ReadLine()); Console.WriteLine("Category"); Console.WriteLine("1. Unknown/Miscellaneous"); Console.WriteLine("2. Cables and Connectors"); Console.WriteLine("3. Cell Phones and Accessories"); Console.WriteLine("4. Headphones"); Console.WriteLine("5. Digital Cameras"); Console.WriteLine("6. PDAs and Accessories"); Console.WriteLine("7. Telephones and Accessories"); Console.WriteLine("8. TVs and Videos - Plasma / LCD"); Console.WriteLine("9. Surge Protector"); Console.WriteLine( "10. Instructional and Tutorials (VHS & DVD)TVs and Console.Write("Your Choice? "); Category = int.Parse(Console.ReadLine());

if (Category == 1) sItem.Category = ItemsCategories.Unknown; if (Category == 2) sItem.Category = ItemsCategories.CablesAndConnectors; if (Category == 3) sItem.Category = ItemsCategories.CellPhonesAndAccessories; if (Category == 4) sItem.Category = ItemsCategories.Headphones; if (Category == 5) sItem.Category = ItemsCategories.DigitalCameras; if (Category == 6) sItem.Category = ItemsCategories.PDAsAndAccessories; if (Category == 7) sItem.Category = ItemsCategories.TelephonesAndAccessories; if (Category == 8) sItem.Category = ItemsCategories.TVsAndVideos; if (Category == 9) sItem.Category = ItemsCategories.SurgeProtectors; if (Category == 10) sItem.Category = ItemsCategories.Instructional; Console.Write("Make: "); sItem.Make = Console.ReadLine(); Console.Write("Model: "); sItem.Model = Console.ReadLine(); Console.Write("Unit Price: ");

C# 3.0 Practical Learning

229

ItemPrice = double.Parse(Console.ReadLine()); if( ItemPrice <= 0 ) sItem.UnitPrice = 0.00D; else sItem.UnitPrice = ItemPrice; return sItem; } static string GetItemCategory(ItemsCategories cat) { string strCategory = "Unknown"; if (cat == ItemsCategories.CablesAndConnectors) strCategory = "Cables & Connectors"; if (cat == ItemsCategories.CellPhonesAndAccessories) strCategory = "Cell Phones & Accessories"; if (cat == ItemsCategories.Headphones) strCategory = "Headphones"; if (cat == ItemsCategories.DigitalCameras) strCategory = "Digital Cameras"; if (cat == ItemsCategories.PDAsAndAccessories) strCategory = "PDAs & Accessories"; if (cat == ItemsCategories.TelephonesAndAccessories) strCategory = "Telephones & Accessories"; if (cat == ItemsCategories.TVsAndVideos) strCategory = "TVs & Videos"; if (cat == ItemsCategories.SurgeProtectors) strCategory = "Surge Protectors"; if (cat == ItemsCategories.Instructional) strCategory = "Instructional"; return strCategory; } static void DescribeStoreItem(StoreItem item) { string strCategory = GetItemCategory(item.Category); Console.WriteLine("Store Item Description"); Console.WriteLine("Item Number: {0}", item.ItemNumber); Console.WriteLine("Category: {0}", strCategory); Console.WriteLine("Make {0}", item.Make); Console.WriteLine("Model: {0}", item.Model); Console.WriteLine("Unit Price: {0:C}", item.UnitPrice); } static void Main() { string strTitle1 = "=-= Nearson Electronics =-="; string strTitle2 = "******* Store Items ******"; Console.WriteLine(strTitle1); Console.WriteLine(strTitle2); StoreItem saleItem = CreateStoreItem(); Console.WriteLine(""); Console.WriteLine(strTitle1); Console.WriteLine(strTitle2); DescribeStoreItem(saleItem);

C# 3.0 Practical Learning

230

Console.WriteLine(""); }

}

}

2. Execute the application to test it. Here is an example:

=-= Nearson Electronics =-= ******* Store Items ****** To create a store item, enter its information Item Number: 937494 Category 1. Unknown/Miscellaneous 2. Cables and Connectors 3. Cell Phones and Accessories 4. Headphones 5. Digital Cameras 6. PDAs and Accessories 7. Telephones and Accessories 8. TVs and Videos - Plasma / LCD 9. Surge Protector 10. Instructional and Tutorials (VHS & DVD)TVs and Videos Your Choice? 5 Make: Canon Model: EOS 30D Unit Price: 1395.95 =-= Nearson Electronics =-= ******* Store Items ****** Store Item Description Item Number: 937494 Category: Digital Cameras Make Canon Model: EOS 30D Unit Price: $1,395.95 Press any key to continue . . .

3. Close the DOS window

Logical Conjunction: AND C# 3.0 Practical Learning

231

Introduction Imagine that a real estate agent who will be using your program is meeting with a potential buyer and asking questions from the following program: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Program { static int Main() { var type = HouseType.Unknown; var choice = 0; var value = 0D; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); if (choice type = if (choice type = if (choice type =

== 1) HouseType.SingleFamily; == 2) HouseType.Townhouse; == 3) HouseType.Condominium;

Console.Write("Up to how much can you afford? $"); value = double.Parse(Console.ReadLine()); Console.WriteLine("\nDesired House Type: Console.WriteLine("Maximum value afforded: }

{0}", type); {0:C}\n", value);

return 0;

}

Suppose a customer responds to these questions: she indicates that she wants single family house but she cannot afford more than $550,000: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1 Up to how much can you afford? $550000 Desired House Type: Maximum value afforded:

SingleFamily $550,000.00

C# 3.0 Practical Learning

232

Press any key to continue . . .

When considering a house for this customer, there are two details to be validated here: the house must be a single family home, second, it must cost less than $550,001. We can create two statements as follows: 1. The house is single family 2. The house costs less than $550,000 From our list of real estate properties, if we find a house that is a single family home, we put it in our list of considered properties: Type of House

House

The house is single family

True

On the other hand, if we find a house that is less than or equal to $550,000, we retain it: Price Range

Value

$550,000

True

One of the ways you can combine two comparisons is by joining them. For our customer, we want a house to meet BOTH criteria. If the house is a town house, based on the request of our customer, its conditional value is false. If the house is more than $550,000, the value of the Boolean Value is true. The Boolean operator used to join two criteria is called AND. This can be illustrated as follows: Type of House House Value

Result

Town House

$625,000

Town House AND $625,000

False

False

False

In C#, the Boolean AND operator is performed using the && operator. Here is an example: using System; public enum HouseType { Unknown, SingleFamily,

C# 3.0 Practical Learning

233

}

Townhouse, Condominium

public class Exercise { static int Main() { var type = HouseType.Unknown; var choice = 0; var value = 0D; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); Console.Write("Up to how much can you afford? $"); value = double.Parse(Console.ReadLine()); if(choice == 1) type = HouseType.SingleFamily; if (choice == 2) type = HouseType.Townhouse; if (choice == 3) type = HouseType.Condominium; Console.WriteLine("\nDesired House Type: Console.WriteLine("Maximum value afforded:

{0}", type); {0:C}", value);

if (type == HouseType.SingleFamily && value <= 550000) Console.WriteLine("\nDesired House Matched"); return 0; }

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1 Up to how much can you afford? $450000 Desired House Type: Maximum value afforded:

SingleFamily $450,000.00

Desired House Matched Press any key to continue . . .

By definition, a logical conjunction combines two conditions. To make the program easier to read, each side of the conditions can be included in parentheses. Here is an example: using System; public enum HouseType

C# 3.0 Practical Learning

234

{ Unknown, SingleFamily, Townhouse, Condominium } public class Exercise { static int Main() { var type = HouseType.Unknown; var choice = 0; var value = 0D; . . .

}

if( (type == HouseType.SingleFamily) && (value <= 550000) ) Console.WriteLine("\nDesired House Matched"); return 0;

}

Suppose we find a single family home. The first condition is true for our customer. With the AND Boolean operator, if the first condition is true, then we consider the second criterion. Suppose that the house we are considering costs $750,500: the price is out of the customer's range. Therefore, the second condition is false. In the AND Boolean algebra, if the second condition is false, even if the first is true, the whole condition is false. This would produce the following table: Type of House House Value

Result

Single Family

$750,500

Single Family AND $750,500

True

False

False

This can be illustrated by the following run of the program: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } class Program { static void Main() { var type = HouseType.Unknown; int choice;

C# 3.0 Practical Learning

235

var value = 0M; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); if (choice type = if (choice type = if (choice type =

== 1) HouseType.SingleFamily; == 2) HouseType.Townhouse; == 3) HouseType.Condominium;

Console.Write("Up to how much can you afford? $"); value = decimal.Parse(Console.ReadLine()); Console.WriteLine("\nDesired House Type: Console.WriteLine("Maximum value afforded:

{0}", type); {0:C}", value);

if (type == HouseType.SingleFamily && value <= 550000) Console.WriteLine("\nDesired House Matched"); else Console.WriteLine("\nThe House Doesn't Match the Desired Criteria"); } }

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1 Up to how much can you afford? $750000 Desired House Type: Maximum value afforded:

SingleFamily $750,000.00

The House Doesn't Match the Desired Criteria Press any key to continue . . .

Suppose we find a townhouse that costs $420,000. Although the second condition is true, the first is false. In Boolean algebra, an AND operation is false if either condition is false: Type of House House Value

Result

Town House

$420,000

Town House AND $420,000

False

True

False

C# 3.0 Practical Learning

236

Here is an example of running the above program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 2 Up to how much can you afford? $420000 Desired House Type: Maximum value afforded:

Townhouse $420,000.00

The House Doesn't Match the Desired Criteria Press any key to continue . . .

If we find a single family home that costs $345,000, both conditions are true. In Boolean algebra, an AND operation is true if BOTH conditions are true. This can be illustrated as follows: Type of House House Value

Result

Single Family

$345,000

Single Family AND $345,000

True

True

True

This can be revealed in the following run of the above program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1 Up to how much can you afford? $345000 Desired House Type: Maximum value afforded:

SingleFamily $345,000.00

Desired House Matched Press any key to continue . . .

These four tables can be resumed as follows: If Condition1 If Condition2 is is

Condition1 AND Condition2

False

False

False

False

True

False

True

False

False

C# 3.0 Practical Learning

237

True

True

True

As you can see, a logical conjunction is true only of BOTH conditions are true.

Combining Conjunctions As seen above, the logical conjunction operator is used to combine two conditions. In some cases, you will need to combine more than two conditions. Imagine a customer wants to purchase a single family house that costs up to $450,000 with an indoor garage. This means that the house must fulfill these three requirements: A. The house is a single family home B. The house costs less than $450,001 C. The house has an indoor garage Here the program that could be used to check these conditions: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Exercise { static int Main() { var type = HouseType.Unknown; var choice = 0; var value = 0D; var hasIndoorGarage = false; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); if (choice type = if (choice type = if (choice type =

== 1) HouseType.SingleFamily; == 2) HouseType.Townhouse; == 3) HouseType.Condominium;

Console.Write("Up to how much can you afford? $"); value = double.Parse(Console.ReadLine());

C# 3.0 Practical Learning

238

Console.Write("Does the house have an indoor garage (1=Yes/0=No)?

");

int ans = int.Parse(Console.ReadLine()); Console.WriteLine("\nDesired House Type: {0}", type); Console.WriteLine("Maximum value afforded: {0:C}", value); Console.Write("House has indoor garage: "); if (ans == 1) Console.WriteLine("Yes"); else Console.WriteLine("No"); == 1))

if ((type == HouseType.SingleFamily) && (value <= 550000) && (ans Console.WriteLine("\nDesired House Matched");

else Criteria");

Console.WriteLine("\nThe House Doesn't Match the Desired

return 0; }

}

We saw that when two conditions are combined, the compiler first checks the first condition, followed by the second. In the same way, if three conditions need to be considered, the compiler evaluates the truthfulness of the first condition: Type of House A

Town House False If the first condition (or any condition) is false, the whole condition is false, regardless of the outcome of the other(s). If the first condition is true, then the second condition is evaluated for its truthfulness: Type of House

Property Value

A

B

Single Family

$655,000

True

False

C# 3.0 Practical Learning

239

If the second condition is false, the whole combination is considered false: A

B

A && B

True

False

False

When evaluating three conditions, if either the first or the second is false, since the whole condition would become false, there is no reason to evaluate the third. If both the first and the second conditions are false, there is also no reason to evaluate the third condition. Only if the first two conditions are true will the third condition be evaluated whether it is true: Type of House

Property Value

Indoor Garage

A

B

C

Single Family

$425,650

None

True

True

False

The combination of these conditions in a logical conjunction can be written as A && B && C. If the third condition is false, the whole combination is considered false: A

B

A && B

C

A && B && C

True

True

True

False

False

To verify this, here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1 Up to how much can you afford? $425000 Does the house have an indoor garage (1=Yes/0=No)? 0 Desired House Type: SingleFamily Maximum value afforded: $425,000.00 House has indoor garage: No The House Doesn't Match the Desired Criteria Press any key to continue . . .

From our discussion so far, the truth table of the combinations can be illustrated as follows: C# 3.0 Practical Learning

240

A

B

C

A && B && C

False

Don't Care

Don't Care

False

True

False

Don't Care

False

True

True

False

False

The whole combination is true only if all three conditions are true. This can be illustrated as follows: A

B

C

A && B && C

False

False

False

False

False

False

True

False

True

False

False

False

True

False

True

False

False

True

False

False

False

True

True

False

True

True

False

False

True

True

True

True

Logical Disjunction: OR Introduction Our real estate company has single family homes, townhouses, and condominiums. All of the condos have only one level, also referred to as a story. Some of the single family homes have one story, some have two and some others have three levels. All townhouses have three levels. Another customer wants to buy a home. The customer says that he primarily wants a condo, but if our real estate company doesn't have a condominium, that is, if the company has only houses, whatever it is, whether a house or a condo, it must have only one level (story) (due to an illness, the customer would not climb the stairs). When considering the properties of our company, we would proceed with these statements: 1. The property is a condominium 2. The property has one story If we find a condo, since all of our condos have only one level, the criterion set by the customer is true. Even if we were considering another (type of) property, it wouldn't matter. This can be resumed in the following table: C# 3.0 Practical Learning

241

Type of House

House

Condominium

True

The other properties would not be considered, especially if they have more than one story: Number of Stories

Value

3

False

To check for either of two conditions, in Boolean algebra, you can use an operator called OR. We can show this operation as follows: Condominium One Story Condominium OR 1 Story

True

False

True

In Boolean algebra, this type of comparison is performed using the OR operator. In C#, the OR operator is performed using the || operator. Here is an example: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Exercise { static int Main() { var type = HouseType.Unknown; var choice = 0; var stories = 1; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); choice = int.Parse(Console.ReadLine()); if (choice type = if (choice type = if (choice type =

== 1) HouseType.SingleFamily; == 2) HouseType.Townhouse; == 3) HouseType.Condominium;

C# 3.0 Practical Learning

242

Console.Write("How many stories? "); stories = int.Parse(Console.ReadLine()); Console.WriteLine("\nDesired House Type: {0}", type); Console.WriteLine("Number of Stories: {0}", stories); if ((type == HouseType.Condominium) || (stories == 1)) Console.WriteLine("\nDesired House Matched"); else Console.WriteLine("\nThe House Doesn't Match the Desired Criteria"); }

return 0;

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 3 How many stories? 6 Desired House Type: Condominium Number of Stories: 6 Desired House Matched Press any key to continue . . .

Suppose that, among the properties our real estate company has available, there is no condominium. In this case, we would then consider the other properties: Type of House

House

Single Family

False

If we have a few single family homes, we would look for one that has only one story. Once we find one, our second criterion becomes true: Type of House

False

One Story Condominium OR 1 Story

True

True

This can be illustrated in the following run of the above program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1

C# 3.0 Practical Learning

243

How many stories? 1 Desired House Type: SingleFamily Number of Stories: 1 Desired House Matched Press any key to continue . . .

If we find a condo and it is one story, both criteria are true. This can be illustrated in the following table: Type of House

One Story Condominium OR 1 Story

False

True

True

True

True

True

The following run of the program demonstrates this: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 3 How many stories? 1 Desired House Type: Condominium Number of Stories: 1 Desired House Matched Press any key to continue . . .

A Boolean OR operation produces a false result only if BOTH conditions ARE FALSE: If Condition1 If Condition2 Condition1 OR Condition2 is is

False

True

True

True

False

True

True

True

True

False

False

False

Here is another example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 2 How many stories? 2 Desired House Type: Townhouse

C# 3.0 Practical Learning

244

Number of Stories:

2

The House Doesn't Match the Desired Criteria Press any key to continue . . .

Combinations of Disjunctions As opposed to evaluating only two conditions, you may face a situation that presents three of them and must consider a combination of more than two conditions.

C# 3.0 Practical Learning

245

CONDITIONAL SWITCHES if Switches The Ternary Operator (?:) The conditional operator behaves like a simple if…else statement. Its syntax is: Condition ? Statement1 : Statement2;

The compiler would first test the Condition. If the Condition is true, then it would execute Statement1, otherwise it would execute Statement2. When you request two numbers from the user and would like to compare them, the following program would do find out which one of both numbers is higher. The comparison is performed using the conditional operator:

using System; public class Exercise { static int Main() { var Number1 = 0; var Number2 = 0; var Maximum = 0; var Num1 = ""; var Num2 = ""; Console.Write("Enter first numbers: "); Num1 = Console.ReadLine(); Console.Write("Enter second numbers: "); Num2 = Console.ReadLine(); Number1 = int.Parse(Num1); Number2 = int.Parse(Num2); Maximum = (Number1 < Number2) ? Number2 : Number1; Console.Write("\nThe maximum of "); Console.Write(Number1); Console.Write(" and "); Console.Write(Number2); Console.Write(" is "); Console.WriteLine(Maximum); Console.WriteLine(); return 0;

C# 3.0 Practical Learning

246

} }

Here is an example of running the program; Enter first numbers: 244 Enter second numbers: 68 The maximum of 244 and 68 is 244

Practical Learning: Introducing Conditional Switches 1. Start Microsoft Visual C# 2. Create a new Console Application named FlowerShop2 3. To create a new class, on the main menu, click Project -> Add Class... 4. Set the Name of the class to Flower and click Add 5. Complete the Flower.cs file as follows: using using using using

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

namespace FlowerShop2 { public enum FlowerType { Roses = 1, Lilies, Daisies, Carnations, LivePlant, Mixed } public enum FlowerColor { Red = 1, White, Yellow, Pink, Orange, Blue, Lavender, Mixed } public enum FlowerArrangement { Bouquet = 1, Vase, Basket, Any }

C# 3.0 Practical Learning

247

public class Flower { public FlowerType Type; public FlowerColor Color; public FlowerArrangement Arrangement; public decimal UnitPrice;

}

public Flower() { Type = FlowerType.Mixed; Color = FlowerColor.Mixed; Arrangement = FlowerArrangement.Vase; UnitPrice = 0.00M; } public Flower(FlowerType type) { Type = type; Color = FlowerColor.Mixed; Arrangement = FlowerArrangement.Vase; UnitPrice = 0.00M; } public Flower(FlowerType type, FlowerColor color, FlowerArrangement argn, decimal price) { Type = type; Color = color; Arrangement = argn; UnitPrice = price; }

}

6. Save the file

if…else if and if…else if…else If you use an if...else conditional statement, you can process only two statements. In some cases, you may deal with more than two conditions. In this case, you can use an if...else if condition. Its formula is: if(Condition1) Statement1; else if(Condition2) Statement2;

The compiler would first check Condition1. If Condition1 is true, then Statement1 would be executed. If Condition1 is false, then the compiler would check Condition2. If Condition2 is true, then the compiler would execute Statement2. Any other result would be ignored. Here is an example: using System; public enum HouseType { Unknown,

C# 3.0 Practical Learning

248

SingleFamily, Townhouse,

Condominium } public class Exercise { static int Main() { var Type = HouseType.Unknown; var Choice = 0; var Garage = ""; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); Choice = int.Parse(Console.ReadLine()); if (Choice == 1) Type = HouseType.SingleFamily; else if (Choice == 2) Type = HouseType.Townhouse; Console.Write("Does the house have an indoor garage (1=Yes/0=No)?

");

var Answer if (Answer Garage else Garage

}

= int.Parse(Console.ReadLine()); == 1) = "Yes"; = "No";

Console.WriteLine("\nDesired House Type: {0}", Type); Console.WriteLine("Has indoor garage? {0}", Garage); return 0;

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1 Does the house have an indoor garage (1=Yes/0=No)? 1 Desired House Type: SingleFamily Has indoor garage? Yes Press any key to continue . . .

Here is another example of running the program: Enter the type of house you want to purchase 1. Single Family

C# 3.0 Practical Learning

249

2. Townhouse 3. Condominium You Choice? 2 Does the house have an indoor garage (1=Yes/0=No)? 6 Desired House Type: Townhouse Has indoor garage? No Press any key to continue . . .

Notice that only two conditions are evaluated. Any condition other than these two is not considered. Because there can be other alternatives, the C# language provides an alternate else as the last resort. Its formula is: if(Condition1) Statement1; else if(Condition2) Statement2; else Statement-n;

if(Condition1) Statement1; else if(Condition2) Statement2; else if(Condition3) Statement3; else Statement-n;

The compiler will check the first condition. If Condition1 is true, it executes Statement1. If Condition1 is false, then the compiler will check the second condition. If Condition2 is true, it will execute Statement2. When the compiler finds a Condition-n to be true, it will execute its corresponding statement. It that Condition-n is false, the compiler will check the subsequent condition. This means you can include as many conditions as you see fit using the else if statement. If after examining all the known possible conditions you still think that there might be an unexpected condition, you can use the optional single else. Here is an example: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Exercise { public static int Main() { var Type = HouseType.Unknown; var Choice = 0; var Garage = ""; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); Choice = int.Parse(Console.ReadLine()); if (Choice == 1)

C# 3.0 Practical Learning

250

Type = HouseType.SingleFamily; else if (Choice == 2) Type = HouseType.Townhouse; else if (Choice == 3) Type = HouseType.Condominium; else Type = HouseType.Unknown; Console.Write("Does the house have an indoor garage (1=Yes/0=No)? ");

var Answer if (Answer Garage else Garage

= int.Parse(Console.ReadLine()); == 1) = "Yes"; = "No";

Console.WriteLine("\nDesired House Type: {0}", Type); Console.WriteLine("Has indoor garage? {0}", Garage); }

return 0;

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 3 Does the house have an indoor garage (1=Yes/0=No)? 0 Desired House Type: Condominium Has indoor garage? No Press any key to continue . . .

Case Switches Introduction When defining an expression whose result would lead to a specific program execution, the switch statement considers that result and executes a statement based on the possible outcome of that expression, this possible outcome is called a case. The different outcomes are listed in the body of the switch statement and each case has its own execution, if necessary. The body of a switch statement is delimited from an opening to a closing curly brackets: “{“ to “}”. The syntax of the switch statement is: switch(Expression) { case Choice1: Statement1; break; case Choice2: Statement2; break;

C# 3.0 Practical Learning

251

case Choice-n: Statement-n; break; }

In C++, you can omit the break keyword in a case. This creates the "fall through" effect as follows: after code executes in a case, if nothing "stops" it, the execution continues to the next case. This has caused problems and confusing execution in the past in some C++ programs. To avoid it, C# requires code interruption at the end of every case. This interruption is done using the break keyword. The expression to examine in a case statement is an integer. Since a member of an enumerator (enum) and the character (char) data types are just other forms of integers, they can be used too. Here is an example of using the switch statement: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Exercise { public static int Main() { var Type = HouseType.Unknown; var Choice = 0; var Garage = ""; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); Choice = int.Parse(Console.ReadLine()); switch (Choice) { case 1: Type = HouseType.SingleFamily; break; case 2: Type = HouseType.Townhouse; break; case 3: Type = HouseType.Condominium; break; }

C# 3.0 Practical Learning

252

Console.Write("Does the house have an indoor garage (1=Yes/0=No)? ");

var Answer if (Answer Garage else Garage

= int.Parse(Console.ReadLine()); == 1) = "Yes"; = "No";

Console.WriteLine("\nDesired House Type: {0}", Type); Console.WriteLine("Has indoor garage? {0}", Garage); }

return 0;

}

When establishing the possible outcomes that the switch statement should consider, at times there will be possibilities other than those listed and you will be likely to consider them. This special case is handled by the default keyword. The default case would be considered if none of the listed cases matches the supplied answer. The syntax of the switch statement that considers the default case would be: switch(Expression) { case Choice1: Statement1; break; case Choice2: Statement2; break; case Choice-n: Statement-n; break; default: Other-Possibility; break; }

In C++, the default section doesn't need a break keyword because it is the last. In C#, every case and the default section must have its own exit mechanism, which is taken care of by a break keyword. Therefore another version of the program above would be using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Exercise { public static int Main() {

C# 3.0 Practical Learning

253

var Type = HouseType.Unknown; var Choice = 0; var Garage = ""; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); Choice = int.Parse(Console.ReadLine()); switch (Choice) { case 1: Type = HouseType.SingleFamily; break; case 2: Type = HouseType.Townhouse; break; case 3: Type = HouseType.Condominium; break; default: Type = HouseType.Unknown; break; } Console.Write("Does the house have an indoor garage (1=Yes/0=No)?

");

var Answer if (Answer Garage else Garage

= int.Parse(Console.ReadLine()); == 1) = "Yes"; = "No";

Console.WriteLine("\nDesired House Type: {0}", Type); Console.WriteLine("Has indoor garage? {0}", Garage); return 0; }

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 8 Does the house have an indoor garage (1=Yes/0=No)? 2 Desired House Type: Unknown Has indoor garage? No Press any key to continue . . .

C# 3.0 Practical Learning

254

Besides a value of an int type, you can also use another variant of integers on a switch statement. For example, you can use letters to validate the cases. Here is an example: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Exercise { public static int Main() { var Type = HouseType.Unknown; var Choice = 0; var Garage = ""; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); Choice = int.Parse(Console.ReadLine()); switch (Choice) { case 1: Type = HouseType.SingleFamily; break; case 2: Type = HouseType.Townhouse; break; case 3: Type = HouseType.Condominium; break; default: Type = HouseType.Unknown; break; } Console.Write("Does the house have an indoor garage (y/n)? "); var Answer = char.Parse(Console.ReadLine()); switch (Answer) { case 'y': Garage = "Yes"; break; case 'Y': Garage = "Yes";

C# 3.0 Practical Learning

255

break; case 'n': Garage = "No"; break; case 'N': Garage = "No"; break; default: Garage = "Not Specified"; break; } Console.WriteLine("\nDesired House Type: {0}", Type); Console.WriteLine("Has indoor garage? {0}", Garage); return 0; }

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 3 Does the house have an indoor garage (y/n)? y Desired House Type: Condominium Has indoor garage? Yes Press any key to continue . . .

Practical Learning: Using Conditional Switches 1. To create a new class, in the Solution Explorer, right-click the project name, position the mouse on Add and click Class... 2. Set the Name of the class to OrderProcessing and click Add 3. Complete the OrderProcessing.cs file as follows: using using using using

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

namespace FlowerShop2 { class OrderProcessing { public Flower FlowerOrder; public int Quantity; public OrderProcessing() {

C# 3.0 Practical Learning

256

FlowerOrder = new Flower(); } public decimal GetTotalPrice() { return Quantity * FlowerOrder.UnitPrice; } public void GetFlowerType() { int choice = 0; Console.WriteLine("Enter the Type of Flower Order"); Console.WriteLine("1. Roses"); Console.WriteLine("2. Lilies"); Console.WriteLine("3. Daisies"); Console.WriteLine("4. Carnations"); Console.WriteLine("5. Live Plant"); Console.WriteLine("6. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine()); switch (choice) { case 1: FlowerOrder.Type break; case 2: FlowerOrder.Type break; case 3: FlowerOrder.Type break; case 4: FlowerOrder.Type break; case 5: FlowerOrder.Type break; default: FlowerOrder.Type break; }

= FlowerType.Roses; = FlowerType.Lilies; = FlowerType.Daisies; = FlowerType.Carnations; = FlowerType.LivePlant; = FlowerType.Mixed;

} public void GetFlowerColor() { int choice = 0; Console.WriteLine("Enter the Color"); Console.WriteLine("1. Red"); Console.WriteLine("2. White"); Console.WriteLine("3. Yellow"); Console.WriteLine("4. Pink"); Console.WriteLine("5. Orange"); Console.WriteLine("6. Blue"); Console.WriteLine("7. Lavender"); Console.WriteLine("8. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine());

C# 3.0 Practical Learning

257

}

switch (choice) { case 1: FlowerOrder.Color break; case 2: FlowerOrder.Color break; case 3: FlowerOrder.Color break; case 4: FlowerOrder.Color break; case 5: FlowerOrder.Color break; case 6: FlowerOrder.Color break; case 7: FlowerOrder.Color break; default: FlowerOrder.Color break; }

= FlowerColor.Red; = FlowerColor.White; = FlowerColor.Yellow; = FlowerColor.Pink; = FlowerColor.Yellow; = FlowerColor.Blue; = FlowerColor.Lavender; = FlowerColor.Mixed;

public void GetFlowerArrangement() { int choice = 0; Console.WriteLine("Enter the Type of Arrangement"); Console.WriteLine("1. Bouquet"); Console.WriteLine("2. Vase"); Console.WriteLine("3. Basket"); Console.WriteLine("4. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine()); switch (choice) { case 1: FlowerOrder.Arrangement break; case 2: FlowerOrder.Arrangement break; case 3: FlowerOrder.Arrangement break; default: FlowerOrder.Arrangement break; }

= FlowerArrangement.Bouquet; = FlowerArrangement.Vase; = FlowerArrangement.Basket; = FlowerArrangement.Any;

} public void ProcessOrder()

C# 3.0 Practical Learning

258

{ GetFlowerType(); GetFlowerColor(); GetFlowerArrangement(); Console.Write("Enter the Unit Price: "); FlowerOrder.UnitPrice = decimal.Parse(Console.ReadLine());

}

Console.Write("Enter Quantity: "); Quantity = int.Parse(Console.ReadLine());

public void ShowOrder() { Console.WriteLine("======================="); Console.WriteLine("==-=-=Flower Shop=-=-=="); Console.WriteLine("-----------------------"); Console.WriteLine("Flower Type: {0}", FlowerOrder.Type); Console.WriteLine("Flower Color: {0}", FlowerOrder.Color); Console.WriteLine("Arrangement: {0}", FlowerOrder.Arrangement); Console.WriteLine("Price: {0:C}", FlowerOrder.UnitPrice); Console.WriteLine("Quantity: {0}", Quantity); Console.WriteLine("Total Price: {0:C}", GetTotalPrice()); Console.WriteLine("======================="); } } }

4. Access the Program.cs file and complete it as follows: using using using using

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

namespace FlowerShop2 { class Program { static void Main() { OrderProcessing order = new OrderProcessing(); order.ProcessOrder(); Console.WriteLine(); order.ShowOrder(); Console.WriteLine(); }

}

}

5. Execute the application and test it. Here is an example: Enter the Type of Flower Order 1. Roses

C# 3.0 Practical Learning

259

2. Lilies 3. Daisies 4. Carnations 5. Live Plant 6. Mixed Your Choice: 4 Enter the Color 1. Red 2. White 3. Yellow 4. Pink 5. Orange 6. Blue 7. Lavender 8. Mixed Your Choice: 7 Enter the Type of Arrangement 1. Bouquet 2. Vase 3. Basket 4. Mixed Your Choice: 3 Enter the Unit Price: 45.85 Enter Quantity: 3 ======================= ==-=-=Flower Shop=-=-== ----------------------Flower Type: Carnations Flower Color: Lavender Arrangement: Basket Price: $45.85 Quantity: 3 Total Price: $137.55 ======================= Press any key to continue . . .

6. Close the DOS window

Combining Cases Each of the cases we have used so far examined only one possibility before executing the corresponding statement. You can combine cases to execute the same statement. To do this, type a case, its value, and the semi-colon. Type another case using the same formula. When the cases are ready, you can then execute the desired statement. Here is an example: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium }

C# 3.0 Practical Learning

260

public class Exercise { public static int Main() { var Type = HouseType.Unknown; var Choice = 0; var Garage = ""; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); Choice = int.Parse(Console.ReadLine()); switch (Choice) { case 1: Type = HouseType.SingleFamily; break; case 2: Type = HouseType.Townhouse; break; case 3: Type = HouseType.Condominium; break; default: Type = HouseType.Unknown; break; } Console.Write("Does the house have an indoor garage (y/n)? "); var Answer = char.Parse(Console.ReadLine()); switch (Answer) { case 'y': case 'Y': Garage = "Yes"; break; case 'n': case 'N': Garage = "No"; break;

}

default: Garage = "Not Specified"; break;

Console.WriteLine("\nDesired House Type: {0}", Type); Console.WriteLine("Has indoor garage? {0}", Garage); }

return 0;

}

C# 3.0 Practical Learning

261

This would produce: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 3 Does the house have an indoor garage (y/n)? Y Desired House Type: Condominium Has indoor garage? Yes Press any key to continue . . .

Using Enumerations One of the most fundamental uses of enumerations is to process them in a switch statement. To do this, you pass the value of an enumeration to a switch. The values of the enumerations are then processed in the case statements. Here is an example: using System; public enum HouseType { Unknown, SingleFamily, Townhouse, Condominium } public class Exercise { public static int Main() { var PropertyType = ""; var Choice = 0; var Garage = ""; Console.WriteLine("Enter the type of house you want to purchase"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.Write("You Choice? "); Choice = int.Parse(Console.ReadLine()); switch ((HouseType)Choice) { case HouseType.SingleFamily: PropertyType = "Single Family"; break; case HouseType.Townhouse: PropertyType = "Townhouse"; break; case HouseType.Condominium: PropertyType = "Condominium";

C# 3.0 Practical Learning

262

break; default: PropertyType = "Unknown"; break; } Console.Write("Does the house have an indoor garage (y/n)? "); var Answer = char.Parse(Console.ReadLine()); switch (Answer) { case 'y': case 'Y': Garage = "Yes"; break; case 'n': case 'N': Garage = "No"; break;

}

default: Garage = "Not Specified"; break;

Console.WriteLine("\nDesired House Type: {0}", PropertyType); Console.WriteLine("Has indoor garage? {0}", Garage); }

return 0;

}

Here is an example of running the program: Enter the type of house you want to purchase 1. Single Family 2. Townhouse 3. Condominium You Choice? 1 Does the house have an indoor garage (y/n)? N Desired House Type: Single Family Has indoor garage? No Press any key to continue . . .

C# 3.0 Practical Learning

263

COUNTING AND LOOPING Conditional Looping

Introduction A loop is a type of conditional statement that keeps checking a condition and executing a statement until the condition is false.

while a Condition is True One of the operators used to perform a loop is called while. Its formula is: while(Condition) Statement;

To execute this expression, the compiler first examines the Condition. If the Condition is true, then it executes the Statement. After executing the Statement, the Condition is checked again. AS LONG AS the Condition is true, it will keep executing the Statement. When or once the Condition becomes false, it exits the loop:

Here is an example: using System; public class Exercise

C# 3.0 Practical Learning

264

{ public static int Main() { var Stories = 0; while( Stories <= 4 ) { Console.WriteLine("Number {0}", Stories); Stories++; } Console.WriteLine(); return 0; }

}

This would produce: Number Number Number Number Number

0 1 2 3 4

Press any key to continue . . .

To effectively execute a while condition, you should make sure you provide a mechanism for the compiler to use or get a reference value for the condition, variable, or expression being checked. This is sometimes in the form of a variable being initialized although it could be some other expression. Such a while condition could be illustrated as follows:

do This while a Condition is True The while loop is used first check a condition and then execute a statement. If the condition is false, the statement would never execute. Consider the following program: 265 C# 3.0 Practical Learning

using System; public class Exercise { public static int Main() { var Stories = 5; while (Stories <= 4) { Console.WriteLine("Number {0}", Stories); Stories++; }

}

Console.WriteLine(); return 0;

}

When this program executes, nothing from the while loop would execute because, as the condition is checked in the beginning, it is false and the compiler would not get to the Statement. In some cases, you may want to execute a statement before checking the condition for the first time. This can be done using the do…while statement. Its formula is: do Statement while (Condition);

The do…while condition executes a Statement first. After the first execution of the Statement, it examines the Condition. If the Condition is true, then it executes the Statement again. It will keep executing the Statement AS LONG AS the Condition is true. Once the Condition becomes false, the looping (the execution of the Statement) would stop. If the Statement is a short one, such as made of one line, simply write it after the do keyword. Like the if and the while statements, the Condition being checked must be included between parentheses. The whole do…while statement must end with a semicolon.

Another version of the counting program seen previously would be: using System;

C# 3.0 Practical Learning

266

public class Exercise { public static int Main() { var Stories = 0; do Console.WriteLine("Number {0}", Stories++); while (Stories <= 4);

}

Console.WriteLine(); return 0;

}

This would produce: Number Number Number Number Number

0 1 2 3 4

Press any key to continue . . .

If the Statement is long and should span more than one line, start it with an opening curly bracket "{" and end it with a closing curly bracket "}".

Practical Learning: Introducing Counting and Looping 1. Start Microsoft Visual C# 2. Create a new Console Application named FlowerShop3 3. To create a new class, in the Class View, right-click the project name -> Add -> Class... 4. Set the Name of the class to Flower and click Add 5. Complete the Flower.cs file as follows: using using using using

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

namespace FlowerShop3 { public enum FlowerType { Roses = 1, Lilies, Daisies, Carnations, LivePlant, Mixed }

C# 3.0 Practical Learning

267

public enum FlowerColor { Red = 1, White, Yellow, Pink, Orange, Blue, Lavender, Mixed } public enum FlowerArrangement { Bouquet = 1, Vase, Basket, Any } class Flower { public FlowerType Type; public FlowerColor Color; public FlowerArrangement Arrangement; public decimal UnitPrice; public Flower() { Type = FlowerType.Mixed; Color = FlowerColor.Mixed; Arrangement = FlowerArrangement.Vase; UnitPrice = 0.00M; } public Flower(FlowerType type) { Type = type; Color = FlowerColor.Mixed; Arrangement = FlowerArrangement.Vase; UnitPrice = 0.00M; } public Flower(FlowerType type, FlowerColor color, FlowerArrangement argn, decimal price) { Type = type; Color = color; Arrangement = argn; UnitPrice = price; } }

}

6. To create a new class, in the Solution Explorer, right-click the project name, position the mouse on Add and click Class... 7. Set the Name of the class to OrderProcessing and click Add 8. Complete the OrderProcessing.cs file as follows: C# 3.0 Practical Learning

268

using using using using

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

namespace FlowerShop3 { class OrderProcessing { public Flower FlowerOrder; public int Quantity; public OrderProcessing() { FlowerOrder = new Flower(); } public decimal GetTotalPrice() { return Quantity * FlowerOrder.UnitPrice; } public void GetFlowerType() { int choice = 0; do {

Console.WriteLine("Enter the Type of Flower Order"); Console.WriteLine("1. Roses"); Console.WriteLine("2. Lilies"); Console.WriteLine("3. Daisies"); Console.WriteLine("4. Carnations"); Console.WriteLine("5. Live Plant"); Console.WriteLine("6. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine()); } while ((choice < 1) || (choice > 6)); switch (choice) { case 1: FlowerOrder.Type break; case 2: FlowerOrder.Type break; case 3: FlowerOrder.Type break; case 4: FlowerOrder.Type break; case 5: FlowerOrder.Type break; default: FlowerOrder.Type break; }

= FlowerType.Roses; = FlowerType.Lilies; = FlowerType.Daisies; = FlowerType.Carnations; = FlowerType.LivePlant; = FlowerType.Mixed;

C# 3.0 Practical Learning

269

} public void GetFlowerColor() { int choice = 0; do {

Console.WriteLine("Enter the Color"); Console.WriteLine("1. Red"); Console.WriteLine("2. White"); Console.WriteLine("3. Yellow"); Console.WriteLine("4. Pink"); Console.WriteLine("5. Orange"); Console.WriteLine("6. Blue"); Console.WriteLine("7. Lavender"); Console.WriteLine("8. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine()); } while ((choice < 1) || (choice > 8));

}

switch (choice) { case 1: FlowerOrder.Color break; case 2: FlowerOrder.Color break; case 3: FlowerOrder.Color break; case 4: FlowerOrder.Color break; case 5: FlowerOrder.Color break; case 6: FlowerOrder.Color break; case 7: FlowerOrder.Color break; default: FlowerOrder.Color break; }

= FlowerColor.Red; = FlowerColor.White; = FlowerColor.Yellow; = FlowerColor.Pink; = FlowerColor.Yellow; = FlowerColor.Blue; = FlowerColor.Lavender; = FlowerColor.Mixed;

public void GetFlowerArrangement() { int choice = 0; do {

Console.WriteLine("Enter the Type of Arrangement"); Console.WriteLine("1. Bouquet"); Console.WriteLine("2. Vase"); Console.WriteLine("3. Basket");

C# 3.0 Practical Learning

270

Console.WriteLine("4. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine()); } while ((choice < 1) || (choice > 4));

}

switch (choice) { case 1: FlowerOrder.Arrangement break; case 2: FlowerOrder.Arrangement break; case 3: FlowerOrder.Arrangement break; default: FlowerOrder.Arrangement break; }

= FlowerArrangement.Bouquet; = FlowerArrangement.Vase; = FlowerArrangement.Basket; = FlowerArrangement.Any;

public void ProcessOrder() { GetFlowerType(); GetFlowerColor(); GetFlowerArrangement(); Console.Write("Enter the Unit Price: "); FlowerOrder.UnitPrice = decimal.Parse(Console.ReadLine()); Console.Write("Enter Quantity: "); Quantity = int.Parse(Console.ReadLine()); } public void ShowOrder() { Console.WriteLine("======================="); Console.WriteLine("==-=-=Flower Shop=-=-=="); Console.WriteLine("-----------------------"); Console.WriteLine("Flower Type: {0}", FlowerOrder.Type); Console.WriteLine("Flower Color: {0}", FlowerOrder.Color); Console.WriteLine("Arrangement: {0}", FlowerOrder.Arrangement); Console.WriteLine("Price: {0:C}", FlowerOrder.UnitPrice); Console.WriteLine("Quantity: {0}", Quantity); Console.WriteLine("Total Price: {0:C}", GetTotalPrice()); Console.WriteLine("======================="); } } }

9. Access the Program.cs file and complete it as follows: using using using using

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

C# 3.0 Practical Learning

271

namespace FlowerShop3 { class Program { static void Main() { OrderProcessing order = new OrderProcessing(); order.ProcessOrder(); Console.WriteLine();

} }

order.ShowOrder(); Console.WriteLine();

}

10.

Execute the application and test it. Here is an example:

Enter the Type of Flower Order 1. Roses 2. Lilies 3. Daisies 4. Carnations 5. Live Plant 6. Mixed Your Choice: 8 Enter the Type of Flower Order 1. Roses 2. Lilies 3. Daisies 4. Carnations 5. Live Plant 6. Mixed Your Choice: 2 Enter the Color 1. Red 2. White 3. Yellow 4. Pink 5. Orange 6. Blue 7. Lavender 8. Mixed Your Choice: 9 Enter the Color 1. Red 2. White 3. Yellow 4. Pink 5. Orange 6. Blue 7. Lavender 8. Mixed Your Choice: 0 Enter the Color 1. Red 2. White

C# 3.0 Practical Learning

272

3. Yellow 4. Pink 5. Orange 6. Blue 7. Lavender 8. Mixed Your Choice: 7 Enter the Type of Arrangement 1. Bouquet 2. Vase 3. Basket 4. Mixed Your Choice: 8 Enter the Type of Arrangement 1. Bouquet 2. Vase 3. Basket 4. Mixed Your Choice: 5 Enter the Type of Arrangement 1. Bouquet 2. Vase 3. Basket 4. Mixed Your Choice: 2 Enter the Unit Price: 42.85 Enter Quantity: 2 ======================= ==-=-=Flower Shop=-=-== ----------------------Flower Type: Lilies Flower Color: Lavender Arrangement: Vase Price: $42.85 Quantity: 2 Total Price: $85.70 ======================= Press any key to continue . . .

11.

Close the DOS window

for The for statement is typically used to count a number of items. At its regular structure, it is divided in three parts. The first section specifies the starting point for the count. The second section sets the counting limit. The last section determines the counting frequency. The syntax of the for statement is: for(Start; End; Frequency) Statement;

The Start expression is a variable assigned the starting value. This could be Count = 0; The End expression sets the criteria for ending the counting. An example would be Count < 24; this means the counting would continue as long as the C# 3.0 Practical Learning

273

Count variable is less than 24. When the count is about to rich 24, because in this case 24 is excluded, the counting would stop. To include the counting limit, use the <= or >= comparison operators depending on how you are counting. The Frequency expression would let the compiler know how many numbers to add or subtract before continuing with the loop. This expression could be an increment operation such as ++Count. Here is an example that applies the for statement: using System; public class Exercise { public static int Main() { for (var Stories = 0; Stories <= 4; Stories++) Console.WriteLine("Number {0}", Stories); Console.WriteLine(); return 0;

} }

This would produce: Number Number Number Number

1 2 3 4

Press any key to continue . . .

Controlling the Conditional Statements Nesting a Conditional Statement Consider the following program: using System; public class Exercise { public static int Main() { var TypeOfHome = 0; do {

Console.WriteLine("What Type of House Would you Like to

Purchase?");

Console.WriteLine("1 - Single Family"); Console.WriteLine("2 - Town House"); Console.WriteLine("3 - Condominium");

C# 3.0 Practical Learning

274

Console.Write("Your Choice? "); TypeOfHome = int.Parse(Console.ReadLine()); } while ((TypeOfHome < 1) || (TypeOfHome > 3)); if (TypeOfHome == 1) Console.WriteLine("\nType of Home: Single Family"); else if (TypeOfHome == 2) Console.WriteLine("\nType of Home: Town House"); else if (TypeOfHome == 3) Console.WriteLine("\nType of Home: Condominium"); Console.WriteLine(); return 0; }

}

This is used to request one of the numbers 1, 2, or 3 from the user. Any number below 1 or above 3 is not accepted. Here is an example of running the program: What Type of House Would you Like to Purchase? 1 - Single Family 2 - Town House 3 - Condominium Your Choice? 8 What Type of House Would you Like to Purchase? 1 - Single Family 2 - Town House 3 - Condominium Your Choice? 6 What Type of House Would you Like to Purchase? 1 - Single Family 2 - Town House 3 - Condominium Your Choice? 3 Type of Home: Condominium Press any key to continue . . .

If the user enters an invalid value, the question is simply being asked again. It would be professional to let the user know why the request came back even though what appears as a normal number was entered. To solve this and other types of problems, you can write one conditional statement inside of another. This is referred to as nesting. To create a conditional statement inside of another, simply proceed as we have done so far to create them. Here is an example: using System; public class Exercise { public static int Main() { var TypeOfHome = 0; do {

C# 3.0 Practical Learning

275

Console.WriteLine("What Type of House Would you Like to Purchase?");

Console.WriteLine("1 - Single Family"); Console.WriteLine("2 - Townhouse"); Console.WriteLine("3 - Condominium"); Console.Write("Your Choice? "); TypeOfHome = int.Parse(Console.ReadLine());

if ((TypeOfHome < 1) || (TypeOfHome > 3)) Console.WriteLine("Invalid Choice: Please try again"); } while ((TypeOfHome < 1) || (TypeOfHome > 3)); if (TypeOfHome == 1) Console.WriteLine("\nType of Home: Single Family"); else if (TypeOfHome == 2) Console.WriteLine("\nType of Home: Townhouse"); else if (TypeOfHome == 3) Console.WriteLine("\nType of Home: Condominium"); Console.WriteLine(); return 0; }

}

Here is another example of running the program: What Type of House Would you Like to Purchase? 1 - Single Family 2 - Town House 3 - Condominium Your Choice? 0 Invalid Choice: Please try again What Type of House Would you Like to Purchase? 1 - Single Family 2 - Town House 3 - Condominium Your Choice? 6 Invalid Choice: Please try againe What Type of House Would you Like to Purchase? 1 - Single Family 2 - Town House 3 - Condominium Your Choice? 2 Type of Home: Town House Press any key to continue . . .

Practical Learning: Nesting Conditions 1. Access the OrderProcessing.cs file and change it as follows: using using using using

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

namespace FlowerShop3

C# 3.0 Practical Learning

276

{ class OrderProcessing { public Flower FlowerOrder; public int Quantity; public OrderProcessing() { FlowerOrder = new Flower(); } public decimal GetTotalPrice() { return Quantity * FlowerOrder.UnitPrice; } public void GetFlowerType() { int choice = 0; do {

Console.WriteLine("Enter the Type of Flower Order"); Console.WriteLine("1. Roses"); Console.WriteLine("2. Lilies"); Console.WriteLine("3. Daisies"); Console.WriteLine("4. Carnations"); Console.WriteLine("5. Live Plant"); Console.WriteLine("6. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine()); if ((choice < 1) || (choice > 6)) Console.WriteLine( "Invalid Value: Please enter a value between 1 and

6");

} while ((choice < 1) || (choice > 6)); switch (choice) { case 1: FlowerOrder.Type break; case 2: FlowerOrder.Type break; case 3: FlowerOrder.Type break; case 4: FlowerOrder.Type break; case 5: FlowerOrder.Type break; default: FlowerOrder.Type break; }

= FlowerType.Roses; = FlowerType.Lilies; = FlowerType.Daisies; = FlowerType.Carnations; = FlowerType.LivePlant; = FlowerType.Mixed;

}

C# 3.0 Practical Learning

277

public void GetFlowerColor() { int choice = 0; do { Console.WriteLine("Enter the Color"); Console.WriteLine("1. Red"); Console.WriteLine("2. White"); Console.WriteLine("3. Yellow"); Console.WriteLine("4. Pink"); Console.WriteLine("5. Orange"); Console.WriteLine("6. Blue"); Console.WriteLine("7. Lavender"); Console.WriteLine("8. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine()); if ((choice < 1) || (choice > 8)) Console.WriteLine( "Invalid Value: Please enter a value between 1 and

8");

} while ((choice < 1) || (choice > 8));

}

switch (choice) { case 1: FlowerOrder.Color break; case 2: FlowerOrder.Color break; case 3: FlowerOrder.Color break; case 4: FlowerOrder.Color break; case 5: FlowerOrder.Color break; case 6: FlowerOrder.Color break; case 7: FlowerOrder.Color break; default: FlowerOrder.Color break; }

= FlowerColor.Red; = FlowerColor.White; = FlowerColor.Yellow; = FlowerColor.Pink; = FlowerColor.Yellow; = FlowerColor.Blue; = FlowerColor.Lavender; = FlowerColor.Mixed;

public void GetFlowerArrangement() { int choice = 0; do {

C# 3.0 Practical Learning

278

Console.WriteLine("Enter the Type of Arrangement"); Console.WriteLine("1. Bouquet"); Console.WriteLine("2. Vase"); Console.WriteLine("3. Basket"); Console.WriteLine("4. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine()); if ((choice < 1) || (choice > 4)) Console.WriteLine( "Invalid Value: Please enter a value between 1 and 4");

} while ((choice < 1) || (choice > 4)); switch (choice) { case 1: FlowerOrder.Arrangement break; case 2: FlowerOrder.Arrangement break; case 3: FlowerOrder.Arrangement break; default: FlowerOrder.Arrangement break; }

= FlowerArrangement.Bouquet; = FlowerArrangement.Vase; = FlowerArrangement.Basket; = FlowerArrangement.Any;

} public void ProcessOrder() { GetFlowerType(); GetFlowerColor(); GetFlowerArrangement(); Console.Write("Enter the Unit Price: "); FlowerOrder.UnitPrice = decimal.Parse(Console.ReadLine());

}

Console.Write("Enter Quantity: "); Quantity = int.Parse(Console.ReadLine());

public void ShowOrder() { Console.WriteLine("======================="); Console.WriteLine("==-=-=Flower Shop=-=-=="); Console.WriteLine("-----------------------"); Console.WriteLine("Flower Type: {0}", FlowerOrder.Type); Console.WriteLine("Flower Color: {0}", FlowerOrder.Color); Console.WriteLine("Arrangement: {0}", FlowerOrder.Arrangement); Console.WriteLine("Price: {0:C}", FlowerOrder.UnitPrice); Console.WriteLine("Quantity: {0}", Quantity); Console.WriteLine("Total Price: {0:C}", GetTotalPrice()); Console.WriteLine("======================="); } }

C# 3.0 Practical Learning

279

}

2. Execute the application and test it. Here is an example: Enter the Type of Flower Order 1. Roses 2. Lilies 3. Daisies 4. Carnations 5. Live Plant 6. Mixed Your Choice: 8 Invalid Value: Please enter a value Enter the Type of Flower Order 1. Roses 2. Lilies 3. Daisies 4. Carnations 5. Live Plant 6. Mixed Your Choice: 0 Invalid Value: Please enter a value Enter the Type of Flower Order 1. Roses 2. Lilies 3. Daisies 4. Carnations 5. Live Plant 6. Mixed Your Choice: 4 Enter the Color 1. Red 2. White 3. Yellow 4. Pink 5. Orange 6. Blue 7. Lavender 8. Mixed Your Choice: 9 Invalid Value: Please enter a value Enter the Color 1. Red 2. White 3. Yellow 4. Pink 5. Orange 6. Blue 7. Lavender 8. Mixed Your Choice: 3 Enter the Type of Arrangement 1. Bouquet 2. Vase 3. Basket 4. Mixed Your Choice: 9 Invalid Value: Please enter a value Enter the Type of Arrangement

between 1 and 6

between 1 and 6

between 1 and 8

between 1 and 4

C# 3.0 Practical Learning

280

1. Bouquet 2. Vase 3. Basket 4. Mixed Your Choice: 5 Invalid Value: Please enter a value between 1 and 4 Enter the Type of Arrangement 1. Bouquet 2. Vase 3. Basket 4. Mixed Your Choice: 3 Enter the Unit Price: 54.95 Enter Quantity: 1 ======================= ==-=-=Flower Shop=-=-== ----------------------Flower Type: Carnations Flower Color: Yellow Arrangement: Basket Price: $54.95 Quantity: 1 Total Price: $54.95 ======================= Press any key to continue . . .

3. Close the DOS window

Breaking the Flow of a Conditional Statement The break statement is used to stop a loop for any reason or condition when necessary. The formula of the break statement is: break;

Although made of only one word, the break statement is a complete statement; therefore, it can (and should always) stay on its own line (this makes the program easy to read). The break statement applies to the most previous conditional statement to it; provided that previous statement is applicable. The break statement can be used in a while condition, in a do…while or a for loops to stop an ongoing action. Here is an example that is used to count the levels of a house from 1 to 12 but it is asked to stop at 3: using System; public class Exercise { public static int Main() { for (var Stories = 1; Stories <= 12; Stories++) { Console.WriteLine("Story {0}", Stories); if (Stories == 3) break;

C# 3.0 Practical Learning

281

}

}

Console.WriteLine(); return 0;

}

This would produce: Story 1 Story 2 Story 3 Press any key to continue . . .

Continuing a Conditional Statement The continue statement uses the following formula: continue;

When processing a loop, if the statement finds a false value, you can use the continue statement inside of a while, a do…while or a for conditional statements to ignore the subsequent statement or to jump from a false Boolean value to the subsequent valid value, unlike the break statement that would exit the loop. Like the break statement, the continue keyword applies to the most previous conditional statement and should stay on its own line. Here is an example when a program is supposed to count the levels of a house from 1 to 6: using System; public class Exercise { public static int Main() { for (var Stories = 1; Stories <= 6; Stories++) { if (Stories == 3) continue; Console.WriteLine("Story {0}", Stories); } Console.WriteLine(); return 0; }

}

This would produce: Story Story Story Story Story

1 2 4 5 6

Press any key to continue . . .

Notice that, when the compiler gets to 3, it ignores it. C# 3.0 Practical Learning

282

Going to a Designated Label The goto statement allows a program execution to jump to another section of the function in which it is being used. In order to use the goto statement, insert a name on a particular section of your function so you can refer to that name. The name, also called a label, is made of one word and follows the rules we have learned about C++ names (the name can be anything), then followed by a colon. Here is an example where the program is supposed to count the levels of a 14 story building: using System; public class Exercise { public static int Main() { for (var Stories = 1; Stories <= 14; Stories++) { if (Stories == 4) goto CountUpTo3; Console.WriteLine("Story {0}", Stories); } CountUpTo3: Console.WriteLine("Our homes have only up to 3 levels\n"); return 0; }

}

This would produce: Story 1 Story 2 Story 3 Our homes have only up to 3 levels Press any key to continue . . .

Conditional Return Some functions are meant to return a value that is conditional of their processing. The fact that a function indicates the type of value it would return may not be clear at the time the function is closed but a function defined other than void must always return a value. You can write a conditional statement, such as if, inside of a function and return a value from that condition. Here is an example: using System; public class Program { enum HouseType { Unknown, SingleFamily, Townhouse, Condominium }; public static int Main() { var Type = GetHouseType();

C# 3.0 Practical Learning

283

switch (Type) { case HouseType.SingleFamily: Console.WriteLine("\nType break; case HouseType.Townhouse: Console.WriteLine("\nType break; case HouseType.Condominium: Console.WriteLine("\nType break; case HouseType.Unknown: Console.WriteLine("\nType break; } }

of Home: Single Family"); of Home: Townhouse"); of Home: Condominium"); of Home. Unknown");

return 0;

private static HouseType GetHouseType() { var Type = 0; Console.WriteLine("What Type of House Would you Like to Purchase?"); Console.WriteLine("1 - Single Family"); Console.WriteLine("2 - Townhouse"); Console.WriteLine("3 - Condominium"); Console.Write("Your Choice? "); Type = int.Parse(Console.ReadLine());

}

if (Type == 1) return HouseType.SingleFamily; else if (Type == 2) return HouseType.Townhouse; else if (Type == 3) return HouseType.Condominium;

}

This GetHouseType() method indicates when one of three values is returned. In reality, this method could get a value other than the three that are considered. If the user enters such a value, the current version of the method would not know what to do. For this reason, the program will not compile. In Microsoft Visual C#, you would receive the following error: 'Program.GetHouseType()': not all code paths return a value

To solve this problem, you must provide a statement that would include any value other than those considered. You can do this by writing a final return that has its own value. Here is an example: using System; public class Program { enum HouseType { Unknown, SingleFamily, Townhouse, Condominium }; public static int Main()

C# 3.0 Practical Learning

284

{ var Type = GetHouseType(); switch (Type) { case HouseType.SingleFamily: Console.WriteLine("\nType break; case HouseType.Townhouse: Console.WriteLine("\nType break; case HouseType.Condominium: Console.WriteLine("\nType break; case HouseType.Unknown: Console.WriteLine("\nType break; } }

of Home: Single Family"); of Home: Townhouse"); of Home: Condominium"); of Home. Unknown");

return 0;

private static HouseType GetHouseType() { var Type = 0; Console.WriteLine("What Type of House Would you Like to Purchase?"); Console.WriteLine("1 - Single Family"); Console.WriteLine("2 - Townhouse"); Console.WriteLine("3 - Condominium"); Console.Write("Your Choice? "); Type = int.Parse(Console.ReadLine());

}

if (Type == 1) return HouseType.SingleFamily; else if (Type == 2) return HouseType.Townhouse; else if (Type == 3) return HouseType.Condominium; else return HouseType.Unknown;

}

Recursion Introduction Imagine that you want to count the positive odd numbers from a certain maximum to a certain minimum. For example, to count the odd numbers from 1 to 9, you would use: 9, 7, 5, 3, and 1 Notice that, to perform this operation, you consider the highest. Then you subtract 2 to get the previous. Again, you subtract 2 from the number to get 285 C# 3.0 Practical Learning

the previous. What you are simply doing is to subtract a constant to what you already have and you invent very little. In computer programming, you can solve this type of problem by first writing a function, and then have the function call itself. This is the basis for recursion.

Creating a Recursive Methods A type of formula to create a recursive method is: ReturnValue Function(Arguments, if any) { Optional Action . . . Function(); Optionan Action . . . }

A recursive method starts with a return value. If it would not return a value, you can define it with void. After its name, the method can take one or more arguments. Most of the time, a recursive method takes at least one argument that it would then modify. In the body of the method, you can take the necessary actions. There are no particular steps to follow when implementing a recursive method but there are two main rules to observe: •

In its body, the method must call itself



Before or after calling itself, the method must check a condition that would allow it to stop, otherwise, it might run continuously

For our example of counting decrementing odd numbers, you could start by creating a method that takes an integer as argument. To exercise some control on the lowest possible values, we will consider only positive numbers. In the body of the method, we will display the current value of the argument, subtract 2, and recall the method itself. Here is our function: using System; public class Exercise { static void OddNumbers(int a) { if (a >= 1) { Console.Write("{0}, ", a); a -= 2; OddNumbers(a); } } public static int Main() { const int Number = 9; Console.WriteLine("Odd Numbers"); OddNumbers(Number);

}

Console.WriteLine(); return 0;

C# 3.0 Practical Learning

286

}

Notice that the method calls itself in its body. This would produce: Odd Numbers 9, 7, 5, 3, 1, Press any key to continue . . .

Using Recursive Methods Recursive methods provide a valuable mechanism for building lists or series, which are value that are either increment or decrement but follow a pattern. Imagine that, instead of simply displaying odd numbers as we did above, you want to add them incrementally. If you have 1, it would also produce 1. If you have 5, you would like to add 1 to 3, then the result to 5, and so on. This can be illustrated as follows: 1

= 1 = 4 = 9

1 + 3 1 + 3 + 5

1 + 3 + 5 + 7 = 16 1 + 3 + 5 + 7 + 9 = 25

To perform this operation, you would consider 1. If the number is less than or equal to 1, the method should return 1. Otherwise, add 2 to 1, then add 2 to the new result. Continue this until you get to the value of the argument. The method can be implemented as follows: using System; public class Exercise { static int AdditionalOdd(int a) { if (a <= 1) return 1; return a + AdditionalOdd(a - 2); } static void OddNumbers(int a) { if (a >= 1) { Console.Write("{0}, ", a); a -= 2; OddNumbers(a); } } public static int Main() { const int Number = 9;

C# 3.0 Practical Learning

287

Console.WriteLine("Odd Numbers"); OddNumbers(Number); Console.WriteLine(); Console.WriteLine("Sum of Odds: {0}\n", AdditionalOdd(Number)); return 0; }

}

This would produce: Odd Numbers 9, 7, 5, 3, 1, Sum of Odds: 25 Press any key to continue . . .

C# 3.0 Practical Learning

288

THE PROPERTIES OF A CLASS Overview of Properties Introduction In C++ and Java, when creating the member variables of a class, programmers usually "hide" these members in private sections (C++) or create them as private (Java). This technique makes sure that a member variable is not accessible outside of the class so that the clients of the class cannot directly influence the value of the member variable. If you create a member variable as private but still want other classes to access or get the value of such a field, you must then create one or two "accessories", like a door in which the external classes must pass through to access the field.

Accessories for Properties A property is a member of a class that plays an intermediary role to a field of the class. For example, if you have a field of class and that member represents the salary of an employee, a property can be the "door" that other classes that need the salary must present their requests to. As such, these external classes cannot just change the salary or retrieve it as they wish. A property can be used to validate their request, to reject or to accept them. A property is used to "filter" access to a field of a class. Therefore, you start by declaring a (private (if you don't make it private, you may be deceiving the purpose of creating a property)) field. Here is an example: using System; public class Square { private double _side; } public class Exercise {

public static int Main() { return 0;

C# 3.0 Practical Learning

289

} }

Obviously this private field cannot be accessed by an outside class. To let the outside classes access this variable, you would/can create a property. To indicate that you are creating a property, there is a syntax you must follow. To start, you must create a member whose formula resembles a method without the parentheses. Since or if the property will be accessed by only by objects of the same program, you can mark it with the internal keyword. If the property will be accessed by objects of this and other programs, you should mark it as public. Therefore, you would start a property as follows: public class Square { private double _side;

}

// This is a new property public double Side { }

With regards to their role, there are two types of properties.

Practical Learning: Introducing Properties 1. Start Microsoft Visual C# and create a Console Application named DepartmentStore2

2. To create a new class, on the main menu, click Project -> Add Class... 3. Set the Name to ShoppingItem and press Enter 4. Change the content of the file as follows: using using using using

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

namespace DepartmentStore2 { class DepartmentStore { private long itemNo; private string nm; private string sz; private decimal price; } }

5. To create a property for each member variable, change the ShoppingItem class as follows: using System; using System.Collections.Generic;

C# 3.0 Practical Learning

290

using System.Linq; using System.Text; namespace DepartmentStore2 { class ShoppingItem { private string itemNo; private string nm; private string sze; private decimal price; // A property for the stock number of an item public string ItemNumber { } // A property for the name of an item public string Name { } // A property for size of a merchandise public string Size { } // A property for the marked price of an item public decimal UnitPrice { } }

}

6. Save the file

Types of Properties Property Readers A property is referred to as read if its role is only to make available the value of the member variable it represents. To create a read property, in the body of the property, type the get keyword and create a body for the keyword, using the traditional curly brackets that delimit a section of code. Here is an example: public class Square { private double _side; // This is a new property public double Side { get {

C# 3.0 Practical Learning

291

} }

}

In the body of the get clause, you can implement the behavior that would be used to make the field's value available outside. The simplest way consists of just returning the corresponding field. Here is an example: public class Square { private double _side;

}

// This is a new property public double Side { get { return _side; } }

A read property is also referred to as read-only property because the clients of the class can only retrieve the value of the property but they cannot change it. Therefore, if you create (only) a read property, you should provide the users with the ability to primarily specify the value of the member variable. To do this, you can create an accessory method or a constructor for the class . Here is an example of such a constructor: public class Square { private double _side; // This is a new property public double Side { get { return _side; } }

}

public Square(double s) { _side = s; }

Once a read property has been created, other classes can access it, for example they can read its value as follows: using System; public class Square { private double _side; // This is a new property

C# 3.0 Practical Learning

292

public double Side { get { return _side; } }

}

public Square(double s) { _side = s; }

public class Exercise { public static int Main() { var sq = new Square(-25.55);

}

Console.WriteLine("Square Side: {0}", sq.Side); return 0;

}

This would produce: Square Side: -25.55 Press any key to continue...

We described a property as serving as a door from outside to its corresponding field, preventing those outside classes to mess with the member variable. Notice that the Square class was given a negative value for the member variable, which is usually unrealistic for the side of a square. In this case and others, while still protecting the field as private, you can use the read property to reset the value of the field or even to reject it. To provide this functionality, you can create a conditional statement in the read property to perform a checking process. Here is an example: using System; public class Square { private double _side; // This is a new property public double Side { get { // If the value given to the side is negative, // then set it to 0 if (_side < 0) return 0; else return _side; } }

C# 3.0 Practical Learning

293

public Square(double s) { _side = s; } } public class Exercise { public static int Main() { var sq1 = new Square(-12.48); var sq2 = new Square(25.55); Console.WriteLine("First Square Characteristics"); Console.WriteLine("Side: {0}\n", sq1.Side);

}

Console.WriteLine("Second Square Characteristics"); Console.WriteLine("Side: {0}\n", sq2.Side); return 0;

}

This would produce: First Square Characteristics Side: 0 Second Square Characteristics Side: 25.55

Practical Learning: Creating Property Readers 1. To create read properties, change the contents of the ShoppingStore.cs file as follows: using using using using

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

namespace DepartmentStore2 { class ShoppingItem { private long itemNo; private string nm; private string sz; private decimal price; // A property for the stock number of an item public long ItemNumber { get { return itemNo; } }

C# 3.0 Practical Learning

294

// A property for the name of an item public string Name { get { return nm; } } // A property for size of a merchandise public string Size { get { if( sz == "0" ) return "Unknown Size or Fits All"; else return sz; } } // A property for the marked price of an item public decimal UnitPrice { get { return price; } }

}

// A constructor used to initialize an item public ShoppingItem(long nbr, string nme, string siz, decimal prc) { itemNo = nbr; nm = nme; sz = siz; price = prc; }

}

2. Access the Program.cs file and change it as follows: using using using using

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

namespace DepartmentStore2 { class Program { static void Main() { long number;

C# 3.0 Practical Learning

295

string name; string size; decimal price; Console.WriteLine("/-/Arrington Department Store/-/"); Console.Write("Enter the Item #: "); number = long.Parse(Console.ReadLine()); Console.Write("Enter the Item Name: "); name = Console.ReadLine(); Console.Write("Enter the Item Size: "); size = Console.ReadLine(); Console.Write("Enter the Unit Price: "); price = decimal.Parse(Console.ReadLine()); ShoppingItem store = new ShoppingItem(number, name, size, price);

} }

Console.WriteLine("\n================================"); Console.WriteLine("/-/Arrington Department Store/-/"); Console.WriteLine("--------------------------------"); Console.WriteLine("Customer Invoice"); Console.WriteLine("Item #: {0}", store.ItemNumber); Console.WriteLine("Description: {0}", store.Name); Console.WriteLine("Item Size: {0}", store.Size); Console.WriteLine("Unit Price: {0:C}", store.UnitPrice); Console.WriteLine("================================\n");

}

3. Execute the program:

/-/Arrington Department Store/-/ Enter the Item #: 622805 Enter the Item Name: Black Leather Hand Bag Enter the Item Size: Medium Enter the Unit Price: 85.95 ================================ /-/Arrington Department Store/-/ --------------------------------

C# 3.0 Practical Learning

296

Customer Invoice Item #: 622805 Description: Black Leather Hand Bag Item Size: Medium Unit Price: $85.95 ================================ Press any key to continue . . .

4. Close the DOS window

Property Writers In our Square class so far, we were using a constructor to create a value for each of the necessary member variables. This meant that we had to always make sure that we knew the value of the field when we declared an instance of the class. Sometimes, this is not effective. For example, you cannot just call a constructor in the middle of the program, that is after the object has been declared, to assign a new value to the field. To solve this kind of problem, you can provide another means of accessing the field any time to change its value. Besides, or instead of, retrieving the value of a field of a class, you may want external classes to be able to change the value of that member. Continuing with our concern to hide a field as private, you can create another type of property. A property is referred to as write if it can change (or write) the value of its corresponding field.

To create a write property, type the set keyword followed by the curly bracket delimiters. Here is an example: public class Square { private double _side;

}

// This is a new property public double Side { set { } }

The minimum assignment you can perform with a write property is to assign it a value that would be provided by the outside world. To support this, C# provides the value contextual keyword (contextual means the word is a keyword only in some cases, depending on how it is being used). Here is an example: public class Square { private double _side;

C# 3.0 Practical Learning

297

// This is a new property public double Side { set { _side = value; } } }

As you see, clients of a class can change the corresponding field of a member variable through the property writer. Based on this relationship, it is not unusual for a client of a class to make an attempt to "mess" with a field. For example, an external object can assign an invalid value to a member variable. Consider the following program: using System; public class Square { public double _side; // This is a new property public double Side { set { _side = value; } } public Square() { _side = 0; } public Square(double s) { _side = s; } public double Perimeter() { return _side * 4; }

}

public double Area() { return _side * _side; }

public class Exercise { public static int Main() { var sq1 = new Square(); var sq2 = new Square();

C# 3.0 Practical Learning

298

sq1._side = -12.48; sq2._side = 25.55; Console.WriteLine("First Square Characteristics"); Console.WriteLine("Side: {0}", sq1._side); Console.WriteLine("Perimeter: {0}", sq1.Perimeter()); Console.WriteLine("Area: {0}\n", sq1.Area()); Console.WriteLine("Second Square Characteristics"); Console.WriteLine("Side: {0}", sq2._side); Console.WriteLine("Perimeter: {0}", sq2.Perimeter()); Console.WriteLine("Area: {0}", sq2.Area()); }

return 0;

}

This would produce: First Square Characteristics Side: -12.48 Perimeter: -49.92 Area: 155.7504 Second Square Characteristics Side: 25.55 Perimeter: 102.2 Area: 652.8025 Press any key to continue...

Because of this, and since it is through the writer that the external objects would change the value of the member variable, you can use the write property, rather than the reader, to validate or reject a new value assigned to the field. Remember that the client objects of the class can only read the value of the field through the read property. Therefore, there may be only little concern on that side.

Read/Write Properties If you create a property that has only a set section, the property is referred to as write-only because the other classes can only assign it a value (or write a value to it). If you create a property that has both a get and a set sections, its corresponding member variable can receive new values from outside the class and the member variable can provide its values to clients of the class. Such a property is referred to as read/write.

Practical Learning: Creating Property Writers 1. To create property writers and complete the program, change the content of the ShoppingItem.cs file as follows: using System; using System.Collections.Generic;

C# 3.0 Practical Learning

299

using System.Linq; using System.Text; namespace DepartmentStore2 { class ShoppingItem { private long itemNo; private string nm; private string sz; private decimal price; // A property for the stock number of an item public long ItemNumber { get { return itemNo; } set {

}

if (itemNo <= 0) itemNo = 0; else itemNo = value;

} // A property for the name of an item public string Name { get { return nm; } set { if (nm == "") nm = "Item no Description"; else nm = value; }

}

// A property for size of a merchandise public string Size { get { if( sz == "0" ) return "Unknown Size or Fits All"; else return sz; } set { sz = value;

C# 3.0 Practical Learning

300

} } // A property for the marked price of an item public decimal UnitPrice { get { return price; } set { if (price < 0) price = 0.00M; else price = value; }

}

public static ShoppingItem Read() { ShoppingItem shop = new ShoppingItem(); Console.Write("Item #: "); shop.itemNo = long.Parse(Console.ReadLine()); Console.Write("Item Name: "); shop.Name = Console.ReadLine(); Console.Write("Item Size (Enter 0 if unknown): "); shop.Size = Console.ReadLine(); Console.Write("Unit Price: "); shop.UnitPrice = decimal.Parse(Console.ReadLine()); }

return shop;

public static void Write(ShoppingItem item) { Console.WriteLine("Item #: {0}", item.ItemNumber); Console.WriteLine("Description: {0}", item.Name); Console.WriteLine("Item Size: {0}", item.Size); Console.WriteLine("Unit Price: {0:C}", item.UnitPrice); } }

}

2. Access the Program.cs file and change it as follows: using using using using

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

namespace DepartmentStore2 { class Program { static void Main() {

C# 3.0 Practical Learning

301

Console.WriteLine("/-/Arrington Department Store/-/"); Console.Write("Enter the following pieces of "); Console.WriteLine("information about the sale item"); ShoppingItem saleItem = ShoppingItem.Read(); Console.WriteLine("\n================================"); Console.WriteLine("/-/Arrington Department Store/-/"); Console.WriteLine("--------------------------------"); ShoppingItem.Write(saleItem); }

}

}

3. Execute the program. Here is an example:

/-/Arrington Department Store/-/ Enter the following pieces of information about the sale item Item #: 114888 Item Name: North Hook Alpine Jacket Item Size (Enter 0 if unknown): Large Unit Price: 275.95 ================================ /-/Arrington Department Store/-/ -------------------------------Item #: 114888 Description: North Hook Alpine Jacket Item Size: Large Unit Price: $275.95 Press any key to continue . . .

4. Close the DOS window

A Boolean Property

C# 3.0 Practical Learning

302

You can create a property as a Boolean type. To do this, first specify its data type as bool. When treating the property, make sure its get accessory returns a Boolean type. A Boolean property is not like the other regular properties. It must specify its value as true or false. As done for Boolean methods, a Boolean property must produce only a true or false value.

Properties of External Classes Properties and Enumerations An enumeration is a technique of creating data type that mimics an integer. After creating it, you can treat it as a pseudo data type. You can declare a variable from it, you can pass it as an argument, and you can return it from a method. Based on these characteristics, you can create a property that is based on an enumeration. To create an enumeration property, you use the same formula as one of the primitive data types we have used previously. Keep it mind that the property is of the type of an enumeration. This means that you cannot request its value like that of a primitive type and, when manipulating it, you must process it appropriately.

Practical Learning: Creating an Enumeration Property 1. Access the ShoppingStore.cs file and change it as follows: using using using using

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

namespace DepartmentStore2 { public enum ItemCategory { Unspecified, Women, Men, Girls, Boys, Babies } class ShoppingItem { private long itemNo; private ItemCategory cat; private string nm; private string sz; private decimal price; // A property for the stock number of an item

C# 3.0 Practical Learning

303

public long ItemNumber { get { return itemNo; } set { if (itemNo <= 0) itemNo = 0; else itemNo = value; }

}

// A property for the category of item public ItemCategory Category { get { return cat; } set { }

cat = value;

}

// A property for the name of an item public string Name { get { return nm; } set {

}

if (nm == "") nm = "Item no Description"; else nm = value;

} // A property for size of a merchandise public string Size { get { if( sz == "0" ) return "Unknown Size or Fits All"; else return sz; } set {

C# 3.0 Practical Learning

304

sz = value; }

}

// A property for the marked price of an item public decimal UnitPrice { get { return price; } set {

}

if (price < 0) price = 0.00M; else price = value;

} public static ShoppingItem Read() { int category = 0; ShoppingItem shop = new ShoppingItem(); Console.Write("Item #: "); shop.itemNo = long.Parse(Console.ReadLine()); Console.WriteLine("Store Items Categories"); Console.WriteLine("\t1. Women"); Console.WriteLine("\t2. Men"); Console.WriteLine("\t3. Girls"); Console.WriteLine("\t4. Boys"); Console.WriteLine("\t5. Babies"); Console.Write("Enter the Category: "); category = int.Parse(Console.ReadLine()); if (category == 1) shop.Category = ItemCategory.Women; else if (category == 2) shop.Category = ItemCategory.Men; else if (category == 3) shop.Category = ItemCategory.Girls; else if (category == 4) shop.Category = ItemCategory.Boys; else if (category == 5) shop.Category = ItemCategory.Babies; else shop.Category = ItemCategory.Unspecified; Console.Write("Item Name: "); shop.Name = Console.ReadLine(); Console.Write("Item Size (Enter 0 if unknown): "); shop.Size = Console.ReadLine(); Console.Write("Unit Price: "); shop.UnitPrice = decimal.Parse(Console.ReadLine()); }

return shop;

public static void Write(ShoppingItem item) {

C# 3.0 Practical Learning

305

Console.WriteLine("Item #: Console.WriteLine("Category: Console.WriteLine("Description: Console.WriteLine("Item Size: Console.WriteLine("Unit Price: }

{0}", item.ItemNumber); {0}", item.Category); {0}", item.Name); {0}", item.Size); {0:C}", item.UnitPrice);

}

}

2. Execute the application and test it. Here is an example:

/-/Arrington Department Store/-/ Enter the following pieces of information about the sale item Item #: 624008 Store Items Categories 1. Women 2. Men 3. Girls 4. Boys 5. Babies Enter the Category: 3 Item Name: Scotta Miniskirt Item Size (Enter 0 if unknown): 11 Unit Price: 35.95 ================================ /-/Arrington Department Store/-/ -------------------------------Item #: 624008 Category: Girls Description: Scotta Miniskirt Item Size: 11 Unit Price: $35.95 Press any key to continue . . .

3. Close the DOS window

A Class as a Property Remember that, after creating a class, it becomes a data type in its own right. We have seen that you could declare a variable from it, you could pass it as argument, and you could return it from a method. As a normal data type, C# 3.0 Practical Learning

306

a class can be validated. This means that its value can be evaluated, rejected, or retrieved. Based on these characteristics of a class, you can create a property from it. To create a property that is based on a class, primarily follow the same formulas we have applied to the other properties. The most important aspect to remember is that the class is composite. That is, it is (likely) made of fields of various types.

Practical Learning: Creating a Property of a Class Type 1. Access the ShoppingItem.cs file and change it as follows: using using using using

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

namespace DepartmentStore2 { public enum ItemCategory { Unspecified, Women, Men, Girls, Boys, Babies } class ShoppingItem { private long itemNo; private ItemCategory cat; private string nm; private string sz; private decimal price; // A property for the stock number of an item public long ItemNumber { get { return itemNo; } set { }

itemNo = value;

} // A property for the category of item public ItemCategory Category { get {

C# 3.0 Practical Learning

307

return cat; } set { }

cat = value;

} // A property for the name of an item public string Name { get { return nm; } set { if (nm == "") nm = "Item no Description"; else nm = value; }

}

// A property for size of a merchandise public string Size { get { if (sz == "0") return "Unknown Size or Fits All"; else return sz; } set { }

sz = value;

} // A property for the marked price of an item public decimal UnitPrice { get { return price; } set { if (price < 0) price = 0.00M; else price = value; }

}

}

C# 3.0 Practical Learning

308

}

2. To create a new class, in the Solution Explorer, right-click the name of the project, position the mouse on Add and click Class... 3. Set the Name to DepartmentStore and click Add 4. Change the file as follows: using using using using

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

namespace DepartmentStore2 { class DepartmentStore { private int qty; private ShoppingItem itm; public int Quantity { get { return qty; } set { if (qty <= 0) qty = 0; else qty = value; } } public ShoppingItem SaleItem { get { return itm; } set { if (itm == null) { itm.ItemNumber = 0; itm.Category = ItemCategory.Unspecified; itm.Name = "Unknown"; itm.Size = "0"; itm.UnitPrice = 0.00M; } else itm = value; } } public DepartmentStore() { itm = new ShoppingItem(); } public void ProcessOrder() { int category;

C# 3.0 Practical Learning

309

Console.WriteLine("/-/Arrington Department Store/-/"); Console.WriteLine("Enter the following pieces of"); Console.WriteLine("information about the sale item"); Console.Write("Item #: "); itm.ItemNumber = long.Parse(Console.ReadLine()); Console.WriteLine("Store Items Categories"); Console.WriteLine("\t1. Women"); Console.WriteLine("\t2. Men"); Console.WriteLine("\t3. Girls"); Console.WriteLine("\t4. Boys"); Console.WriteLine("\t5. Babies"); Console.Write("Enter the Category: "); category = int.Parse(Console.ReadLine()); if (category == 1) itm.Category = ItemCategory.Women; else if (category == 2) itm.Category = ItemCategory.Men; else if (category == 3) itm.Category = ItemCategory.Girls; else if (category == 4) itm.Category = ItemCategory.Boys; else if (category == 5) itm.Category = ItemCategory.Babies; else itm.Category = ItemCategory.Unspecified; Console.Write("Item Name: "); itm.Name = Console.ReadLine(); Console.Write("Item Size (Enter 0 if unknown): "); itm.Size = Console.ReadLine(); Console.Write("Unit Price: "); itm.UnitPrice = decimal.Parse(Console.ReadLine()); Console.Write("How many samples of "); Console.Write(itm.Name); Console.Write(": "); qty = int.Parse(Console.ReadLine()); } public void DisplayReceipt() { decimal totalPrice = itm.UnitPrice * Quantity;

} }

Console.WriteLine("\n================================"); Console.WriteLine("/-/Arrington Department Store/-/"); Console.WriteLine("--------------------------------"); Console.WriteLine("Item #: {0}", itm.ItemNumber); Console.WriteLine("Category: {0}", itm.Category); Console.WriteLine("Description: {0}", itm.Name); Console.WriteLine("Item Size: {0}", itm.Size); Console.WriteLine("Unit Price: {0:C}", itm.UnitPrice); Console.WriteLine("Quantity: {0}", Quantity); Console.WriteLine("Total Price: {0:C}\n", totalPrice); Console.WriteLine("\n================================");

}

5. Access the Program.cs file and change it as follows: C# 3.0 Practical Learning

310

using using using using

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

namespace DepartmentStore2 { class Program { static void Main() { DepartmentStore store = new DepartmentStore(); store.ProcessOrder(); store.DisplayReceipt(); }

}

}

6. Execute the application and test it. Here is an example:

/-/Arrington Department Store/-/ Enter the following pieces of information about the sale item Item #: 444412 Store Items Categories 1. Women 2. Men 3. Girls 4. Boys 5. Babies Enter the Category: 1 Item Name: Stretch Cotton Shirt Item Size (Enter 0 if unknown): 14 Unit Price: 55.95 How many samples of Stretch Cotton Shirt: 2 ================================ /-/Arrington Department Store/-/ -------------------------------Item #: 444412 Category: Women Description: Stretch Cotton Shirt Item Size: 14

C# 3.0 Practical Learning

311

Unit Price: $55.95 Quantity: 2 Total Price: $111.90 ================================ Press any key to continue . . .

7. Close the DOS window

C# 3.0 Practical Learning

312

Inheritance Introduction to Inheritance Definition

Volley Ball

Football

Basketball

Handball

Golf

The primary characteristic of the objects on the above pictures is that they are balls used in different sports. Another characteristic they share is that they are round. On the other hand, although these balls are used in sport, one made for one sport cannot (or should not) be used in another sport (of course, it is not unusual for a footballer to mess with a basketball on a lawn but it is not appropriate). The common characteristics of these objects can be listed in a group like a C# class. The class would appear as: class Ball { TypeOfSport; Size; }

If you were asked to create a class to represent these balls, you may be tempted to implement a general class that defines each ball. This may be a bad idea because, despite their round resemblance, there are many internal differences among these balls. Programming languages like C# provide an alternate solution to this type of situation. Inheritance consists of creating a class whose primary definition or behavior is based on another class. In other words, inheritance starts by having a class that can provide behavior that other classes can improve on.

Practical Learning: Introducing Inheritance C# 3.0 Practical Learning

313

1. Start Microsoft Visual C# 2005 Express Edition and create a new Console Application named RealEstate2 2. To create a new class, in the Class View, right-click the name of the project, position the mouse on Add and click Class... 3. Set the Name to Property and press Enter 4. Change the file as follows: using using using using

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

namespace RealEstate2 { public enum PropertyCondition { Unknown, Excellent, Good, NeedsRepair, BadShape } public class Property { private private private private private private

string propNbr; PropertyCondition cond; int beds; float baths; int yr; decimal val;

public Property() { } public string PropertyNumber { get { return propNbr; } set

C# 3.0 Practical Learning

314

{ if (propNbr == "") propNbr = "N/A"; else propNbr = value; }

}

public PropertyCondition Condition { get { return cond; } set { cond = value; } } public int Bedrooms { get { if (beds <= 1) return 1; else return beds; } set { beds = value; } } public float Bathrooms { get { return baths; } set { baths = value; } } public int YearBuilt { get { return yr; } set { yr = value; } } public decimal Value { get { return val; } set { val = value; } } }

}

5. To create a new class, in the Solution Explorer, right-click the name of the project, position the mouse on Add and click Class... 6. Set the Name to PropertyListing and press Enter 7. Change the file as follows: using using using using

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

namespace RealEstate2

C# 3.0 Practical Learning

315

{ public enum PropertyType { Unknown, SingleFamily, Townhouse,

Condominium } public class PropertyListing { private Property prop; private PropertyType tp; public Property ListProperty { get { return prop; } set { prop = value; } } public PropertyType Type { get { return tp; } set { tp = value; } } public PropertyListing() { prop = new Property(); } public void CreateListing() { Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("-=- Property Creation -=-"); Console.WriteLine("\nTypes of Properties"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condonium"); Console.WriteLine("4. Don't Know"); Console.Write("Enter Type of Property: "); int propType = int.Parse(Console.ReadLine()); Console.Write("\nEnter Property #: "); ListProperty.PropertyNumber = Console.ReadLine(); Console.WriteLine("\nProperties Conditions"); Console.WriteLine("1. Excellent"); Console.WriteLine("2. Good (may need minor repair)"); Console.WriteLine("3. Needs Repair"); Console.Write("4. In Bad Shape (property needs "); Console.WriteLine("major repair or rebuild)"); Console.Write("Enter Property Condition: "); int condition = int.Parse(Console.ReadLine()); if (condition == 1) ListProperty.Condition = PropertyCondition.Excellent; else if (condition == 2) ListProperty.Condition = PropertyCondition.Good;

C# 3.0 Practical Learning

316

else if (condition == 3) ListProperty.Condition = PropertyCondition.NeedsRepair; else if (condition == 4) ListProperty.Condition = PropertyCondition.BadShape; else ListProperty.Condition = PropertyCondition.Unknown; switch ((PropertyType)propType) { case PropertyType.SingleFamily: Type = PropertyType.SingleFamily; break; case PropertyType.Townhouse: Type = PropertyType.Townhouse; break; case PropertyType.Condominium: Type = PropertyType.Condominium; break;

}

default: Type = PropertyType.Unknown; break;

Console.Write("\nHow many bedrooms? "); ListProperty.Bedrooms = int.Parse(Console.ReadLine()); Console.Write("How many bathrooms? "); ListProperty.Bathrooms = float.Parse(Console.ReadLine()); Console.Write("Year built: "); ListProperty.YearBuilt = int.Parse(Console.ReadLine()); Console.Write("Property Value: }

");

ListProperty.Value = decimal.Parse(Console.ReadLine());

public void ShowProperty() { Console.WriteLine("=================================="); Console.WriteLine(" =//=//= Altair Realty =//=//="); Console.WriteLine("-=-=-=- Properties Listing -=-=-=-"); Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", ListProperty.PropertyNumber); Console.WriteLine("Property Type: {0}", Type); switch (Type) { case PropertyType.SingleFamily: case PropertyType.Townhouse: Type = PropertyType.SingleFamily; break; case PropertyType.Condominium: break; } Console.WriteLine("Condition:

C# 3.0 Practical Learning

{0}", 317

} }

ListProperty.Condition); Console.WriteLine("Bedrooms: {0}", ListProperty.Bedrooms); Console.WriteLine("Bathrooms: {0}", ListProperty.Bathrooms); Console.WriteLine("Year Built: {0}", ListProperty.YearBuilt); Console.WriteLine("Market Value: {0:C}", ListProperty.Value); Console.WriteLine("==================================");

}

8. Access the Program.cs file and change it as follows: using using using using

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

namespace RealEstate2 { class Program { static void Main() { PropertyListing listing = new PropertyListing();

} }

listing.CreateListing(); Console.WriteLine("\n"); listing.ShowProperty(); Console.WriteLine();

}

9. Execute the application and test it. Here is an example: =//= Altair Realty =//= -=- Property Creation -=Types of Properties 1. Single Family 2. Townhouse 3. Condominium 4. Don't Know Enter Type of Property: 2 Enter Property #: 66DG8P Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 2

C# 3.0 Practical Learning

318

How many bedrooms? How many bathrooms? Year built: Property Value:

2 1.0 1994 325880.75

================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 66DG8P Property Type: Townhouse Condition: Good Bedrooms: 2 Bathrooms: 1 Year Built: 1994 Market Value: $325,880.75 ================================== Press any key to continue . . .

10.

Close the DOS window

Class Derivation As you may have guessed, in order to implement inheritance, you must first have a class that provides the fundamental definition or behavior you need. There is nothing magical about such a class. It could appear exactly like any of the classes we have used so far. Here is an example: using System; public class Circle { private double _radius; public double Radius { get { return _radius; } set { if( _radius < 0 ) _radius = 0.00; else _radius = value; } } public double Diameter { get { return Radius * 2; } } public double Circumference

C# 3.0 Practical Learning

319

{ get { }

return Diameter * 3.14159;

}

}

public double Area { get { return Radius * Radius * 3.14159; } }

class Exercise { public static int Main() { var Round = new Circle(); Round.Radius = 25.55; Console.WriteLine("Circle Characteristics"); Console.WriteLine("Side: {0}", Round.Radius); Console.WriteLine("Diameter: {0}", Round.Diameter); Console.WriteLine("Circumference: {0}", Round.Circumference); Console.WriteLine("Area: {0}", Round.Area); return 0; }

}

This would produce: Circle Characteristics Side: 25.55 Diameter: 51.1 Circumference: 160.535249 Area: 2050.837805975 Press any key to continue

The above class is used to process a circle. It can request or provide a radius. It can also calculate the circumference and the area of a circle. Now, suppose you want to create a class for a sphere. You could start from scratch as we have done so far. On the other hand, since a sphere is primarily a 3dimensional circle, and if you have a class for a circle already, you can simply create your sphere class that uses the already implemented behavior of a circle class. Creating a class that is based on another class is also referred to as deriving a class from another. The first class serves as parent or base. The class that is based on another class is also referred to as child or derived. To create a class based on another, you use the following formula: 320 C# 3.0 Practical Learning

class NewChild : BaseClass { // Body of the new class }

In this formula, you start with the class keyword followed by a name from your class. On the right side of the name of your class, you must type the : operator, followed by the name of the class that will serve as parent. Of course, the BaseClass class must have been defined; that is, the compiler must be able to find its definition. Based on the above formula, you can create a sphere class based on the earlier mentioned Circle class as follows: class Sphere : Circle { // The class is ready }

After deriving a class, it becomes available and you can use it just as you would any other class. Here is an example: using System; class Circle { private double _radius; public double Radius { get { if( _radius < 0 ) return 0.00; else return _radius; } set { _radius = value; } } public double Diameter { get { return Radius * 2; } } public double Circumference { get { return Diameter * 3.14159; } } public double Area { get

C# 3.0 Practical Learning

321

{ } }

return Radius * Radius * 3.14159;

}

class Sphere : Circle { } class Exercise { public static int Main() { var Round = new Circle(); Round.Radius = 25.55; Console.WriteLine("Circle Characteristics"); Console.WriteLine("Side: {0}", Round.Radius); Console.WriteLine("Diameter: {0}", Round.Diameter); Console.WriteLine("Circumference: {0}", Round.Circumference); Console.WriteLine("Area: {0}", Round.Area); var Ball = new Sphere(); Ball.Radius = 25.55; Console.WriteLine("\nSphere Characteristics"); Console.WriteLine("Side: {0}", Ball.Radius); Console.WriteLine("Diameter: {0}", Ball.Diameter); Console.WriteLine("Circumference: {0}", Ball.Circumference); Console.WriteLine("Area: {0}", Ball.Area); return 0; }

}

This would produce: Circle Characteristics Side: 25.55 Diameter: 51.1 Circumference: 160.535249 Area: 2050.837805975 Sphere Characteristics Side: 25.55 Diameter: 51.1 Circumference: 160.535249 Area: 2050.837805975 Press any key to continue

When a class is based on another class, all public (we will also introduce another inheritance-oriented keyword for this issue) members of the parent class are made available to the derived class that can use them as easily. While other methods and classes can also use the public members of a class, the difference is that the derived class can call the public members of the parent as if they belonged to the derived class. That is, the child class doesn't have to "qualify" the public members of the parent class when these public C# 3.0 Practical Learning

322

members are used in the body of the derived class. This is illustrated in the following program: using System; class Circle { private double _radius; public double Radius { get { if( _radius < 0 ) return 0.00; else return _radius; } set { _radius = value; } } public double Diameter { get { return Radius * 2; } } public double Circumference { get { return Diameter * 3.14159; } } public double Area { get { return Radius * Radius * 3.14159; } } public void ShowCharacteristics() { Console.WriteLine("Circle Characteristics"); Console.WriteLine("Side: {0}", Radius); Console.WriteLine("Diameter: {0}", Diameter); Console.WriteLine("Circumference: {0}", Circumference); Console.WriteLine("Area: {0}", Area); } } class Sphere : Circle {

C# 3.0 Practical Learning

323

}

public void ShowCharacteristics() { // Because Sphere is based on Circle, you can access // any public member(s) of Circle without qualifying it(them) Console.WriteLine("\nSphere Characteristics"); Console.WriteLine("Side: {0}", Radius); Console.WriteLine("Diameter: {0}", Diameter); Console.WriteLine("Circumference: {0}", Circumference); Console.WriteLine("Area: {0}\n", Area); }

class Exercise { public static int Main() { var Round = new Circle(); Round.Radius = 25.55; Round.ShowCharacteristics(); var Ball = new Sphere(); Ball.Radius = 25.55; Ball.ShowCharacteristics(); return 0; }

}

This would produce the same result.

Practical Learning: Inheriting 1. On the main menu, click Project -> Add -> Class... 2. Set the Name to HouseType and press Enter 3. To derive a class, change the file as follows: using using using using

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

namespace RealEstate2 { public class HouseType : Property { private int nbrOfStories; private bool basement; private bool garage; public int Stories { get { return nbrOfStories; } set { nbrOfStories = value; } }

C# 3.0 Practical Learning

324

public bool FinishedBasement { get { return basement; } set { basement = value; } }

}

public bool IndoorGarage { get { return garage; } set { garage = value; } }

}

4. On the main menu, click Project -> Add -> Class... 5. Set the Name to Condominium and press Enter 6. To create another class based on the Property class, change the file as follows: using using using using

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

namespace RealEstate2 { public class Condominium : Property { private bool handicap;

}

public bool HandicapAccessible { get { return handicap; } set { handicap = value; } }

}

7. Access the PropertyListing.cs file file and change it as follows: using using using using

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

namespace RealEstate2 { public enum PropertyType { Unknown, SingleFamily, Townhouse, Condominium }

C# 3.0 Practical Learning

325

class PropertyListing { private Property prop; private HouseType hse; private Condominium cond; private PropertyType tp; public Property ListProperty { get { return prop; } set { prop = value; } } public HouseType House { get { return hse; } set { hse = value; } } public Condominium Condo { get { return cond; } set { cond = value; } } public PropertyType Type { get { return tp; } set { tp = value; } } public PropertyListing() { prop = new Property(); hse = new HouseType(); cond = new Condominium(); } public void CreateListing() { char answer; Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("-=- Property Creation -=-"); Console.WriteLine("\nTypes of Properties"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condonium"); Console.WriteLine("4. Don't Know"); Console.Write("Enter Type of Property: "); int propType = int.Parse(Console.ReadLine()); Console.Write("\nEnter Property #: "); ListProperty.PropertyNumber = Console.ReadLine(); Console.WriteLine("\nProperties Conditions"); Console.WriteLine("1. Excellent");

C# 3.0 Practical Learning

326

Console.WriteLine("2. Good (may need minor repair)"); Console.WriteLine("3. Needs Repair"); Console.Write("4. In Bad Shape (property needs "); Console.WriteLine("major repair or rebuild)"); Console.Write("Enter Property Condition: "); int condition = int.Parse(Console.ReadLine()); if (condition == 1) ListProperty.Condition = PropertyCondition.Excellent; else if (condition == 2) ListProperty.Condition = PropertyCondition.Good; else if (condition == 3) ListProperty.Condition = PropertyCondition.NeedsRepair; else if (condition == 4) ListProperty.Condition = PropertyCondition.BadShape; else ListProperty.Condition = PropertyCondition.Unknown;

");

switch ((PropertyType)propType) { case PropertyType.SingleFamily: Type = PropertyType.SingleFamily; Console.Write("\nHow many stories (levels)? "); House.Stories = int.Parse(Console.ReadLine()); Console.Write("Does it have an indoor car garage (y/n): answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else House.IndoorGarage = false; Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false; break; case PropertyType.Townhouse: Type = PropertyType.Townhouse; Console.Write("\nHow many stories (levels)? "); House.Stories = int.Parse(Console.ReadLine()); Console.Write("Does it have an indoor car garage (y/n):

");

answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else House.IndoorGarage = false; Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false; break; case PropertyType.Condominium: Type = PropertyType.Condominium;

C# 3.0 Practical Learning

327

Console.Write("\nIs the building accessible to handicapped (y/n): ");

answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) Condo.HandicapAccessible = true; else Condo.HandicapAccessible = false; break;

}

}

default: Type = PropertyType.Unknown; break;

Console.Write("\nHow many bedrooms? "); ListProperty.Bedrooms = int.Parse(Console.ReadLine()); Console.Write("How many bathrooms? "); ListProperty.Bathrooms = float.Parse(Console.ReadLine()); Console.Write("Year built: "); ListProperty.YearBuilt = int.Parse(Console.ReadLine()); Console.Write("Property Value: "); ListProperty.Value = decimal.Parse(Console.ReadLine());

public void ShowProperty() { Console.WriteLine("=================================="); Console.WriteLine(" =//=//= Altair Realty =//=//="); Console.WriteLine("-=-=-=- Properties Listing -=-=-=-"); Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", ListProperty.PropertyNumber); Console.WriteLine("Property Type: {0}", Type); switch(Type) { case PropertyType.SingleFamily: case PropertyType.Townhouse: Type = PropertyType.SingleFamily; Console.WriteLine("Stories: {0}", House.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", House.IndoorGarage); Console.WriteLine("Finished Basement: {0}", House.FinishedBasement); break; case PropertyType.Condominium: Console.WriteLine("Handicapped Accessible Building: {0}", }

Condo.HandicapAccessible); break;

Console.WriteLine("Condition: ListProperty.Condition); Console.WriteLine("Bedrooms: ListProperty.Bedrooms); Console.WriteLine("Bathrooms: ListProperty.Bathrooms);

C# 3.0 Practical Learning

{0}", {0}", {0}", 328

Console.WriteLine("Year Built: ListProperty.YearBuilt); Console.WriteLine("Market Value: ListProperty.Value); } } }

{0}", {0:C}",

8. Execute the application and test it. Here is an example: =//= Altair Realty =//= -=- Property Creation -=Types of Properties 1. Single Family 2. Townhouse 3. Condonium 4. Don't Know Enter Type of Property: 1 Enter Property #: 4LP804 Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 3 How many stories (levels)? 3 Does it have an indoor car garage (y/n): y Is the basement finished(y/n): n How many bedrooms? How many bathrooms? Year built: Property Value:

4 2.5 1996 640885.80

================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 4LP804 Property Type: SingleFamily Stories: 3 Has Indoor Car Garage: True Finished Basement: False Condition: NeedsRepair Bedrooms: 4 Bathrooms: 2.5 Year Built: 1996 Market Value: $640,885.80 Press any key to continue . . .

9. Close the DOS window and return to your programming environment

C# 3.0 Practical Learning

329

Implementation of Derived Members You can notice in the above example that the derived class produces the same results as the base class. In reality, inheritance is used to solve various Object-Oriented Programming (OOP) problems. One of them consists of customizing, adapting, or improving the behavior of a feature (property or method, etc) of the parent class. For example, although both the circle and the sphere have an area, their areas are not the same. A circle is a flat surface but a sphere is a volume, which makes its area very much higher. Since they use different formulas for their respective area, you should implement a new version of the area in the sphere. Based on this, when deriving your class from another class, you should be aware of the properties and methods of the base class so that, if you know that the parent class has a certain behavior or a characteristic that is not conform to the new derived class, you can do something about that. A new version of the area in the sphere can be calculated as follows: using System; class Circle { private double _radius; public double Radius { get { if( _radius < 0 ) return 0.00; else return _radius; } set { _radius = value; } }

C# 3.0 Practical Learning

330

public double Diameter { get { return Radius * 2; } } public double Circumference { get { return Diameter * 3.14159; } } public double Area { get { return Radius * Radius * 3.14159; } } } class Sphere : Circle { public double Area { get { return 4 * Radius * Radius * 3.14159; } } } class Exercise { public static int Main() { var Round = new Circle(); Round.Radius = 25.55; Console.WriteLine("Circle Characteristics"); Console.WriteLine("Side: {0}", Round.Radius); Console.WriteLine("Diameter: {0}", Round.Diameter); Console.WriteLine("Circumference: {0}", Round.Circumference); Console.WriteLine("Area: {0}", Round.Area); var Ball = new Sphere(); Ball.Radius = 25.55; Console.WriteLine("\nSphere Characteristics"); Console.WriteLine("Side: {0}", Ball.Radius); Console.WriteLine("Diameter: {0}", Ball.Diameter); Console.WriteLine("Circumference: {0}", Ball.Circumference); Console.WriteLine("Area: {0}", Ball.Area); return 0; }

C# 3.0 Practical Learning

331

}

This would produce: Circle Characteristics Side: 25.55 Diameter: 51.1 Circumference: 160.535249 Area: 2050.837805975 Sphere Characteristics Side: 25.55 Diameter: 51.1 Circumference: 160.535249 Area: 8203.3512239 Press any key to continue

Notice that, this time, the areas of both figures are not the same even though their radii are similar. Besides customizing member variables and methods of a parent class, you can add new members as you wish. This is another valuable feature of inheritance. In our example, while the is a flat shape, a sphere has a volume. In this case, you may need to calculate the volume of a sphere as a new method or property of the derived class. Here is an example: using System; class Circle { private double _radius; public double Radius { get { if (_radius < 0) return 0.00; else return _radius; } set { _radius = value; } } public double Diameter { get { return Radius * 2; } } public double Circumference { get { return Diameter * 3.14159; }

C# 3.0 Practical Learning

332

}

} public double Area { get { return Radius * Radius * 3.14159; } }

class Sphere : Circle { public double Area { get { return 4 * Radius * Radius * 3.14159; } } public double Volume { get { return 4 * 3.14159 * Radius * Radius * Radius / 3; } } } class Exercise { public static int Main() { var Round = new Circle(); Round.Radius = 25.55; Console.WriteLine("Circle Characteristics"); Console.WriteLine("Side: {0}", Round.Radius); Console.WriteLine("Diameter: {0}", Round.Diameter); Console.WriteLine("Circumference: {0}", Round.Circumference); Console.WriteLine("Area: {0}", Round.Area); var Ball = new Sphere(); Ball.Radius = 25.55; Console.WriteLine("\nSphere Characteristics"); Console.WriteLine("Side: {0}", Ball.Radius); Console.WriteLine("Diameter: {0}", Ball.Diameter); Console.WriteLine("Circumference: {0}", Ball.Circumference); Console.WriteLine("Area: {0}", Ball.Area); Console.WriteLine("Volume: {0}\n", Ball.Volume); return 0; }

}

This would produce: Circle Characteristics Side: 25.55

C# 3.0 Practical Learning

333

Diameter: 51.1 Circumference: 160.535249 Area: 2050.837805975 Sphere Characteristics Side: 25.55 Diameter: 51.1 Circumference: 160.535249 Area: 8203.3512239 Volume: 209595.623770645 Press any key to continue

If you create a property or method in a derived class and that property or method already exists in the parent class, when you access the property or method in the derived class, you must make sure you indicate what member you are accessing. To make this possible, the C# language provides the base keyword. To access a property or method of a parent class from the derived class, type the base keyword, followed by the period operator, followed by the name of the property or method of the base class.

The new Modifier Imagine you create a class used to process a circle as we saw earlier. You can use this as the base class for a sphere. Both the circle and the sphere have an area but their values are different. This means that, as mentioned in our introduction to inheritance, when deriving the sphere class, you would have to calculate a new area for the cube. If you create or declare a new member in a derived class and that member has the same name as a member of the base class, when creating the new member, you may want to indicate to the compiler that, instead of overriding that same method that was defined in the base class, you want to create a brand new and independent version of that method. When doing this, you would be asking the compiler to hide the member of the base class that has the same name, when the member of the current class is invoked. To do this, type the new keyword to its left. Here is an example: using System; class Circle { private double _radius; public double Radius { get { return (_radius < 0) ? 0.00 : _radius; } set { _radius = value; } } public double Diameter { get { return Radius * 2; } } public double Circumference {

C# 3.0 Practical Learning

334

get

{ return Diameter * 3.14159; }

} public double Area { get { return Radius * Radius * 3.14159; } } } class Sphere : Circle { new public double Area { get { return 4 * Radius * Radius * 3.14159; } }

}

public double Volume { get { return 4 * 3.14159 * Radius * Radius * Radius / 3; } }

class Exercise { public static int Main() { var Round = new Circle(); Round.Radius = 25.55; Console.WriteLine("Circle Characteristics"); Console.WriteLine("Side: {0}", Round.Radius); Console.WriteLine("Diameter: {0}", Round.Diameter); Console.WriteLine("Circumference: {0}", Round.Circumference); Console.WriteLine("Area: {0}", Round.Area); var Ball = new Sphere(); Ball.Radius = 25.55; Console.WriteLine("\nSphere Characteristics"); Console.WriteLine("Side: {0}", Ball.Radius); Console.WriteLine("Diameter: {0}", Ball.Diameter); Console.WriteLine("Circumference: {0}", Ball.Circumference); Console.WriteLine("Area: {0}", Ball.Area); Console.WriteLine("Volume: {0}\n", Ball.Volume); }

return 0;

}

C# 3.0 Practical Learning

335

Polymorphism and Abstraction Characteristics of Inheritance Namespaces and Inheritance Imagine you had created a class named Person in a namespace named People as follows: Source File: Persons.cs using System; namespace People { public class Person { private string _name; private string _gdr; public Person() { this._name = "Not Available"; this._gdr = "Unknown"; } public Person(string name, string gender) { this._name = name; this._gdr = gender; } private string FullName { get { return _name; } set { _name = value; } }

}

private string Gender { get { return _gdr; } set { _gdr = value; } }

}

C# 3.0 Practical Learning

336

If you decide to derive a class from it, remember that this class belongs to a namespace. To inherit from this class, the compiler will need to know the namespace in which the class was created. Class inheritance that involves namespaces relies on qualification, like the calling of the members of a namespace. To derive a class from a class member of a namespace, type the name of the namespace, followed by the period operator ".", and followed by the name of the base namespace. Here is an example: Source File: StaffMembers.cs using System; namespace HighSchool { public class Teacher : People.Person { private string _pos; public Teacher() { this._pos = "Staff Member"; } public Teacher(string pos) { this._pos = pos; } private string Position { get { return _pos; } set { _pos = value; } } }

}

If you need to call the class that was defined in a different namespace, remember to qualify its name with the period operator. Here is an example: Source File: Exercise.cs using System; class Exercise { public static int Main() { People.Person man = new People.Person("Hermine Sandt", "Male"); HighSchool.Teacher staff = new HighSchool.Teacher("Vice Principal");

}

Console.WriteLine(); return 0;

}

C# 3.0 Practical Learning

337

Alternatively, to use the contents of a namespace, prior to calling a member of that namespace, you can type the using keyword followed by the name of the namespace. Here is an example: Source File: Exercise.cs using System; using People; using HighSchool; class Exercise { public static int Main() { Person man = new Person("Hermine Sandt", "Male"); Teacher staff = new Teacher("Vice Principal"); Console.WriteLine(); return 0; }

}

Practical Learning: Using Inheritance With Namespaces 1. Start Microsoft Visual C# and create a Console Application named Geometry2

2. To create a new class, on the main menu, click Project -> Add Class... 3. Set the Name to Square and press Enter 4. Change the file as follows: using System; namespace Geometry2 { public class Square { private double _side; public Square() { _side = 0.00; }

}

public Square(double s) { _side = s; }

}

5. To create a new class, on the main menu, click Project -> Add Class... 6. Set the Name to Rectangle and press Enter C# 3.0 Practical Learning

338

7. Change the file as follows: using System; namespace Geometry2 { public class Rectangle { double _length; double _height; public Rectangle() { _length = 0.00; _height = 0.00; }

}

public Rectangle(double L, double H) { _length = L; _height = H; }

}

8. Save all

Protected Members To maintain a privileged relationship with its children, a parent class can make a member available only to classes derived from it. With this relationship, some members of a parent class have a protected access level. Of course, as the class creator, it is your job to specify this relationship. To create a member that derived classes only can access, type the protected keyword to its left. Here are examples: Source File: Persons.cs using System; public class Person { private string _name; private string _gdr; public Person() { this._name = "Not Available"; this._gdr = "Unknown"; } public Person(string name, string gender) { this._name = name; this._gdr = gender; } protected string FullName

C# 3.0 Practical Learning

339

{ get { return _name; } set { _name = value; } } protected string Gender { get { return _gdr; } set { _gdr = value; } } public void Show() { Console.WriteLine("Full Name: {0}", this.FullName); Console.WriteLine("Gender: {0}", this.Gender); }

}

You can access protected members only in derived classes. Therefore, if you instantiate a class outside, you can call only public members: Source File: Exercise.cs using System; class Exercise { public static int Main() { People.Person man = new People.Person("Hermine Sandt", "Male"); Console.WriteLine("Staff Member"); man.Show(); Console.WriteLine(); return 0; }

}

This would produce: Staff Member Full Name: Hermine Sandt Gender: Male

If you create a class member and mark it as protected, the classes derived of its parent class, created in the current program or outside the current program, can access it. If you want the member to be accessed only by derived classes implemented in the same program but not derived classes implemented outside of the current program, mark the member as protected internal. Here are examples: Source File: Persons.cs using System; public class Person { private string _name; private string _gdr;

C# 3.0 Practical Learning

340

public Person() { this._name = "Not Available"; this._gdr = "Unknown"; } public Person(string name, string gender) { this._name = name; this._gdr = gender; } protected internal string FullName { get { return _name; } set { _name = value; } } protected internal string Gender { get { return _gdr; } set { _gdr = value; } } public void Show() { Console.WriteLine("Full Name: {0}", this.FullName); Console.WriteLine("Gender: {0}", this.Gender); } }

Virtual Members We have just mentioned that you can create a new version of a member in a derived class for a member that already exists in the parent class. After doing this, when you call that member in your program, you need to make sure that the right member gets called, the member in the base class or the equivalent member in the derived class. When you create a base class, if you anticipate that a certain property or method would need to be redefined in the derived class, you can indicate this to the compiler. On the other hand, while creating your classes, if you find out that you are customizing a property or a method that already exists in the base class, you should let the compiler know that you are providing a new version. In both cases, the common member should be created as virtual. To create a virtual member, in the base class, type the virtual keyword to the left of the property or method. Based on this, the Area property of our Circle class can be created as follows:

class Circle { public virtual double Area { get {

C# 3.0 Practical Learning

341

return Radius * Radius * 3.14159; }

}

}

In Microsoft Visual C#, unlike C++, if you omit the virtual keyword, the (Microsoft Visual C#) compiler would display a warning. When you derive a class from an abstract class, since the methods (if any) of the abstract class were not implemented, you must implement each one of them in the derived class. When customizing virtual members in a derived class, to indicate that a member is already virtual in the base class and that you are defining a new version, type the override keyword to the left of its declaration. For example, the Area property in our Sphere class can be created as follows: class Sphere : Circle { public override double Area { get { return 4 * Radius * Radius * 3.14159; } } public double Volume { get { return 4 * 3.14159 * Radius * Radius * Radius; } } }

In the same way, when implementing an abstract method of a class, type the override keyword to its left.

Practical Learning: Using Virtual Members 1. To create a new class, on the main menu, click Project -> Add Class... 2. Set the Name to a ShapeDescription and press Enter 3. Change the file as follows: using using using using

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

namespace Geometry2 { public class ShapeDescription { public virtual string Description() {

C# 3.0 Practical Learning

342

string Msg = "A quadrilateral is a geometric figure " + "that has four sides and four angles."; return Msg; }

}

}

4. Save the file as Quadrilaterals.cs in the Shapes1 folder 5. Access the Square.cs file and override the Description method as follows: using using using using

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

namespace Geometry2 { public class Square : ShapeDescription { private double _side; public Square() { _side = 0.00; } public Square(double s) { _side = s; } public override string Description() { // Get the introduction from the parent string Introduction = base.Description() + "\nA square is a quadrilateral that has four " + "equal sides and four right angles"; return Introduction; }

}

}

6. Access Rectangle.cs file and change it as follows: using using using using

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

namespace Geometry2 { public class Rectangle : ShapeDescription { double _length; double _height;

C# 3.0 Practical Learning

343

public Rectangle() { _length = 0.00; _height = 0.00; } public Rectangle(double L, double H) { _length = L; _height = H; } public override string Description() { // Get the introduction from the parent string Introduction = base.Description(); string Msg = Introduction + "\nA rectangle is a quadrilateral that has adjacent "

+

"perpendicular sides. This implies that its four " + "angles are right."; return Msg; } }

}

7. Access the Program.cs file and change it as follows: using using using using

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

class Exercise { static void DisplaySquare(Square S) { Console.WriteLine("Square Characteristics"); Console.WriteLine("Description: {0}", S.Description()); } static void DisplayRectangle(Rectangle R) { Console.WriteLine("Rectangle Characteristics"); Console.WriteLine("Description: {0}", R.Description()); } static void Main() { Square Sq = new Square(); Rectangle Rect = new Rectangle(); Console.WriteLine("========================================"); DisplaySquare(Sq); Console.WriteLine("========================================"); DisplayRectangle(Rect); Console.WriteLine("========================================");

C# 3.0 Practical Learning

344

}

Console.WriteLine();

}

8. Execute the project. This would produce: ======================================== Square Characteristics Description: A quadrilateral is a geometric figure that has four sides and four angles. A square is a quadrilateral that has four equal sides and four right angles ======================================== Rectangle Characteristics Description: A quadrilateral is a geometric figure that has four sides and four angles. A rectangle is a quadrilateral that has adjacent perpendicular sides. This implies that its four angles are right. ========================================

9. Close the DOS window

Abstract Classes In a program, you can create a class whose role is only meant to provide fundamental characteristics for other classes. This type of class cannot be used to declare a variable. Such a class is referred to as abstract. Therefore, an abstract class can be created only to serve as a parent class for other classes. To create an abstract class, type the abstract keyword to the left of its name. Here is an example: abstract class Ball { protected int TypeOfSport; protected string Dimensions; }

Practical Learning: Creating an Abstract Class 1. To create an abstract class, access the ShapeDescription.cs file and change it as follows: using using using using

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

namespace Geometry2 { public abstract class ShapeDescription { public virtual string Description() {

C# 3.0 Practical Learning

345

string Msg = "A quadrilateral is a geometric figure " + "that has four sides and four angles."; return Msg; }

}

}

2. Save the file

Abstract Properties and Methods When creating a class that would mainly be used as a base for future inheritance, you can create one or more properties and make them abstract. To do this, when creating the property, type the abstract keyword to its left. Because you would not define the property, you can simply type the get keyword and its semi-colon in the body of the property. A method of a class also can be made abstract. An abstract method can be a member of only an abstract class. If you make a method abstract in a class, you must not implement the method. To create an abstract method, when creating its class, type the abstract keyword to the left of the method's name. End the declaration with a semi-colon and no body for the method since you cannot implement it. Here is an example: public abstract class Ball { protected int TypeOfSport; protected string Dimensions; }

public abstract CalculateArea();

In the same way, you can create as many properties and methods as you see fit. You can choose what properties and methods to make abstract. This is important for inheritance.

Practical Learning: Creating an Abstract Property 1. To create an abstract property, access the ShapeDescription.cs file and change its class as follows: using using using using

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

namespace Geometry2 { public abstract class ShapeDescription { public abstract string Name { get; } public virtual string Description() { string Msg = "A quadrilateral is a geometric figure " +

C# 3.0 Practical Learning

346

"that has four sides and four angles."; } }

return Msg;

}

2. Access the Square.cs file and change it as follows: using using using using

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

namespace Geometry2 { public class Square : ShapeDescription { private double _side; public Square() { _side = 0.00; } public Square(double s) { _side = s; } public override string Name { get { return "Square"; } } public override string Description() { // Get the introduction from the parent string Introduction = base.Description() + "\nA square is a quadrilateral that has four " + "equal sides and four right angles";

} }

return Introduction;

}

3. Access the Rectangle.cs file and change it as follows: using using using using

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

namespace Geometry2 { public class Rectangle : ShapeDescription {

C# 3.0 Practical Learning

347

double _length; double _height; public Rectangle() { _length = 0.00; _height = 0.00; } public Rectangle(double L, double H) { _length = L; _height = H; } public override string Name { get { return "Rectangle"; } } public override string Description() { // Get the introduction from the parent string Introduction = base.Description(); string Msg = Introduction + "\nA rectangle is a quadrilateral that has adjacent

" +

"perpendicular sides. This implies that its four " + "angles are right."; return Msg; } }

}

4. Access the Program.cs file and change it as follows: using using using using

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

namespace Geometry2 { public class Program { static void DisplaySquare(Square S) { Console.WriteLine("Square Characteristics"); Console.WriteLine("Name: {0}", S.Name); Console.WriteLine("Description: {0}", S.Description()); } static void DisplayRectangle(Rectangle R) { Console.WriteLine("Rectangle Characteristics"); Console.WriteLine("Name: {0}", R.Name); Console.WriteLine("Description: {0}", R.Description());

C# 3.0 Practical Learning

348

} static void Main() { FlatShapes.Square Sq = new FlatShapes.Square(); FlatShapes.Rectangle Rect = new FlatShapes.Rectangle(); Console.WriteLine("========================================")

;

DisplaySquare(Sq); Console.WriteLine("========================================") ;

DisplayRectangle(Rect); Console.WriteLine("========================================")

;

Console.WriteLine(); }

}

}

5. Execute the project. This would produce: ======================================== Square Characteristics Name: Square Description: A quadrilateral is a geometric figure that has four sides and four angles. A square is a quadrilateral that has four equal sides and four right angles ======================================== Rectangle Characteristics Name: Rectangle Description: A quadrilateral is a geometric figure that has four sides and four angles. A rectangle is a quadrilateral that has adjacent perpendicular sides. This implies that its four angles are right. ========================================

6. Close the DOS window

Sealed Classes Any of the classes we have used so far in our lessons can be inherited from. If you create a certain class and don't want anybody to derive another class from it, you can mark it as sealed. In other words, a sealed class is one that cannot serve as base for another class. To mark a class as sealed, type the sealed keyword to the left of the class keyword. Here is an example: public sealed class Ball { public int TypeOfSport; public string Dimensions; }

There is not much to do about a sealed class. Simply remember that no class can be derived from it. 349 C# 3.0 Practical Learning

Interfaces Introduction Imagine you start creating a class and, while implementing or testing it, you find out that this particular class can be used instead as a general base that other classes can be derived from. An interface is a special class whose purpose is to serve as a template that actual classes can be based on. An interface is primarily created like a class: it has a name, a body and can have members. To create an interface, instead of the class keyword, you use the interface keyword. By convention, the name of an interface starts with I. Here is an example: interface ICourtDimensions { }

Practical Learning: Introducing Interfaces 1. On the main menu, click Project -> Add New Item... 2. In the Templates list, click Interface 3. Set the Name to Quadrilateral and click Add 4. Change the file as follows: using using using using

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

namespace Geometry2 { interface IQuadrilateral { } }

5. Save the file

The Members of an Interface As done for a class, the members of an interface are listed in its body. In an interface, you cannot declare fields like those we have used in other classes. Instead, if you want some type of member variable, you can create a property. If you create a property in an interface, you cannot define that property. One of the rules of an interface is that you cannot define any of its members. This is also valid for its properties. Therefore, if you create a property in an interface: C# 3.0 Practical Learning

350



You can indicate that it would be read-only by adding an empty getter property to it. Here is an example:

public interface ICourtDimensions { double Length { get; } } •

You can indicate that it would be write-only by adding an empty setter property to it. Here is an example:

public interface ICourtDimensions { double Length { set; } } •

You can indicate that it would be used to write values to it and to read values from it. To provide this information, add a getter and a setter accessories to it. Here is an example:

public interface ICourtDimensions { double Length { get; set; } }

In the same way, you can create as many properties as you judge necessary in an interface. Besides the properties, an interface can also have other types of members such as methods. Here is an example of an interface that has one read-only property named NameOfSport, one read/write property named NumberOfPlayers, and one method named SportCharacteristics: public interface IBall { int NumberOfPlayers { get; set; } string NameOfSport { get; } }

void SportCharacteristics();

Practical Learning: Creating Members of an Interface 1. To create a property, change the file as follows: using System; using System.Collections.Generic; using System.Linq;

C# 3.0 Practical Learning

351

using System.Text; namespace Geometry2 { interface IQuadrilateral { double Area { get; } } }

2. Save the file

An Interface as a Base Class An interface is used to lay a foundation for other classes. For this reason, it is the prime candidate for class derivation. To derive from an interface, use the same technique we have applied in inheritance so far. Here is an example of a class named SportBall that derives from an interface named ISportType: public class SportBall : ISportType { int players; string sport; }

Just as you can derive a class from an interface, you can create an interface that itself is based on another interface. Here is an example: public interface ISportType : IBall { SportCategory Type { get; } }

The C# language doesn't allow multiple inheritance, which is the ability to create a class based on more than one class. Multiple inheritance is allowed only if the bases are interfaces. To create multiple inheritance, separate the names of interface, with a comma. Here is an example: public interface ISportType : IBall, ICourtDimensions { SportCategory Type { get; } }

You can also involve a class as parent in a multiple inheritance scenario but there must be only one class. Here is an example in which a class called Sports derives from one class and various interfaces: public interface Sports: Player, IBall, ICourtDimensions { }

Practical Learning: Inheriting From an Interface C# 3.0 Practical Learning

352

1. On the main menu, click Project -> Add New Item... 2. In the Templates list, click Interface 3. Set the Name to RightAngle and click Add 4. Change the file as follows: using using using using

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

namespace Geometry2 { interface IRightAngle : IQuadrilateral { double Base { get; set; } double Height { get; set; } double Perimeter { get; } } }

5. Access the Square.cs file and change it as follows: using using using using

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

namespace Geometry2 { public class Square : ShapeDescription, IRightAngle { . . . } }

6. Access the Rectangle.cs file and change it as follows: using System; namespace Geometry2 { public class Rectangle : ShapeDescription, IRightAngle { . . . } }

7. Save all

Implementation of Derived Classes of an Interface After creating an interface, you can derive other interfaces or other classes from it. If you are deriving other interfaces from an interface, you can just C# 3.0 Practical Learning

353

proceed as you see fit. For example, you can add or not add one or more new properties, you can add or not add one or more methods, etc. Here is an example: Source File: Preparation.cs public enum SportCategory { SinglePlayer, Collective, Unknown } public interface ICourtDimensions { double Length { get; set; } double Width { get; set; } } public interface IBall { int NumberOfPlayers { get; set; } string NameOfSport { get; } }

void SportCharacteristics();

public interface ISportType : IBall, ICourtDimensions { SportCategory Type { get; } }

If you derive a class, from an interface, you must implement all properties that were created in the interface. This means that you must define them so that, when a variable is declared of that class, the properties have meaning. In the same way, if you create a class that is based on an interface, you must implement all methods that were declared in the interface. If you derive a class from an interface that itself was derived from another interface, in your class, you must define all properties that were created in the whole parental lineage and you must implement all methods that were created in the parent and grant-parent interfaces. Here is an example: Source File: Sport.cs using System; public class SportBall : ISportType {

C# 3.0 Practical Learning

354

int players; string sport; SportCategory _type; double Len; double Wdt; public SportBall(int nbr, SportCategory tp, string name) { players = nbr; _type = tp; sport = name; } public int NumberOfPlayers { get { return players;} set { players = value;} } public string NameOfSport { get { return sport; } } public SportCategory Type { get { return _type; } } public double Length { get { return Len; } set { Len = value; } } public double Width { get { return Wdt; } set { Wdt = value; } }

Wdt); }

public void SportCharacteristics() { Console.WriteLine("Sport Characteristics"); Console.WriteLine("Name of Sport: {0}", NameOfSport); Console.WriteLine("Type of Sport: {0}", Type); Console.WriteLine("# of Players: {0}", NumberOfPlayers); Console.WriteLine("Court Dimensions: {0}m x {1}m", Len, }

Once the class is ready, you can then use it as you see fit. Here is an example: Source File: Exercise.cs using System; class Exercise

C# 3.0 Practical Learning

355

{ public static int Main() { SportBall volley = new SportBall(6, SportCategory.Collective, "Volley Ball"); volley.Length = 18; volley.Width = 9; volley.SportCharacteristics(); Console.WriteLine(); SportBall tennis = new SportBall(1, SportCategory.SinglePlayer, "Table Tennis"); tennis.Length = 23.7; tennis.Width = 8.25; tennis.SportCharacteristics(); Console.WriteLine(); return 0; }

}

This would produce: Sport Characteristics Name of Sport: Volley Ball Type of Sport: Collective # of Players: 6 Court Dimensions: 18m x 9m Sport Characteristics Name of Sport: Table Tennis Type of Sport: SinglePlayer # of Players: 1 Court Dimensions: 23.7m x 8.25m

Practical Learning: Implementing Derived Members of an Interface 1. Access the Square.cs file and change it as follows: using using using using

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

namespace Geometry2 { public class Square : ShapeDescription, IRightAngle { private double _side; public Square() { _side = 0.00; }

C# 3.0 Practical Learning

356

public Square(double s) { _side = s; } public override string Name { get { return "Square"; } } public override string Description() { // Get the introduction from the parent string Introduction = base.Description() + " " + "A square is a quadrilateral that has four " + "equal sides and four right angles"; }

return Introduction;

public double Base { get { return (_side < 0) ? 0.00 : _side; } set { _side = value; } } public double Height { get { return (_side < 0) ? 0.00 : _side; } set { _side = value; } } public double Area { get { return Base * Base; } } public double Perimeter { get { return Base * 4; } } }

}

2. Access the Rectangle.cs file and change it as follows: using using using using

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

namespace Geometry2 { public class Rectangle : ShapeDescription, IRightAngle { double _length; double _height; public Rectangle()

C# 3.0 Practical Learning

357

{ _length = 0.00; _height = 0.00; } public Rectangle(double L, double H) { _length = L; _height = H; } public override string Name { get { return "Rectangle"; } } public override string Description() { // Get the introduction from the parent string Introduction = base.Description();

}

string Msg = Introduction + " " + "\nA rectangle is a quadrilateral that has adjacent " + "perpendicular sides. This implies that its four " + "angles are right."; return Msg;

public double Base { get { return _length; } set { _length = value; } } public double Height { get { return _height; } set { _height = value; } } public double Area { get{ return Base * Height; } } public double Perimeter { get { return 2 * (Base + Height); } } }

}

3. Access the Program.cs file and change it as follows: using using using using

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

C# 3.0 Practical Learning

358

namespace Geometry2 { public class Program { static Square CreateASquare() { double side; Console.Write("Enter the side of the square: "); side = double.Parse(Console.ReadLine()); Square Sqr = new Square(side); return Sqr; } static void DisplaySquare(Square S) { Console.WriteLine("Square Characteristics"); Console.WriteLine("Name: {0}", S.Name); Console.WriteLine("Description: {0}", S.Description()); Console.WriteLine("----------------------------"); Console.WriteLine("Side: {0}", S.Base); Console.WriteLine("Perimeter: {0}", S.Perimeter); Console.WriteLine("Area: {0}", S.Area); } static Rectangle CreateARectangle() { double Len, Hgt; Console.WriteLine("Enter the dimensions of the rectangle"); Console.Write("Base: "); Len = double.Parse(Console.ReadLine()); Console.Write("Height: "); Hgt = double.Parse(Console.ReadLine());

}

Rectangle Recto = new Rectangle(Len, Hgt); return Recto;

static void DisplayRectangle(Rectangle R) { Console.WriteLine("Rectangle Characteristics"); Console.WriteLine("Name: {0}", R.Name); Console.WriteLine("Description: {0}", R.Description()); Console.WriteLine("----------------------------"); Console.WriteLine("Base: {0}", R.Base); Console.WriteLine("Height: {0}", R.Height); Console.WriteLine("Perimeter: {0}", R.Perimeter); Console.WriteLine("Area: {0}", R.Area); } static int Main() { Square Sq = new Square(); Rectangle Rect = new Rectangle(); Sq = CreateASquare(); Rect = CreateARectangle();

C# 3.0 Practical Learning

359

Console.WriteLine("============================"); DisplaySquare(Sq); Console.WriteLine("============================"); DisplayRectangle(Rect); Console.WriteLine("============================");

} }

Console.WriteLine(); return 0;

}

4. Execute the application and test it. Here is an example: Enter the side of the square: 44.16 Enter the dimensions of the rectangle Base: 58.62 Height: 36.06 ============================ Square Characteristics Name: Square Description: A quadrilateral is a geometric figure that has four sides and four angles. A square is a quadrilateral that has four equal sides and four right angles ---------------------------Side: 44.16 Perimeter: 176.64 Area: 1950.1056 ============================ Rectangle Characteristics Name: Rectangle Description: A quadrilateral is a geometric figure that has four sides and four angles. A rectangle is a quadrilateral that has adjacent perpendicular sides. This implies that its four angles are right. ---------------------------Base: 58.62 Height: 36.06 Perimeter: 189.36 Area: 2113.8372 ============================ Press any key to continue . . .

5. Close the DOS window

Class Partial Implementation In all of the classes we have defined so far, we were using a single file to implement the class. In C#, you can create a class (the same class) in different files. This means that you can start a class in one file and continue it in another file or in other files. This is referred to as partial implementation. If you have programmed in C++ or C++/CLI, don't confuse its header and source files with C#'s partial implementation of classes. In C++ or C++/CLI, you can include the structure of a class with its member C# 3.0 Practical Learning

360

variables (called fields in C#) and the declaration of its methods. In C+ +, a header file has the extension .h. Here is an example of a C++/CLI header file: Header File: Cylinder.h #pragma once using namespace System; public ref class CCylinder { private: double rad; double hgt; public: CCylinder(void); CCylinder(double radius, double height); property double Radius { double get() { return rad; } void set(double value) { rad = value; } } property double Height { double get() { return hgt; } void set(double value) { hgt = value; } } double Volume(); };

In C++, after creating a header file, you can create its associated source file. The source file has the extention .cpp. Here is an example of the source file corresponding to the above header file: Source File: Cylinder.cpp #include "Cylinder.h" CCylinder::CCylinder(void) : rad(0.00), hgt(0.00) { } CCylinder::CCylinder(double radius, double height) : rad(radius), hgt(height) { } double CCylinder::Volume() { return rad * rad * hgt * Math::PI; }

C# 3.0 Practical Learning

361

The above class can be tested with the following: Source File: Exercise.cpp #include "Cylinder.h" using namespace System; CCylinder ^ Initialize() { CCylinder ^ c = gcnew CCylinder(36.12, 18.84); return c; } const void Show(CCylinder ^ vol) { Console::WriteLine(L"Radius: {0}", vol->Radius); Console::WriteLine(L"Height: {0}", vol->Height); Console::WriteLine(L"Volume: {0}", vol->Volume()); } int main() { CCylinder ^ cyl = Initialize(); Show(cyl); return 0; }

As we have seen so far, in C#, you cannot simply and only declare a method in a file for a forward (later) implementation, as it's done in C, C++, C++/CLI, and (Object) Pascal. In C#, to create a class in various classes, start the class in one file but precede the class keyword with partial. Here is an example of a file named first.cs that contains some (2) private fields and some (2) properties: Source File: geometry1.cs using System; partial class Cylinder { private double rad; private double hgt; public Cylinder(double radius, double height) { this.rad = radius; this.hgt = height; } public double Radius { get { return rad; } set { rad = value; } }

C# 3.0 Practical Learning

362

public double Height { get { return hgt; } set { hgt = value; } } }

After creating the class in one file, you can use as any of the classes as we have done so far. Here is an example: Source File: Exercise.cs using System; class Program { static Cylinder Initialize() { Cylinder c = new Cylinder(36.12, 18.84); return c; } static void Show(Cylinder vol) { Console.WriteLine("Radius: {0}", vol.Radius); Console.WriteLine("Height: {0}", vol.Height); } static int Main() { Cylinder cyl = Initialize(); Show(cyl); Console.WriteLine(); return 0; }

}

This would produce: Radius: 36.12 Height: 18.84 Press any key to continue . . .

If you had created a partial class, or you got a partial class from somebody (not as part of a DLL or nor from another type of library), and you find out that the class is not complete, you can then complement it. One of the rules you must observe is that the partial class must have been marked as partial, as we did above. One of the advantages of partial implementation is that you don't have to get back to the first or previous file to modify it in order to complement the class. You can simply start another file and continue the class in it. Two other rules you must observe are that you must use the same name for the class and you must precede the class keyword with partial. Here is an example: Source File: geometry2.cs using System;

C# 3.0 Practical Learning

363

partial class Cylinder { public Cylinder() { this.rad = 0.00; this.hgt = 0.00; } public double Volume() { return rad * rad * hgt * Math.PI; } }

This class can then be tested as follows: Source File: Exercise.cs using System; class Program { static Cylinder Initialize() { Cylinder c = new Cylinder(); c.Radius = 42.66; c.Height = 26.48; return c; } static void Show(Cylinder vol) { Console.WriteLine("Radius: {0}", vol.Radius); Console.WriteLine("Height: {0}", vol.Height); Console.WriteLine("Volume: {0}", vol.Volume()); } static int Main() { Cylinder cyl = Initialize(); Show(cyl);

}

Console.WriteLine(); return 0;

}

This would produce: Radius: 42.66 Height: 26.48 Volume: 151394.310951986 Press any key to continue . . .

C# 3.0 Practical Learning

364

Once a partial class has been created, you can create another based on it. The child class doesn't have to be partial, although it can be.

Practical Learning: Partially Implementing a Class 1. Start Microsoft Visual C# and create a Console Application named Geometry3

2. To add a new source file, on the main menu, click Project -> Add New Item... 3. In the Templates list, click Code File 4. Set the Name to circle1 and click Add 5. Change the file as follows: public partial class Circle { private double _radius; public double Radius { get { return (this._radius <= 0) ? 0.00 : this._radius; } set { this._radius = value; } } public double Diameter { get { return this.Radius * 2; } } public double Circumference { get { return Diameter * 3.14159; } }

}

public double Area { get { return this.Radius * this.Radius * 3.14159; } }

6. To create a new source file, in the Solution Explorer, right-click Geometry3 -> Add -> New Item... 7. In the Templates list, make sure Code File is selected; otherwise, click it. Set the Name to circle2 and click Add 8. Change the file as follows: using using using using

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

public partial class Circle

C# 3.0 Practical Learning

365

{ public Circle() { this.Radius = 0.00; } public Circle(double radius) { this.Radius = radius; }

}

public void Present() { Console.WriteLine("Radius: Console.WriteLine("Diameter: Console.WriteLine("Circumference: Console.WriteLine("Area: }

{0}", {0}", {0}", {0}",

this.Radius); this.Diameter); this.Circumference); this.Area);

9. To test the class, access the Program.cs file and change it as follows: using using using using

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

namespace Geometry3 { class Program { static Circle Initialize() { Console.Write("Enter the radius: "); double rad = double.Parse(Console.ReadLine()); Circle c = new Circle(rad); return c; } static int Main() { Console.WriteLine( "This application allows you to process a circle"); Circle circ = Initialize(); Console.WriteLine("\n=============================="); Console.WriteLine("Circle Characteristics"); Console.WriteLine("------------------------------"); circ.Present(); Console.WriteLine("==============================\n"); } }

return 0;

}

10.

Execute the application to sew the result. Here is an example: C# 3.0 Practical Learning

366

This application allows you to process a circle Enter the radius: 10.08 ============================== Circle Characteristics -----------------------------Radius: 10.08 Diameter: 20.16 Circumference: 63.3344544 Area: 319.205650176 ============================== Press any key to continue . . .

11. Return to your programming environment 12. To create a new source file, on the main menu, click Project -> Add New Item... 13. In the Templates list, make sure Code File is selected; otherwise, click it. Set the Name to cylinder1 and press Enter 14. using using using using

Change the file as follows: System; System.Collections.Generic; System.Linq; System.Text;

public partial class Cylinder : Circle { private double hgt; public double Height { get { return (this.hgt <= 0) ? 0.00 : this.hgt; } set { this.hgt = value; } } public double LateralArea { get { return this.Circumference * Height; } } public double TotalArea { get { return this.Area + this.LateralArea; } }

}

public double Volume { get { return this.Radius * this.Radius * this.Height * Math.PI; } }

C# 3.0 Practical Learning

367

15. To create a new source file, in the Solution Explorer, right- click Geometry3 -> Add -> New Item... 16. In the Templates list, make sure Code File is selected; otherwise, click it. Set the Name to cylindder2 and click Add 17. using using using using

Change the file as follows: System; System.Collections.Generic; System.Linq; System.Text;

public partial class Cylinder : Circle { // This is the default constructor of the cylinder // This constructor assumes that we don't have any dimension public Cylinder() { this.Radius = 0.00; } // This constructor assumes that there exists a radius // The radius could have been specified on a parent circle public Cylinder(double height) { this.Height = height; } // This constructor can be used to specify both // the radius of the base and the height of the volume // The radius can also have been defined by a parent circle public Cylinder(double radius, double height) { this.Radius = radius; this.Height = height; } new public void Present() { Console.WriteLine("Height: Console.WriteLine("Lateral Area: Console.WriteLine("Total Area: Console.WriteLine("Volume: }

{0}", {0}", {0}", {0}",

this.Height); this.LateralArea); this.TotalArea); this.Volume);

}

18. To test the class, access the Program.cs file and change it as follows: using using using using

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

namespace Geometry3 { class Program

C# 3.0 Practical Learning

368

{ static Circle Initialize() { Console.Write("Enter the radius: "); double rad = double.Parse(Console.ReadLine());

}

Circle c = new Circle(rad); return c;

static double GetHeight() { Console.Write("Enter the height: "); double hgt = double.Parse(Console.ReadLine()); }

return hgt;

static int Main() { Console.WriteLine( "This application allows you to process a cylinder"); Circle circ = Initialize(); double height = GetHeight(); Cylinder cldr = new Cylinder(circ.Radius, height); Console.WriteLine("\n================================"); Console.WriteLine("=//=Cylinder Characteristics=//="); Console.WriteLine("================================"); Console.WriteLine(" =-= Base Characteristics =-="); Console.WriteLine("--------------------------------"); circ.Present(); Console.WriteLine("------------------------------"); Console.WriteLine("=-= Volume Characteristics =-="); cldr.Present(); Console.WriteLine("================================\n"); } }

return 0;

}

19.

Execute the application to sew the result. Here is an example:

This application allows you to process a cylinder Enter the radius: 85.15 Enter the height: 44.95 ================================ =//=Cylinder Characteristics=//= ================================ =-= Base Characteristics =-= -------------------------------Radius: 85.15 Diameter: 170.3 Circumference: 535.012777 Area: 22778.168980775 -----------------------------=-= Volume Characteristics =-=

C# 3.0 Practical Learning

369

Height: 44.95 Lateral Area: 24048.82432615 Total Area: 46826.993306925 Volume: 1023879.5605199 ================================ Press any key to continue . . .

20.

Return to your programming environment

C# 3.0 Practical Learning

370

Delegates and Events Fundamentals of Delegates Introduction The C and C++ languages have long used the concept of function pointer. This was even more useful when programming for the Microsoft Windows operating systems because the Win32 library relies on the concept of callback functions. Callback functions are used in Microsoft Windows programming to process messages. For this reason and because of their functionality, callback functions were carried out in the .NET Framework but they were defined with the name of delegate. A delegate is a special type of user-defined variable that is declared globally, like a class. A delegate provides a template for a method, like an interface provides a template for a class. Like an interface, a delegate is not defined. Its role is to show what a useful method would look like. To support this concept, a delegate can provide all the necessary information that would be used on a method. This includes a return type, no argument or one or more arguments.

Practical Learning: Introducing Delegates 1. Start Microsoft Visual C# and create a Console Application named WattsALoan1

2. To create a new class, on the main menu, click Project -> Add Class... 3. Change the name of the file to LoanEvaluation and click Add 4. Change the contents of the file as follows: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace WattsALoan1 { public class LoanEvaluation { public double GetPrincipal()

C# 3.0 Practical Learning

371

{ Console.Write("Enter the Principal: $"); double P = double.Parse(Console.ReadLine()); return P; } public double GetInterestRate() { Console.Write("Enter the Interest Rate (%): "); double r = double.Parse(Console.ReadLine()); return r; } public int GetPeriod() { Console.Write("Enter the number of months: int t = int.Parse(Console.ReadLine());

");

return t; }

}

}

5. Access the Program.cs file and change it as follows: using using using using

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

namespace WattsALoan1 { public class Program { static int Main() { int NumberOfPeriods; double Principal, IntRate; LoanEvaluation loan = new LoanEvaluation(); Console.WriteLine( "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %");

");

%\n");

Console.WriteLine("Loan Processing\n"); Console.WriteLine( "This program allows you to calculate the amount of money a Console.WriteLine( "customer will owe at the end of the lifetime of a loan\n"); Principal = loan.GetPrincipal(); IntRate = loan.GetInterestRate(); NumberOfPeriods = loan.GetPeriod(); Console.WriteLine( "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

C# 3.0 Practical Learning

372

Console.WriteLine("================================"); Console.WriteLine("Loan Estimation"); Console.WriteLine("--------------------------------"); Console.WriteLine("Principal: {0:C}", Principal); Console.WriteLine("Interest: {0:P}", IntRate / 100); Console.WriteLine("Period: {0} months", NumberOfPeriods); Console.WriteLine("================================\n"); return 0; }

}

}

6. Execute the application test it. Here is an example: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Loan Processing This program allows you to calculate the amount of money a customer will owe at the end of the lifetime of a loan Enter the Principal: $14500 Enter the Interest Rate (%): 12.25 Enter the number of months: 48 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ================================ Loan Estimation -------------------------------Principal: $14,500.00 Interest: 12.25 % Period: 48 months ================================ Press any key to continue . . .

7. Close the DOS window 8. In the above program, the clerk was asked to provide the number of months for the period of the loan. Depending on the loan, one customer may want to specify the number of days necessary to pay the loan. Another customer may want to pay a loan over a number of years. To make this possible, we will allow the clerk to select the type of period for a loan. Access the LoanProcecssing.cs file and change the file as follows: using using using using

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

namespace WattsALoan1 { class LoanEvaluation { public double GetPrincipal()

C# 3.0 Practical Learning

373

{ Console.Write("Enter the Principal: $"); double P = double.Parse(Console.ReadLine()); return P; } public double GetInterestRate() { Console.Write("Enter the Interest Rate (%): "); double r = double.Parse(Console.ReadLine()); return r; } public void GetPeriod(ref int TypeOfPeriod, ref int Periods) { Console.WriteLine("How do you want to enter the length of

time?");

Console.WriteLine("1 - In Days"); Console.WriteLine("2 - In Months"); Console.WriteLine("3 - In Years"); Console.Write("Your Choice: "); TypeOfPeriod = int.Parse(Console.ReadLine()); if (TypeOfPeriod == 1) { Console.Write("Enter the number of days: "); Periods = int.Parse(Console.ReadLine()); } else if (TypeOfPeriod == 2) { Console.Write("Enter the number of months: "); Periods = int.Parse(Console.ReadLine()); } else if (TypeOfPeriod == 3) { Console.Write("Enter the number of years: "); Periods = int.Parse(Console.ReadLine()); } else { TypeOfPeriod = 0; // The user made an invalid selection. So, we will give

up

} }

Console.WriteLine("Bad Selection\n");

}

}

9. Access the Program.cs file and change it as follows: using using using using

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

namespace WattsALoan1

C# 3.0 Practical Learning

374

{ public class Program { static int Main() { int Periods = 0; int TypeOfPeriod = 0; double Principal, IntRate; string PeriodName = null; LoanEvaluation loan = new LoanEvaluation(); Console.WriteLine( "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); Console.WriteLine( "This program allows you to calculate the amount of money a "); Console.WriteLine( "customer will owe at the end of the lifetime of a loan\n"); Console.WriteLine("Loan Processing\n"); Principal = loan.GetPrincipal(); IntRate = loan.GetInterestRate();

here

loan.GetPeriod(ref TypeOfPeriod, ref Periods); if (TypeOfPeriod == 0) { // Since the user made a bad selection, stop the program return 0; }// Since this "if" condition has a "return 0" line, if the

"if" of would

// condition produces true, the "return 0" means the function // would be terminated. If the condition is false, the inside // this "if" condition would not execute and the function // continue. This means that, if the condition is false, then // the "else' is implied. Therefore, we don't have to write

an

// "else" condition: it is automatic. if (TypeOfPeriod == 1) { PeriodName = "days"; } else if (TypeOfPeriod == 2) { PeriodName = "months"; } else if (TypeOfPeriod == 3) { PeriodName = "years"; } Console.WriteLine( "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); Console.WriteLine("=================================="); Console.WriteLine("Loan Estimation"); Console.WriteLine("----------------------------------"); Console.WriteLine("Principal: {0:C}", Principal);

C# 3.0 Practical Learning

375

Console.WriteLine("Interest: {0:P}", IntRate / 100); Console.WriteLine("Period: {0} {1}", Periods, PeriodName); Console.WriteLine("==================================\n"); return 0; }

}

}

10.

Execute the application and test it. Here is an example:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% This program allows you to calculate the amount of money a customer will owe at the end of the lifetime of a loan Loan Processing Enter the Principal: $7500.00 Enter the Interest Rate (%): 8.75 How do you want to enter the length of time? 1 - In Days 2 - In Months 3 - In Years Your Choice: 3 Enter the number of years: 4 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ================================== Loan Estimation ---------------------------------Principal: $7,500.00 Interest: 8.75 % Period: 4 years ================================== Press any key to continue . . .

11.

Close the DOS window

Creating a Delegate To create a delegate, you use the delegate keyword. The basic formula used to create a delegate is: [attributes] [modifiers] delegate ReturnType Name ([formal-parameters]);

The attributes factor can be a normal C# attribute. The modifier can be one or an appropriate combination of the following keywords: new, public, private, protected, or internal. The delegate keyword is required. The ReturnType can be any of the data types we have used so far. It can also be a type void or the name of a class. The Name must be a valid C# name. C# 3.0 Practical Learning

376

Because a delegate is some type of a template for a method, you must use parentheses, required for every method. If this method will not take any argument, leave the parentheses empty. Here is an example: using System; public delegate void Simple(); public class Program { static int Main() { return 0; } }

After declaring a delegate, it only provides a template for a method, not an actual method. In order to use it, you must define a method that would carry an assignment to perform. That method must have the same return type and the same (number of) argument(s), if any. For example, the above declared delegate is of type void and it does not take any argument. you can define a corresponding method as follows: public delegate void Simple(); public class Exercise { public void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } }

With such a method implemented, you can associate it to the name of the delegate. To do that, where you want to use the method, declare a variable of the type of the delegate and assign the method to the delegate variable. Because you are assigning the method to a delegate, one of the rules of delegates is that you must not apply the parentheses to the method. Here is an example public class Program { static int Main() { Exercise exo = new Exercise(); Simple msg = exo.Welcome; return 0; }

}

Accessing a Delegate C# 3.0 Practical Learning

377

Introduction Once you have assigned a method to a delegate variable, you can you the delegate variable as if it were a defined method. That is, you can call as you would a normal method. Here is an example: using using using using

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

public delegate void Simple(); public class Exercise { public void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } } namespace Delegates { public class Program { static int Main() { Exercise exo = new Exercise(); Simple msg = exo.Welcome; msg(); return 0; }

}

}

This would produce: Welcome to the Wonderful World of C# Programming! Press any key to continue . . .

A Static Method for a Delegate In the above example, we had to declare a variable of the (Exercise) class before accessing the method. An alternative is to create the associated method as static. That way, you would not need to declare the variable first. Here is an example: using System; public delegate void Simple(); public class Exercise { public static void Welcome()

C# 3.0 Practical Learning

378

{ Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } } public class Program { static int Main() { Simple msg = Exercise.Welcome; msg(); return 0; }

}

An Anonymous Delegate In the above examples, we had to create a method that would be associated with a delegate. You can create a delegate, then, when you need to use, create a type of local implementation of a method and use it. In other words, you do not have to explicitly define a method prior to using the delegate. Such a method is referred to as anymous. Before implementing an anonymous method, first declare the delegate you will use: using System; public delegate void Simple(); public class Program { static int Main() { return 0; } }

To create an anonymous method, declare a variable for the delegate and assign it the delegate keyword as if it were a method. That is, followed by parentheses and curly brackets that would represent the body of the method. In the body of the anonymous method, do whatever you want. Here is an example: using System; public delegate void Simple(); public class Program { static int Main() { Simple msg = delegate() {

C# 3.0 Practical Learning

379

Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); }; return 0; }

}

Once you have done this, you can then call the delegate variable as if it were a normal method. Here is an example: using System; public delegate void Simple(); public class Program { static int Main() { Simple msg = delegate() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); }; msg(); }

return 0;

}

The Lambda Operator You can also create an anonymous method using an operator called lambda and represented by =>. From our example above, to use the lambda operator to create an anonymous method, omit the delegate keyword and follow the parentheses by the operator. Here is an example: using System; public delegate void Simple(); public class Program { static int Main() { Simple msg = () => { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); }; return 0; }

}

Once you have done this, you can call the delegate variable as a method. Here is an example: C# 3.0 Practical Learning

380

using System; public delegate void Simple(); public class Program { static int Main() { Simple msg = () => { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); }; msg(); return 0; }

}

A Delegate that Returns a Value You can create a delegate that returns a value. When creating the delegate, specify the data type to the left side of the name of the delegate. When defining a method that would be associated with the delegate, remember that the method must return the same type of value. In the body of the method, use it as you see fit. Before exiting the method, make sure you appropriately return a value. To use the method, follow the same approach as above. This time, when calling the delegate variable, you should use the parentheses. Here is an example: using System; delegate double Doubler(); public class Exercise { public static double MultiplyBy2() { return 255 * 2; } } public class Program { static int Main() { Doubler By2 = Exercise.MultiplyBy2; Console.WriteLine("Number = {0}", By2()); }

return 0;

}

This would produce: C# 3.0 Practical Learning

381

Number = 510 Press any key to continue . . .

In the same way, you can create an anonymous method that implements the delegate. To do this, follow the same rule we defined earlier. For example, you can use the delegate keyword. Here is an example: using System; delegate double Doubler(); public class Program { static int Main() { Doubler By2 = delegate() { return 255 * 2; }; Console.WriteLine("Number = {0}", By2()); }

return 0;

}

Or you can use the lambda operator: using System; delegate double Doubler(); public class Program { static int Main() { Doubler By2 = () => { return 255 * 2; }; Console.WriteLine("Number = {0}", By2()); }

return 0;

}

Delegates Compositions One of the characteristics that set delegates apart from C/C++ function pointers is that one delegate can be added to another using the + operation. This is referred to as composition. This is done by adding one delegate variable to another as in a = b + c.

Delegates and Arguments C# 3.0 Practical Learning

382

Introduction If you want to use a method that takes arguments and associate it to a delegate, when declaring the delegate, provide the necessary argument(s) in its parentheses. Here is an example of a delegate that takes two arguments (and returns a value): delegate double Doubler(double x);

When defining the associated method, besides returning the same type of value if not void, make sure that the method takes the same number of arguments. Here is an example: public class Algebra { public static double MultiplyBy2(double a) { return a * 2; } }

Using an Argumentative Delegate To associate the method to the delegate, you can declare a variable for the delegate and assign the name of the method to it. Here is an example: using System; delegate double Doubler(double x); public class Algebra { public static double MultiplyBy2(double a) { return a * 2; } } public class Program { static int Main() { Doubler dbl = Algebra.MultiplyBy2; Console.WriteLine("Result = {0}", dbl); }

return 0;

}

Notice that only the name of the method is passed to the delegate. To actually use the delegate, when calling it, add the parentheses to it and in the parentheses, provide a value for the argument(s). Here is an example: using System; delegate double Doubler(double x);

C# 3.0 Practical Learning

383

public class Algebra { public static double MultiplyBy2(double a) { return a * 2; } } public class Program { static int Main() { Doubler dbl = Algebra.MultiplyBy2; Console.WriteLine("Result = {0}", dbl(248)); return 0; }

}

This would produce: Result = 496 Press any key to continue . . .

A Lambda Expression You can create an anonymous method for a delegate that takes one or more arguments. You can do this using the delegate keyword. In its parentheses, pass an argument that is the same type as the argument of the delegate. Then, in the body of the method, do what you judge necessary. When calling the variable of the delegate, use the same rules we have applied so far. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = delegate(double alpha) { return alpha * 2; }; Console.WriteLine("Result = {0}", dbl(248)); return 0; }

}

This technique of using the delegate keyword was introduced in C# 2.0 and has been updated with the lambda operator. Therefore, this was probably the last time we use it since we have been able to apply to different types of delegates. C# 3.0 Practical Learning

384

Instead of the delegate keyword, you can define an anonymous method using the lambda operator. In this case, in the parentheses of the lambda expression, enter the data type of the argument followed by its name. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = (double alpha) => { }; return 0; }

}

In the body of the anonymous method, use the argument as you see fit. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = (double alpha) => { return alpha * 2; }; return 0; }

}

After defining the method, you can call it like a normal method. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = (double alpha) => { return alpha * 2; }; Console.WriteLine("Result = {0}", dbl(248)); return 0;

C# 3.0 Practical Learning

385

} }

In our example, we specified the type of the argument. If you want, you can let the compiler figure out the type of argument. In this case, pass only the name of the argument and not its type. Here is an example: using System; delegate double Doubler(double x); public class Program { static int Main() { Doubler dbl = (alpha) => { return alpha * 2; }; Console.WriteLine("Result = {0}", dbl(248)); }

return 0;

}

A Delegate With Many Arguments A delegate can take more than one argument. To start, when declaring it, pass the desired number of arguments. If you will use a method to associate to the delegate, then create the method also. Here is an example: delegate double Addition(double x, double y); public class Algebra { public static double Plus(double a, double b) { return a + b; } }

To use the delegate, follow the techniques we have applied so far and call the delegate as a method. Here is an example: using System; delegate double Addition(double x, double y); public class Algebra { public static double Plus(double a, double b) { return a + b; } } public class Exercise {

C# 3.0 Practical Learning

386

static int Main() { Addition Operation = Algebra.Plus; Console.WriteLine("Result = {0}", Operation(52.04, 9.368)); return 0; }

}

This would produce: Result = 61.408 Press any key to continue . . .

If you want to use a lambda expression to create an anonymous method, in its parentheses, pass the right number of arguments. In the body of the anonymous method, use the arguments ad you see fit. To use the delegate, call it as you would a normal method. Here is an example: using System; delegate double Addition(double x, double y); public class Exercise { static int Main() { Addition Operation = (x, y) => { return x + y; }; Console.WriteLine("Result = {0}", Operation(52.04, 9.368)); return 0; }

}

Practical Learning: Passing Arguments to a Delegate 1. Access the LoanEvaluation.cs file and change it as follows: using using using using

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

namespace WattsALoan1 { public class LoanEvaluation { public double GetPrincipal() { Console.Write("Enter the Principal: $"); double P = double.Parse(Console.ReadLine());

C# 3.0 Practical Learning

387

}

return P;

public double GetInterestRate() { Console.Write("Enter the Interest Rate (%): "); double r = double.Parse(Console.ReadLine()); }

return r;

public double GetPeriod(ref int TypeOfPeriod, ref double Periods) { Console.WriteLine("How do you want to enter the length of time?");

Console.WriteLine("1 - In Days"); Console.WriteLine("2 - In Months"); Console.WriteLine("3 - In Years"); Console.Write("Your Choice: "); TypeOfPeriod = int.Parse(Console.ReadLine()); if (TypeOfPeriod == 1) { Console.Write("Enter the number of days: "); Periods = double.Parse(Console.ReadLine()); return Periods / 360; } else if (TypeOfPeriod == 2) { Console.Write("Enter the number of months: "); Periods = double.Parse(Console.ReadLine()); return Periods / 12; } else if (TypeOfPeriod == 3) { Console.Write("Enter the number of years: "); Periods = double.Parse(Console.ReadLine()); return Periods; } else { TypeOfPeriod = 0; // The user made an invalid selection. So, we will give

up

Console.WriteLine("Bad Selection\n"); return 0.00; }

}

// Interest = Principal * rate * time in years public double InterestAmount(double P, double r, double t) { return P * (r / 100) * t; } }

}

2. Access the Program.cs file C# 3.0 Practical Learning

388

3. To declare and use a delegate, change the Program.cs file as follows: using using using using

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

namespace WattsALoan1 { delegate double Add2Values(double Value1, double Value2); public class Program { static int Main() { double Principal, IntRate, Period, AmountPaidAsInterest; int TypeOfPeriod = 0; double Periods = 0D; string PeriodName = null; LoanEvaluation loan = new LoanEvaluation(); Console.WriteLine("\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"); Console.WriteLine( "This program allows you to calculate the amount of money a "); Console.WriteLine( "customer will owe at the end of the lifetime of a loan\n"); Console.WriteLine("Loan Processing\n"); Principal = loan.GetPrincipal(); IntRate = loan.GetInterestRate(); Period = loan.GetPeriod(ref TypeOfPeriod, ref Periods); AmountPaidAsInterest = loan.InterestAmount(Principal, IntRate, Period); // A lambda expression Add2Values Add = (double Value1, double Value2) => { return Value1 + Value2; }; if (TypeOfPeriod == 0) { // Since the user made a bad selection, stop the program here "if"

return 0; }// Since this "if" condition has a "return 0" line, if the // condition produces true, the "return 0" means the function // would be terminated. If the condition is false, the inside

of would an

// this "if" condition would not execute and the function // continue. This means that, if the condition is false, then // the "else' is implied. Therefore, we don't have to write // "else" condition: it is automatic. if (TypeOfPeriod == 1) {

C# 3.0 Practical Learning

389

PeriodName = "days"; } else if (TypeOfPeriod == 2) { PeriodName = "months"; } else if (TypeOfPeriod == 3) { PeriodName = "years"; } Console.WriteLine("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); Console.WriteLine("=================================="); Console.WriteLine("Estimate on loan"); Console.WriteLine("----------------------------------"); Console.WriteLine("Principal: {0:C}", Principal); Console.WriteLine("Interest: {0:P}", IntRate / 100); Console.WriteLine("Period: {0} {1}", Periods, PeriodName); Console.WriteLine("--------------------------------"); Console.WriteLine("Total Amount Paid: {0:C}", Add); Console.WriteLine("Interest paid on Loan: {0:C}", AmountPaidAsInterest); Console.WriteLine("==================================\n"); } }

return 0;

}

4. Execute the program and test it. Here is an example: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% This program allows you to calculate the amount of money a customer will owe at the end of the lifetime of a loan Loan Processing Enter the Principal: $12500 Enter the Interest Rate (%): 10.55 How do you want to enter the length of time? 1 - In Days 2 - In Months 3 - In Years Your Choice: 2 Enter the number of months: 42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ================================== Estimate on loan ---------------------------------Principal: $12,500.00 Interest: 10.55 % Period: 42 months -------------------------------Total Amount Paid: $17,115.63 Interest paid on Loan: $4,615.63 ==================================

C# 3.0 Practical Learning

390

Press any key to continue . . .

5. Close the DOS window and return to your programming environment

A Delegate Passed as Argument Using delegates, one method can be indirectly passed as argument to another method. To proceed, first declare the necessary delegate. Here is a example of such a delegate: public delegate double Squared(double x); public class Circle { private double _radius;

}

public double Radius { get { return _radius; } set { _radius = value; } }

A delegate can be passed as argument to a method. Such an argument would be used as if it were a method itself. This means that, when accessed in the body of the method, the name of the delegate must be accompanied by parentheses and if the delegate takes an argument or arguments, the argument(s) must be provided in the parentheses of the called delegate. Here is an example: public delegate double Squared(double x); public class Circle { private double _radius; public double Radius { get { return _radius; } set { _radius = value; } } public double Area(Squared sqd) { return sqd(_radius) * Math.PI; } }

After declaring a delegate, remember to define a method that implements the needed behavior of that delegate. You can define the associated method in a class other than the one where the delegate would be used. Here is an example: using System; public class Exercise { public static double ValueTimesValue(double Value)

C# 3.0 Practical Learning

391

{ }

}

return Value * Value;

static int Main() { return 0; }

You can also define the method in the class where the delegate would be needed. Once the method that implements the delegate is known, you can use the delegate as you see fit. To do that, you can declare a variable of the type of that delegate and assign it to the variable. Here is an example: using System; public delegate double Squared(double x); public class Circle { private double _radius; public double Radius { get { return _radius; } set { _radius = value; } } public double Area(Squared sqd) { return sqd(_radius) * Math.PI; } } public class Exercise { public static double ValueTimesValue(double Value) { return Value * Value; } static int Main() { Squared Sq = ValueTimesValue; return 0; }

}

This declaration gives life to the delegate and can then be used as we have proceed with delegates so far. Here is an example: using System; public delegate double Squared(double x); public class Circle { private double _radius;

C# 3.0 Practical Learning

392

public double Radius { get { return _radius; } set { _radius = value; } } public double Area(Squared sqd) { return sqd(_radius) * Math.PI; } } public class Exercise { public static double ValueTimesValue(double Value) { return Value * Value; } static int Main() { Squared Sqr = ValueTimesValue; Console.WriteLine("Circle Area: {0}\n", Sqr(24.68)); return 0; }

}

This would produce: Circle Area: 609.1024 Press any key to continue . . .

In the same way, you can use a lambda expression to implement an anonymous method that would be associated with a delegate. Here is an example: using System; public delegate double Squared(double x); public class Circle { private double _radius; public double Radius { get { return _radius; } set { _radius = value; } }

}

public double Area(Squared sqd) { return sqd(_radius) * Math.PI; }

C# 3.0 Practical Learning

393

public class Exercise { static int Main() { Squared Sqr = (a) => { return a * a; }; Console.WriteLine("Circle Area: {0}\n", Sqr(24.68)); }

return 0;

}

Delegates and Classes Introduction So far, we have learned how to create and use delegate of primitive types. We learned how to create a void delegate, how to create a delegate that returns a value, and how to create a delegate that takes one or more argument. Just as a reminder, here is an example: using System; delegate double Multiplication(); public class Cube { private double _side; public double Side { get { return _side; } set { _side = value; } } public Cube() { _side = 0; } public Cube(double s) { _side = s; } internal double Area() { return 6 * Side * Side; } internal double Volume() { return Side * Side * Side;

C# 3.0 Practical Learning

394

} } public class Exercise { static int Main() { Cube SmallBox = new Cube(25.58); Multiplication AreaDefinition = SmallBox.Area; Multiplication VolDefinition = SmallBox.Volume; Console.WriteLine("Cube Characteristics"); Console.WriteLine("Side: {0}", SmallBox.Side); Console.WriteLine("Area: {0}", AreaDefinition); Console.WriteLine("Volume: {0}\n", VolDefinition); }

return 0;

}

This would produce: Cube Characteristics Side: 25.58 Area: 3926.0184 Volume: 16737.925112

A Delegate that Returns an Object A delegate can be created to return a value that is of a class type. Of course you must know the class you want to use because the compiler would like to know the type of value that the delegate would return. You can use one of the many built-in classes of the .NET Framework or you can create your own class. When creating the delegate, specify the name of the class to its left as the returned type of value. Here is an example: delegate Person Creator(); public class Person { public string FirstName; public string LastName; }

After doing this, you can create a method that implements the delegate. The method must return the same type of value as the delegate. Here is an example: using System; delegate Person Creator(); public class Person { public string FirstName; public string LastName; }

C# 3.0 Practical Learning

395

public class Exercise { private static Person Create() { Person pers = new Person(); pers.FirstName = "Julius"; pers.LastName = "Krands"; return pers; } }

To use the delegate, declare a variable for it and assign the method to it. Here is an example: using System; delegate Person Creator(); public class Person { public string FirstName; public string LastName; } public class Exercise { private static Person Create() { Person pers = new Person(); pers.FirstName = "Julius"; pers.LastName = "Krands"; return pers; } static int Main() { Creator crt = Create; }

return 0;

}

You can then call use the variable as you see fit. Instead of explicitly creating a method that implements the delegate, you can create an anonymous method using a lambda expression. In the body of the anonymous method, make sure you return a value of the type of the delegate. Here is an example: using System; delegate Person Creator(); public class Person { public string FirstName; public string LastName; } public class Exercise {

C# 3.0 Practical Learning

396

static int Main() { Creator Create = () => { var PersonalInformation = new Person(); PersonalInformation.FirstName = "Julius"; PersonalInformation.LastName = "Krands"; };

}

return PersonalInformation;

Create(); return 0;

}

A Delegate that Takes an Object as Argument A delegate can be created to receive a class type as argument. When creating the delegate, in its parentheses, specify the class whose value it takes as argument. Here is an example: using System; delegate void Anchor(Person p); public class Person { public string FirstName; public string LastName; }

To use the delegate, you can first create a method that implements the delegate, then declare a variable for the delegate and assign the method to it. If you prefer to create an anonymous method using a lambda expression, in the parentheses, enter a name for the argument and use that argument in the body of the method as you see fit. Here is an example: public class Exercise { static int Main() { Anchor personal = (individual) => { Console.WriteLine("=//= Personal Information =//="); Console.WriteLine("First Name: {0}", sample.FirstName); Console.WriteLine("Last Name: {0}", sample.LastName); }; return 0; }

}

You can then call the method as you see fit. Here is an example: using System; delegate Person Creator();

C# 3.0 Practical Learning

397

delegate void Anchor(Person p); public class Person { public string FirstName; public string LastName; } public class Exercise { static int Main() { var PersonalInformation = new Person(); Creator Create = () => { PersonalInformation.FirstName = "Julius"; PersonalInformation.LastName = "Krands"; };

return PersonalInformation;

Anchor personal = (individual) => { Console.WriteLine("=//= Personal Information =//="); Console.WriteLine("First Name: {0}", individual.FirstName); Console.WriteLine("Last Name: {0}", individual.LastName); }; Create(); personal(PersonalInformation); return 0; }

}

This would produce: =//= Personal Information =//= First Name: Julius Last Name: Krands Press any key to continue . . .

In the same way: •

You can create a delegate that takes a class as argument and returns a class type



You can create a delegate that takes more than one argument. One of the arguments could be a class type and the other(s) a class or a primitive type

Events Introduction C# 3.0 Practical Learning

398

Except for the main class of your program (the class that contains the Main() method), every class is mostly meant to interact with other, either to request values and methods of the other classes or to provide other classes with some values or a behavior they need. When a class A requests a value or service from another class B, class A is referred to as a client of class B. This relationship is important not simply because it establishes a relationship between both classes but also because class B should be ready to provide the value or behavior that a client needs at a certain time. While a class B is asked to provide some values or methods to another class A, many things would happen. In fact, there is an order that things should follow. For example, during the lifetime of a program, that is, while a program is running, a class may be holding a value it can provide to its client but at another time, that value may not be available anymore, for any reason; nothing strange, this is just the ways it happens. Because different things can happen to a class B while a program is running, and because only class B would be aware of these, it must be able to signal to the other classes when there is a change. This is the basis of events: An event is an action that occurs on an object and affects it in a way that its clients must be made aware of. Events are mostly familiar to those who do graphical (GUI) programming as they are able to "visually" work on Windows controls and as they are able to access the objects on which actions are happening and the objects that must know when these actions occur. Still, because events are dealt with in C#, you should be aware of their functionality. Although events are mostly used in Windows controls programming, they can also be implemented in console applications.

Event Creation An event is declared like a pseudo-variable but based on a delegate. Therefore, to declare an event, you must have a delegate that would implement it. Here is an example: using System; delegate void dlgSimple(); class Exercise { public static void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } }

To actually declare an event, you use the event keyword with the following formula: [attributes] [modifiers] event type declarator; [attributes] [modifiers] event type member-name {accessor-declarations};

The attributes factor can be a normal C# attribute.

C# 3.0 Practical Learning

399

The modifier can be one or a combination of the following keywords: public, private, protected, internal, abstract, new, override, static, virtual, or extern. The event keyword is required. It is followed by the name of the delegate that specifies its behavior. If the event is declared in the main class, it should be made static. Like everything in a program, an event must have a name. This would allow the clients to know what (particular) event occurred. Here is an example: using System; delegate void dlgSimple(); class Exercise { public static event dlgSimple Simply; public static void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } }

After declaring the event, you must define a method that calls the event. Here is an example: using System; delegate void dlgSimple(); class Exercise { public static event dlgSimple Simply; public static void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); }

}

public static void SayHello() { Simply(); }

When the event occurs, its delegate would be invoked. This specification is also referred to as hooking up an event. As the event occurs (or fires), the method that implements the delegate runs. This provides complete functionality for the event and makes the event ready to be used. Before using an event, you must combine it to the method that implements it. This can be done by passing the name of the method to the appropriate delegate, as we learned when studying delegates. You can then assign this variable to the event's name using the += operator. Once this is done, you can call the event. Here is an example: C# 3.0 Practical Learning

400

using System; delegate void dlgSimple(); class Exercise { public static event dlgSimple Simply; public static void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } public static void SayHello() { Simply(); } static int Main() { Simply += new dlgSimple(Welcome); SayHello(); }

return 0;

}

Instead of the += operator used when initializing the event, you can implement add and remove of the event class. Here is an example: using System; delegate void dlgSimple(); class Exercise { public event dlgSimple Simply { add { Simply += new dlgSimple(Welcome); } remove { Simply -= new dlgSimple(Welcome); } } public void Welcome() { Console.WriteLine("Welcome to the Wonderful World of C# Programming!"); } }

C# 3.0 Practical Learning

401

Structures Fundamentals of Structures Introduction A structure is an enhanced version of the primitive data types we have used in previous lessons. Like a class, a structure is created from one variable of a primitive type or by combining various variables of primitive types. To create a structure, you use the same formula as for a class but with the struct keyword. Here is an example of a structure: struct Integer { }

Like a class, a structure can have fields. They are listed in the body of the structure. Here is an example: struct Integer { private int val; }

A structure can also have properties. Here is an example: struct Integer { private int val;

}

public int Value { get { return val; } set { val = value; } }

A structure can also have methods. Here is an example: struct Integer { private int val; public int Value { get { return val; } set { val = value; } }

C# 3.0 Practical Learning

402

public int Read() { return int.Parse(Console.ReadLine()); } }

Structure Declaration Like any other data type, to use a structure, you can first declare a variable from it. To allocation memory for a variable declared from a structure, use the new operator as done for a class. Here is an example: using System; struct Integer { private int val; public int Value { get { return val; } set { val = value; } } public int Read() { return int.Parse(Console.ReadLine()); } } class Program { static int Main() { Integer Natural = new Integer(); return 0; } }

As done for variables of the other types and as seen for classes, to declare a variable for a structure, you can use the var keyword. After declaring the variable, you can use the object the same way you would a class. You can access its members (fields, properties, and methods) using the period operator. Here is an example: using System; struct Integer { private int val; public int Value { get { return val; } set { val = value; } }

C# 3.0 Practical Learning

403

public int Read() { return int.Parse(Console.ReadLine()); } } class Program { static int Main() { var Natural = new Integer(); Console.Write("Enter a natural number: "); // Accessing a property of the structure Natural.Value = // Calling a method of the structure Natural.Read(); Console.WriteLine("The value you entered was: {0}", Natural.Value); return 0; } }

Here is an example of running the program: Enter a natural number: 248 The value you entered was: 248 Press any key to continue . . .

Although there are many similarities in the behaviors of classes and structures, you should use a structure when the object you are creating is meant to represent relatively small values. Like primitive data types and unlike a class, a structure is a value type.

Techniques of Using Structures A Structure as a Property Once a structure exists, you can use it like a data type. For example, you can create a property that is a structure type. The rules are the same we reviewed for creating a property of a class. After creating the property, you can use it as you see fit. Here is an example: using System; public struct Real { private double val; public double Value { get { return val; } set { val = value; } }

C# 3.0 Practical Learning

404

public double Read() { return double.Parse(Console.ReadLine()); } } public struct Rectangle { Real len; Real hgt; public Real Length { get { return len; } set { len = value; } } public Real Height { get { return hgt; } set { hgt = value; } } public void CreateRectangle() { Real rat = new Real(); Console.WriteLine("Enter the dimensions of the rectangle"); Console.Write("Enter the length: "); len.Value = rat.Read(); Console.Write("Enter the height: "); hgt.Value = rat.Read(); }

}

public class Program { static int Main() { var Rect = new Rectangle(); Rect.CreateRectangle(); Console.WriteLine(); Console.WriteLine("Rectangle Characteristics"); Console.WriteLine("Length: {0}", Rect.Length.Value); Console.WriteLine("Height: {0}", Rect.Height.Value); Console.WriteLine("Perimeter: {0}", (Rect.Length.Value + Rect.Height.Value) * 2); Console.WriteLine("Area: {0}", Rect.Length.Value * Rect.Height.Value); }

return 0;

}

Here is an example of running the program: Enter the dimensions of the rectangle

C# 3.0 Practical Learning

405

Enter the length: 44.84 Enter the height: 26.75 Rectangle Characteristics Length: 44.84 Height: 26.75 Perimeter: 143.18 Area: 1199.47 Press any key to continue . . .

Returning a Structure From a Method Like regular data type or a class, a structure can serve as the return type of a method. The rules are more related to those of a class. When creating the method, type the name of the structure on the left side of the name of the method. In the body of the method, implement the desired behavior. Before exiting the method, make sure you return a valid value that is of the type of the structure. When a method returns a value of the type of a structure, you can assign the method to a variable of the type of the structure. Here is an example of implementing a method that returns a structure type, including calling the method and using its value: using System; public struct Real { private double val; public double Value { get { return val; } set { val = value; } } public double Read() { return double.Parse(Console.ReadLine()); } } public struct Rectangle { Real len; Real hgt; public Real Length { get { return len; } set { len = value; } } public Real Height { get { return hgt; } set { hgt = value; } }

C# 3.0 Practical Learning

406

public void CreateRectangle() { Real rat = new Real();

}

Console.WriteLine("Enter the dimensions of the rectangle"); len = GetLength(); Console.Write("Enter the height: "); hgt.Value = rat.Read();

public Real GetLength() { Real rat = new Real(); Console.Write("Enter the length: "); rat.Value = rat.Read(); return rat; }

}

public class Program { static int Main() { var Rect = new Rectangle(); Rect.CreateRectangle(); Console.WriteLine(); Console.WriteLine("Rectangle Characteristics"); Console.WriteLine("Length: {0}", Rect.Length.Value); Console.WriteLine("Height: {0}", Rect.Height.Value); Console.WriteLine("Perimeter: {0}", (Rect.Length.Value + Rect.Height.Value) * 2); Console.WriteLine("Area: {0}", Rect.Length.Value * Rect.Height.Value); }

return 0;

}

Here is an example of running the application: Enter the dimensions of the rectangle Enter the length: 36.04 Enter the height: 22.86 Rectangle Characteristics Length: 36.04 Height: 22.86 Perimeter: 117.8 Area: 823.8744 Press any key to continue . . .

Passing a Structure as Argument Like a data type, a structure can be passed as argument to a method. The argument is primarily passed as done for a class. After passing the argument, C# 3.0 Practical Learning

407

in the body of the method, you can access the public members of the structure, using the period operator. Here is an example: using System; public struct Real { private double val; public double Value { get { return val; } set { val = value; } }

}

public double Read() { return double.Parse(Console.ReadLine()); }

public struct Rectangle { Real len; Real hgt; public Real Length { get { return len; } set { len = value; } } public Real Height { get { return hgt; } set { hgt = value; } } public void CreateRectangle() { Real rat = new Real(); Console.WriteLine("Enter the dimensions of the rectangle"); len = GetLength(); Console.Write("Enter the height: "); hgt.Value = rat.Read(); } public Real GetLength() { Real rat = new Real();

}

Console.Write("Enter the length: "); rat.Value = rat.Read(); return rat;

} public class Program {

C# 3.0 Practical Learning

408

public static void ShowCharacteristics(Rectangle rect) { Console.WriteLine("Rectangle Characteristics"); Console.WriteLine("Length: {0}", rect.Length.Value); Console.WriteLine("Height: {0}", rect.Height.Value); Console.WriteLine("Perimeter: {0}", (rect.Length.Value + rect.Height.Value) * 2); Console.WriteLine("Area: {0}", rect.Length.Value * rect.Height.Value); } static int Main() { var Rect = new Rectangle(); Rect.CreateRectangle(); Console.WriteLine(); ShowCharacteristics(Rect); return 0; }

}

Here is an example of running the program: Enter the dimensions of the rectangle Enter the length: 114.55 Enter the height: 82.72 Rectangle Characteristics Length: 114.55 Height: 82.72 Perimeter: 394.54 Area: 9475.576 Press any key to continue . . .

When you pass a structure to a method as we did above, it referred to as passing by value. A copy of the value of the structure is passed to the method. If the method modifies the argument, the original variable would stay intact. If you want the method to modify the value of the structure, you can pass the argument by reference. You can do this using the (rules of the) ref and the out keywords. Here is an example of passing a structure by reference using the ref keyword: using System; public struct Real { private double val; public double Value { get { return val; } set { val = value; } } public double Read() { return double.Parse(Console.ReadLine());

C# 3.0 Practical Learning

409

} } public struct Rectangle { Real len; Real hgt; public Real Length { get { return len; } set { len = value; } } public Real Height { get { return hgt; } set { hgt = value; } } public void CreateRectangle() { Console.WriteLine("Enter the dimensions of the rectangle"); len = GetLength(); GetHeight(ref hgt); } public Real GetLength() { Real rat = new Real();

}

Console.Write("Enter the length: "); rat.Value = rat.Read(); return rat;

public void GetHeight(ref Real rl) { Real rat = new Real();

}

Console.Write("Enter the height: "); rl.Value = rat.Read();

} public class Program { static int Main() { Rectangle rect = new Rectangle(); rect.CreateRectangle(); Console.WriteLine(); Console.WriteLine("Rectangle Characteristics"); Console.WriteLine("Length: {0}", rect.Length.Value); Console.WriteLine("Height: {0}", rect.Height.Value); Console.WriteLine("Perimeter: {0}", (rect.Length.Value + rect.Height.Value) * 2); Console.WriteLine("Area: {0}",

C# 3.0 Practical Learning

410

rect.Length.Value * rect.Height.Value); return 0; }

}

Here is an example of running the program: Enter the dimensions of the rectangle Enter the length: 75.82 Enter the height: 55.64 Rectangle Characteristics Length: 75.82 Height: 55.64 Perimeter: 262.92 Area: 4218.6248 Press any key to continue . . .

Built-In Structures: The Integral Data Types Introduction The C# language (actually the .NET Framework) treats each primitive data type as a class. In fact, each data type was created as a structure. Some characteristics are common to many of these structures while some other aspects are unique to some others. To support the routine operations of regular variables, each structure that represents a primitive type is equipped with some member variables and methods.

Conversion to a String With a value of a primitive type, at one time or another, you may need to convert the value of a variable from its type to a string. To support this, each structure of a primitive type is equipped with a method named ToString. This method is overloaded with various versions. One of the versions of this method takes no argument. The syntax of this method is: public override string ToString();

Another version of this method takes as argument a string. This string holds an expression used to format the value of the variable that called the method. The syntax of this method is: public string ToString(string format);

You can pass the desired string to format the value to be displayed.

Parsing a String In Lesson 5, we saw how to retrieve a value from the console and convert it to the desired value. To support this operation, each structure of a primitive C# 3.0 Practical Learning

411

data type is equipped with a static method named Parse. The syntaxes of this method are: byte public static byte Parse(string s); sbyte public static sbyte Parse(string s); short public static short Parse(string s); ushort <=> UInt16 public static ushort Parse(string s); int <=> Int32 public static int Parse(string s); uint <=> UInt32 public static uint Parse(string s); long <=> Int64 public static long Parse(string s);

unsigned long <=> uint64 public static ulong Parse(string s);

Here is an example of calling this method: using System; class Program { static int Main() { double value = 0; Console.Write("Enter a Value: "); value = double.Parse(Console.ReadLine()); Console.WriteLine("Value Entered: {0}", value); return 0; }

}

Here is an example of executing the program: Enter a Value: 245.85 Value Entered: 245.85 Press any key to continue . . .

C# 3.0 Practical Learning

412

You can also parse a value that is not primarily known. To support values other than byte types, you can use another version of the Equals() method that takes as argument an object type. The syntaxes of this version of the method are: byte public static byte Parse(string s) sbyte public static sbyte Parse(string s) short public static short Parse(string s) ushort <=> UInt16 public static ushort Parse(string s) int <=> Int32 public static int Parse(string s) uint <=> UInt32 public static uint Parse(string s) long <=> Int64 public static long Parse(string s)

unsigned long <=> uint64 public static ulong Parse(string s)

When calling this method, if a bad value is passed to the Parse() method, for example if the user enters an invalid value to a double.Parse(Console.ReadLine()) call, the program produces an error (in Lesson 17, we will learn that the program throws an exception). To assist you with this type of problem, each structure of a primitive type is equipped with a method named TryParse. This method is overloaded with two versions that each returns a bool. One of the versions of this method takes two arguments: a string and a variable passed as an out reference. The syntaxes of this method are: byte public static bool TryParse(string s, out byte result) sbyte public static bool TryParse(string s, out sbyte result) short

C# 3.0 Practical Learning

413

public static bool TryParse(string s, out short result) ushort <=> UInt16 public static bool TryParse(string s, out ushort result) int <=> Int32 public static bool TryParse(string s, out int result) uint <=> UInt32 public static bool TryParse(string s, out uint result) long <=> Int64 public static bool TryParse(string s, out long result)

unsigned long <=> uint64 public static bool TryParse(string s, out ulong result)

Based on this, if a double variable calls this method, the first argument is passed a string and the second argument is passed as an out double. This means that the second argument is returned from the method also. When the TryParse() method is called: •

If the first argument passed to the method is valid, the method returns two values: true and the entered value is stored in the out argument



If the value of the first argument is invalid, the method returns false and the default value of the data type is stored in the out argument. For example, if the variable that called the method is on type int but the user entered the wrong value, the method returns two values: false and 0 (because 0 is the default value of an int. If the variable that called the method is on type char but the user entered a bad value, the method returns two values: false and an empty character (because the default value of a char is empty).

Here is another example of running the above program: Enter a Value: 506GH False: Value Entered = 0 Press any key to continue . . .

Notice that the compiler didn't produce (throw) an error (an exception).

The Minimum and Maximum Values of a Primitive Type In Lesson 1, we saw that, when you declare a variable, the compiler reserves an amount of memory space preparing to store its value. As different variables have different requirements, some of them use less or more memory than others. When you declare a variable, the data type you specify allows the compiler to know how mush space would be needed to store the value of that variable. There is a minimum and a maximum values that can be stored in the memory space reserved for a variable. Based on this, a value 414 C# 3.0 Practical Learning

such as 224855 can be stored in space reserved for an int variable but it is beyond the space reserved for a Byte or a short. To help you find out the minimum value that a data type can hold, each structure of a primitive type is equipped with a constant member named MinValue. In the same way, the maximum value that a data type can support is represented by a constant field named MaxValue. You can check these minimum and maximum with the following program: using System; class Program { static int Main() { Console.WriteLine( "================================================================= ======"); Console.WriteLine("C# Type .NET Structure Minimum Maximum"); Console.WriteLine( "================================================================= ======"); Console.WriteLine("char Char {0}\t\t\t{1}", char.MinValue, char.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("byte Byte {0}\t\t\t{1}", byte.MinValue, byte.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("sbyte SByte {0}\t\t\t{1}", sbyte.MinValue, sbyte.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("short Int16 {0}\t\t\t{1}", short.MinValue, short.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("ushort UInt16 {0}\t\t\t{1}", UInt16.MinValue, UInt16.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("int Int32 {0}\t\t{1}", int.MinValue, int.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("uint UInt32 {0}\t\t\t{1}", UInt32.MinValue, UInt32.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("long Int64 {0}\t{1}",

C# 3.0 Practical Learning

415

long.MinValue, long.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("uint64 UInt64 {0}\t\t\t{1}", UInt64.MinValue, UInt64.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("float Single {0}\t\t{1}", float.MinValue, float.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("double Double {0}\t{1}",| double.MinValue, double.MaxValue); Console.WriteLine( "----------------------------------------------------------------------"); Console.WriteLine("decimal Decimal {0} {1}", decimal.MinValue, decimal.MaxValue); Console.WriteLine( "============================================================="); return 0; }

}

This would produce: ======================================================================= C# Type .NET Structure Minimum Maximum ======================================================================= char Char ? ----------------------------------------------------------------------byte Byte 0 255 ----------------------------------------------------------------------sbyte SByte -128 127 ----------------------------------------------------------------------short Int16 -32768 32767 ----------------------------------------------------------------------ushort UInt16 0 65535 ----------------------------------------------------------------------int Int32 -2147483648 2147483647 ----------------------------------------------------------------------uint UInt32 0 4294967295 ----------------------------------------------------------------------long Int64 -9223372036854775808 9223372036854775807 ----------------------------------------------------------------------uint64 UInt64 0 18446744073709551615 ----------------------------------------------------------------------float Single -3.402823E+38 3.402823E+38 ----------------------------------------------------------------------double Double -1.79769313486232E+308 1.79769313486232E+308 ----------------------------------------------------------------------decimal Decimal -79228162514264337593543950335 79228162514264337593543950335 ============================================================= Press any key to continue . . .

C# 3.0 Practical Learning

416

Value Comparisons One of the most common operations performed on variables consists of comparing their values: to find out whether they are equal or to know whether one is higher than the other. These operations can be performed using the Boolean operators we reviewed in Lesson 8. The Boolean operations are part of the C# language. To formally implement them, each structure of a data type is equipped with a method named CompareTo that is overloaded with two versions. One of the implementations of the CompareTo() method compares a value or the value of a variable of the same type, with the variable that calls the method. This method takes one argument that is the same type as the variable that is calling it. The syntaxes of this method are: byte public int CompareTo(byte value) sbyte public int CompareTo(sbyte value) short public int CompareTo(short value) ushort <=> UInt16 public int CompareTo(ushort value) int <=> Int32 public int CompareTo(int value) uint <=> UInt32 public int CompareTo(uint value) long <=> Int64 public int CompareTo(long value)

unsigned long <=> uint64 public int CompareTo(ulong value)

The method returns an int value. For example, imagine you have two int variables named Variable1 and Variable2, you can call the CompareTo() method of the first variable to compare its value to that of the second variable. This would be done as in: int result = Variable1.CompareTo(Variable2);

The end result would be as follows:

C# 3.0 Practical Learning

417



If the value of Variable1 is greater than the value of Variable2, the method returns 1



If the value of Variable1 is less than the value of Variable2, the method returns -1



If the values of both variables are equal, the method returns 0

Here is an example: using System; class Program { static int Main() { int Variable1 = 248; int Variable2 = 72937; int result = Variable1.CompareTo(Variable2); Console.WriteLine("{0} compared to {1} produces {2}", Variable1, Variable2, result); return 0; }

}

This would produce: 248 compared to 72937 produces -1 Press any key to continue . . .

Another version of the CompareTo() method allows you to compare the value of a variable with a variable whose type is not the same as the variable that called it. Since all types and classes of C# are based on object, this second version takes as argument an object object. The method return an int value. The syntax of this version is: public int CompareTo(object value);

Notice that you can use the CompareTo() method to test for equality. Another method used to check the equality of two variables is the Equals() method. The Equals() method is overloaded in two versions and each takes one argument. The Equals() method returns a Boolean value. One of the versions of this method takes as argument a value of the same type as the variable that called it. The syntaxes of this version are: byte public bool Equals(byte obj) sbyte public bool Equals(sbyte obj) short public bool Equals(short obj) ushort <=> UInt16

C# 3.0 Practical Learning

418

public bool Equals(ushort obj) int <=> Int32 public bool Equals(int obj) uint <=> UInt32 public bool Equals(uint obj) long <=> Int64 public bool Equals(long obj)

unsigned long <=> uint64 public bool Equals(ulong obj)

The method compares the values of the variable that called it and the argument, as in bool result = Variable1.Equals(Variable2);

The comparison is performed as follows: •

If the value of the first variable is the same as that of the second variable, the method returns true



If the values of the variables are different, the method returns false

Here is an example: using System; class Program { static int Main() { int Variable1 = 1407; int Variable2= 59266; bool result = value1.Equals(value2); Console.WriteLine("{0} = {1} produces {2}", Variable1, Variable2, result); return 0; }

}

This would produce: 1407 = 59266 produces False Press any key to continue . . .

The other version of the Equals() method takes as argument an object value. The syntax of this version is: public override bool Equals(object obj);

C# 3.0 Practical Learning

419

Here is an example: using System; class Program { static int Main() { int value1 = 824; object value2 = 824; bool result = value1.Equals(value2); Console.WriteLine("{0} = {1} produces {2}", value1, value2, result); return 0; }

}

This would produce: 824 = 824 produces True Press any key to continue . . .

Built-In Structures: The Boolean Type Introduction As seen in previous lessons, the bool data type is used to represent a value considered as being true or false. In the .NET Framework, the bool data type is represented by the Boolean structure. The true value of a bool variable is represented by the TrueString field and the false value is represented by the FalseString member variable. In other words, when true (or false) is represented as a string, "true" (or "false"” is the same as TrueString (or FalseString).

Parsing a Boolean Variable We saw in a Lesson 8 that you could retrieve the value of a Boolean variable from a user. To support this, the Boolean structure is equipped with a static method named Parse. The Boolean.Parse() method is declared as follows: public static bool Parse(string value);

This method takes as argument a string. The argument must contain either the word True (case-insensitive) or the word False. If the argument is passed as "True", the method returns true. If the argument is "false", this method returns false. Here is an example: using System; class Program { static int Main() { bool result = bool.Parse("TRUE");

C# 3.0 Practical Learning

420

Console.WriteLine("Result: {0}", result); return 0; }

}

This would produce: Result: True Press any key to continue . . .

When calling the Boolean.Parse() method to retrieve the value of a Boolean variable, if the supplied value is "TRUE" or "FALSE", the compiler would process it. If the value is not valid, the program would produce an error. Here is an example: using System; class Program { static int Main() { bool HouseHas3Bedrooms = bool.Parse("ItHas3Bedrooms"); Console.WriteLine("House has 3 bedrooms: {0}", HouseHas3Bedrooms); return 0; } }

To avoid the error, the Boolean structure provides the TryParse() method. Its syntax is: public static bool TryParse(string value, out bool result);

The first argument is the value to be parsed. If that value is valid, the second argument holds the True or False value of the first. Here is an example: using System; class Program { static int Main() { bool alt; bool HouseHas3Bedrooms = bool.TryParse("True", out alt); Console.WriteLine("House has 3 bedrooms: {0}", HouseHas3Bedrooms); Console.WriteLine("Alternate value: {0}", alt); return 0; } }

This would produce: House has 3 bedrooms: True Alternate value: True Press any key to continue . . .

C# 3.0 Practical Learning

421

Consider this other version of the same program: using System; class Program { static int Main() { bool alt; bool HouseHas3Bedrooms = bool.TryParse("False", out alt); Console.WriteLine("House has 3 bedrooms: {0}", HouseHas3Bedrooms); Console.WriteLine("Alternate value: {0}", alt); return 0; } }

This would produce: House has 3 bedrooms: True Alternate value: False Press any key to continue . . .

Notice that the first argument returns True although it was passed as False. This means that, if the value of the first argument is valid, it is the second argument, not the first, that holds the result. If the first argument is not valid, the second argument returns a False value. Consider the following version of the program: using System; class Program { static int Main() { bool alt; bool HouseHas3Bedrooms = bool.TryParse("Don't Know", out alt); Console.WriteLine("House has 3 bedrooms: {0}", HouseHas3Bedrooms); Console.WriteLine("Alternate value: {0}", alt); return 0; } }

This would produce: House has 3 bedrooms: False Alternate value: False Press any key to continue . . .

Comparisons of Boolean Variables In C#, to compare the values of two Boolean variables for equality, you can use the equality operator "==". Here is an example: using System;

C# 3.0 Practical Learning

422

class Program { static int Main() { bool House1Has3Bedrooms = true; bool House2Has3Bedrooms = false; Console.WriteLine("House1 House1Has3Bedrooms); Console.WriteLine("House2 House2Has3Bedrooms); Console.WriteLine("House1 {0}", House1Has3Bedrooms == return 0; } }

has 3 bedrooms: {0}", has 3 bedrooms: {0}", and House2 have the number of bedrooms: House2Has3Bedrooms);

This would produce: House1 has 3 bedrooms: True House2 has 3 bedrooms: False House1 and House2 have the number of bedrooms: False Press any key to continue . . .

To support this comparison, the Boolean structure of the .NET Framework is equipped with the Equals() method. Its syntax is: public bool Equals(bool obj);

This method takes one argument as the Boolean value or variable to be compared to the variable that called it. Here is an example of calling it: using System; class Program { static int Main() { bool House1Has3Bedrooms = false; bool House2Has3Bedrooms = false; Console.WriteLine("House1 has 3 bedrooms: {0}", House1Has3Bedrooms); Console.WriteLine("House2 has 3 bedrooms: {0}", House2Has3Bedrooms); Console.WriteLine("House1 and House2 have the number of bedrooms: {0}", House1Has3Bedrooms.Equals(House2Has3Bedrooms)); return 0; } }

This would produce: House1 has 3 bedrooms: False House2 has 3 bedrooms: False House1 and House2 have the number of bedrooms: True Press any key to continue . . .

C# 3.0 Practical Learning

423

The Equals() method can easily be called by one Boolean variable that receives another Boolean variable as argument. If you don't know the exact type of value of the argument, you can still pass it an object value. To support this, the Equals() method has another version whose syntax is: public override bool Equals(Object obj);

This version takes as argument a variable that is of any type. Besides the equality, you can also compare two Boolean variables to know whether one is lower than the other. To support this, the Boolean structure is equipped with the CompareTo() method. Its syntax is: public int CompareTo(bool value);

If the type of variable is not necessarily a Boolean type, you can pass it as an object value. To do this, you can use the other version of the CompareTo() method. Its syntax is: public int CompareTo(Object obj);

Floating-Point Numbers Introduction As seen in Lesson 2, to support floating-point numbers, you can use the float, the double, or the decimal data types. The C# float data type originates from the Single structure of the .NET Framework. The double data type is based on the Double structure of the .NET Framework. The C# decimal data type is type-defined from the .NET Framework’s Decimal structure. To declare a floating-point variable, you can use one of these data types and initialize it. When initializing a floating-point variable, you should make sure you assign it a value that can fit in the memory allocated for it. As mentioned for the integer data types, the minimum value that a float variable can hold is represented by the MinValue constant of the Single structure and the MinValue field of the Double. The maximum value that a float or a double variable can hold is named MaxValue. After declaring and initializing a float or a double variable, it should hold an appropriate value. If you get the variable’s value some other way, at one time or another, you may not know what value is stored in the memory allocated for the variable. In fact, the variable may hold a value that is not a number. To check whether the variable is holding a value that is not a number, you can access its NaN constant. To do this, type the float or double data type, followed by the period operator, and followed by the NaN constant. Here is an example: using System; class Program { static int Main()

C# 3.0 Practical Learning

424

{ double number = 0D;

}

if( number == double.NaN ) Console.WriteLine("The value is not a number"); return 0;

}

Another technique you can use to check this characteristic is to IsNaN() method of either the Single or the Double structure.

Operations on Floating-Point Numbers Using one integer and one floating-point number, or with two floating-point numbers, you can perform one of the routine arithmetic operations such as the addition, the subtraction, the multiplication, or the division. When it comes to the division and if performed on two constants, you can get a positive or a negative number. In highly precise calculations, you may have to deal with an approximate number whose exact value is not known. For example, the smallest positive number is called epsilon. In the Double and the Single structures, this constant is named Epsilon. For the single-precision type, the epsilon is equal to 1.445. For a double-precision type, the epsilon constant is equivalent to 4.94065645841247-324. As you can see, this number is extremely low. When dealing with real numbers, some operations produce very little or very large numbers. In algebra, the smallest number is called negative infinity. In the .NET Framework, the negative infinity is represented by a constant named NegativeInfinity. To access this number, type either float or double, followed by a period operator, followed by the name of this constant. Here is an example: using System; class Program { static int Main() { Console.WriteLine("Negative Infinity = {0}", double.NegativeInfinity); return 0; } }

To find out if a variable holds a negative infinity value, you can call the IsNegativeInfinity() method from the variable. The syntaxes of this method are: public static bool IsNegativeInfinity(float f); public static bool IsNegativeInfinity(double d);

On the other extreme, the possible largest number is named positive infinity. This constant is represented in the .NET Framework by the PositiveInfinity value. To access this constant, type float or double, followed by the period, followed by the name of this constant. To find out if a variable’s value is a C# 3.0 Practical Learning

425

positive infinity, you can call its IsPositiveInfinity() method. The syntaxes of this method are: public static bool IsPositiveInfinity(float f); public static bool IsPositiveInfinity(double d);

To check whether the value of a variable is one of the infinities, you can call its IsInfinity() method. The syntaxes of this method are: public static bool IsInfinity(float f); public static bool IsInfinity(double d);

Comparison Operations Because floating-point numbers can be approximate, you should be careful when comparing them, especially for equality. Consider the following examples: using System; class Program { static int Main() { double number1 = 22.15D; double number2 = 22.15D;

}

if( number1 == number2 ) Console.WriteLine("The values are equal"); return 0;

}

This would produce: The values are equal Press any key to continue . . .

For the sake of discussion, these values of these variables were limited to 2 decimal places. If they represented hourly salaries of employees, the comparison would be easily performed and can produce an exact result. If you want to apply more precision do the numbers, for example if the variables represent weight values, you would need more places on the right side of the decimal separator. Consider the following program: using System; class Program { static int Main() { double number1 = 22.156D; double number2 = 22.157D; if( number1 == number2 ) Console.WriteLine("The values are equal"); else Console.WriteLine("The values are NOT equal");

C# 3.0 Practical Learning

426

return 0; }

}

This would produce: The values are NOT equal Press any key to continue . . .

This time, because of more precision, the variables don’t hold the same value. Besides the equality, you can also compare floating-point variables to find out if one has a value lower than the other. To support such operations, the Single and the Double structures are equipped with a method named CompareTo. The rules of this method are functionally the same as those we reviewed for integers.

C# 3.0 Practical Learning

427

Built-In Classes The Object Class Introduction C# was clearly created to improve on C++ and possibly offer a new alternative. To achieve this goal, Microsoft created a huge library to accompany the language. The .NET Framework is a huge library made of various classes and constants you can directly use in your C# application without necessarily explicitly loading an external library. To start, this main library of C# provides a class called Object. As you may have realized by now, every variable or function in C# (as in Java) must belong to a class, unlike C/C++ where you can have global variables or functions. Therefore, you always have to create at least one class for your application. As such, when you create a class, it automatically inherits its primary characteristics from the parent of all classes: Object.

Practical Learning: Introducing Ancestor Classes 1. Start Microsoft Visual C# and create a Console Application named Sport1 2. To create a new class, in the Solution Explorer, right-click Sport1 -> Add -> Class... 3. Set the Name to Sport and click Add 4. Change the file as follows: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Sport1 { class Sport { private double _ballWeight; private int _players; private double _courtLength; private double _courtWidth;

C# 3.0 Practical Learning

428

public double BallWeight { get { return _ballWeight; } set { _ballWeight = value; } } public int NumberOfPlayers { get { return _players; } set { _players = value; } } public double CourtLength { get { return _courtLength; } set { _courtLength = value; } }

}

public double CourtWidth { get { return _courtWidth; } set { _courtWidth = value; } }

}

5. Access the Program.cs file and change it as follows: using using using using

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

namespace Sport1 { class Program { static int Main() { Sport tennis = new Sport(); tennis.BallWeight = 57.50; // grams tennis.NumberOfPlayers = 1; // Singles game tennis.CourtLength = 23.70; // meters tennis.CourtWidth = 8.23; // meters; Console.WriteLine("Sport Characteristics"); Console.WriteLine("Ball Weight: {0} grams", tennis.BallWeight); Console.WriteLine("Players on each side: {0}", tennis.NumberOfPlayers); Console.WriteLine("Court Dimensions(LxW): {0}m X {1}m\n", tennis.CourtLength, tennis.CourtWidth); return 0; }

}

}

C# 3.0 Practical Learning

429

6. Execute the application: Sport Characteristics Ball Weight: 57.5 grams Players on each side: 1 Court Dimensions(LxW): 23.7m X 8.23m Press any key to continue . . .

7. Close the DOS window

Equality of Two Class Variables When you declare and initialize two variables, one of the operations you may want to subsequently perform is to compare their value. To support this operation, the Object class provides its children with a method called Equals. The Equals() method comes in two versions. The first has the following syntax: public virtual bool Equals(object obj);

This version allows you to call the Equals() method on a declared variable and pass the other variable as argument. Here is an example: using System; class BookCollection { static void Main() { // First book int NumberOfPages1 = 422; // Second book int NumberOfPages2 = 858; // Third book int NumberOfPages3 = 422; if( NumberOfPages1.Equals(NumberOfPages2) == true ) Console.WriteLine("The first and the second books have the same number of pages"); else Console.WriteLine("The first and the second books have different number of pages"); if( NumberOfPages1.Equals(NumberOfPages3) == true ) Console.WriteLine("The first and the third books have the same number of pages"); else Console.WriteLine("The first and the third books have different number of pages"); } }

This would produce: The first and the second books have different number of pages The first and the third books have the same number of pages

C# 3.0 Practical Learning

430

The first version of the Object.Equals method is declared as virtual, which means you can override it if you create your own class. The second version of the Object.Equals() method is: public static bool Equals(object obj2, object obj2);

As a static method, to use it, you can pass the variables of the two classes whose values you want to compare. In both cases, if the values of the variables are similar, the Equals() method returns true. If they are different, the method returns false. If you are using the Equals() method to compare the variables of two primitive types, the comparison should be straight forward. If you want to use this methods on variables declared from your own class, you should provide your own implementation of this method.

Practical Learning: Implementing Equality 1. Access the Sport.cs file 2. To create your own implementation of the Equals() method, change the file as follows: using using using using

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

namespace Sport1 { class Sport { . . . public double CourtWidth { get { return _courtWidth; } set { _courtWidth = value; } } public override bool Equals(Object obj) { Sport sp = (Sport)obj; if ((_ballWeight == sp._ballWeight) && (_players == sp._players) && (_courtLength == sp._courtLength) && (_courtWidth == sp._courtWidth)) return true; return false; }

}

}

3. Access the Program.cs file and change it as follows: C# 3.0 Practical Learning

431

using using using using

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

namespace Sport1 { class Program { static int Main() { Sport Euro2002 = new Sport(); Sport CAN2004 = new Sport(); Sport tennis = new Sport(); Euro2002.BallWeight = 435; // grams Euro2002.NumberOfPlayers = 11; // persons for each team Euro2002.CourtLength = 100; // meters Euro2002.CourtWidth = 60; // meters tennis.BallWeight = 57.50; // grams tennis.NumberOfPlayers = 1; // Singles game tennis.CourtLength = 23.70; // meters tennis.CourtWidth = 8.23; // meters; CAN2004.BallWeight = 435; // grams CAN2004.NumberOfPlayers = 11; // persons for each team CAN2004.CourtLength = 100; // meters CAN2004.CourtWidth = 60; // meters if (CAN2004.Equals(tennis) == true) Console.WriteLine("The CAN2004 and the tennis variables are equal"); else Console.WriteLine("The Euro2002 and the tennis variables are not equal"); if (Euro2002.Equals(CAN2004) == true) Console.WriteLine("The Euro2002 and CAN2004 variables are equal"); else Console.WriteLine("The Euro2002 and CAN2004 variables are not equal"); return 0; }

}

}

4. Execute the application. This would produce: The Euro2002 and the tennis variables are not equal The Euro2002 and CAN2004 variables are equal Press any key to continue . . .

5. Close the DOS window

Stringing a Class C# 3.0 Practical Learning

432

In previous lessons, we learned that, to convert the value of a variable declared from a primitive type to a string, you could call the ToString() function. Here is an example: using System; class BookCollection { static int Main() { int NumberOfPages = 422; Console.WriteLine("Number of Pages: {0}", NumberOfPages.ToString()); return 0; } }

In many programming languages such as C++, programmers usually have to overload an (extractor) operator to display the value(s) of class' variable to the screen. The Object class provides an alternative to this somewhat complicated solution, through the ToString() method. It syntax is: public virtual string ToString();

Although the Object class provides this method as non abstract, its implemented version is more useful if you use a primitive type such as int, double and their variances or a string variable. The best way to rely on it consists of overriding it in your own class if you desired to use its role.

Practical Learning: Converting to String 1. Access the Sport.cs file 2. To implement and use a ToString() method, change the file as follows: using using using using

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

namespace Sport1 { class Sport { private double _ballWeight; private int _players; private double _courtLength; private double _courtWidth; public double BallWeight { get { return _ballWeight; } set { _ballWeight = value; } }

C# 3.0 Practical Learning

433

public int NumberOfPlayers { get { return _players; } set { _players = value; } } public double CourtLength { get { return _courtLength; } set { _courtLength = value; } } public double CourtWidth { get { return _courtWidth; } set { _courtWidth = value; } } public override bool Equals(Object obj) { Sport sp = (Sport)obj; if ((_ballWeight == sp._ballWeight) && (_players == sp._players) && (_courtLength == sp._courtLength) && (_courtWidth == sp._courtWidth)) return true; }

return false;

public override string ToString() { string person = null; if (NumberOfPlayers.Equals(1)) person = " person"; else person = " persons"; string result = "\nBall Weight: " + BallWeight + " grams" + "\nPlayers on each side: " + NumberOfPlayers + person + "\nCourt Dimensions(LxW): " + CourtLength + "m X " + CourtWidth + "m"; } }

return result;

}

3. Access the Program.cs file and change it as follows: using using using using

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

C# 3.0 Practical Learning

434

namespace Sport1 { class Program { static int Main() { Sport CAN2004 = new Sport(); Sport tennis = new Sport(); tennis.BallWeight = 57.50; // grams tennis.NumberOfPlayers = 1; // Singles game tennis.CourtLength = 23.70; // meters tennis.CourtWidth = 8.23; // meters; CAN2004.BallWeight = 435; // grams CAN2004.NumberOfPlayers = 11; // persons for each team CAN2004.CourtLength = 100; // meters CAN2004.CourtWidth = 60; // meters Console.WriteLine("===================================="); Console.WriteLine("Cup Game Characteristics"); Console.Write("------------------------------------"); Console.WriteLine(CAN2004); Console.WriteLine("\n===================================="); Console.WriteLine("Tennis Game Characteristics"); Console.Write("------------------------------------"); Console.WriteLine(tennis); Console.WriteLine("\n===================================="); } }

return 0;

}

4. Execute the application. This would produce: ==================================== Cup Game Characteristics -----------------------------------Ball Weight: 435 grams Players on each side: 11 persons Court Dimensions(LxW): 100m X 60m ==================================== Tennis Game Characteristics -----------------------------------Ball Weight: 57.5 grams Players on each side: 1 person Court Dimensions(LxW): 23.7m X 8.23m ==================================== Press any key to continue . . .

5. Close the DOS window

Boxing and Un-Boxing C# 3.0 Practical Learning

435

When we study inheritance, we will learn that all data types used in a C# program are "based on" an object called object. As introduced earlier, you can use this data type to declare a variable that would hold any type of value. Because this is some type of a "universal" data type, it can also be initialized with any value. Here are examples: using System; class Exercise { static void Main() { object Number = 244; object Thing = "Professor Kabba";

}

Console.WriteLine(Number); Console.WriteLine(Thing);

}

This would produce: 244 Professor Kabba

As you can see, when an object variable is initialized, the compiler finds out the type of value that was assigned to it. This is referred to as boxing. This mechanism is transparently done in C# (and in Visual Basic but not in Visual C++ 2003 (it is possible that something will be done in the next version, or not)). If you declare a variable using a primitive data type (int, float, double, etc), at one time, you may be interested in converting the value of that variable into an object. Here is an example: using System; class Exercise { static int Main() { int Number = 244; object Thing = Number;

}

Console.WriteLine(Number); Console.WriteLine(Thing); return 0;

}

This would produce: 244 244

This operation is referred to as unboxing. As you can see, this operation is performed transparently (Visual C++ 2003 doesn't do it transparently).

C# 3.0 Practical Learning

436

Boxing and unboxing make C# a very flexible and wonderful language (if you misuse it, of course it can be dangerous).

Finalizing a Variable While a constructor, created for each class, is used to instantiate a class. The Object class provides the Finalize() method as a type of destructor.

Other Built-In Classes The System namespace provides one of the largest definition of classes of the .NET Framework, but it doesn't contain everything. For example, when you start writing graphical user interface (GUI) applications, you will have to use other namespaces. The namespaces are contained in libraries called assemblies. The actual classes used in various applications are created and defined in these libraries. Before using a class, you must know the name of the assembly in which it is defined. You must also know the name of its namespace. These three pieces of information, the name of the class, the namespace in which it is defined, and the name of the assembly in which the namespace is contained, are very important. Because there are so many classes, namespaces, and libraries, the MSDN documentation is your best reference. We can only mention a few, especially those that are relevant for the subjects we are reviewing.

Random numbers Introduction Imagine you have a series of numbers, such these: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, and 20. Imagine you want to select one of these numbers, any of them. A number is referred to as random if it has been selected from a pool without a specific pattern to follow. For example, if you decide to select the value 17 from this list, if there was an exact reason that number was selected, then it is not considered random. In reality, it is difficult for a number to qualify as random. For this reason, most random numbers are referred to as pseudo-random.

Getting a Random Number To support the ability to create or choose a random number, the .NET Framework provides the Random class. To start, you can declare a variable of this class, using one of its two constructors. Here is an example that uses the default constructor: using System; class Program { static int Main() {

C# 3.0 Practical Learning

437

Random rndNumber = new Random(); return 0; }

}

After creating the variable, you can start getting numbers from it. To do this, you call the Next() method, which is overloaded in three versions. One of the versions of this method takes no argument and its syntax is: public virtual int Next();

This method generates a randomly selected integer between 0 and the MinValue value of the int data type. Here is an example: using System; class Program { static int Main() { Random rndNumbers = new Random(); int rndNumber = rndNumbers.Next(); Console.WriteLine("Number: {0}", rndNumber); }

return 0;

}

Here is an example of running the program: Number: 1369872590 Press any key to continue . . .

In the same way, you can call this version of the Next() method repeatedly to get random. Here is an example: using System; class Program { static int Main() { Random rndNumbers = new Random(); int rndNumber = 0; for (int nbr = 1; nbr < 9; nbr++) { rndNumber = rndNumbers.Next(); Console.WriteLine("Number: {0}", rndNumber); } }

return 0;

}

Here is an example of running the program: Number: 1924504148 Number: 1257846191

C# 3.0 Practical Learning

438

Number: 424740120 Number: 1009211682 Number: 544356245 Number: 708951978 Number: 759684741 Number: 1325535324 Press any key to continue . . .

The Seed of a Random Number Consider the following program: using System; class Program { static int Main() { Random rndNumbers = new Random(); int rndNumber = rndNumbers.Next(); Console.WriteLine("Number: {0}", rndNumber); return 0; }

}

Here is an example of running the program: Number: 573991745 Press any key to continue . . .

Here is another example of running the same program: Number: 334223329 Press any key to continue . . .

Notice that the numbers generated are different. When creating a program that repeatedly gets a series of random numbers, you may (or may not) want the Random class to generate the same number over and over again. A seed is a constant value that controls whether a random generation would produce the same result every time it occurs. For example, using a seed, you can impose it upon the Random class to generate the same number every time the Next() method is called. To support the ability to use a seed, the Random class is equipped with a second constructor whose syntax is: public Random(int Seed);

Based on this, to specify a seed, when declaring a Random variable, pass a constant integer to the constructor. Here is an example: using System; class Program { static int Main() { Random rndNumbers = new Random(20); int rndNumber = rndNumbers.Next();

C# 3.0 Practical Learning

439

Console.WriteLine("Number: {0}", rndNumber); }

return 0;

}

Here is one example of running the program: Number: 375271809 Press any key to continue . . .

Here is another example of running the same program: Number: 375271809 Press any key to continue . . .

Notice that the numbers are the same. Consider this program also: using System; class Program { static int Main() { Random rndNumbers = new Random(20); int rndNumber = 0; for (int nbr = 1; nbr < 5; nbr++) { rndNumber = rndNumbers.Next(); Console.WriteLine("Number: {0}", rndNumber); } return 0; }

}

Here is one example of running the program: Number: 375271809 Number: 1472524622 Number: 1605850688 Number: 1776011503 Press any key to continue . . .

Here is another example of running the same program: Number: 375271809 Number: 1472524622 Number: 1605850688 Number: 1776011503 Press any key to continue . . .

Notice that the sequences are the same. In both cases, this indicates that, if you specify a seed, the Random class would generate the same number or the same sequence of numbers.

Generating Random Numbers in a Range of Numbers C# 3.0 Practical Learning

440

So far, we have been using with any number that would fit an integer. In some assignments, you may want to restrict the range of numbers that can be extracted. Fortunately, the Random class allows this. Using the Random class, you can generate random positive numbers up to a maximum of your choice. To support this, the Random class is equipped with another version of the Next() method whose syntax is: public virtual int Next(int maxValue);

The argument to pass to the method determines the highest integer that can be generated by the Next() method. The method returns an integer. Here is an example that generates radom numbers from 0 to 20: using System; class Program { static int Main() { Random rndNumbers = new Random(); int rndNumber = 0; for (int nbr = 1; nbr < 9; nbr++) { rndNumber = rndNumbers.Next(20); Console.WriteLine("Number: {0}", rndNumber); } }

return 0;

}

Here is an example of running the program: Number: 1 Number: 7 Number: 1 Number: 16 Number: 14 Number: 19 Number: 3 Number: 1 Press any key to continue . . .

The above version of the Next() method generates numbers starting at 0. If you want, you can specify the minimum and the maximum range of numbers that the Next() method must work with. To support this, the Random class is equipped with one more version of this method and that takes two arguments. Its syntax is: public virtual int Next(int minValue, int maxValue);

The first argument specifies the lowest value that can come from the range. The second argument holds the highest value that the Next() method can generate. Therefore, the method would operate between both values. Here is an example that generates random numbers from 6 to 18: using System;

C# 3.0 Practical Learning

441

class Program { static int Main() { Random rndNumbers = new Random(); int rndNumber = 0; for (int nbr = 1; nbr < 9; nbr++) { rndNumber = rndNumbers.Next(6, 18); Console.WriteLine("Number: {0}", rndNumber); } }

return 0;

}

Here is an example of running the program: Number: 17 Number: 9 Number: 8 Number: 15 Number: 10 Number: 9 Number: 13 Number: 11 Press any key to continue . . .

Notice that the numbers are between 6 and 18.

Built-In Assemblies and Libraries Microsoft Visual Basic Functions

One of the strengths of Visual Basic, from its beginning, was its huge library of functions. Unfortunately, even when Visual Basic was part of the Visual Studio 6.0 environment, its functions belonged only to it and to its child languages such as VBA and VBScript. When Visual Studio .NET was created, the developers of Visual Basic added all of its valuable functions and in fact made them available to the other languages that use the .NET Framework. This means that those wonderful functions are available to use in your C# programs. The functions of Microsoft Visual Basic still belong to it and they can be called transparently in a Visual Basic application. If you want to use them in a nonVisual Basic application, you must remember to reference its library. Most (if not all) of the functions of Visual Basic are created in the Microsoft.VisualBasic.dll assembly but they might be in different namespaces. Based on this, you can include any Visual Basic function in your program. Here is an example: Source File: Exercise.cs

C# 3.0 Practical Learning

442

using System; class Exercise { static void Main() { double Number; double Result; Console.Write("Enter a number: "); string strNbr = Console.ReadLine(); if( !Microsoft.VisualBasic.Information.IsNumeric(strNbr) ) Number = 0.00; else Number = Microsoft.VisualBasic.Conversion.Val(strNbr); Result = Number * 2; }

Console.WriteLine("{0} * 2 = {1}", Number, Result);

}

When compiling the program, you must Microsoft.VisualBasic.dll library. Here is an example:

reference

the

csc /reference:Microsoft.VisualBasic.dll Exercise.cs

C# Custom Libraries Introduction If the .NET Framework doesn't have a class you are looking for, you can create one and be able to use it over and over again in different programs. You can even create a commercial class and be able to distribute or sell it. To make this possible, you can "package" one or more classes in a library. A library is a program that contains classes and/or other resources that other programs can use. Such a program is created with the same approach as the programs we have done so far. Because a library is not an executable, it doesn't need the Main() function. A library usually has the extension .dll.

Creating a Library A library can be made of a single file or as many files as necessary. A file that is part of a library can contain one or more classes. Each class should implement a behavior that can eventually be useful and accessible to other classes. The classes in a library are created exactly like those we have used so far. Everything depends on how you compile it. To create a library, start by typing its code in a text file. Once the library is ready, to compile it, at the Command Prompt, you would type: csc /target:library NameOfFile.cs

C# 3.0 Practical Learning

443

and press Enter. After doing this, a library with the name of the file and the extension .dll would be created. If you want a custom name, use the following syntax: csc /target:library /out:DesiredNameOfLibrary.dll NameOfFile.cs

Practical Learning: Creating a Library 1. To start a new project, on the main menu, click File -> New Project... 2. In the New Project dialog box, click Class Library 3. Set the Name to Operations1 and click OK 4. Change the file as follows: using using using using

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

namespace Operations1 { public class Operations { public static double Addition(double x, double y) { return x + y; } public static double Subtraction(double x, double y) { return x - y; } public static double Multiplication(double x, double y) { return x * y; } public static double Division(double x, double y) { if (y == 0) return 0; return x / y; } }

}

5. In the Solution Explorer, right-click Class1.cs and click Rename 6. Change the name to Operations.cs and press Enter 7. To save the project, on the Standard toolbar, click the Save All button 8. Click Save to save everything 9. On the main menu, click Project -> Operations1 Properties C# 3.0 Practical Learning

444

10. In the Output Type combo box, make sure Class Library is selected:

11.

Click the X button to close the Properties window

12. To create the library, on the main menu, click Build -> Build Solution 13. To start another project, on the main menu, click File -> New Project... 14.

In the New Project dialog box, select Console Application

15. Set the Name to Algebra1 and press Enter 16. In the Solution Explorer, right-click References and click Add Reference... 17.

Click the Browse tab

18. In the list of folders, double-click Operations1 and locate the Operations1.dll file (it should be in the Release (or the Debug) sub-folder of the bin folder)

C# 3.0 Practical Learning

445

19. Click Operations1.dll

20. Click OK. In the Solution Explorer, expand the References node if necessary and make sure that there is a new node labeled Operations1 21.

Access the Program.cs file and change it as follows:

using System; namespace Algebra1 { class Program { static int Main() { double Number1 = 244.58; double Number2 = 5082.88; double Result = Operations1.Operations.Addition(Number1, Number2); Console.WriteLine("{0} + {1} = {2}\n", Number1, Number2, Result); return 0; }

}

}

22.

Execute the application to test it. This would produce:

244.58 + 5082.88 = 5327.46 Press any key to continue . . .

C# 3.0 Practical Learning

446

23.

Close the DOS window

A Library Created in Another Language Using a Visual C++/CLI Library One of the most important sought goals in .NET is to allow different languages to collaborate, such as sharing code. One way this can happen is to be able to use the functionality of one language into another. As an illustration, we saw earlier that you could use the rich library of Visual Basic functions in a C# application. As no library is ever complete, you may still need functionality that is not easily found. Furthermore, you may be working with a team of C++ programmers who have already created a set of functions or complex operations. You should be able to use that existing code.

Creating a Library In previous years, it used to be a challenge to create a library, especially in C++. Fortunately, Microsoft Visual C++ now makes it particularly easy to create one, because a wizard highly assists you. To create a library, first display the New Project dialog box. After specifying Visual C++, in the Templates list, click Class Library and give it a name. In the body of the file, you can create the classes and/or functions as you see fit. Here is an example: // Business.h #pragma once using namespace System; namespace Business { public ref class Finance { public: double CalculateDiscount(double MarkedPrice, double DiscountRate) { return MarkedPrice * DiscountRate / 100; } }; }

Once the project is ready, you must build it (on the main menu, Build -> Build Business). As a result, the compiler would create a file with the .dll extension:

C# 3.0 Practical Learning

447

Normally, as far as creating a library, that's it.

Using the Library Creating a library in C++ is easy. To use it, there are a few rules you must follow. To start, you must make sure that your project can "physically" find the library. Probably the easiest way to take care of this is to copy the dll file and paste it in the folder that contains your project's executable. You can also do this directly in Visual Studio by importing the library file as we saw earlier. In your project, you should include the System.Runtime.InteropServices namespace. Before the section where the library will be accessed, enter the DllImport attribute that takes as argument the name of the library passed as a string. Here is an example: using System; using System.Runtime.InteropServices; using Business; namespace DepartmentStore { class Exercise { [DllImport("Business.dll")] public static extern double CalculateDiscount(double price, double discount) static int Main() { Finance fin = new Finance(); double markedPrice = 275.50; double discountRate = 25.00; // % double discountAmount = fin.CalculateDiscount(markedPrice, discountDate); double netPrice = markedPrice - discountAmount); 448 C# 3.0 Practical Learning

Console.WriteLine("Marked Price: Console.WriteLine("Discount Rate: 100);

Console.WriteLine("Discount Amount: {0:C}", discountAmount); Console.WriteLine("Net Price: {0:C}\n", netPrice); }

}

{0:C}", markedPrice); {0:P}", discountRate /

return 0;

}

This makes your library code ready to be used, which you can do as you would any other code. This means that you can compile your program the way we did in the previous section.

Using the Win32 Library The Microsoft Windows operating system was originally written in C, the parent language of C++ and C# (also of Java and JavaScript). To allow programmers to create applications, Microsoft released a library called Win32. This is a series of functions and classes, etc, that you previously had to use. As time has changed, you don't need to exclusively use Win32 anymore to create a Windows application. Nonetheless, Win32 is still everywhere and it is not completely avoidable because many or some of the actions you would want to perform in a Windows application are still available only in Win32. Fortunately, in most cases, it is not always difficult to use some of these functions in a C# applications, as long as you observe some rules. Here is an example: using System; using System.Runtime.InteropServices; namespace Win32Applied { class Program { [DllImport("Kernel32.dll")] public static extern bool SetConsoleTitle(string strMessage); static int Main() { SetConsoleTitle("C# Programming"); } }

return 0;

}

C# 3.0 Practical Learning

449

Introduction to Exception Handling Introduction to Exceptions Overview During the execution of a program, the computer will face two types of situations: those it is prepared to deal with and those it is not. Imagine you write a program that requests a number from the user: using System; class Program { static int Main() { double side; Console.WriteLine("Square Processing"); Console.Write("Enter Side: "); side = double.Parse(Console.ReadLine()); Console.WriteLine("\nSquare Characteristics"); Console.WriteLine("Side: {0}", side); Console.WriteLine("Perimeter: {0}", side * 4); return 0; }

}

This is a classic easy program. When it comes up, the user is asked to simply type a number. The number would then be multiplied by 4 and display the result. Imagine that a user types something that is not a valid number, such as the name of a country or somebody’s telephone number. Since this program was expecting a number and it is not prepared to multiply a string to a number, it would not know what to do. The only alternative the compiler would have is to send the problem to the operating system, hoping that the OS would know what to do. What actually happens is that, whenever the compiler is handed a task, it would try to perform the assignment. If it can’t perform the assignment, for any reason it is not prepared for, it would produce an error. As a programmer, if you can anticipate the type of error that could occur in your program, you can identify the error yourself and deal with it by telling the compiler what to do when this type of error occurs. C# 3.0 Practical Learning

450

Practical Learning: Introducing Exception Handling 1. Start Microsoft Visual C# and create a Console Application named GeorgetownCleaningServices5

2. To create a new class, in the Solution Explorer, right-click GeorgetownCleaningServices2 -> Add -> Class... 3. Set the Name to CleaningOrderInfo and click OK 4. Change the file as follows: using System; namespace GeorgetownCleaningServices5 { public class CleaningOrderInfo { // Basic information about an order public string CustomerName; public string HomePhone; public DateTime OrderDate; public DateTime OrderTime; // Unsigned numbers to represent cleaning items public uint NumberOfShirts; public uint NumberOfPants; public uint NumberOfDresses; } }

5. To create a new class, on the main menu, click Project -> Add Class... 6. Set the Name to OrderProcessing and press Enter 7. Change the file as follows: using System; namespace GeorgetownCleaningServices5 { public class sealed OrderProcessing { #region Objects used to process an order // Price of items const decimal PriceOneShirt = 0.95M; const decimal PriceAPairOfPants = 2.95M; const decimal PriceOneDress = 4.55M; const decimal TaxRate = 0.0575M; // 5.75% CleaningOrderInfo cleaningOrder; // Each private private private

of these sub totals will be used for cleaning items decimal SubTotalShirts; decimal SubTotalPants; decimal SubTotalDresses;

C# 3.0 Practical Learning

451

// Values used to process an order private decimal TotalOrder; private decimal TaxAmount; private decimal SalesTotal; private decimal AmountTended; private decimal Difference; #endregion #region Actions used to process and present an order public OrderProcessing() { cleaningOrder = new CleaningOrderInfo(); } public void ProcessOrder() { Console.WriteLine("-/- Georgetown Cleaning Services -/-"); // Request order information from the user Console.Write("Enter Customer Name: "); cleaningOrder.CustomerName = Console.ReadLine(); Console.Write("Enter Customer Phone: "); cleaningOrder.HomePhone = Console.ReadLine(); Console.Write("Enter the order date(mm/dd/yyyy): "); cleaningOrder.OrderDate = DateTime.Parse(Console.ReadLine()); Console.Write("Enter the order time(hh:mm AM/PM): "); cleaningOrder.OrderTime = DateTime.Parse(Console.ReadLine()); // Request the quantity of each category of items Console.Write("Number of Shirts: "); cleaningOrder.NumberOfShirts = uint.Parse(Console.ReadLine()); Console.Write("Number of Pants: "); cleaningOrder.NumberOfPants = uint.Parse(Console.ReadLine()); Console.Write("Number of Dresses: "); cleaningOrder.NumberOfDresses = uint.Parse(Console.ReadLine()); // Perform the necessary calculations SubTotalShirts = cleaningOrder.NumberOfShirts * PriceOneShirt; SubTotalPants = cleaningOrder.NumberOfPants * PriceAPairOfPants; SubTotalDresses = cleaningOrder.NumberOfDresses * PriceOneDress; // Calculate the "temporary" total of the order TotalOrder = SubTotalShirts + SubTotalPants + SubTotalDresses; // Calculate the tax amount using a constant rate TaxAmount = TotalOrder * TaxRate; // Add the tax amount to the total order SalesTotal = TotalOrder + TaxAmount; // Communicate the total to the user... Console.WriteLine("\nThe Total order is: {0:C}", SalesTotal); // and request money for the order

C# 3.0 Practical Learning

452

Console.Write("Amount Tended? "); AmountTended = decimal.Parse(Console.ReadLine()); // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - SalesTotal; }

ShowReceipt();

private void ShowReceipt() { Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.WriteLine("Customer: {0}", cleaningOrder.CustomerName); Console.WriteLine("Home Phone: {0}", cleaningOrder.HomePhone); Console.WriteLine("Order Date: {0:D}", cleaningOrder.OrderDate); Console.WriteLine("Order Time: {0:t}", cleaningOrder.OrderTime); Console.WriteLine("------------------------------------"); Console.WriteLine("Item Type Qty Unit/Price Sub-Total"); Console.WriteLine("------------------------------------"); Console.WriteLine("Shirts {0,3} {1,4} {2,6}", cleaningOrder.NumberOfShirts, PriceOneShirt, SubTotalShirts); Console.WriteLine("Pants {0,3} {1,4} {2,6}", cleaningOrder.NumberOfPants, PriceAPairOfPants, SubTotalPants); Console.WriteLine("Dresses {0,3} {1,4} {2,6}", cleaningOrder.NumberOfDresses, PriceOneDress, SubTotalDresses); Console.WriteLine("------------------------------------"); Console.WriteLine("Total Order: {0,6}", TotalOrder.ToString("C")); Console.WriteLine("Tax Rate: {0,6}", TaxRate.ToString("P")); Console.WriteLine("Tax Amount: {0,6}", TaxAmount.ToString("C")); Console.WriteLine("Net Price: {0,6}", SalesTotal.ToString("C")); Console.WriteLine("------------------------------------"); Console.WriteLine("Amount Tended: {0,6}", AmountTended.ToString("C")); Console.WriteLine("Difference: {0,6}", Difference.ToString("C")); Console.WriteLine("===================================="); } #endregion } }

8. Access the program.cs file and change it as follows: C# 3.0 Practical Learning

453

using System; namespace GeorgetownCleaningServices5 { class Program { static int Main() { OrderProcessing Order = new OrderProcessing();

} }

Order.ProcessOrder(); return 0;

}

9. Execute the application and test it. Here is an example: -/- Georgetown Cleaning Services -/Enter Customer Name: Peter Moonstruck Enter Customer Phone: (301) 728-8830 Enter the order date(mm/dd/yyyy): 04/22/2006 Enter the order time(hh:mm AM/PM): 08:46 Number of Shirts: 5 Number of Pants: 2 Number of Dresses: 3 The Total order is: $25.70 Amount Tended? 30 ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Peter Moonstruck Home Phone: (301) 728-8830 Order Date: Saturday, April 22, 2006 Order Time: 8:46 AM -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 5 0.95 4.75 Pants 2 2.95 5.90 Dresses 3 4.55 13.65 -----------------------------------Total Order: $24.30 Tax Rate: 5.75 % Tax Amount: $1.40 Net Price: $25.70 -----------------------------------Amount Tended: $30.00 Difference: $4.30 ==================================== Press any key to continue . . .

10.

Close the DOS window

Exceptional Behaviors C# 3.0 Practical Learning

454

An exception is an unusual situation that could occur in your program. As a programmer, you should anticipate any abnormal behavior that could be caused by the user entering wrong information that could otherwise lead to unpredictable results. The ability to deal with a program’s eventual abnormal behavior is called exception handling. C# provides three keywords to handle an exception.

1. Trying the normal flow: To deal with the expected behavior of a program, use the try keyword as in the following syntax: try {Behavior}

The try keyword is required. It lets the compiler know that you are attempting a normal flow of the program. The actual behavior that needs to be evaluated is included between an opening curly bracket “{“ and a closing curly bracket “}”. Inside of the brackets, implement the normal flow that the program must follow, at least for this section of the code. Here is an example: using System; class Program { static int Main() { double side; Console.WriteLine("Square Processing"); try { Console.Write("Enter Side: "); side = double.Parse(Console.ReadLine()); Console.WriteLine("\nSquare Characteristics"); Console.WriteLine("Side: {0}", side); Console.WriteLine("Perimeter: {0}", side * 4); } }

return 0;

}

2. Catching Errors: During the flow of the program as part of the try section, if an abnormal behavior occurs, instead of letting the program crash or instead of letting the compiler send the error to the operating system, you can transfer the flow of the program to another section that can deal with it. The syntax used by this section is: catch {WhatToDo}

This section always follows the try section. There must not be any code between the try’s closing bracket and the catch section. The catch keyword is required and follows the try section. Combined with the try 455 C# 3.0 Practical Learning

block, the syntax of an exception would be: try {

// Try the program flow } catch { // Catch the exception }

A program that includes a catch section would appear as follows: using System; public class Exercise { static int Main() { double Number; try {

Console.Write("Type a number: "); Number = double.Parse(Console.ReadLine());

Console.WriteLine("\n{0} * 2 = {1}", Number, Number * 2); } catch { } }

return 0;

}

Practical Learning: Introducing Vague Exceptions 1. To introduce exceptions, access the OrderProcessing.cs file and change it as follows: using System; namespace GeorgetownCleaningServices5 { class OrderProcessing { . . . No Change public void ProcessOrder() { . . . No Change

C# 3.0 Practical Learning

456

// Request the quantity of each category of items try { Console.Write("Number of Shirts: "); Order.NumberOfShirts = uint.Parse(Console.ReadLine()); } catch { } try { Console.Write("Number of Pants: "); Order.NumberOfPants = uint.Parse(Console.ReadLine()); } catch { } try { Console.Write("Number of Dresses: "); Order.NumberOfDresses = uint.Parse(Console.ReadLine()); } catch { } . . . No Change // and request money for the order try { Console.Write("Amount Tended? "); AmountTended = decimal.Parse(Console.ReadLine()); } catch { } // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - SalesTotal; ShowReceipt(); } private void ShowReceipt() { . . . No Change } }

}

2. Execute the application to test it 3. Close the DOS window

Exceptions and Custom Messages C# 3.0 Practical Learning

457

As mentioned already, if an error occurs when processing the program in the try section, the compiler transfers the processing to the next catch section. You can then use the catch section to deal with the error. At a minimum, you can display a message to inform the user. Here is an example: using System; class Program { static int Main() { double side; Console.WriteLine("Square Processing"); try { Console.Write("Enter Side: "); side = double.Parse(Console.ReadLine()); Console.WriteLine("\nSquare Characteristics"); Console.WriteLine("Side: {0}", side); Console.WriteLine("Perimeter: {0}", side * 4); } catch { Console.WriteLine("There was a problem with the program"); } }

return 0;

}

Here is an error of running the program: Square Processing Enter Side: w4 There was a problem with the program Press any key to continue . . .

Of course, this type of message is not particularly clear but this time, the program will not crash. In the next sections, we will learn better ways of dealing with the errors and the messages.

Practical Learning: Displaying Custom Messages 1. To display custom messages to the user, change the OrderProcessing.cs file as follows: using System; namespace GeorgetownCleaningServices5 { class OrderProcessing { . . . No Change public void ProcessOrder()

C# 3.0 Practical Learning

458

{ . . . No Change // Request the quantity of each category of items try { Console.Write("Number of Shirts: "); Order.NumberOfShirts = uint.Parse(Console.ReadLine()); } catch { Console.WriteLine("The value you typed for the number of "

+

"shirts is not a valid number");

}

try { Console.Write("Number of Pants: "); Order.NumberOfPants = uint.Parse(Console.ReadLine()); } catch { Console.WriteLine("The value you typed for the number of "

+

"pair or pants is not a valid number");

}

try { Console.Write("Number of Dresses: "); Order.NumberOfDresses = uint.Parse(Console.ReadLine()); } catch { Console.WriteLine("The value you typed for the number of "

+

"dresses is not a valid number");

} . . . No Change

try { Console.Write("Amount Tended? "); AmountTended = decimal.Parse(Console.ReadLine()); } catch { Console.WriteLine( "You were asked to enter an amount of money but..."); } // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - SalesTotal; }

ShowReceipt();

C# 3.0 Practical Learning

459

}

private void ShowReceipt() { . . . No Change }

}

2. Execute the application to test it. Here is an example: -/- Georgetown Cleaning Services -/Enter Customer Name: Alexandria Enter Customer Phone: (102) 797-8382 Enter the order date(mm/dd/yyyy): 04/02/2001 Enter the order time(hh:mm AM/PM): 09:22 AM Number of Shirts: 6 Number of Pants: W The value you typed for the number of pair or pants is not a valid number Number of Dresses: 5 The Total order is: $30.09 Amount Tended? _100D You were asked to enter an amount of money but... ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Alexandria Home Phone: (102) 797-8382 Order Date: Monday, April 02, 2001 Order Time: 9:22 AM -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 6 0.95 5.70 Pants 0 2.95 0 Dresses 5 4.55 22.75 -----------------------------------Total Order: $28.45 Tax Rate: 5.75 % Tax Amount: $1.64 Net Price: $30.09 -----------------------------------Amount Tended: $0.00 Difference: ($30.09) ====================================

3. Close the DOS window

Exceptions in the .NET Framework The Exception Class

C# 3.0 Practical Learning

460

In traditionally-oriented error dealing languages such as C/C++, Object Pascal, or Visual Basic, you could create any exception of your choice, including numeric or strings. To customize exception handling, you could also create your own class(es). Most libraries such as Borland's VCL and Microsoft's MFC also shipped with their own classes to handle exceptions. Even the Win32 library provides its type of mechanism to face errors. To support exception handling, the .NET Framework provides a special class called Exception. Once the compiler encounters an error, the Exception class allows you to identify the type of error and take an appropriate action. Normally, Exception mostly serves as the general class of exceptions. Anticipating various types of problems that can occur in a program, Microsoft derived various classes from Exception to make this issue friendlier. As a result, almost any type of exception you may encounter already has a class created to deal with it. Therefore, when your program faces an exception, you can easily identify the type of error. There are so many exception classes that we cannot study or review them all. The solution we will use is to introduce or review a class when we meet its type of error.

The Exception's Message In exception handling, errors are dealt with in the catch section. To do this, use catch as if it were a method. This means that, on the right side of catch, open a parenthesis, declare a variable of the type of exception you want to deal with. By default, an exception is first of type Exception. Based on this, a typical formula to implement exception handling is: try {

// Process the normal flow of the program here } catch(Exception e) { // Deal with the exception here }

When an exception occurs in the try section, code compilation is transferred to the catch section. If you declare the exception as an Exception type, this class will identify the error. One of the properties of the Exception class is called Message. This property contains a string that describes the type of error that occurred. You can then access this Exception.Message property to display an error message if you want. Here is an example: using System; class Program { static int Main() { double side; Console.WriteLine("Square Processing"); try {

C# 3.0 Practical Learning

461

Console.Write("Enter Side: "); side = double.Parse(Console.ReadLine()); Console.WriteLine("\nSquare Characteristics"); Console.WriteLine("Side: {0}", side); Console.WriteLine("Perimeter: {0}", side * 4);

} catch(Exception ex) { Console.WriteLine(ex.Message); } return 0; }

}

Here is an example of running the program: Square Processing Enter Side: Wer24 Input string was not in a correct format. Press any key to continue . . .

Custom Error Messages As you can see, one of the strengths of the Exception.Message property is that it gives you a good indication of the type of problem that occurred. Sometimes, the message provided by the Exception class may not appear explicit enough. In fact, you may not want to show it to the user since, as in this case, the user may not understand what the expression "correct format" in this context means and why it is being used. As an alternative, you can create your own message and display it to the user. Here is an example: using System; class Program { static int Main() { double side; Console.WriteLine("Square Processing"); try { Console.Write("Enter Side: "); side = double.Parse(Console.ReadLine()); Console.WriteLine("\nSquare Characteristics"); Console.WriteLine("Side: {0}", side); Console.WriteLine("Perimeter: {0}", side * 4);

} catch(Exception ex) { because " +

Console.WriteLine("The operation could not be carried "the number you typed is not valid");

C# 3.0 Practical Learning

462

} return 0; }

}

Here is an example of running the program: Square Processing Enter Side: 24.Gh The operation could not be carried because the number you typed is not valid Press any key to continue . . .

You can also combine the Exception.Message message and your own message: using System; class Program { static int Main() { double side; Console.WriteLine("Square Processing"); try { Console.Write("Enter Side: "); side = double.Parse(Console.ReadLine()); Console.WriteLine("\nSquare Characteristics"); Console.WriteLine("Side: {0}", side); Console.WriteLine("Perimeter: {0}", side * 4);

} catch(Exception ex) { Console.Write(ex.Message); Console.WriteLine( " Consequently, The operation could not be carried because

" +

}

"the number you typed is not valid");

return 0; }

}

Here is an example of running the program: Square Processing Enter Side: 25.KL48 Input string was not in a correct format.. Consequently, The operation could not be carried because the number you typed is not valid Press any key to continue . . .

A Review of .NET Exception Classes C# 3.0 Practical Learning

463

Introduction The .NET Framework provides various classes to handle almost any type of exception you can think of. There are so many of these classes that we can only mention the few that we regularly use in our application. There are two main ways you can use one of the classes of the .NET Framework. If you know for sure that a particular exception will be produced, pass its name to the catch() clause. You don't have to name the argument. Then, in the catch() section, display a custom message. The second option you have consists of using the throw keyword. We will study it later. From now on, we will try to always indicate the type of exception that could be thrown if something goes wrong in a program

The FormatException Exception When studying data formatting in Lesson 5, we saw that everything the user types into an application using the keyboard is primarily a string and that you must convert it to the appropriate type before using it. When you request a specific type of value from the user, after the user has typed it and you decide to convert it to the appropriate type, if your conversion fails, the program produces an error. The error is of the FormatException class. Here is a program that deals with a FormatException exception: using System; class Program { static int Main() { double side; Console.WriteLine("Square Processing"); try { Console.Write("Enter Side: "); side = double.Parse(Console.ReadLine()); Console.WriteLine("\nSquare Characteristics"); Console.WriteLine("Side: {0}", side); Console.WriteLine("Perimeter: {0}", side * 4); } catch(FormatException) { Console.WriteLine("\nYou typed an invalid number"); } }

return 0;

}

Here is an example of running the program: Square Processing Enter Side: 25.9G

C# 3.0 Practical Learning

464

You typed an invalid number Press any key to continue . . .

Practical Learning: Using the FormatException Class 1. Change the OrderProcessing.cs file as follows (this includes the complete current version of the file): using System; namespace GeorgetownCleaningServices5 { class OrderProcessing { #region Objects used to process an order // Price of items const decimal PriceOneShirt = 0.95M; const decimal PriceAPairOfPants = 2.95M; const decimal PriceOneDress = 4.55M; const decimal TaxRate = 0.0575M; // 5.75% CleaningOrderInfo cleaningOrder; // Each private private private

of these sub totals will be used for cleaning items decimal SubTotalShirts; decimal SubTotalPants; decimal SubTotalDresses;

// Values used to process an order private decimal TotalOrder; private decimal TaxAmount; private decimal SalesTotal; private decimal AmountTended; private decimal Difference; #endregion #region Actions used to process and present an order public OrderProcessing() { cleaningOrder = new CleaningOrderInfo(); } public void ProcessOrder() { Console.WriteLine("-/- Georgetown Cleaning Services -/-"); // Request order information from the user Console.Write("Enter Customer Name: "); cleaningOrder.CustomerName = Console.ReadLine(); Console.Write("Enter Customer Phone: "); cleaningOrder.HomePhone = Console.ReadLine(); try {

Console.Write("Enter the order date(mm/dd/yyyy):

C# 3.0 Practical Learning

"); 465

cleaningOrder.OrderDate = DateTime.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The value you entered is not a valid date"); } try { Console.Write("Enter the order time(hh:mm AM/PM): "); cleaningOrder.OrderTime = DateTime.Parse(Console.ReadLine()); } catch { Console.WriteLine("The value you entered is not a valid time"); } // Request the quantity of each category of items try { Console.Write("Number of Shirts: "); cleaningOrder.NumberOfShirts = uint.Parse(Console.ReadLine()); if (cleaningOrder.NumberOfShirts < uint.MinValue) throw new OverflowException("Negative value not " "allowed for shirts"); } catch (FormatException) { Console.WriteLine("The value you typed for the number " + "shirts is not a valid number"); } try { Console.Write("Number of Pants: "); cleaningOrder.NumberOfPants = uint.Parse(Console.ReadLine()); } catch(FormatException) { Console.WriteLine("The value you typed for the number " + "pair or pants is not a valid number"); } try { Console.Write("Number of Dresses: "); cleaningOrder.NumberOfDresses = uint.Parse(Console.ReadLine()); } catch(FormatException) { Console.WriteLine("The value you typed for the number " + "dresses is not a valid number"); }

C# 3.0 Practical Learning

+

of

of

of

466

// Perform the necessary calculations SubTotalShirts = cleaningOrder.NumberOfShirts * PriceOneShirt; SubTotalPants = cleaningOrder.NumberOfPants * PriceAPairOfPants; SubTotalDresses = cleaningOrder.NumberOfDresses * PriceOneDress; // Calculate the "temporary" total of the order TotalOrder = SubTotalShirts + SubTotalPants + SubTotalDresses; // Calculate the tax amount using a constant rate TaxAmount = TotalOrder * TaxRate; // Add the tax amount to the total order SalesTotal = TotalOrder + TaxAmount; // Communicate the total to the user... Console.WriteLine("\nThe Total order is: {0:C}", SalesTotal); // and request money for the order try { Console.Write("Amount Tended? "); AmountTended = decimal.Parse(Console.ReadLine()); } catch(FormatException) { Console.WriteLine("You were asked to enter an " + "amount of money but..."); } // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - SalesTotal; }

ShowReceipt();

private void ShowReceipt() { Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.WriteLine("Customer: {0}", cleaningOrder.CustomerName); Console.WriteLine("Home Phone: {0}", cleaningOrder.HomePhone); Console.WriteLine("Order Date: {0:D}", cleaningOrder.OrderDate); Console.WriteLine("Order Time: {0:t}", cleaningOrder.OrderTime); Console.WriteLine("------------------------------------"); Console.WriteLine("Item Type Qty Unit/Price Sub-Total"); Console.WriteLine("------------------------------------"); Console.WriteLine("Shirts {0,3} {1,4} {2,6}", cleaningOrder.NumberOfShirts, PriceOneShirt, SubTotalShirts); Console.WriteLine("Pants {0,3} {1,4} {2,6}", cleaningOrder.NumberOfPants, PriceAPairOfPants, SubTotalPants);

C# 3.0 Practical Learning

467

Console.WriteLine("Dresses {0,3} {1,4} {2,6}", cleaningOrder.NumberOfDresses, PriceOneDress, SubTotalDresses); Console.WriteLine("------------------------------------"); Console.WriteLine("Total Order: {0,6}", TotalOrder.ToString("C")); Console.WriteLine("Tax Rate: {0,6}", TaxRate.ToString("P")); Console.WriteLine("Tax Amount: {0,6}", TaxAmount.ToString("C")); Console.WriteLine("Net Price: {0,6}", SalesTotal.ToString("C")); Console.WriteLine("------------------------------------"); Console.WriteLine("Amount Tended: {0,6}", AmountTended.ToString("C")); Console.WriteLine("Difference: {0,6}", Difference.ToString("C")); Console.WriteLine("===================================="); } #endregion } }

2. Execute the application and test it. Here is an example: -/- Georgetown Cleaning Services -/Enter Customer Name: Allen Dons Enter Customer Phone: 202-442-0400 Enter the order date(mm/dd/yyyy): 7/14/2005 Enter the order time(hh:mm AM/PM): 8:46 AM Number of Shirts: 5 Number of Pants: 2 Number of Dresses: 0 The Total order is: $11.26 Amount Tended? 15 ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Allen Dons Home Phone: 202-442-0400 Order Date: Thursday, July 14, 2005 Order Time: 8:46 AM -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 5 0.95 4.75 Pants 2 2.95 5.90 Dresses 0 4.55 0.00 -----------------------------------Total Order: $10.65 Tax Rate: 5.75 % Tax Amount: $0.61 Net Price: $11.26 -----------------------------------Amount Tended: $15.00 Difference: $3.74 ====================================

C# 3.0 Practical Learning

468

Press any key to continue . . .

3. Close the DOS window

The OverflowException Exception A computer application receives, processes, and produces values on a regular basis as the program is running. To better manage these values, as we saw when studying variables and data types in Lesson 1 and Lesson 2, the compiler uses appropriate amounts of space to store its values. It is not unusual that either you the programmer or a user of your application provides an value that is beyond the allowed range based on the data type. For example, we saw that a byte uses 8 bits to store a value and a combination of 8 bits can store a number no more than 255. If you provide a value higher than 255 to be stored in a byte, you get an error. Consider the following program: using System; // An Exercise class class Exercise { static int Main() { byte NumberOfPages; Console.Write("Enter the number of pages of the newspaper: "); NumberOfPages = byte.Parse(Console.ReadLine()); Console.WriteLine("Number of Pages of the Newspaper: {0}\n", NumberOfPages); } return 0; }

When a value beyond the allowable range is asked to be stored in memory, the compiler produces (the expression is "throws" as we will learn soon) an error of the OverflowException class. Here is an example of running the program: Enter the number of pages of the newspaper: 824 Unhandled Exception: System.OverflowException: Value was either too large or too small for an unsigned byte. at System.Byte.Parse(String s, NumberStyles style, IFormatProvider provider) at System.Byte.Parse(String s) at Exercise.Main() in c:\programs\msvcs .net 2003\project17\exercise.cs:line 11

As with the other errors, when this exception is thrown, you should take an appropriate action.

The ArgumentOutOfRangeException Exception C# 3.0 Practical Learning

469

Once again, when studying the techniques of converting or formatting values in Lesson 5, we saw that a value was passed to the Parse() method of its data type for analysis. For a primitive data type, the Parse() method scans the string and if the string cannot be converted into a valid value, the compiler usually produces a FormatException exception as we saw above. Other classes such as DateTime also use a Parse() method to scan the value submitted to it. For example, if you request a date value from the user, the DateTime.Parse() method scans the string to validate it. In US English, Parse() expects the user to type a string in the form m/d/yy or mm/dd/yy or mm/dd/yyyy. Consider the following program: using System; // An Exercise class class Exercise { static int Main() { DateTime DateHired; Console.Write("Enter Date Hired: "); DateHired = DateTime.Parse(Console.ReadLine()); Console.WriteLine("Date Hired: {0:d}\n", DateHired); return 0; }

}

If the user types a value that cannot be converted into a valid date, the compiler produces an ArgumentOutOfRangeException exception. Here is an example of running the above program: Enter Date Hired: 1244/04/258 Unhandled Exception: System.FormatException: String was not recognized as a valid DateTime. at System.DateTimeParse.Lex(Int32 dps, __DTString str, DateTimeToken dtok, DateTimeRawInfo raw, DateTimeResult result, DateTimeFormatInfo& dtfi) at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles) at System.DateTime.Parse(String s, IFormatProvider provider, DateTimeStyles styles) at System.DateTime.Parse(String s, IFormatProvider provider) at System.DateTime.Parse(String s) at Exercise.Main() in c:\programs\msvcs .net 2003\project17\exercise.cs:line 11

One way you can avoid this is to guide the user but still take appropriate actions.

The DivideByZeroException Exception Division by zero is an operation to always avoid. It is so important that it is one of the most fundamental exceptions of the computer. It is addressed at C# 3.0 Practical Learning

470

the core level even by the Intel and AMD processors. It is also addressed by the operating systems at their level. It is also addressed by most, if not all, compilers. It is also addressed by most, if not all, libraries. This means that this exception is never welcomed anywhere. The .NET Framework also provides it own class to face this operation. If an attempt to divide a value by 0 is performed, the compiler produces a DivideByZeroException exception.

C# 3.0 Practical Learning

471

Using Exception Handling Techniques of Using Exceptions Introduction As mentioned in the previous lesson, the Exception class is equipped with a Message property that holds a string about the error that occurred. The message of this property may not be particularly useful to a user. Fortunately, you can create your own message and pass it to the Exception class. To be able to receive custom messages, the Exception class provides the following constructor: public Exception(string message);

Besides using this class or one of its derived classes in a catch clause, you can call this constructor to give a new and customized implementation of the exception.

Practical Learning: Using Exceptions 1. Start Microsoft Visual C# and create a new Console Application named RealEstate3

2. To create a new class, in the Class View, right-click the name of the project, position the mouse on Add and click Class... 3. Set the Name to Property and press Enter 4. Change the file as follows: using System; namespace RealEstate3 { public enum PropertyCondition { Unknown, Excellent, Good, NeedsRepair, BadShape }

C# 3.0 Practical Learning

472

public class Property { private string propNbr; private PropertyCondition cond; private short beds; private float baths; private int yr; private decimal val; public Property() { } public string PropertyNumber { get { return propNbr; } set { if (propNbr == "") propNbr = "N/A"; else propNbr = value; } } public PropertyCondition Condition { get { return cond; } set { cond = value; } } public short Bedrooms { get { if (beds <= 1) return 1; else return beds; } set { beds = value; } } public float Bathrooms { get{ return (baths <= 0) ? 0.00f : baths; } set { baths = value; } } public int YearBuilt { get { return yr; } set { yr = value; } } public decimal Value { get{ return (val <= 0) ? 0.00M : val; } set { val = value; }

C# 3.0 Practical Learning

473

} }

}

5. On the main menu, click Project -> Add Class... 6. Set the Name to HouseType and press Enter 7. To derive a class, change the file as follows: using System; namespace RealEstate3 { public class HouseType : Property { private short nbrOfStories; private bool basement; private bool garage; public short Stories { get { return nbrOfStories; } set { nbrOfStories = value; } } public bool FinishedBasement { get { return basement; } set { basement = value; } }

}

public bool IndoorGarage { get { return garage; } set { garage = value; } }

}

8. On the main menu, click Project -> Add -> Class... 9. Set the Name to Condominium and press Enter 10. To create another class based on the Property class, change the file as follows: using System; namespace RealEstate3 { public class Condominium : Property {

private bool handicap; public bool HandicapAccessible

C# 3.0 Practical Learning

474

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

}

}

11. 12. To create a new class, in the Solution Explorer, right-click RealEstate3, position the mouse on Add and click Class... 13. Set the Name to PropertyListing and press Enter 14.

Change the file as follows:

using System; namespace RealEstate3 { public enum PropertyType { Unknown, SingleFamily, Townhouse, Condominium } public class PropertyListing { private Property prop; private HouseType hse; private Condominium cond; private PropertyType tp; public Property ListProperty { get { return prop; } set { prop = value; } } public HouseType House { get { return hse; } set { hse = value; } } public Condominium Condo { get { return cond; } set { cond = value; } } public PropertyType Type { get { return tp; } set { tp = value; } }

C# 3.0 Practical Learning

475

public PropertyListing() { prop = new Property(); hse = new HouseType(); cond = new Condominium(); } public void CreateListing() { char answer = 'n'; short propType = 1; short condition = 1; Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("-=- Property Creation -=-"); try { Console.WriteLine("\nTypes of Properties"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.WriteLine("4. Don't Know"); Console.Write("Enter Type of Property: "); propType = short.Parse(Console.ReadLine()); } catch (FormatException ex) { Console.WriteLine(ex.Message); } Console.Write("\nEnter Property #: "); ListProperty.PropertyNumber = Console.ReadLine(); try { Console.WriteLine("\nProperties Conditions"); Console.WriteLine("1. Excellent"); Console.WriteLine("2. Good (may need minor repair)"); Console.WriteLine("3. Needs Repair"); Console.Write("4. In Bad Shape (property needs "); Console.WriteLine("major repair or rebuild)"); Console.Write("Enter Property Condition: "); condition = short.Parse(Console.ReadLine()); } catch (FormatException ex) { Console.WriteLine(ex.Message); } if (condition == 1) ListProperty.Condition else if (condition == 2) ListProperty.Condition else if (condition == 3) ListProperty.Condition else if (condition == 4) ListProperty.Condition else ListProperty.Condition

= PropertyCondition.Excellent; = PropertyCondition.Good; = PropertyCondition.NeedsRepair; = PropertyCondition.BadShape; = PropertyCondition.Unknown;

C# 3.0 Practical Learning

476

switch ((PropertyType)propType) { case PropertyType.SingleFamily: Type = PropertyType.SingleFamily; try { Console.Write("\nHow many stories (levels)? ");

House.Stories = short.Parse(Console.ReadLine()); } catch (FormatException ex) { Console.WriteLine(ex.Message); } try { Console.Write( "Does it have an indoor car garage (y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else House.IndoorGarage = false; } catch (FormatException) { Console.WriteLine("Invalid Indoor Car Garage Answer"); } try { Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false; } catch (FormatException) { Console.WriteLine("Invalid Basement Answer"); } break;

(y/n): ");

case PropertyType.Townhouse: Type = PropertyType.Townhouse; try { Console.Write("\nHow many stories (levels)? "); House.Stories = short.Parse(Console.ReadLine()); } catch (FormatException ex) { Console.WriteLine(ex.Message); } Console.Write("Does it have an indoor car garage answer = char.Parse(Console.ReadLine());

C# 3.0 Practical Learning

477

if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else House.IndoorGarage = false; Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false; break; case PropertyType.Condominium: Type = PropertyType.Condominium; Console.Write( "\nIs the building accessible to handicapped (y/n):

");

answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) Condo.HandicapAccessible = true; else Condo.HandicapAccessible = false; break; default: Type = PropertyType.Unknown; break; } try { Console.Write("\nHow many bedrooms? "); ListProperty.Bedrooms = short.Parse(Console.ReadLine()); } catch (FormatException ex) { Console.WriteLine(ex.Message); } try { Console.Write("How many bathrooms? "); ListProperty.Bathrooms = float.Parse(Console.ReadLine()); } catch (FormatException ex) { Console.WriteLine(ex.Message); } try { Console.Write("Year built: "); ListProperty.YearBuilt = int.Parse(Console.ReadLine()); } catch (FormatException ex) { Console.WriteLine(ex.Message); } try { Console.Write("Property Value: "); ListProperty.Value = decimal.Parse(Console.ReadLine());

C# 3.0 Practical Learning

478

} catch (FormatException ex) { Console.WriteLine(ex.Message); } } public void ShowProperty() { Console.WriteLine("=================================="); Console.WriteLine(" =//=//= Altair Realty =//=//="); Console.WriteLine("-=-=-=- Properties Listing -=-=-=-"); Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", ListProperty.PropertyNumber); Console.WriteLine("Property Type: {0}", Type); switch (Type) { case PropertyType.SingleFamily: case PropertyType.Townhouse: Type = PropertyType.SingleFamily; Console.WriteLine("Stories: {0}", House.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", House.IndoorGarage); Console.WriteLine("Finished Basement: {0}", House.FinishedBasement); break; case PropertyType.Condominium: Console.WriteLine("Handicapped Accessible Building:

{0}",

Condo.HandicapAccessible); break; } Console.WriteLine("Condition: ListProperty.Condition); Console.WriteLine("Bedrooms: ListProperty.Bedrooms); Console.WriteLine("Bathrooms: ListProperty.Bathrooms); Console.WriteLine("Year Built: ListProperty.YearBuilt); Console.WriteLine("Market Value: ListProperty.Value); }

{0}", {0}", {0}", {0}", {0:C}",

}

}

15.

Access the Program.cs file and change it as follows:

using System; namespace RealEstate3 { public static class Program {

C# 3.0 Practical Learning

479

static int Main() { PropertyListing listing = new PropertyListing(); listing.CreateListing(); Console.WriteLine("\n"); listing.ShowProperty(); Console.WriteLine(); return 0; }

}

}

16.

Execute the application and test it. Here is an example:

=//= Altair Realty =//= -=- Property Creation -=Types of Properties 1. Single Family 2. Townhouse 3. Condominium 4. Don't Know Enter Type of Property: 1 Enter Property #: 276744 Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 3 How many stories (levels)? -2 Does it have an indoor car garage (y/n): g Is the basement finished(y/n): m How many bedrooms? How many bathrooms? Year built: Property Value:

-5 3684634 87324 2

================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 276744 Property Type: SingleFamily Stories: -2 Has Indoor Car Garage: False Finished Basement: False Condition: NeedsRepair Bedrooms: 1 Bathrooms: 3684634 Year Built: 87324 Market Value: $2.00

C# 3.0 Practical Learning

480

Press any key to continue . . .

17.

Close the DOS window

Throwing an Exception When a bad behavior occurs in your application, the program is said to throw an exception. Your job is to know, as much as possible, when and why this would happen. In the previous lesson and in the above section, we saw that, when an application throws an exception, you could display your own message. To effectively address a particular exception, you need to identify the (exact, if possible) section of code where the exception would occur and you should know why the error would be produced. After identifying the area in code where an exception is likely to occur, you can further customize the behavior of your application. To customize the throwing of an exception, in the section of code where you are anticipating the error, type the throw keyword followed by a new instance of the Exception class (or one of its derived classes) using the constructor that takes a string. Here is an example: using System; class Program { static int Main() { double Operand1, Operand2; double Result = 0.00; char Operator; Console.WriteLine( "This program allows you to perform an operation on two numbers"); try { Console.Write("Enter a number: "); Operand1 = double.Parse(Console.ReadLine()); Console.Write("Enter an operator: "); Operator = char.Parse(Console.ReadLine()); Console.Write("Enter a number: "); Operand2 = double.Parse(Console.ReadLine()); if (Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw new Exception(Operator.ToString()); switch (Operator) { case '+':

C# 3.0 Practical Learning

481

Result = Operand1 + Operand2; break; case '-': Result = Operand1 - Operand2; break; case '*': Result = Operand1 * Operand2; break; case '/': Result = Operand1 / Operand2; break; default: Console.WriteLine("Bad Operation"); break;

} Console.WriteLine("\n{0} {1} {2} = {3}", Operand1, Operator, Operand2, Result); } catch (Exception ex) { Console.WriteLine("\nOperation Error: {0} is not a valid operator", ex.Message); } return 0; }

}

Here is an example of running the program: This program allows you to perform an operation on two numbers Enter a number: 124.55 Enter an operator: & Enter a number: 36.85 Operation Error: & is not a valid operator Press any key to continue . . .

Practical Learning: Throwing an Exception 1. Access the PropertyListing.cs file 2. To throw some exceptions, change the file as follows: using System; namespace RealEstate3 { public enum PropertyType { Unknown, SingleFamily,

C# 3.0 Practical Learning

482

}

Townhouse, Condominium

class PropertyListing { . . . No Change public void CreateListing() { . . . No Change switch ((PropertyType)propType) { case PropertyType.SingleFamily: Type = PropertyType.SingleFamily; try { Console.Write("\nHow many stories (levels)? "); House.Stories = short.Parse(Console.ReadLine()); if (House.Stories < 1) { House.Stories = 1; throw new OverflowException( "The number of stories must be positive"); } } catch (OverflowException ex) { Console.WriteLine(ex.Message); } . . . No Change break; case PropertyType.Townhouse: Type = PropertyType.Townhouse; try { Console.Write("\nHow many stories (levels)? "); House.Stories = short.Parse(Console.ReadLine()); if (House.Stories < 1) { House.Stories = 1; throw new OverflowException( "The number of stories must be positive"); } } catch (OverflowException ex) { Console.WriteLine(ex.Message); } . . . No Change } . . . No Change

C# 3.0 Practical Learning

483

}

}

public void ShowProperty() { . . . No Change }

}

3. Execute the application and test it. Here is an example: =//= Altair Realty =//= -=- Property Creation -=Types of Properties 1. Single Family 2. Townhouse 3. Condominium 4. Don't Know Enter Type of Property: 2 Enter Property #: 463864 Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 3 How many stories (levels)? -3 The number of levels must be positive Does it have an indoor car garage (y/n): G Is the basement finished(y/n): K How many bedrooms? How many bathrooms? Year built: Property Value:

-4 -2 2994 425885

================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 463864 Property Type: Townhouse Stories: 1 Has Indoor Car Garage: False Finished Basement: False Condition: NeedsRepair Bedrooms: 1 Bathrooms: 0.00 Year Built: 2994 Market Value: $425,885.00 Press any key to continue . . .

4. Close the DOS window C# 3.0 Practical Learning

484

Catching Various Exceptions In the examples above, when we anticipated some type of problem, we instructed the compiler to use our default catch section. We left it up to the compiler to find out when there was a problem and we provided a catch section to deal with it. A method with numerous or complex operations and requests can also produce different types of errors. With such a type of program, you should be able to face different problems and deal with them individually, each by its own kind. To do this, you can create different catch sections, each made for a particular error. The formula used would be: try {

// Code to Try } catch(Arg1) { // One Exception } catch(Arg2) { // Another Exception }

The compiler would proceed in a top-down: 1. Following the normal flow of the program, the compiler enters the try block 2. If no exception occurs in the try block, the rest of the try block is executed If an exception occurs in the try block, the compiler registers the type of error that occurred. If there is a throw line, the compiler registers it also: a. The compiler gets out of the try section b. The compiler examines the first catch. If the first catch matches the thrown error, that catch executes and the exception handling routine may seize. If the first catch doesn’t match the thrown error, the compiler proceeds with the next catch c. The compiler checks the next match, if any, and proceeds as in the first catch. This continues until the compiler finds a catch that matches the thrown error d. If one of the catches matches the thrown error, its body executes. If no catch matches the thrown error, the compiler calls the Exception class and uses the default message Multiple catches are written if or when a try block is expected to throw different types of errors. Once again, consider the previous program. That program works fine as long as the user types a valid sequence of values made of a number, a valid arithmetic operator, and a number. Anything else, such as an invalid number, an unexpected operator, or a wrong sequence (such as a number then another number instead of an operator), would cause an error. Obviously various bad things could happen when this program is running. To handle the exceptions that this program could produce, you can 485 C# 3.0 Practical Learning

start with the most likely problem that would occur. Trusting that a user is able to provide the two numbers that are requested, it is possible that a user would type an invalid operator. For example, for this program we will perform only the addition (+), the subtraction(-), the multiplication(*), and the division(/). Therefore, we will first validate the operator. This can be done as follows: using System; class Program { static int Main() { double Operand1, Operand2; double Result = 0.00; char Operator; Console.WriteLine("This program allows you to perform an operation on two numbers"); try { Console.Write("Enter a number: "); Operand1 = double.Parse(Console.ReadLine()); Console.Write("Enter an operator: "); Operator = char.Parse(Console.ReadLine()); Console.Write("Enter a number: "); Operand2 = double.Parse(Console.ReadLine()); if (Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw new Exception(Operator.ToString()); switch (Operator) { case '+': Result = Operand1 + Operand2; break; case '-': Result = Operand1 - Operand2; break; case '*': Result = Operand1 * Operand2; break; case '/': Result = Operand1 / Operand2; break; default: Console.WriteLine("Bad Operation"); break; }

C# 3.0 Practical Learning

486

Console.WriteLine("\n{0} {1} {2} = {3}", Operand1, Operator, Operand2, Result); } catch (Exception ex) { Console.WriteLine("\nOperation Error: {0} is not a valid operator", ex.Message); } }

return 0;

}

When this program runs, if the user provides a valid number followed by a wrong operator, we call the Exception(string message) constructor and pass it a string converted from the character that was typed. Imagine that the user wants to perform a division. You need to tell the compiler what to do if the user enters the denominator as 0 (or 0.00). If this happens, probably the best option is to display a message and get out. Fortunately, the .NET Framework provides the DivideByZeroException class to deal with an exception caused by division by zero. As done with the message passed to the Exception class, you can compose your own message and pass it to the DivideByZeroException(string message) constructor. Here is an example that catches two types of exceptions: using System; class Program { static int Main() { double Operand1, Operand2; double Result = 0.00; char Operator; Console.WriteLine("This program allows you to perform an operation on two numbers"); try { Console.Write("Enter a number: "); Operand1 = double.Parse(Console.ReadLine()); Console.Write("Enter an operator: "); Operator = char.Parse(Console.ReadLine()); Console.Write("Enter a number: "); Operand2 = double.Parse(Console.ReadLine()); if (Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw new Exception(Operator.ToString());

allowed");

if (Operator == '/') if (Operand2 == 0) throw new DivideByZeroException("Division by zero is not

C# 3.0 Practical Learning

487

switch (Operator) { case '+': Result = Operand1 + Operand2; break; case '-': Result = Operand1 - Operand2; break; case '*': Result = Operand1 * Operand2; break; case '/': Result = Operand1 / Operand2; break; default: Console.WriteLine("Bad Operation"); break; } Console.WriteLine("\n{0} {1} {2} = {3}", Operand1, Operator, Operand2, Result); } catch (DivideByZeroException ex) { Console.WriteLine(ex.Message); } catch (Exception ex) { Console.WriteLine("\nOperation Error: {0} is not a valid operator", ex.Message); } }

return 0;

}

When running this program, if the user types a wrong operator, the compiler gets out of the try block and looks for a catch that takes an Exception as argument. It finds the second and executes it. If the user enters the right values (a number, an operator, and another number), then the compiler finds out if the operator entered was a forward slash “/” used to perform a division. If the user wants to perform a division, the compiler finds out if the second operand, the denominator, is 0. If it is, we create a DivideByZeroException instance and pass our own message to it. Based on this exception, the compiler gets out of the try block and starts looking for a catch block that takes a DivideByZeroException argument. It finds it in the first catch. Therefore, the compiler executes it.

Practical Learning: Catching Various Exceptions 1. Change the PropertyListing.cs file as follows: using System;

C# 3.0 Practical Learning

488

namespace RealEstate3 { public enum PropertyType { Unknown, SingleFamily, Townhouse, Condominium } class PropertyListing { private Property prop; private HouseType hse; private Condominium cond; private PropertyType tp; public Property ListProperty { get { return prop; } set { prop = value; } } public HouseType House { get { return hse; } set { hse = value; } } public Condominium Condo { get { return cond; } set { cond = value; } } public PropertyType Type { get { return tp; } set { tp = value; } } public PropertyListing() { prop = new Property(); hse = new HouseType(); cond = new Condominium(); } public void CreateListing() { char answer = 'n'; short propType = 1; short condition = 1; Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("-=- Property Creation -=-"); try { Console.WriteLine("\nTypes of Properties");

C# 3.0 Practical Learning

489

Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.WriteLine("4. Don't Know"); Console.Write("Enter Type of Property: "); propType = short.Parse(Console.ReadLine());

number");

} catch (FormatException) { Console.WriteLine("The value you entered is not a valid } catch (Exception) { Console.WriteLine("Something bad happened and we don't like

it");

} Console.Write("\nEnter Property #: "); ListProperty.PropertyNumber = Console.ReadLine(); try { Console.WriteLine("\nProperties Conditions"); Console.WriteLine("1. Excellent"); Console.WriteLine("2. Good (may need minor repair)"); Console.WriteLine("3. Needs Repair"); Console.Write("4. In Bad Shape (property needs "); Console.WriteLine("major repair or rebuild)"); Console.Write("Enter Property Condition: "); condition = short.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The value you typed for the property condition is not good"); } catch (Exception) { Console.WriteLine("Something unacceptable has just happened"); } if (condition == 1) ListProperty.Condition else if (condition == 2) ListProperty.Condition else if (condition == 3) ListProperty.Condition else if (condition == 4) ListProperty.Condition else ListProperty.Condition

= PropertyCondition.Excellent; = PropertyCondition.Good; = PropertyCondition.NeedsRepair; = PropertyCondition.BadShape; = PropertyCondition.Unknown;

switch ((PropertyType)propType) { case PropertyType.SingleFamily: Type = PropertyType.SingleFamily; try {

C# 3.0 Practical Learning

490

Console.Write("\nHow many stories (levels)? "); House.Stories = short.Parse(Console.ReadLine()); if (House.Stories < 1) { House.Stories = 1; throw new OverflowException("The number of levels must be positive");

} } catch (OverflowException ex) { Console.WriteLine(ex.Message); } catch (FormatException) { Console.WriteLine("The number you entered for the stories is not allowed"); } catch (Exception) { Console.WriteLine("This is one of those abnormal behaviors"); } try { Console.Write("Does it have an indoor car garage (y/n): ");

answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else House.IndoorGarage = false;

Answer");

} catch (FormatException) { Console.WriteLine("Invalid Indoor Car Garage } try { Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false; } catch (FormatException) { Console.WriteLine("Invalid Basement Answer"); } break; case PropertyType.Townhouse: Type = PropertyType.Townhouse; try {

C# 3.0 Practical Learning

491

Console.Write("\nHow many stories (levels)? "); House.Stories = short.Parse(Console.ReadLine()); if (House.Stories < 1) { House.Stories = 1; throw new OverflowException("The number of levels must be positive");

} } catch (OverflowException ex) { Console.WriteLine(ex.Message); } catch (FormatException) { Console.WriteLine("The number you entered for the stories is not allowed"); } catch (Exception) { Console.WriteLine("This is one of those abnormal behaviors"); } Console.Write("Does it have an indoor car garage

(y/n): ");

answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else House.IndoorGarage = false; Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false; break; case PropertyType.Condominium: Type = PropertyType.Condominium; Console.Write("\nIs the building accessible to handicapped (y/n): ");

answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) Condo.HandicapAccessible = true; else Condo.HandicapAccessible = false; break;

} try {

default: Type = PropertyType.Unknown; break;

Console.Write("\nHow many bedrooms? "); ListProperty.Bedrooms = short.Parse(Console.ReadLine());

C# 3.0 Practical Learning

492

} catch (FormatException) { Console.WriteLine( "The value you entered for the number of bedrooms is not acceptable"); } catch (Exception) { Console.WriteLine("The program has decided to stop"); } try {

Console.Write("How many bathrooms? "); ListProperty.Bathrooms = float.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The value you decided to enter for the bedrooms is rejected"); } catch (Exception) { Console.WriteLine("The computer doesn't like what is going on"); } try {

Console.Write("Year built: "); ListProperty.YearBuilt = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("You didn't enter a valid number for the year built"); } catch (Exception) { Console.WriteLine("Whatever, whatever, whatever"); } try {

Console.Write("Property Value: "); ListProperty.Value = decimal.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine( "The value of a property must be a good decimal number"); } catch (Exception) { Console.WriteLine( "This is where the application draws the line: it stops!"); } } public void ShowProperty()

C# 3.0 Practical Learning

493

{ Console.WriteLine("=================================="); Console.WriteLine(" =//=//= Altair Realty =//=//="); Console.WriteLine("-=-=-=- Properties Listing -=-=-=-"); Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", ListProperty.PropertyNumber); Console.WriteLine("Property Type: {0}", Type); switch (Type) { case PropertyType.SingleFamily: case PropertyType.Townhouse: Type = PropertyType.SingleFamily; Console.WriteLine("Stories: {0}", House.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", House.IndoorGarage); Console.WriteLine("Finished Basement: {0}", House.FinishedBasement); break; case PropertyType.Condominium: Console.WriteLine("Handicapped Accessible Building:

{0}",

Condo.HandicapAccessible); break; } Console.WriteLine("Condition: ListProperty.Condition); Console.WriteLine("Bedrooms: ListProperty.Bedrooms); Console.WriteLine("Bathrooms: ListProperty.Bathrooms); Console.WriteLine("Year Built: ListProperty.YearBuilt); Console.WriteLine("Market Value: ListProperty.Value); }

{0}", {0}", {0:F}", {0}", {0:C}",

}

}

2. Execute the application and test it. Here is an example: =//= Altair Realty =//= -=- Property Creation -=Types of Properties 1. Single Family 2. Townhouse 3. Condominium 4. Don't Know Enter Type of Property: 1 Enter Property #: 228046 Properties Conditions 1. Excellent

C# 3.0 Practical Learning

494

2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 4 How many stories (levels)? -5 The number of levels must be positive Does it have an indoor car garage (y/n): y Is the basement finished(y/n): Not at all Invalid Basement Answer How many bedrooms? Apparently 3 or 4 The value you entered for the number of bedrooms is not acceptable How many bathrooms? 1 can flush, the owner is working on another The value you decided to enter for the bedrooms is rejected Year built: Around 1962 You didn't enter a valid number for the year built Property Value: A little over 420000 The value of a property must be an good decimal number ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 228046 Property Type: SingleFamily Stories: 1 Has Indoor Car Garage: True Finished Basement: False Condition: BadShape Bedrooms: 1 Bathrooms: 0.00 Year Built: 0 Market Value: $0.00 Press any key to continue . . .

3. Close the DOS window

Exception Nesting The calculator simulator we have studied so far performs a division as one of its assignments. We learned that, in order to perform any operation, the compiler must first make sure that the user has entered a valid operator. Provided the operator is one of those we are expecting, we also must make sure that the user typed valid numbers. Even if these two criteria are met, it was possible that the user enter 0 for the denominator. The block that is used to check for a non-zero denominator depends on the exception that validates the operators. The exception that could result from a zero denominator depends on the user first entering a valid number for the denominator. You can create an exception inside of another. This is referred to as nesting an exception. This is done by applying the same techniques we used to nest conditional statements. This means that you can write an exception that depends on, or is subject to, another exception. To nest an exception, write a try block in the body of the parent exception. The nested try block must be followed by its own catch(es) clause. To effectively handle the exception, C# 3.0 Practical Learning

495

make sure you include an appropriate throw in the try block. Here is an example: using System; class Program { static int Main() { double Operand1, Operand2; double Result = 0.00; char Operator; Console.WriteLine( "This program allows you to perform an operation on two numbers"); try { Console.Write("Enter a number: "); Operand1 = double.Parse(Console.ReadLine()); Console.Write("Enter an operator: "); Operator = char.Parse(Console.ReadLine()); Console.Write("Enter a number: "); Operand2 = double.Parse(Console.ReadLine()); if (Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw new Exception(Operator.ToString()); switch (Operator) { case '+': Result = Operand1 + Operand2; Console.WriteLine("\n{0} + {1} = {2}", Operand1, Operand2, Result); break; case '-': Result = Operand1 - Operand2; Console.WriteLine("\n{0} - {1} = {2}", Operand1, Operand2, Result); break; case '*': Result = Operand1 * Operand2; Console.WriteLine("\n{0} * {1} = {2}", Operand1, Operand2, Result); break;

try

case '/': // The following exception is nested in the previous try { if (Operand2 == 0) throw new DivideByZeroException("Division by zero is

not allowed");

C# 3.0 Practical Learning

496

Result = Operand1 / Operand2; Console.WriteLine("\n{0} / {1} = {2}", Operand1, Operand2, Result);

} catch (DivideByZeroException ex) { Console.WriteLine(ex.Message); } break;

} } catch (Exception ex) { Console.WriteLine("\nOperation Error: {0} is not a valid operator", ex.Message); } return 0; }

}

Here is an example of running the program: This program allows you to perform an operation on two numbers Enter a number: 324.53 Enter an operator: / Enter a number: 0 Division by zero is not allowed Press any key to continue . . .

Exceptions and Methods One of the most effective techniques used to deal with code is to isolate assignments. We learned this when studying methods of classes. For example, the switch statement that was performing the operations in the “normal” version of our program can be written as follows: using System; class Program { static int Main() { double Number1, Number2; double Result = 0.00; char Operator; Console.WriteLine( "This program allows you to perform an operation on two numbers"); try {

Console.WriteLine("To proceed, enter"); Console.Write("First Number: "); Number1 = double.Parse(Console.ReadLine());

C# 3.0 Practical Learning

497

Console.Write("An Operator (+, -, * or /): "); Operator = char.Parse(Console.ReadLine()); if (Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw new Exception(Operator.ToString()); Console.Write("Second Number: "); Number2 = double.Parse(Console.ReadLine()); if (Operator == '/') if (Number2 == 0) throw new DivideByZeroException("Division by zero is not allowed"); Result = Calculator(Number1, Number2, Operator); Console.WriteLine("\n{0} {1} {2} = {3}", Number1, Operator, Number2, Result); } catch (FormatException) { Console.WriteLine("The number you typed is not valid"); } catch (DivideByZeroException ex) { Console.WriteLine(ex.Message); } catch (Exception ex) { Console.WriteLine( "\nOperation Error: {0} is not a valid operator", ex.Message); } }

return 0;

static double Calculator(double Value1, double Value2, char Symbol) { double Result = 0.00; switch (Symbol) { case '+': Result = Value1 + Value2; break; case '-': Result = Value1 - Value2; break; case '*': Result = Value1 * Value2; break; case '/': Result = Value1 / Value2; break; } return Result;

C# 3.0 Practical Learning

498

} }

Here is one example of running the program: This program allows you to perform an operation on two numbers To proceed, enter First Number: 248.84 An Operator (+, -, * or /): * Second Number: 57.93 248.84 * 57.93 = 14415.3012 Press any key to continue . . .

Here is another example of running the program: This program allows you to perform an operation on two numbers To proceed, enter First Number: 12.55 An Operator (+, -, * or /): [ Operation Error: [ is not a valid operator Press any key to continue . . .

You can still use regular methods along with methods that handle exceptions. As done in Main(), any method of a program can take care of its own exceptions that would occur in its body. Here is an example of an exception handled in a method: using System; class Program { static int Main() { double Number1, Number2; double Result = 0.00; char Operator; Console.WriteLine( "This program allows you to perform an operation on two numbers"); try {

Console.WriteLine("To proceed, enter"); Console.Write("First Number: "); Number1 = double.Parse(Console.ReadLine()); Console.Write("An Operator (+, -, * or /): "); Operator = char.Parse(Console.ReadLine()); if (Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw new Exception(Operator.ToString()); Console.Write("Second Number: "); Number2 = double.Parse(Console.ReadLine()); Result = Calculator(Number1, Number2, Operator);

C# 3.0 Practical Learning

499

} catch (FormatException) { Console.WriteLine("The number you typed is not valid"); } catch (Exception ex) { Console.WriteLine( "\nOperation Error: {0} is not a valid operator", ex.Message); } return 0; } static double Calculator(double Value1, double Value2, char Symbol) { double Result = 0.00; switch (Symbol) { case '+': Result = Value1 + Value2; Console.WriteLine("\n{0} + {1} = {2}", Value1, Value2,

Result);

break; case '-': Result = Value1 - Value2; Console.WriteLine("\n{0} - {1} = {2}", Value1, Value2,

Result);

break; case '*': Result = Value1 * Value2; Console.WriteLine("\n{0} * {1} = {2}", Value1, Value2,

Result);

break; case '/': // The following exception is nested in the previous try try { if (Value2 == 0) throw new DivideByZeroException("Division by zero is not allowed"); Result = Value1 / Value2; Console.WriteLine("\n{0} / {1} = {2}", Value1, Value2, Result);

}

} catch (DivideByZeroException ex) { Console.WriteLine(ex.Message); } break;

return Result; }

C# 3.0 Practical Learning

500

}

Isolating assignments and handing them to method is an important matter in the area of application programming. Consider a program that handles a simple exception such as this one: using System; class Program { static int Main() { double Number1, Number2; double Result = 0.00; char Operator = '/'; Console.WriteLine("This program allows you to perform a division of two numbers"); try {

Console.Write("Enter a number: "); Number1 = double.Parse(Console.ReadLine()); Console.Write("Enter a number: "); Number2 = double.Parse(Console.ReadLine()); if (Number2 == 0) throw new DivideByZeroException("Division by zero is not

allowed"); Result = Number1 / Number2; Console.WriteLine("\n{0} / {1} = {2}", Number1, Number2, Result);

} catch (DivideByZeroException ex) { Console.WriteLine(ex.Message); } return 0;

}

}

One of the ways you can use methods in exception routines is to have a central method that receives variables, and sends them to other external methods. The external method tests the value of a variable. If an exception occurs, the external method displays or sends a throw. This throw can be picked up by the method that sent the error. Observe the following example that implements this scenario: using System; class Program { static int Main() { double Number1, Number2;

C# 3.0 Practical Learning

501

Console.WriteLine("This program allows you to perform a division of two numbers"); try { Console.Write("Enter a number: "); Number1 = double.Parse(Console.ReadLine()); Console.Write("Enter a number: "); Number2 = double.Parse(Console.ReadLine()); Division(Number1, Number2); } catch(DivideByZeroException ex) { Console.WriteLine(ex.Message); } }

return 0;

static void Division(double a, double b) { double Result; // If an exception occurred, if( b == 0 ) // then throw a string to the function caller throw new DivideByZeroException("Division by zero is not allowed"); Result = a / b; Console.WriteLine("\n{0} / {1} = {2}", a, b, Result); }

}

In this program, the Division method receives two values that it is asked to perform a division with. The Division method analyzes the second argument that represents the denominator. If this argument is zero, an exception is found and the Division method throws a DivideByZeroException exception. A method can also be called to perform more than one test to eventually throw more than one exception. Such a method can (and should) be programmed to throw different types of exceptions.

Custom Exceptions Introduction As seen in the previous lesson and in the above sections, exception handling is a great part of the .NET Framework. As high as it is supported by various classes of the .NET, it is possible that you want to further customize the handling of exceptions in your application. One way you can do this is to create your own exception class.

Creating an Exceptional Class C# 3.0 Practical Learning

502

The Exception class of the .NET Framework is a great tool for handling exceptions in a C# application. To deal with particular errors, various classes are derived from Exception. If for some reason the Exception class and none of the Exception-based classes fulfills your requirement, you can derive a new class from Exception or from one of the available Exception-based classes. To derive a class from Exception or from one of its classes, simply follow the rules we reviewed from class inheritance. Here is an example of a class based on Exception: public class CustomException : Exception { }

There is no real rule to follow as to what class to derive from but it may be a good idea to derive your class from one that already addresses your issue but not the way you want. For example, if you want to create a class that would process numeric values but you think the FormatException class is not doing what you want, you can derive your class from FormatException. After deriving the class, you can add the necessary members as you see fit. Remember that the primary characteristic of an exception is to present a message to the user. In Exception-based classes, this message is represented by the Message property. Therefore, if you want to prepare a custom message for your class, you can override or new this property. Here is an example: public class IntegerException : Exception { public override string Message { get { return "The value you entered is not a valid integer"; } } }

Once you have created and customized your exceptional class, you can use it the same way you would another exception class, such as throwing it. Here is an example using System; public class DigitException : Exception { private char c; public DigitException(char x) { c = x; } public override string Message { get { return "The character you entered is not a valid digit"; }

C# 3.0 Practical Learning

503

} } class Program { static int Main() { try { char chNumber = '0'; Console.Write("Enter a digit (0 to 9): "); chNumber = char.Parse(Console.ReadLine()); if ((chNumber != '0') && (chNumber != '1') && (chNumber != '2') && (chNumber != '3') && (chNumber != '4') && (chNumber != '5') && (chNumber != '6') && (chNumber != '7') && (chNumber != '8') && (chNumber != '9')) throw new DigitException(chNumber); Console.WriteLine("Number: {0}\n", chNumber); } catch (DigitException ex) { Console.WriteLine(ex.Message); } catch (FormatException ex) { Console.WriteLine(ex.Message); } catch (Exception ex) { Console.WriteLine(ex.Message); } }

return 0;

}

Here is an example of running the program: Enter a digit (0 to 9): 8 Number: 8 Press any key to continue . . .

Here is another example of running the program: Enter a digit (0 to 9): w The character you entered is not a valid digit Press any key to continue . . .

C# 3.0 Practical Learning

504

C# 3.0 Practical Learning

505

Introduction to Arrays A Series of Similar Items Introduction Imagine you want to create a program that would use a series of numbers. In algebra, we represent such a series as follows: X1, X2, X3, X4, X5. You can also represent a list of names as follows: Alex Gaston Hermine Jerry So far, to use a series of items, we were declaring a variable for each of them. If the list was made of numbers, we would declare variables for such numbers as follows:

using System; public class Exercise { static int Main() { var Number1 = var Number2 = var Number3 = var Number4 = var Number5 = }

12.44; 525.38; 6.28; 2448.32; 632.04;

return 0;

}

Instead of using individual variables that share the same characteristics, you can group them in an entity like a regular variable. This group is called an array. Therefore, an array is a series of items of the same kind. It could be a C# 3.0 Practical Learning

506

group of numbers, a group of cars, a group of words, etc but all items of the array must be of the same type.

Practical Learning: Introducing Arrays •

Start Microsoft Visual C# and create a Console Application named VideoCollection1

Array Creation Before creating an array, you must first decide the type its items will be made of. Is it a group of numbers, a group of chairs, a group of buttons on a remote control? This information allows the compiler to know how much space each item of the group will require. This is because each item of the group will occupy its own memory space, just like any of the variables we have used so far. After deciding about the type of data of each item that makes up the series, you must use a common name to identify them. The name is simply the same type of name you would use for a variable as we have used so far. The name allows you and the compiler to identify the area in memory where the items are located. Thirdly, you must specify the number of items that will constitute the group. For the compiler to be able to allocate an adequate amount of space for the items of the list, once it knows how much space each item will require, it needs to know the number of items so an appropriate and large enough amount of space can be reserved. The number of items of an array is included in square brackets, as in [5]. An array is considered a reference type. Therefore, an array requests its memory using the new operator. Based on this, one of the formulas to declare an array is: DataType[] VariableName = new DataType[Number];

Alternatively, you can use the var keyword to create an array. The formula to use would be: var VariableName = new DataType[Number];

In these formulas, the DataType factor can be one of the types we have used so far (char, int, float, double, decimal, string, etc). It can also be the name of a class as we will learn in Lesson 23. Like a normal variable, an array must have a name, represented in our formula as VariableName. The square brackets on the left of the assignment operator are used to let the compiler know that you are declaring an array instead of a regular variable. The new operator allows the compiler to reserve memory. The Number factor is used to specify the number of items of the list. Based on the above formula, here is an example of an array variable: using System; public class Exercise

C# 3.0 Practical Learning

507

{ static void Main() { double numbers = new double[5]; } }

Using the var keyword, this array can also be declared as follows: using System; public class Exercise { static void Main() { var Numbers = new double[5]; } }

Practical Learning: Creating an Array 1. To create arrays, change the Programs.cs file as follows: using using using using

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

namespace VideoCollection1 { public class Program { static void Main(string[] args) { long[] ShelfNumbers = new long[10]; string[] Titles = new string[10]; string[] Directors = new string[10]; int[] Lengths = new int[10]; string[] Ratings = new string[10]; double[] Prices = new double[10]; } } }

2. Save the file

Introduction to Initializing an Array When creating an array, you can specify the number of items that make up its list. Each item of the series is referred to as a member or an element of the array. Once the array has been created, each one of its members is initialized with a 0 value. Most, if not all, of the time, you will need to change the value of each member to a value of your choice. This is referred to as initializing the array.

C# 3.0 Practical Learning

508

An array is primarily a variable; it is simply meant to carry more than one value. Like every other variable, an array can be initialized. There are two main techniques you can use to initialize an array. If you have declared an array as done above, to initialize it, you can access each one of its members and assign it a desired but appropriate value. In algebra, if you create a series of values as X1, X2, X3, X4, and X5, each member of this series can be identified by its subscript number. In this case the subscripts are 1, 2, 3, 4, and 5. This subscript number is also called an index. In the case of an array also, each member can be referred to by an incremental number called an index. A C# (like a C/C++) array is zero-based. This means that the first member of the array has an index of 0, the second has an index of 1, and so on. In algebra, the series would be represented as X0, X1, X2, X3, and X4. In C#, the index of a member of an array is written in its own square brackets. This is the notation you would use to locate each member. One of the actions you can take would consist of assigning it a value. Here is an example: using System; public class Exercise { static void Main() { var Numbers = new double[5]; Numbers[0] Numbers[1] Numbers[2] Numbers[3] Numbers[4] }

= = = = =

12.44; 525.38; 6.28; 2448.32; 632.04;

}

Besides this technique, you can also initialize the array as a whole when declaring it. To do this, on the right side of the declaration, before the closing semi-colon, type the values of the array members between curly brackets and separated by a comma. Here is an example: using System; public class Exercise { static void Main() { var Numbers = new double[5] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; } }

If you use this second technique, you don't have to specify the number of items in the series. In this case, you can leave all square brackets empty: using System; public class Exercise

C# 3.0 Practical Learning

509

{

}; }

static void Main() { var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }

If you leave the square brackets empty, the compiler will figure out the number of items.

Practical Learning: Initializing Some Arrays 1. To initialize the arrays, change the file as follows: using using using using

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

namespace VideoCollection1 { class Program { static void Main(string[] args) { long[] ShelfNumbers = new long[] { 2985, 8024, 5170, 1304, 9187, 1193, 3082, 8632, 4633, 9623 }; string[] Titles = new string[] { "The Distinguished Gentleman", "A Perfect Murder", "Chalte Chalte", "Ransom", "Not Another Teen Movie", "Madhubaala", "Get Shorty", "Sneakers", "Born Invincible", "Hush" }; string[] Directors = new string[] { "Jonathan Lynn", "Andrew Davis", "Aziz Mirza", "Ron Howard", "Joel Gallen", "Shivram Yadav", "Barry Sonnenfeld", "Paul Alden Robinson", "Unknown", "Jonathan Darby" }; int[] Lengths = new int[] { 112, 108, 145, 121, 100, 0, 105, 126, 90, 96 }; string[] Ratings = new string[] { "R", "R", "N/R", "R", "Unrated", "N/R", "R", "PG-13", "N/R", "PG-13" }; double[] Prices = new double[] { 14.95D, 19.95D, 22.45D, 14.95D, 9.95D,

C# 3.0 Practical Learning

510

17.50D, } }

9.95D,

9.95D,

5.95D, 8.75D

};

}

2. Save the file

Other Techniques of Initializing an Array We have initialized our arrays so far with values we specified directly in the curly brackets. If you have declared and initialized some variables of the same type, you can use them to initialize an array. Here is an example: using System; public class Exercise { static void Main() { var Area = 97394.2204D; var Distance = 982.84D; var Level = 27D; var Quantity = 237957.704D; var Measures = new double[] { Area, Distance, Level, Quantity }; }

}

The values can also come from constant variables. Here is an example: using System; public class Exercise { static void Main() { const double PI = 3.141592653; var SqureRootOf2 = 1.414D; var e = 2.718D; const double RadiusOfEarth = 6370; // km var ln2 = 0.6931; ln2 }; } }

var Measures = new double[] { PI, SqureRootOf2, e, RadiusOfEarth,

The values can also come from calculations, whether the calculation is from an initialized variable or made locally in the curly brackets. Here is an example: using System; public class Exercise { static void Main()

C# 3.0 Practical Learning

511

{ const double DensityOfWater = 1000; // kg/m3 ; var MassOfEarth = 5.98 * 10e24; // kg var EarthMoonDistance = 2.39 * 10e5; // miles var Measures = new double[] { DensityOfWater, 9.30 * 10.7, MassOfEarth, EarthMoonDistance }; }

}

The rule to follow is that, at the time the array is created, the compiler must be able to know exactly the value of each member of the array, no guessing. All of the arrays we have declared so far were using only numbers. The numbers we used were decimal constants. If the array is made of integers, you can use decimal, hexadecimal values, or a combination of both. Here is an example: using System; public class Exercise { static void Main() { var Red = 0xFF0000; var SomeColor = 0x800000; var Colors = new int[] { 2510, Red, 818203, SomeColor, 0xF28AC }; }

}

An array can have types of values of any of the data types we have used so far. The rule to follow is that all members of the array must be of the same type. For example, you can declare an array of Boolean values, as long as all values can be evaluated to true or false. Here is an example: using System; public class Exercise { static void Main() { var FullTimeStudents = new bool[] { true, true, true, false, true, false }; } }

As stated already, each values of a Boolean array must be evaluated to true or false. This means that you can use variables or expressions as members of the array. Here is an example: using System; public class Exercise { static void Main() { var House1Value = 460885.85D;

C# 3.0 Practical Learning

512

var House2Value = 685770.00D; var Conparisons = new bool[] { 25 < 10, House1Value == House2Value, true }; } }

As we will see when studying arrays and classes, you can use this technique to create an array of dates, times, or date and time values. Here is an example: using System; public class Exercise { static void Main() { var DateHired = new DateTime(1998, 10, 08); var IndependenceDay = new DateTime(1960, 1, 1); }

var Dates = new DateTime[] { DateHired, IndependenceDay };

}

Accessing the Members of an Array Introduction After initializing an array, which means after each of its members has been given a value, you can access a member of the array to get, manipulate or even change its value. To access a member of the array, you use the square brackets as we saw above. As done for normal variables, one of the reasons of accessing a member of an array would be to display its value on the console screen, which can be done by passing it to a Console.Write() or a Console.WriteLine() method. Here is an example: using System; public class Exercise { static int Main() { var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; Console.Write(Numbers[3]); }

return 0;

}

In the same way, you can use the curly brackets notation to display the value of a member: using System;

C# 3.0 Practical Learning

513

public class Exercise { static int Main() { var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; Console.Write("Number: {0} ", Numbers[3]); }

return 0;

}

In the same way, you can access 1, a few or all members of the array.

Practical Learning: Using the Members of an Array 1. To show the values of a member of an array, change the Program.cs file as follows: using using using using

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

namespace VideoCollection1 { class Program { static void Main(string[] args) { long[] ShelfNumbers = new long[] { 2985, 8024, 5170, 1304, 9187, 1193, 3082, 8632 }; . . . No Change double[] Prices = new double[] { 14.95D, 19.95D, 22.45D, 14.95D, 9.95D, 17.50D, 9.95D, 9.95D, 5.95D, 8.75D };

} }

Console.WriteLine("==============================="); Console.WriteLine("Video Information"); Console.WriteLine("-------------------------------"); Console.WriteLine("Shelf #: {0}", ShelfNumbers[1]); Console.WriteLine("Title: {0}", Titles[1]); Console.WriteLine("Director: {0}", Directors[1]); Console.WriteLine("Length: {0} minutes", Lengths[1]); Console.WriteLine("Rating: {0}", Ratings[1]); Console.WriteLine("Price: {0}", Prices[1]); Console.WriteLine("===============================");

}

C# 3.0 Practical Learning

514

2. Execute the application and test it. Here is an example: =============================== Video Information ------------------------------Shelf #: 8024 Title: A Perfect Murder Director: Andrew Davis Length: 108 minutes Rating: R Price: 19.95 =============================== Press any key to continue . . .

3. Close the DOS window

For an Indexed Member of the Array We saw how you can use the square brackets to access each member of the array one at a time. That technique allows you to access one, a few, or each member. If you plan to access all members of the array instead of just one or a few, you can use the for loop. The formula to follow is: for(DataType Initializer; EndOfRange; Increment) Do What You Want;

In this formula, the for keyword, the parentheses, and the semi-colons are required. The DataType factor is used to specify how you will count the members of the array. The Initializer specifies how you would indicate the starting of the count. As seen in Lesson 12, this initialization could use an initialized int-based variable. The EndOfRange specifies how you would stop counting. If you are using an array, it should combine a conditional operation (<, <=, >, >=, or !=) with the number of members of the array minus 1. The Increment factor specifies how you would move from one index to the next. Here is an example: using System; public class Exercise { static int Main() { var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; for (var i = 0; i < 5; i++) Console.WriteLine(Numbers[i]); }

return 0;

}

C# 3.0 Practical Learning

515

This would produce: 12.44 525.38 6.28 2448.32 632.04 Press any key to continue . . .

When using a for loop, you should pay attention to the number of items you use. If you use a number n less than the total number of members - 1, only the first n members of the array would be accessed. Here is an example: using System; public class Exercise { static int Main() { var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; for (var i = 0; i < 3; i++) Console.WriteLine("Number: {0}", Numbers[i]); }

return 0;

}

This would produce: Number: 12.44 Number: 525.38 Number: 6.28 Press any key to continue . . .

On the other hand, if you use a number of items higher than the number of members minus one, the compiler would throw an IndexOutOfRangeException exception. Here is an example: using System; public class Exercise { static int Main() { var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; for (var i = 0; i < 12; i++) Console.WriteLine("Number: {0}", Numbers[i]); }

return 0;

}

This would produce:

C# 3.0 Practical Learning

516

After the nasty dialog box, you would get:

Therefore, when the number of items is higher than the number of members 1, the compiler may process all members. Then, when it is asked to process members beyond the allowed range, it finds out that there is no other array member. So it gets upset. You could solve the above problem by using exception handling to handle an IndexOutOfRangeException exception. Here is an example: using System; public class Exercise { static int Main()

C# 3.0 Practical Learning

517

{ var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04

};

try {

for (var i = 0; i < 12; i++) Console.WriteLine("Number: {0}", Numbers[i]);

} catch (IndexOutOfRangeException) { Console.WriteLine("You tried to access values beyond " + "the allowed range of the members of the array."); } return 0; } }

This would produce: Number: 12.44 Number: 525.38 Number: 6.28 Number: 2448.32 Number: 632.04 You tried to access values beyond the allowed range of the members of the array. Press any key to continue . . .

This solution should not be encouraged. Fortunately, C# and the .NET Framework provide better solutions.

Practical Learning: Using a for Loop 1. To use a for loop, change the Program.cs file as follows: using using using using

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

namespace VideoCollection1 { class Program { static void Main(string[] args) { . . . No Change Console.WriteLine("==============================="); Console.WriteLine("Videos Information"); for (int i = 0; i < 10; i++) { Console.WriteLine("==============================="); Console.WriteLine("Video {0}", i + 1); Console.WriteLine("-------------------------------");

C# 3.0 Practical Learning

518

Console.WriteLine("Shelf #: Console.WriteLine("Title: Console.WriteLine("Director: Console.WriteLine("Length: Console.WriteLine("Rating: Console.WriteLine("Price:

} }

{0}", ShelfNumbers[i]); {0}", Titles[i]); {0}", Directors[i]); {0} minutes", Lengths[i]); {0}", Ratings[i]); {0}", Prices[i]);

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

}

2. Execute the application to see the result: =============================== Videos Information =============================== Video 1 ------------------------------Shelf #: 2985 Title: The Distinguished Gentleman Director: Jonathan Lynn Length: 112 minutes Rating: R Price: 14.95 =============================== Video 2 ------------------------------Shelf #: 8024 Title: A Perfect Murder Director: Andrew Davis Length: 108 minutes Rating: R Price: 19.95 =============================== Video 3 ------------------------------Shelf #: 5170 Title: Chalte Chalte Director: Aziz Mirza Length: 145 minutes Rating: N/R Price: 22.45 =============================== Video 4 ------------------------------Shelf #: 1304 Title: Ransom Director: Ron Howard Length: 121 minutes Rating: R Price: 14.95 =============================== Video 5 ------------------------------Shelf #: 9187 Title: Not Another Teen Movie Director: Joel Gallen Length: 100 minutes

C# 3.0 Practical Learning

519

Rating: Unrated Price: 9.95 =============================== Video 6 ------------------------------Shelf #: 1193 Title: Madhubaala Director: Shivram Yadav Length: 0 minutes Rating: N/R Price: 17.5 =============================== Video 7 ------------------------------Shelf #: 3082 Title: Get Shorty Director: Barry Sonnenfeld Length: 105 minutes Rating: R Price: 9.95 =============================== Video 8 ------------------------------Shelf #: 8632 Title: Sneakers Director: Paul Alden Robinson Length: 126 minutes Rating: PG-13 Price: 9.95 =============================== Video 9 ------------------------------Shelf #: 4633 Title: Born Invincible Director: Unknown Length: 90 minutes Rating: N/R Price: 5.95 =============================== Video 10 ------------------------------Shelf #: 9623 Title: Hush Director: Jonathan Darby Length: 96 minutes Rating: PG-13 Price: 8.75 =============================== Press any key to continue . . .

For Each Member in the Array In a for loop, you should know the number of members of the array. If you don't, the C# language allows you to let the compiler use its internal mechanism to get this count and use it to know where to stop counting. To assist you with this, C# provides the foreach operator. To use it, the formula to follow is: C# 3.0 Practical Learning

520

foreach (type identifier in expression) statement

The foreach and the in keywords are required. The first factor of this syntax, type, can be var or the type of the members of the array. It can also be the name of a class as we will learn in Lesson 23. The identifier factor is a name of the variable you will use. The expression factor is the name of the array variable. The statement is what you intend to do with the identifier or as a result of accessing the member of the array. Like a for loop that accesses all members of the array, the foreach operator is used to access each array member, one at a time. Here is an example: using System; public class Exercise { static int Main() { var Numbers = new double[] { 12.44, 525.38, 6.28, 2448.32, 632.04 }; foreach(var n in Numbers) Console.WriteLine("Number: {0} ", n); return 0; }

}

This would produce: Employees Records Employee Name: Joan Fuller Employee Name: Barbara Boxen Employee Name: Paul Kumar Employee Name: Bertrand Entire

Anonymous Arrays Introduction In previous sections, when creating an array, we were specifying its type. As seen in our introduction to variables, a good feature of the var keyword is that, when using it to declare and initialize a variable, you ask the compiler to figure out what type of data the variable is holding. This concept is also valid for an array. An anonymous array is an array variable whose type is left to the compiler to determine, based on the types of values of the array.

Creating an Anonymous Array C# 3.0 Practical Learning

521

As done for variables so far, when creating an array, you can use the var keyword, initialize the array, but not specify its data type. The formula to use is: var ArrayName = new[] { Initialization };

The formula is almost similar to that of a normal array, with keywords and operators you are already familiar with. The ArrayName factor is the name of the variable. Notice that the new keyword is directly followed by the square brackets. In the curly brackets, you must initialize the array by providing the necessary values. For the compiler to be able to figure out the type and amount of memory to allocate for the array variable, all values must be of the same type or the same category: If each value is a number without a decimal part, the compiler checks their range and concludes whether the array needs 32 bits or 64 bits. Here is an example:



using System; using System.Linq; public class Exercise { static int Main() { var Naturals = new[] { 2735, 20, 3647597, 3408, 957 }; var Values = new[] { 0x91FF22, 8168, 0x80080, 0xF822FF, 202684 }; return 0; }

}

If the values are numeric but at least one of them includes a decimal part, the compiler concludes that the array is made of floating-point numbers. If you want to control their precision (float, double, or decimal), add the appropriate suffix to each value. This also means that you can use a combination of natural and decimal numbers, but the presence of at least one number with a decimal part would convert the array into floating point instead of int-based. Here is an example:



using System; using System.Linq; public class Exercise { static int Main() { var Singles = new[] { 1244F, 525.38F, 6.28F, 2448.32F, 632.04F }; var Doubles = new[] { 3.212D, 3047.098D, 732074.02, 18342.3579 }; var Values = new[] { 17.230M, 4808237M, 222.4203M, 948.002009M }; }

return 0;

}

C# 3.0 Practical Learning

522

If the members are made of true and false values, then compiler will allocate memory for Boolean values for the array. Here is an example:



using System; using System.Linq; public class Exercise { static int Main() { var Qualifications = new[] { true, true, false, true, false }; return 0; }

}

If the members contain values included in single-quotes, the array will be treated as a series of characters. Here is an example:



using System; using System.Linq; public class Exercise { static int Main() { var Categories = new[] { 'C', 'F', 'B', 'C', 'A' }; return 0; }

}

If the values of the members are included in double-quotes, then the array will be considered a group of strings. Here is an example:



using System; using System.Linq; public class Exercise { static int Main() { var Friends = new[] { "Mark", "Frank", "Charlotte", "Jerry" }; return 0; }

}

Accessing the Members of an Anonymous Array After creating an anonymous array, you can access each member using its index. Here is an example that uses a for loop: using System;

C# 3.0 Practical Learning

523

using System.Linq; public class Exercise { static int Main() { var Friends = new[] { "Mark", "Frank", "Charlotte", "Jerry" }; for (var i = 0; i < 4; i++) Console.WriteLine("Friend: {0}", Friends[i]); }

return 0;

}

This would produce: Friend: Mark Friend: Frank Friend: Charlotte Friend: Jerry Press any key to continue . . .

In the same way, you can use a foreach statement to access each member of the array. Here is an example: using System; using System.Linq; public class Exercise { static int Main() { var Friendlies = new[] { "Mark", "Frank", "Charlotte", "Jerry" }; for (var i = 0; i < 4; i++) Console.WriteLine("Friend: {0}", Friendlies[i]); Console.WriteLine("-----------------------------------"); var Qualifications = new[] { true, true, false, true, false }; foreach (var qualifies in Qualifications) Console.WriteLine("The Member Qualifies: {0}", qualifies); Console.WriteLine("-----------------------------------"); }

return 0;

}

This would produce: Friend: Mark Friend: Frank Friend: Charlotte Friend: Jerry ----------------------------------The Member Qualifies: True The Member Qualifies: True The Member Qualifies: False The Member Qualifies: True

C# 3.0 Practical Learning

524

The Member Qualifies: False ----------------------------------Press any key to continue . . .

Selecting a Value From an Array Introduction Because an array is a list of items, it could include values that are not useful in all scenarios. For example, having an array made of too many values, at one time you may want to isolate only the first n members of the array, or the last m members of the array, or a range of members from an index i to an index j. Another operation you may be interested to perform is to find out if this or that value exists in the array. One more interesting operation would be to find out what members or how many members of the array respond to this or that criterion. All these operations are useful and possible with different techniques.

Using for and foreach Consider the following program: using System; using System.Linq; public class Exercise { static int Main() { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; for (var i = 0; i < 10; i++) Console.WriteLine("Number: {0}", Numbers[i]); return 0; }

}

This would produce: Number: 102 Number: 44 Number: 525 Number: 38 Number: 6 Number: 28 Number: 24481 Number: 327 Number: 632 Number: 104 Press any key to continue . . .

C# 3.0 Practical Learning

525

Imagine you want to access only the first n members of the array. To do this, you can use an if conditional statement nested in a for or a foreach loop. Here is an example that produces the first 4 values of the array: using System; using System.Linq; public class Exercise { static int Main() { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; for (var i = 0; i < 10; i++) if (i < 4) Console.WriteLine("Number: {0}", Numbers[i]); }

return 0;

}

This would produce: Number: 102 Number: 44 Number: 525 Number: 38 Press any key to continue . . .

You can use the same technique to get the last m members of the array. You can also use a similar technique to get one or a few values inside of the array, based on a condition of your choice. Here is an example that gets the values that are multiple of 5 from the array: using System; using System.Linq; public class Exercise { static int Main() { var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481, 327, 632, 104 }; for (var i = 0; i < 10; i++) if (Numbers[i] % 5 == 0) Console.WriteLine("Number: {0}", Numbers[i]); }

return 0;

}

This would produce: Number: 525 Press any key to continue . . .

Practical Learning: Checking a Value From an Array C# 3.0 Practical Learning

526

1. To check a value from an array, change the file as follows: using using using using

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

namespace VideoCollection1 { class Program { static void Main(string[] args) { long[] ShelfNumbers = new long[] { 2985, 8024, 5170, 1304, 9187, 1193, 3082, 8632, 4633, 9623 }; string[] Titles = new string[] { "The Distinguished Gentleman", "A Perfect Murder", "Chalte Chalte", "Ransom", "Not Another Teen Movie", "Madhubaala", "Get Shorty", "Sneakers", "Born Invincible", "Hush" }; string[] Directors = new string[] { "Jonathan Lynn", "Andrew Davis", "Aziz Mirza", "Ron Howard", "Joel Gallen", "Shivram Yadav", "Barry Sonnenfeld", "Paul Alden Robinson", "Unknown", "Jonathan Darby" }; int[] Lengths = new int[] { 112, 108, 145, 121, 100, 0, 105, 126, 90, 96 }; string[] Ratings = new string[] { "R", "R", "N/R", "R", "Unrated", "N/R", "R", "PG-13", "N/R", "PG-13" }; double[] Prices = new double[] { 14.95D, 19.95D, 22.45D, 14.95D, 9.95D, 17.50D, 9.95D, 9.95D, 5.95D, 8.75D }; foreach (int Code in ShelfNumbers) Console.Write("{0}\t", Code); long ShelfNumber = 0; Console.Write("Enter the shelf number of the " + "video you want to check: "); ShelfNumber = long.Parse(Console.ReadLine()); Console.WriteLine(); for (int i = 0; i < 10; i++)

C# 3.0 Practical Learning

527

{

Lengths[i]);

if (ShelfNumbers[i] == ShelfNumber) { Console.WriteLine("==============================="); Console.WriteLine("Video Information"); Console.WriteLine("-------------------------------"); Console.WriteLine("Shelf #: {0}", ShelfNumbers[i]); Console.WriteLine("Title: {0}", Titles[i]); Console.WriteLine("Director: {0}", Directors[i]); Console.WriteLine("Length: {0} minutes", Console.WriteLine("Rating: Console.WriteLine("Price:

} }

{0}", Ratings[i]); {0}", Prices[i]);

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

}

2. Execute the application to test it 3. When prompted, enter a shelf number and press Enter. Here is an example: 2985 8024 5170 1304 9187 1193 3082 8632 9623 Enter the shelf number of the video you want to check: 8632

4633

=============================== Video Information ------------------------------Shelf #: 8632 Title: Sneakers Director: Paul Alden Robinson Length: 126 minutes Rating: PG-13 Price: 9.95 =============================== Press any key to continue . . .

4. Close the DOS window and return to your programming environment

C# 3.0 Practical Learning

528

Arrays and Classes An Array of a Primitive Type as a Field Introduction As we have used them so far, an array is primarily a variable. As such, it can be declared as a member variable of a class. To create a field as an array, you can declare it like a normal array in the body of the class. Here is an example: public class CoordinateSystem { private int[] Points; }

Like any field, when an array has been declared as a member variable, it is made available to all the other members of the same class. You can use this feature to initialize the array in one method and let other methods use the initialized variable. This also means that you don't have to pass the array as argument nor do you have to explicitly return it from a method.

After or when declaring an array, you must make sure you allocate memory for it prior to using. Unlike C++, you can allocate memory for an array when declaring it. Here is an example: public class CoordinateSystem { private int[] Points = new int[4]; }

You can also allocate memory for an array field in a constructor of the class. Here is an example: public class CoordinateSystem { private int[] Points; public CoordinateSystem() { Points = new int[4]; } }

If you plan to use the array as soon as the program is running, you can initialize it using a constructor or a method that you know would be called before the array can be used. Here is an example: C# 3.0 Practical Learning

529

public class CoordinateSystem { private int[] Points; public CoordinateSystem() { Points = new int[4];

}

Points[0] Points[1] Points[2] Points[3]

= = = =

2; 5; 2; 8;

}

Practical Learning: Introducing Arrays and Classes 1. Start Microsoft Visual C# and create a Console Application named RentalProperties1

2. To create a new class, in the Solution Explorer, right-click RenatlProperties1 -> Add -> Class... 3. Set the Name to RentalProperty and press Enter 4. Change the file as follows: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace RentalProperties1 { public enum PropertyType { SingleFamily, Townhouse, Apartment, Unknown }; public class RentalProperty { private long[] PropertyNumbers; private PropertyType[] Types; private short[] Bedrooms; private float[] Bathrooms; private double[] MonthlyRent; public RentalProperty() { PropertyNumbers = new long[] { 192873, 498730, 218502, 612739, 457834, 927439, 570520, 734059 }; Types = new PropertyType[] { PropertyType.SingleFamily, PropertyType.SingleFamily, PropertyType.Apartment, PropertyType.Apartment, PropertyType.Townhouse, PropertyType.Apartment, PropertyType.Apartment, PropertyType.Townhouse };

C# 3.0 Practical Learning

530

Bedrooms = new short[] { 5, 4, 2, 1, 3, 1, 3, 4 }; Bathrooms = new float[] { 3.50F, 2.50F, 1.00F, 1.00F, 2.50F, 1.00F, 2.00F, 1.50F };

} }

MonthlyRent = new double[] { 2250.00D, 1885.00D, 1175.50D, 945.00D, 1750.50D, 1100.00D, 1245.95D, 1950.25D };

}

5. Save all and accept the suggested name of the project

Presenting the Array After an array has been created as a field, it can be used by any other member of the same class. Based on this, you can use a member of the same class to request values that would initialize it. You can also use another method to explore the array. Here is an example: using System; public class CoordinateSystem { private int[] Points; public CoordinateSystem() { Points = new int[4]; Points[0] Points[1] Points[2] Points[3]

= = = =

2; -5; 2; 8;

} public void ShowPoints() { Console.WriteLine("Points Coordinates"); Console.WriteLine("P({0}, {1})", Points[0], Points[1]); Console.WriteLine("Q({0}, {1})", Points[2], Points[3]); } } public class Exercise { static int Main() { var Coordinates = new CoordinateSystem(); Coordinates.ShowPoints(); return 0; }

}

This would produce: Points Coordinates

C# 3.0 Practical Learning

531

P(2, -5) Q(2, 8) Press any key to continue . . .

Practical Learning: Presenting an Array 1. To show the values of the array, change the file as follows: using using using using

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

namespace RentalProperties1 { public enum PropertyType { SingleFamily, Townhouse, Apartment, Unknown }; public class RentalProperty { private long[] PropertyNumbers; private PropertyType[] Types; private short[] Bedrooms; private float[] Bathrooms; private double[] MonthlyRent; public RentalProperty() { PropertyNumbers = new long[] { 192873, 498730, 218502, 612739, 457834, 927439, 570520, 734059 }; Types = new PropertyType[] { PropertyType.SingleFamily, PropertyType.SingleFamily, PropertyType.Apartment, PropertyType.Apartment, PropertyType.Townhouse, PropertyType.Apartment, PropertyType.Apartment, PropertyType.Townhouse }; Bedrooms = new short[] { 5, 4, 2, 1, 3, 1, 3, 4 }; Bathrooms = new float[] { 3.50F, 2.50F, 1.00F, 1.00F, 2.50F, 1.00F, 2.00F, 1.50F };

}

); Rent"); );

MonthlyRent = new double[] { 2250.00D, 1885.00D, 1175.50D, 945.00D, 1750.50D, 1100.00D, 1245.95D, 1950.25D };

public void ShowListing() { Console.WriteLine("Properties Listing"); Console.WriteLine("=============================================" Console.WriteLine("Prop #

Property Type Beds Baths Monthly

Console.WriteLine("---------------------------------------------" for (int i = 0; i < 8; i++)

C# 3.0 Practical Learning

532

{ Console.WriteLine("{0}\t{1}\t{2} {3:F}{4,12}", PropertyNumbers[i], Types[i], Bedrooms[i], Bathrooms[i], MonthlyRent[i]);

} Console.WriteLine("============================================="

); }

}

}

2. Access the Program.cs file and change it as follows: using using using using

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

namespace RentalProperties1 { class Program { static void Main(string[] args) { RentalProperty Property = new RentalProperty(); } }

Property.ShowListing();

}

3. Execute the application to see the result Properties Listing ============================================= Prop # Property Type Beds Baths Monthly Rent --------------------------------------------192873 SingleFamily 5 3.50 2250 498730 SingleFamily 4 2.50 1885 218502 Apartment 2 1.00 1175.5 612739 Apartment 1 1.00 945 457834 Townhouse 3 2.50 1750.5 927439 Apartment 1 1.00 1100 570520 Apartment 3 2.00 1245.95 734059 Townhouse 4 1.50 1950.25 ============================================= Press any key to continue . . .

4. Close the DOS window and return to your programming environment

Arrays and Methods Introduction

C# 3.0 Practical Learning

533

Each member of an array holds a legitimate value. Therefore, you can pass a single member of an array as argument. You can pass the name of the array variable with the accompanying index to a method. The main purpose of using an array is to use various values grouped under one name. Still, an array is primarily a variable. As such, it can be passed to a method and it can be returned from a method.

An Array Passed as Argument Like a regular variable, an array can be passed as argument. To do this, in the parentheses of a method, provide the data type, the empty square brackets, and the name of the argument. Here is an example: public class CoordinateSystem { public void ShowPoints(int[] Points) { } }

When an array has been passed to a method, it can be used in the body of the method as any array can be, following the rules of array variables. For example, you can display its values. The simplest way you can use an array is to display the values of its members. This could be done as follows: public class CoordinateSystem { public void ShowPoints(int[] Points) { Console.WriteLine("Points Coordinates"); Console.WriteLine("P({0}, {1})", Points[0], Points[1]); Console.WriteLine("Q({0}, {1})", Points[2], Points[3]); } }

To call a method that takes an array as argument, simply type the name of the array in the parentheses of the called method. Here is an example: using System; public class CoordinateSystem { public void ShowPoints(int[] Points) { Console.WriteLine("Points Coordinates"); Console.WriteLine("P({0}, {1})", Points[0], Points[1]); Console.WriteLine("Q({0}, {1})", Points[2], Points[3]); } } public class Exercise { static int Main() { var Points = new int[] { -3, 3, 6, 3 }; var Coordinates = new CoordinateSystem();

C# 3.0 Practical Learning

534

}

Coordinates.ShowPoints(Points); return 0;

}

This would produce: Points Coordinates P(-3, 3) Q(6, 3) Press any key to continue . . .

When an array is passed as argument to a method, the array is passed by reference. This means that, if the method makes any change to the array, the change would be kept when the method exits. You can use this characteristic to initialize an array from a method. Here is an example: using System; public class CoordinateSystem { public void Initialize(int[] Coords) { Coords[0] = -4; Coords[1] = -2; Coords[2] = -6; Coords[3] = 3; }

}

public void ShowPoints(int[] Points) { Console.WriteLine("Points Coordinates"); Console.WriteLine("P({0}, {1})", Points[0], Points[1]); Console.WriteLine("Q({0}, {1})", Points[2], Points[3]); }

public class Exercise { static int Main() { var System = new int[4]; var Coordinates = new CoordinateSystem(); Coordinates.Initialize(System); Coordinates.ShowPoints(System); return 0; }

}

This would produce: Points Coordinates P(-4, -2) Q(-6, 3) Press any key to continue . . .

Notice that the CreateNumbers() method receives an un-initialized array but returns it with new values. To enforce the concept of passing a variable by C# 3.0 Practical Learning

535

reference, you can also accompany an array argument with the ref keyword, both when defining the method and when calling it. Here is an example: using System; public class CoordinateSystem { public void Initialize(ref int[] Coords) { Coords[0] = -4; Coords[1] = -2; Coords[2] = -6; Coords[3] = 3; } public void ShowPoints(int[] Points) { Console.WriteLine("Points Coordinates"); Console.WriteLine("P({0}, {1})", Points[0], Points[1]); Console.WriteLine("Q({0}, {1})", Points[2], Points[3]); } } public class Exercise { static int Main() { var System = new int[4]; var Coordinates = new CoordinateSystem(); Coordinates.Initialize(ref System); Coordinates.ShowPoints(System); }

return 0;

}

Instead of just one, you can create a method that receive more than one array and you can create a method that receives a combination of one or more arrays and one or more regular arguments. There is no rule that sets some restrictions. You can also create a method that takes one or more arrays as argument(s) and returns a regular value of a primitive type.

Returning an Array From a Method Like a normal variable, an array can be returned from a method. This means that the method would return a variable that carries various values. When declaring or defining the method, you must specify its data type. When the method ends, it would return an array represented by the name of its variable. You can create a method that takes an array as argument and returns another array as argument.

C# 3.0 Practical Learning

536

To declare a method that returns an array, on the left of the method's name, provide the type of value that the returned array will be made of, followed by empty square brackets. Here is an example: using System; public class CoordinateSystem { public int[] Initialize() { } }

Remember that a method must always return an appropriate value depending on how it was declared. In this case, if it was specified as returning an array, then make sure it returns an array and not a regular variable. One way you can do this is to declare and possibly initialize a local array variable. After using the local array, you return only its name (without the square brackets). Here is an example: using System; public class CoordinateSystem { public int[] Initialize() { var Coords = new int[] { 12, 5, -2, -2 }; return Coords; }

}

When a method returns an array, that method can be assigned to an array declared locally when you want to use it. Remember to initialize a variable with such a method only if the variable is an array. Here is an example: using System; public class CoordinateSystem { public int[] Initialize() { var Coords = new int[] { 12, 5, -2, -2 }; }

}

return Coords;

public void ShowPoints(int[] Points) { Console.WriteLine("Points Coordinates"); Console.WriteLine("P({0}, {1})", Points[0], Points[1]); Console.WriteLine("Q({0}, {1})", Points[2], Points[3]); }

public class Exercise {

C# 3.0 Practical Learning

537

static int Main() { var System = new int[4]; var Coordinates = new CoordinateSystem(); System = Coordinates.Initialize(); Coordinates.ShowPoints(System); return 0; }

}

The method could also be called as follows: public class Exercise { static int Main() { var Coordinates = new CoordinateSystem(); var System = Coordinates.Initialize(); Coordinates.ShowPoints(System); return 0; }

}

If you initialize an array variable with a method that doesn't return an array, you would receive an error.

Main()'s Argument Introduction When a program starts, it looks for an entry point. This is the role of the Main() method. In fact, a program, that is an executable program, starts by, and stops with, the Main() method. The way this works is that, at the beginning, the compiler looks for a method called Main. If it doesn't find it, it produces an error. If it finds it, it enters the Main() method in a top-down approach, starting just after the opening curly bracket. If it finds a problem and judges that it is not worth continuing, it stops and lets you know. If, or as long as, it doesn't find a problem, it continues line after line, with the option to even call or execute a method in the same file or in another file. This process continues to the closing curly bracket "}". Once the compiler finds the closing bracket, the whole program has ended and stops. If you want the user to provide additional information when executing your program, you can take care of this in the Main() method. Consider the following code written in a file saved as Exercise.cs: using System; public class Exercise { static int Main() {

C# 3.0 Practical Learning

538

string FirstName = "James"; string LastName = "Weinberg"; double WeeklyHours = 36.50; double HourlySalary = 12.58; string FullName = LastName + ", " + FirstName; double WeeklySalary = WeeklyHours * HourlySalary; Console.WriteLine("Employee Payroll"); Console.WriteLine("Full Name: {0}", FullName); Console.WriteLine("WeeklySalary: {0}", WeeklySalary.ToString("C")); return 0; } }

To execute the application, at the Command Prompt and after Changing to the Directory that contains the file, you would type csc Exercise.cs

and press Enter. To execute the program, you would type the name Exercise and press Enter. The program would then prompt you for the information it needs.

Command Request from Main() To compile a program, you would simply type the csc command at the command prompt. Then, to execute a program, you would type its name at the prompt. If you distribute a program, you would tell the user to type the name of the program at the command prompt. In some cases, you may want the user to type additional information besides the name of the program. To request additional information from the user, you can pass a string argument to the Main() method. The argument should be passed as an array and make sure you provide a name for the argument. Here is an example: using System; class ObjectName { static int Main(string[] args) { return 0; } }

The reason you pass the argument as an array is so you can use as many values as you judge necessary. To provide values at the command prompt, the user types the name of the program followed by each necessary value. Here is an example:

C# 3.0 Practical Learning

539

The values the user would provide are stored in a zero-based array without considering the name of the program. The first value (that is, after the name of the program) is stored at index 0, the second at index 1, etc. Based on this, the first argument is represented by args[0], the second is represented by args[1], etc. Each of the values the user types is a string. If any one of them is not a string, you should/must convert/cast its string first to the appropriate value. Consider the following source code: using System; namespace CSharpLessons { public class Exercise { static int Main(string[] Argument) { string FirstName; string LastName; Double WeeklyHours; Double HourlySalary; FirstName = Argument[0]; LastName = Argument[1]; WeeklyHours = Double.Parse(Argument[2]); HourlySalary = Double.Parse(Argument[3]); string FullName = LastName + ", " + FirstName; Double WeeklySalary = WeeklyHours * HourlySalary; Console.WriteLine("Employee Payroll"); Console.WriteLine("Full Name: {0}", FullName); Console.WriteLine("WeeklySalary: {0}", WeeklySalary.ToString("C")); return 0; }

}

}

C# 3.0 Practical Learning

540

To compile it at the Command Prompt, after switching to the directory that contains the file, you would type csc Exercise.cs

and press Enter. To execute the program, you would type Exercise followed by a first name, a last name, and two decimal values. An example would be Exercise Catherine Engolo 42.50 20.48

An Array of Objects Introduction As done for primitive types, you can create an array of values where each member of the array is based on a formal class. Of course, you must have a class first. You can use one of the already available classes or you can create your own class. Here is an example: using System; public enum EmploymentStatus { FullTime, PartTime, Unknown }; public class Employee { private long emplNbr; private string name; private EmploymentStatus st; private double wage; public long EmployeeNumber { get { return emplNbr; } set { emplNbr = value; } } public string EmployeeName { get { return name; } set { name = value; }

C# 3.0 Practical Learning

541

} public EmploymentStatus Status { get { return st; } set { st = value; } } public double HourlySalary { get { return wage; } set { wage = value; } } }

Practical Learning: Introducing Arrays of Objects 1. Create a new Console Application named RentalProperties2 2. To create a new class, in the Solution Explorer, right-click RenatlProperties1 -> Add -> Class... 3. Set the Name to RentalProperty and press Enter 4. Change the file as follows: using using using using

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

namespace RentalProperties2 { public enum PropertyType { SingleFamily, Townhouse, Apartment, Unknown }; public class RentalProperty { private long nbr; private PropertyType tp; private short bd; private float bt; private double rnt; public RentalProperty() { nbr = 0; tp = PropertyType.Unknown; bd = 0; bt = 0.0F; rnt = 0D; } public RentalProperty(long PropNbr, PropertyType Type, short Beds, float Baths, double Rent)

C# 3.0 Practical Learning

542

{

}

PropNbr = nbr; Type = PropertyType.Unknown; Beds = bd; Baths = bt; Rent = rnt;

public long PropertyNumber { get { return nbr; } set { nbr = value; } } public PropertyType TypeOfProperty { get { return tp; } set { tp = value; } } public short Bedrooms { get { return bd; } set { bd = value; } } public float Bathrooms { get { return bt; } set { bt = value; } } public double MonthlyRent { get { return rnt; } set { rnt = value; } } }

}

5. Save all and accept the suggested name of the project

Creating an Array of Objects To create an array of objects, you can declare an array variable and use the square brackets to specify its size. Here is an example: public static class Exercise { static void Main(string[] args) { Employee[] StaffMembers = new Employee[3]; }

return 0;

}

You can also use the var keyword to create the array but omit the first square brackets. Here is an example: 543 C# 3.0 Practical Learning

public static class Exercise { static void Main(string[] args) { var StaffMembers = new Employee[3]; return 0; }

}

Initializing an Array of Objects If you create an array like this, you can then access each member using its index, allocate memory for it using the new operator, then access each of its fields, still using its index, to assign it the desired value. Here is an example: public static class Exercise { static void Main(string[] args) { var StaffMembers = new Employee[3]; StaffMembers[0] = new Employee(); StaffMembers[0].EmployeeNumber = 20204; StaffMembers[0].EmployeeName = "Harry Fields"; StaffMembers[0].Status = EmploymentStatus.FullTime; StaffMembers[0].HourlySalary = 16.85; StaffMembers[1] = new Employee(); StaffMembers[1].EmployeeNumber = 92857; StaffMembers[1].EmployeeName = "Jennifer Almonds"; StaffMembers[1].Status = EmploymentStatus.FullTime; StaffMembers[1].HourlySalary = 22.25; StaffMembers[2] = new Employee(); StaffMembers[2].EmployeeNumber = 42963; StaffMembers[2].EmployeeName = "Sharon Culbritt"; StaffMembers[2].Status = EmploymentStatus.PartTime; StaffMembers[2].HourlySalary = 10.95; return 0; }

}

As an alternative, you can also initialize each member of the array when creating it. To do this, before the semi-colon of creating the array, open the curly brackets, allocate memory for each member and specify the values of each field. To do this, you must use a constructor that takes each member you want to initialize, as argument. Here is an example: using System; public enum EmploymentStatus { FullTime, PartTime, Unknown };

C# 3.0 Practical Learning

544

public class Employee { private long emplNbr; private string name; private EmploymentStatus st; private double wage; public Employee() { } public Employee(long Number, string Name, EmploymentStatus EStatus, double Salary) { emplNbr = Number; name = Name; st = EStatus; wage = Salary; } public long EmployeeNumber { get { return emplNbr; } set { emplNbr = value; } } public string EmployeeName { get { return name; } set { name = value; } } public EmploymentStatus Status { get { return st; } set { st = value; } }

}

public double HourlySalary { get { return wage; } set { wage = value; } }

public static class Exercise { static void Main(string[] args) { var StaffMembers = new Employee[] { new Employee(20204, "Harry Fields", EmploymentStatus.FullTime, 16.85), new Employee(92857, "Jennifer Almonds", EmploymentStatus.FullTime, 22.25), new Employee(42963, "Sharon Culbritt", EmploymentStatus.PartTime, 10.95) };

C# 3.0 Practical Learning

545

return 0; }

}

If using the var keyword and a constructor to initialize the array, you can omit calling the name of the class before the square brackets. Here is an example: public static class Exercise { static void Main(string[] args) { var StaffMembers = new[] { new Employee(20204, "Harry Fields", EmploymentStatus.FullTime, 16.85), new Employee(92857, "Jennifer Almonds", EmploymentStatus.FullTime, 22.25), new Employee(42963, "Sharon Culbritt", EmploymentStatus.PartTime, 10.95) }; return 0; }

}

Accessing the Members of the Array After creating and initializing the array, you can use it as you see fit. For example, you may want to display its values to the user. You can access any member of the array by its index, then use the same index to get its field(s) and consequently its (their) value(s). Here is an example: public static class Exercise { static void Main(string[] args) { var StaffMembers = new Employee[] { new Employee(20204, "Harry Fields", EmploymentStatus.FullTime, 16.85), new Employee(92857, "Jennifer Almonds", EmploymentStatus.FullTime, 22.25), new Employee(42963, "Sharon Culbritt", EmploymentStatus.PartTime, 10.95) }; Console.WriteLine("Employee Record"); Console.WriteLine("---------------------------"); Console.WriteLine("Employee #: {0}", StaffMembers[2].EmployeeNumber); Console.WriteLine("Full Name: {0}", StaffMembers[2].EmployeeName); Console.WriteLine("Status: {0}", StaffMembers[2].Status); Console.WriteLine("Hourly Wage {0}", StaffMembers[2].HourlySalary); Console.WriteLine("---------------------------\n"); return 0; }

C# 3.0 Practical Learning

546

}

This would produce: Employee Record --------------------------Employee #: 42963 Full Name: Sharon Culbritt Status: PartTime Hourly Wage 10.95 --------------------------Press any key to continue . . .

Once again, remember that the index you use must be higher than 0 but lower than the number of members - 1. Otherwise, the compiler would throw an IndexOutRangeException exception. In the same way, you can use a for loop to access all members of the array using their index. Here is an example: public static class Exercise { static void Main(string[] args) { var StaffMembers= new Employee[] { new Employee(20204, "Harry Fields", EmploymentStatus.FullTime, 16.85), new Employee(92857, "Jennifer Almonds", EmploymentStatus.FullTime, 22.25), new Employee(42963, "Sharon Culbritt", EmploymentStatus.PartTime, 10.95) }; Console.WriteLine("Employees Records"); Console.WriteLine("=========================="); for (int i = 0; i < 3; i++) { Console.WriteLine("Employee #: {0}", StaffMembers[i].EmployeeNumber); Console.WriteLine("Full Name: {0}", StaffMembers[i].EmployeeName); Console.WriteLine("Status: {0}", StaffMembers[i].Status); Console.WriteLine("Hourly Wage {0}", StaffMembers[i].HourlySalary); Console.WriteLine("---------------------------"); } return 0; }

}

To access each member of the array, you can use the foreach operator that allows you to use a name for each member and omit the square brackets. Here is an example: public static class Exercise { static void Main(string[] args)

C# 3.0 Practical Learning

547

{ var StaffMembers = new Employee[] { new Employee(20204, "Harry Fields", EmploymentStatus.FullTime, 16.85), new Employee(92857, "Jennifer Almonds", EmploymentStatus.FullTime, 22.25), new Employee(42963, "Sharon Culbritt", EmploymentStatus.PartTime, 10.95) }; Console.WriteLine("Employees Records"); Console.WriteLine("=========================="); foreach(var Member in StaffMembers) { Console.WriteLine("Employee #: {0}", Member.EmployeeNumber); Console.WriteLine("Full Name: {0}", Member.EmployeeName); Console.WriteLine("Status: {0}", Member.Status); Console.WriteLine("Hourly Wage {0}", Member.HourlySalary); Console.WriteLine("---------------------------"); } return 0; }

}

This would produce: Employees Records ========================== Employee #: 20204 Full Name: Harry Fields Status: FullTime Hourly Wage 16.85 --------------------------Employee #: 92857 Full Name: Jennifer Almonds Status: FullTime Hourly Wage 22.25 --------------------------Employee #: 42963 Full Name: Sharon Culbritt Status: PartTime Hourly Wage 10.95 --------------------------Press any key to continue . . .

Practical Learning: Using an Array of Objects 1. Access the Program.cs file and change it file as follows: using using using using

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

namespace RentalProperties2 {

C# 3.0 Practical Learning

548

public class Program { static void Main(string[] args) { RentalProperty[] Properties = new RentalProperty[8]; Properties[0] = new RentalProperty(); Properties[0].PropertyNumber = 192873; Properties[0].TypeOfProperty = PropertyType.SingleFamily; Properties[0].Bedrooms = 5; Properties[0].Bathrooms = 3.50F; Properties[0].MonthlyRent = 2250.00D; Properties[1] = new RentalProperty(); Properties[1].PropertyNumber = 498730; Properties[1].TypeOfProperty = PropertyType.SingleFamily; Properties[1].Bedrooms = 4; Properties[1].Bathrooms = 2.50F; Properties[1].MonthlyRent = 1885.00D; Properties[2] = new RentalProperty(); Properties[2].PropertyNumber = 218502; Properties[2].TypeOfProperty = PropertyType.Apartment; Properties[2].Bedrooms = 2; Properties[2].Bathrooms = 1.00F; Properties[2].MonthlyRent = 1175.50D; Properties[3] = new RentalProperty(); Properties[3].PropertyNumber = 612739; Properties[3].TypeOfProperty = PropertyType.Apartment; Properties[3].Bedrooms = 1; Properties[3].Bathrooms = 1.00F; Properties[3].MonthlyRent = 945.00D; Properties[4] = new RentalProperty(); Properties[4].PropertyNumber = 457834; Properties[4].TypeOfProperty = PropertyType.Townhouse; Properties[4].Bedrooms = 3; Properties[4].Bathrooms = 2.50F; Properties[4].MonthlyRent = 1750.50D; Properties[5] = new RentalProperty(); Properties[5].PropertyNumber = 927439; Properties[5].TypeOfProperty = PropertyType.Apartment; Properties[5].Bedrooms = 1; Properties[5].Bathrooms = 1.00F; Properties[5].MonthlyRent = 1100.00D; Properties[6] = new RentalProperty(); Properties[6].PropertyNumber = 570520; Properties[6].TypeOfProperty = PropertyType.Apartment; Properties[6].Bedrooms = 3; Properties[6].Bathrooms = 2.00F; Properties[6].MonthlyRent = 1245.95D; Properties[7] = new RentalProperty(); Properties[7].PropertyNumber = 734059; Properties[7].TypeOfProperty = PropertyType.Townhouse; Properties[7].Bedrooms = 4; Properties[7].Bathrooms = 1.50F; Properties[7].MonthlyRent = 1950.25D; Console.WriteLine("Properties Listing"); Console.WriteLine("=============================================" );

Console.WriteLine("Prop #

Property Type Beds Baths Monthly

Rent");

C# 3.0 Practical Learning

549

Console.WriteLine("---------------------------------------------" );

for (int i = 0; i < 8; i++) { Console.WriteLine("{0}\t{1}\t{2} {3:F}{4,12}", Properties[i].PropertyNumber, Properties[i].TypeOfProperty, Properties[i].Bedrooms, Properties[i].Bathrooms, Properties[i].MonthlyRent); } Console.WriteLine("============================================="

); }

}

}

2. Execute the application to see the result Properties Listing ============================================= Prop # Property Type Beds Baths Monthly Rent --------------------------------------------192873 SingleFamily 5 3.50 2250 498730 SingleFamily 4 2.50 1885 218502 Apartment 2 1.00 1175.5 612739 Apartment 1 1.00 945 457834 Townhouse 3 2.50 1750.5 927439 Apartment 1 1.00 1100 570520 Apartment 3 2.00 1245.95 734059 Townhouse 4 1.50 1950.25 ============================================= Press any key to continue . . .

3. Close the DOS window and return to your programming environment

A Class Array as a Field Introduction Like a primitive type, an array of objects can be made a field of a class. You can primarily declare the array and specify its size. Here is an example: public class CompanyRecords { Employee[] Employees = new Employee[2]; }

After doing this, you can then initialize the array from the index of each member. Alternatively, as we saw for field arrays of primitive types, you can declare the array in the body of the class, then use a constructor or another method of the class to allocate memory for it. To initialize the array, remember that each member is a value that must be allocated on the heap. Therefore, apply the new operator on each member of the array to allocate its memory, and then initialize it. Here is an example: 550 C# 3.0 Practical Learning

public class CompanyRecords { Employee[] Employees; public CompanyRecords() { Employees = new Employee[2]; Employees[0] = new Employee(); Employees[0].EmployeeNumber = 70128; Employees[0].EmployeeName = "Frank Dennison"; Employees[0].Status = EmploymentStatus.PartTime; Employees[0].HourlySalary = 8.65; Employees[1] = new Employee(); Employees[1].EmployeeNumber = 24835; Employees[1].EmployeeName = "Jeffrey Arndt"; Employees[1].Status = EmploymentStatus.Unknown; Employees[1].HourlySalary = 16.05; }

}

If the class used as field has an appropriate constructor, you can use it to initialize each member of the array. Here is an example: public class CompanyRecords { Employee[] Employees; public CompanyRecords() { Employees = new Employee[] { new Employee(70128, "Justine Hearson", EmploymentStatus.PartTime, 10.62), new Employee(24835, "Bertha Hack", EmploymentStatus.FullTime, 18.94), new Employee(70128, "Frank Dennison", EmploymentStatus.Seasonal, 12.48), new Employee(24835, "Jeffrey Arndt", EmploymentStatus.PartTime, 16.05), }; } }

Using the Array Once you have created and initialized the array, you can use it as you see fit, such as displaying its values to the user. You must be able to access each member of the array, using its index. Once you have accessed member, you can get to its fields or properties. Here is an example: using System; public enum EmploymentStatus { FullTime, PartTime, Seasonal,

C# 3.0 Practical Learning

551

Unknown }; public class Employee { private long emplNbr; private string name; private EmploymentStatus st; private double wage; public Employee() { } public Employee(long Number, string Name, EmploymentStatus EStatus, double Salary) { emplNbr = Number; name = Name; st = EStatus; wage = Salary; } public long EmployeeNumber { get { return emplNbr; } set { emplNbr = value; } } public string EmployeeName { get { return name; } set { name = value; } } public EmploymentStatus Status { get { return st; } set { st = value; } }

}

public double HourlySalary { get { return wage; } set { wage = value; } }

public class CompanyRecords { Employee[] Employees; public CompanyRecords() { Employees = new Employee[] { new Employee(70128, "Justine Hearson", EmploymentStatus.PartTime, 10.62), new Employee(24835, "Bertha Hack", EmploymentStatus.FullTime, 18.94),

C# 3.0 Practical Learning

552

};

new Employee(70128, "Frank Dennison", EmploymentStatus.Seasonal, 12.48), new Employee(24835, "Jeffrey Arndt", EmploymentStatus.PartTime, 16.05),

} public void ShowRecords() { Console.WriteLine("Employees Records"); Console.WriteLine("==========================");

}

foreach (var Member in Employees) { Console.WriteLine("Employee #: {0}", Member.EmployeeNumber); Console.WriteLine("Full Name: {0}", Member.EmployeeName); Console.WriteLine("Status: {0}", Member.Status); Console.WriteLine("Hourly Wage {0}", Member.HourlySalary); Console.WriteLine("---------------------------"); }

} public static class Exercise { static void Main(string[] args) { var Records = new CompanyRecords(); Records.ShowRecords(); return 0; }

}

This would produce: Employees Records ========================== Employee #: 70128 Full Name: Justine Hearson Status: PartTime Hourly Wage 10.62 --------------------------Employee #: 24835 Full Name: Bertha Hack Status: FullTime Hourly Wage 18.94 --------------------------Employee #: 70128 Full Name: Frank Dennison Status: Seasonal Hourly Wage 12.48 --------------------------Employee #: 24835 Full Name: Jeffrey Arndt Status: PartTime Hourly Wage 16.05 --------------------------Press any key to continue . . .

C# 3.0 Practical Learning

553

Arrays of Objects and Methods Passing an Array of Objects as Argument As done for an array of a primitive type, you can pass an array of objects as arguments. You follow the same rules we reviewed; that is, in the parentheses of a method, enter the class name, the empty square brackets, and the name of the argument. Here is an example: public class CompanyRecords { public CompanyRecords(Employee[] Employees) { } }

You can then access each member of the argument and do what you judge necessary. For example, you can display the values that the argument is holding. To call a method that takes an array of objects, in its parentheses, just enter the name of the array. Here is an example: public class CompanyRecords { public CompanyRecords(Employee[] Employees) { Employees = new Employee[] { new Employee(70128, "Justine Hearson", EmploymentStatus.PartTime, 10.62), new Employee(24835, "Bertha Hack", EmploymentStatus.FullTime, 18.94), new Employee(70128, "Frank Dennison", EmploymentStatus.Seasonal, 12.48), new Employee(24835, "Jeffrey Arndt", EmploymentStatus.PartTime, 16.05), }; } } public static class Exercise { static void Main(string[] args) { var Values = new Employee[4]; CompanyRecords Records = new CompanyRecords(Values); Records.ShowRecords(); }

return 0;

}

As stated for an array of primitive type, an array of objects passed as argument is treated as a reference. You can use this characteristic of arrays C# 3.0 Practical Learning

554

to initialize the array. You can also indicate that the array is passed by reference by preceding its name with the ref keyword.

Returning an Array of Objects An array of objects can be returned from a method. To indicate this when defining the method, first type the name of the class followed by square brackets. Here is an example: public class CompanyRecords { public Employee[] RegisterEmployees() { } }

In the body of the method, you can take care of any assignment you want. The major rule to follow is that, before exiting the method, you must return an array of the class indicated on the left side of the method name. To use the method, you can simply call. If you want, since the method returns an array, you can retrieve that series and store it in a local array value for later use. Here is an example: using System; public enum EmploymentStatus { FullTime, PartTime, Seasonal, Unknown }; public class Employee { private long emplNbr; private string name; private EmploymentStatus st; private double wage; public Employee() { } public Employee(long Number, string Name, EmploymentStatus EStatus, double Salary) { emplNbr = Number; name = Name; st = EStatus; wage = Salary; } public long EmployeeNumber { get { return emplNbr; } set { emplNbr = value; }

C# 3.0 Practical Learning

555

} public string EmployeeName { get { return name; } set { name = value; } } public EmploymentStatus Status { get { return st; } set { st = value; } } public double HourlySalary { get { return wage; } set { wage = value; } } } public class CompanyRecords { public CompanyRecords() { } public Employee[] RegisterEmployees() { var Employees = new Employee[] { new Employee(70128, "Justine Hearson", EmploymentStatus.PartTime, 10.62), new Employee(24835, "Bertha Hack", EmploymentStatus.FullTime, 18.94), new Employee(70128, "Frank Dennison", EmploymentStatus.Seasonal, 12.48), new Employee(24835, "Jeffrey Arndt", EmploymentStatus.PartTime, 16.05), }; return Employees; } public void ShowRecords(ref Employee[] Records) { Console.WriteLine("Employees Records"); Console.WriteLine("==========================");

}

foreach (var Staff in Records) { Console.WriteLine("Employee #: {0}", Staff.EmployeeNumber); Console.WriteLine("Full Name: {0}", Staff.EmployeeName); Console.WriteLine("Status: {0}", Staff.Status); Console.WriteLine("Hourly Wage {0}", Staff.HourlySalary); Console.WriteLine("---------------------------"); }

} public static class Exercise

C# 3.0 Practical Learning

556

{ static void Main(string[] args) { var Records = new CompanyRecords(); var Contractors = Records.RegisterEmployees(); Records.ShowRecords(ref Contractors); return 0; }

}

Practical Learning: Using Array of Objects With Methods 1. To apply what we learned in the last few sections, change the file as follows: using using using using

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

namespace RentalProperties2 { public class Program { private static void ShowProperties(RentalProperty[] Properties) { Console.WriteLine("Properties Listing"); Console.WriteLine("========================================== ==="); Console.WriteLine("Prop # Property Type Beds Baths Monthly Rent"); Console.WriteLine("--------------------------------------------"); for (int i = 0; i < 8; i++) { Console.WriteLine("{0}\t{1}\t{2} {3:F}{4,12}", Properties[i].PropertyNumber, Properties[i].TypeOfProperty, Properties[i].Bedrooms, Properties[i].Bathrooms, Properties[i].MonthlyRent); } Console.WriteLine("========================================== ==="); } private static RentalProperty[] CreateListing() { RentalProperty[] HousesToRent = new RentalProperty[8]; HousesToRent[0] = new RentalProperty(); HousesToRent[0].PropertyNumber = 192873; HousesToRent[0].TypeOfProperty = PropertyType.SingleFamily; HousesToRent[0].Bedrooms = 5; HousesToRent[0].Bathrooms = 3.50F; HousesToRent[0].MonthlyRent = 2250.00D; 557 C# 3.0 Practical Learning

HousesToRent[1] = new RentalProperty(); HousesToRent[1].PropertyNumber = 498730; HousesToRent[1].TypeOfProperty = PropertyType.SingleFamily; HousesToRent[1].Bedrooms = 4; HousesToRent[1].Bathrooms = 2.50F; HousesToRent[1].MonthlyRent = 1885.00D; HousesToRent[2] = new RentalProperty(); HousesToRent[2].PropertyNumber = 218502; HousesToRent[2].TypeOfProperty = PropertyType.Apartment; HousesToRent[2].Bedrooms = 2; HousesToRent[2].Bathrooms = 1.00F; HousesToRent[2].MonthlyRent = 1175.50D; HousesToRent[3] = new RentalProperty(); HousesToRent[3].PropertyNumber = 612739; HousesToRent[3].TypeOfProperty = PropertyType.Apartment; HousesToRent[3].Bedrooms = 1; HousesToRent[3].Bathrooms = 1.00F; HousesToRent[3].MonthlyRent = 945.00D; HousesToRent[4] = new RentalProperty(); HousesToRent[4].PropertyNumber = 457834; HousesToRent[4].TypeOfProperty = PropertyType.Townhouse; HousesToRent[4].Bedrooms = 3; HousesToRent[4].Bathrooms = 2.50F; HousesToRent[4].MonthlyRent = 1750.50D; HousesToRent[5] = new RentalProperty(); HousesToRent[5].PropertyNumber = 927439; HousesToRent[5].TypeOfProperty = PropertyType.Apartment; HousesToRent[5].Bedrooms = 1; HousesToRent[5].Bathrooms = 1.00F; HousesToRent[5].MonthlyRent = 1100.00D; HousesToRent[6] = new RentalProperty(); HousesToRent[6].PropertyNumber = 570520; HousesToRent[6].TypeOfProperty = PropertyType.Apartment; HousesToRent[6].Bedrooms = 3; HousesToRent[6].Bathrooms = 2.00F; HousesToRent[6].MonthlyRent = 1245.95D; HousesToRent[7] = new RentalProperty(); HousesToRent[7].PropertyNumber = 734059; HousesToRent[7].TypeOfProperty = PropertyType.Townhouse; HousesToRent[7].Bedrooms = 4; HousesToRent[7].Bathrooms = 1.50F; HousesToRent[7].MonthlyRent = 1950.25D; }

return HousesToRent;

static void Main(string[] args) { RentalProperty[] Properties = CreateListing(); ShowProperties(Properties); }

}

}

2. Execute the application to see the result 3. Close the DOS window and return to your programming environment

C# 3.0 Practical Learning

558

Arrays and Delegates Introduction While a regular method can be used to return an array, you can use the features of a delegate to return an array of methods or to take an array of methods as arguments. Of course before proceeding, you must first create the necessary delegate. Here is an example: using System; delegate double Measure(double R); public static class Program { static int Main(string[] args) { return 0; } }

Before creating the array, you must first know or have the methods you would be referring to. These methods must have a similar signature. This means that they must return the same type of value, they must have the same number of arguments and they must have the same type(s) of argument(s), if any. Here are examples of such functions: using System; delegate double Measure(double R); public class Circle { const double PI = 3.14159; double Diameter(double Radius) { return Radius * 2; } double Circumference(double Radius) { return Diameter(Radius) * PI; }

}

double Area(double Radius) { return Radius * Radius * PI; }

public static class Program { static void Main(string[] args) return 0; }

{

C# 3.0 Practical Learning

559

}

An Array of Delegates To create an array of delegates, declare a normal array as we have done so far. You can initialize each member using its index and calling the corresponding method. This can be done as follows: using System; delegate double Measure(double R); public class Circle { const double PI = 3.14159; public double Diameter(double Radius) { return Radius * 2; } public double Circumference(double Radius) { return Diameter(Radius) * PI; }

}

public double Area(double Radius) { return Radius * Radius * PI; }

public static class Program { static void Main(string[] args) { double R = 12.55; Circle circ = new Circle(); Measure[] Calc = new Measure[3]; Calc[0] = new Measure(circ.Diameter); double D = Calc[0](R); Calc[1] = new Measure(circ.Circumference); double C = Calc[1](R); Calc[2] = new Measure(circ.Area); double A = Calc[2](R); Console.WriteLine("Circle Characteristics"); Console.WriteLine("Diameter: {0}", D); Console.WriteLine("Circumference: {0}", C); Console.WriteLine("Area: {0}\n", A); }

return 0;

}

You can also list the members of the array when creating it. After creating the array, you can retrieve its value and store it in a variable. Here is an example: public static class Program

C# 3.0 Practical Learning

560

{ static void Main(string[] args) { double R = 12.55; Circle circ = new Circle(); Measure[] Calc = new Measure[] { new Measure(circ.Diameter), new Measure(circ.Circumference), new Measure(circ.Area) }; double D = Calc[0](R); double C = Calc[1](R); double A = Calc[2](R); Console.WriteLine("Circle Characteristics"); Console.WriteLine("Diameter: {0}", D); Console.WriteLine("Circumference: {0}", C); Console.WriteLine("Area: {0}\n", A); return 0; }

}

The above code could also be written as follows: public static class Program { static void Main(string[] args) { double R = 12.55; Circle circ = new Circle(); Measure[] Calc = new Measure[] { new Measure(circ.Diameter), new Measure(circ.Circumference), new Measure(circ.Area) }; Console.WriteLine("Circle Characteristics"); Console.WriteLine("Diameter: {0}", Calc[0](R)); Console.WriteLine("Circumference: {0}", Calc[1](R)); Console.WriteLine("Area: {0}\n", Calc[2](R)); }

return 0;

}

This would produce: Circle Characteristics Diameter: 25.1 Circumference: 78.8539 Area: 494.808

C# 3.0 Practical Learning

561

Multidimensional Arrays Fundamentals of Multidimensional Arrays Introduction The arrays we used so far were made of a uniform series, where all members consisted of a simple list, like a column of names on a piece of paper. Also, all items fit in one list. This type of array is referred to as onedimensional. In some cases, you may want to divide the list in delimited sections. For example, if you create a list of names, you may want part of the list to include family members and another part of the list to include friends. Instead of creating a second list, you can add a second dimension to the list. In other words, you would create a list of a list, or one list inside of another list, although the list is still made of items with common characteristics.

A multidimensional array is a series of arrays so that each arrays contains its own sub-array(s).

Practical Learning: Introducing Multidimensional Arrays 1. Create a new Console Application named DepartmentStore3 2. Change the Program.cs file as follows: using using using using

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

namespace DepartmentStore3 { public class Program { static void Main(string[] args) { long ItemID = 0; string Description = "Unknown"; double Price = 0.00D; Console.WriteLine("Receipt"); Console.WriteLine("Item Number: {0}", ItemID); Console.WriteLine("Description: {0}", Description); Console.WriteLine("Unit Price: {0:C}\n", Price);

C# 3.0 Practical Learning

562

} }

}

3. Execute the application to see the result. This would produce: Receipt Item Number: 0 Description: Unknown Unit Price: $0.00 Press any key to continue . . .

4. Close the DOS window

Creating a Two-Dimensional Array The most basic multidimensional array is made of two dimensions. This is referred to as two-dimensional. To create a two-dimensional array, declare the array variable as we have done so far but add a comma in the square brackets. The formula you would use is: DataType[,] VariableName;

The pair of brackets is empty but must contain a comma. There are various ways you can initialize a two-dimensional array. If you are declaring the array variable but are not ready to initialize it, use the following formula: DataType[,] VariableName = new DataType[Number1,Number2];

Or you can use the var keyword: var VariableName = new DataType[Number1,Number2];

Either way, in the right pair of square brackets, enter two integers separated by a comma. Here is an example: using System; public static class Exercise { public static int Main(string[] args) { var Members = new string[2, 4]; }

return 0;

}

In our declaration, the Members variable contains two lists. Each of the two lists contains 4 elements. This means that the first list contains 4 elements and the second list contains 4 elements. Therefore, the whole list is made of 8 elements (2 * 4 = 8). Because the variable is declared as a string, each of the 8 items must be a string. You can also create a two-dimensional array that takes more than two lists, such as 3, 4, 5 or more. Here is an example: C# 3.0 Practical Learning

563

using System; public static class Exercise { public static int Main(string[] args) { var Prices = new double[5, 8]; return 0; }

}

This time, the variable has 5 lists and each list contains 8 elements. This means that the whole variable contains 5 * 8 = 40 elements. If you want to declare the array variable using the first formula where you don't know the sizes of the lists, you must use the data type of the array and you can omit the right square brackets. Here is an example: using System; public static class Exercise { public static int Main(string[] args) { string[,] Members; }

return 0;

}

In this case also, remember that you need the square brackets. If you use the var keyword, you don't need the left square brackets but, in the right square brackets, you must specify the sizes. You can initialize an array variable when declaring it. To do this, on the right side of the declaration, before the closing semi-colon, type an opening and a closing curly brackets. Inside of the brackets, include a pair of an opening and a closing curly brackets for each internal list of the array. Then, inside of a pair of curly brackets, provide a list of the values of the internal array, just as you would do for a one-dimensional array. Here is an example: using System; public static class Exercise { public static int Main(string[] args) { var Members = new string[2, 4] { {"Celeste", "Mathurin", "Alex", "Germain"}, // First List {"Jeremy", "Mathew", "Anselme", "Frederique"} // Second List }; }

return 0;

}

C# 3.0 Practical Learning

564

When initializing a two-dimensional array, remember the dimensions. The number on the left side of the right comma specifies the number of main lists and the number on the right side of the right comma specifies the number of elements in each list. Here is an example: using System; public static class Exercise { public static int Main(string[] args) { var Prices = new double[5, 8] { { 10.50, 2.35, 49.75, 202.35, 8.70, 58.20, 34.85, 48.50 }, { 23.45, 878.50, 26.35, 475.90, 2783.45, 9.50, 85.85, 792.75 }, { 47.95, 72.80, 34.95, 752.30, 49.85, 938.70, 45.05, 9.80 }, { 759.25, 73.45, 284.35, 70.95, 82.05, 34.85, 102.30, 84.50 }, { 29.75, 953.45, 79.55, 273.45, 975.90, 224.75, 108.25, 34.05 } }; return 0; }

}

If you use this technique to initialize an array, you can omit specifying the dimension of the array. That is, you can remove the numbers in the right square brackets. Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Members = new string[,] { {"Celeste", "Mathurin", "Alex", "Germain"}, // First List {"Jeremy", "Mathew", "Anselme", "Frederique"} // Second List }; }

return 0;

}

Practical Learning: Creating a Two-Dimensional Array 1. To create and use a two-dimensional array, change the file as follows: using using using using

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

C# 3.0 Practical Learning

565

namespace DepartmentStore3 { public class Program { static void Main(string[] args) { long ItemID = 0; string Description = "Unknown"; double Price = 0.00D; // The first list contains women's items // The other contains non-women items long[,] ItemNumber = new long[2, 5] { { 947783, 934687, 973947, 987598, 974937 }, { 739579, 367583, 743937, 437657, 467945 } }; string[,] ItemName = new string[2, 5] { { "Women Double-faced wool coat", "Women Floral Silk Tank Blouse", "Women Push Up Bra", "Women Chiffon Blouse", "Women Bow Belt Skirtsuit" }, { "Men Cotton Polo Shirt", "Children Cable-knit Sweater "Children Bear Coverall Cotton", "Baby three-piece Set "Girls Jeans with Heart Belt };

", ", "

}

double[,] UnitPrice = new double[2, 5] { };

} }

{ 275.25D, 180.05D, 50.00D, 265.35D, 245.55D }, { 45.55D, 25.65D, 28.25D, 48.55D, 19.95D }

Console.WriteLine("Receipt"); Console.WriteLine("Item Number: {0}", ItemID); Console.WriteLine("Description: {0}", Description); Console.WriteLine("Unit Price: {0:C}\n", Price);

}

2. Save the file

Accessing the Members of a Two-Dimensional Array

C# 3.0 Practical Learning

566

To use the members of a two-dimensional array, you can access each item individually. For example, to initialize a two-dimensional array, you can access each member of the array and assign it a value. The external list is zero-based. In other words, the first list has an index of 0, the second list has an index of 1. Internally, each list is zero-based and behaves exactly like a one-dimensional array. To access a member of the list, type the name of the variable followed by its square brackets. In the brackets, type the index of the list, a comma, and the internal index of the member whose access you need. If you create an array without initializing using the curly brackets, you can use this technique of accessing the members by the square brackets to initialize each member of the array. Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Members = new string[2,4]; Members[0, Members[0, Members[0, Members[0, Members[1, Members[1, Members[1, Members[1, }

0] 1] 2] 3] 0] 1] 2] 3]

= = = = = = = =

"Celeste"; "Mathurin"; "Alex"; "Germain"; "Jeremy"; "Mathew"; "Anselme"; "Frederique";

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

Member Member Member Member Member Member Member Member

of of of of of of of of

the the the the the the the the

First List First List First List First List Second List Second List Second List Second List

return 0;

}

You can use this same technique to retrieve the value of each member of the array. Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Members = new string[2,4]; Members[0, Members[0, Members[0, Members[0, Members[1, Members[1, Members[1, Members[1,

0] 1] 2] 3] 0] 1] 2] 3]

= = = = = = = =

"Celeste"; "Mathurin"; "Alex"; "Germain"; "Jeremy"; "Mathew"; "Anselme"; "Frederique";

Console.WriteLine(Members[0, Console.WriteLine(Members[0, Console.WriteLine(Members[0, Console.WriteLine(Members[0, Console.WriteLine(Members[1, Console.WriteLine(Members[1,

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

Member Member Member Member Member Member Member Member

of of of of of of of of

the the the the the the the the

First List First List First List First List Second List Second List Second List Second List

0]); 1]); 2]); 3]); 0]); 1]);

C# 3.0 Practical Learning

567

Console.WriteLine(Members[1, 2]); Console.WriteLine(Members[1, 3]); }

return 0;

}

This would produce: Celeste Mathurin Alex Germain Jeremy Mathew Anselme Frederique Press any key to continue . . .

As we described it earlier, a two-dimensional array is list of two array, or two arrays of arrays. In order words, the second arrays are nested in the first arrays. In the same way, if you want to access them using a loop, you can nest one for loop inside of a first for loop. The external loop accesses a member of the main array and the second loop accesses the internal list of the current array. Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Members = new string[2,4]; Members[0, Members[0, Members[0, Members[0, Members[1, Members[1, Members[1, Members[1,

0] 1] 2] 3] 0] 1] 2] 3]

= = = = = = = =

"Celeste"; "Mathurin"; "Alex"; "Germain"; "Jeremy"; "Mathew"; "Anselme"; "Frederique";

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

Member Member Member Member Member Member Member Member

of of of of of of of of

the the the the the the the the

First List First List First List First List Second List Second List Second List Second List

for (int External = 0; External < 2; External++) for (int Internal = 0; Internal < 4; Internal++) Console.WriteLine(Members[External, Internal]); }

return 0;

}

To apply a foreach operator, access only each member of the internal list. Here is an example: using System; public static class Exercise { static int Main(string[] args) {

C# 3.0 Practical Learning

568

var Members = new string[2, 4]; Members[0, Members[0, Members[0, Members[0, Members[1, Members[1, Members[1, Members[1,

0] 1] 2] 3] 0] 1] 2] 3]

= = = = = = = =

"Celeste"; "Mathurin"; "Alex"; "Germain"; "Jeremy"; "Mathew"; "Anselme"; "Frederique";

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

Member Member Member Member Member Member Member Member

of of of of of of of of

the the the the the the the the

First List First List First List First List Second List Second List Second List Second List

foreach (var Internal in Members) Console.WriteLine(Internal); return 0; }

}

Practical Learning: Accessing the Members 1. To retrieve the values of a two-dimensional array, change the file as follows: using using using using

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

namespace DepartmentStore3 { public class Program { static void Main(string[] args) { long ItemID = 0; string Description = "Unknown"; double Price = 0.00D; // The first list contains women's items // The other contains non-women items long[,] ItemNumber = new long[2, 5] { { 947783, 934687, 973947, 987598, 974937 }, { 739579, 367583, 743937, 437657, 467945 } }; string[,] ItemName = new string[2, 5] { { "Women Double-faced wool coat", "Women Floral Silk Tank Blouse", "Women Push Up Bra", "Women Chiffon Blouse", "Women Bow Belt Skirtsuit"

}, { "Men Cotton Polo Shirt", "Children Cable-knit Sweater "Children Bear Coverall Cotton",

C# 3.0 Practical Learning

", 569

}

"Baby three-piece Set "Girls Jeans with Heart Belt

", "

}; double[,] UnitPrice = new double[2, 5] { { 275.25D, 180.05D, 50.00D, 265.35D, 245.55D }, { 45.55D, 25.65D, 28.25D, 48.55D, 19.95D } }; // Order Processing try { Console.Write("Enter Item Number: "); ItemID = long.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine( "Invalid Number - The program will terminate\n"); } for (int i = 0; i < 2; i++) { for (int j = 0; j < 5; j++) { if (ItemID == ItemNumber[i, j]) { Description = ItemName[i, j]; Price = UnitPrice[i, j]; } } } Console.WriteLine("Receipt"); Console.WriteLine("Item Number: {0}", ItemID); Console.WriteLine("Description: {0}", Description); Console.WriteLine("Unit Price: {0:C}\n", Price); }

}

}

2. Execute the application and test it. Here is an example: Enter Item Number: 739579 Receipt Item Number: 739579 Description: Men Cotton Polo Shirt Unit Price: $45.55 Press any key to continue . . .

3. Close the DOS window 4. Execute the application again and enter a different item number. Here is an example:

C# 3.0 Practical Learning

570

Enter Item Number: 273644 Receipt Item Number: 273644 Description: Unknown Unit Price: $0.00 Press any key to continue . . .

5. Close the DOS window

Multidimensional Arrays Introduction Beyond two dimensions, you can create an array variable that represents various lists, and each list contains various internal lists, and each internal list contains its own elements. This is referred to as a multidimensional array. One of the rules you must follow is that, as always, all members of the array must be of the same type.

Creating a Multidimensional Array To create a multidimensional array, add as many commas in the square brackets as you judge them necessary. If you only want to declare the variable without indicating the actual number of lists, you can specify the data type followed by square brackets and the commas. Here is an example that represents a three-dimensional array that is not initialized: using System; public static class Exercise { static int Main(string[] args) { double[,,] Number; }

return 0;

}

If you know the types of members the array will use, you can use the assignment operator and specify the numbers of lists in the square brackets. Here is an example: using System; public static class Exercise { static int Main(string[] args) { double[,,] Number = new double[2, 3, 5]; return 0; }

}

C# 3.0 Practical Learning

571

In this case, you can use the var keyword on the left side of the name of the variable: using System; public static class Exercise { static int Main(string[] args) { var Number = new double[2, 3, 5]; }

return 0;

}

In this example, we are creating 2 groups of items. Each of the two groups is made of three lists. Each list contains 5 numbers. As a result, the array contains 2 * 3 * 5 = 30 members.

Initializing a Multidimensional Array As always, there are various ways you can initialize an array. To initialize a multidimensional array when creating it, you use an opening and a closing curly brackets for each list but they must be nested. The most external pair of curly brackets represents the main array. Inside of the main curly brackets, the first nested curly brackets represent a list of the first dimension. Inside of those brackets, you use another set curly brackets to represent a list that would be nested. You continue this up to the most internal array. Then, in that last set, you initialize the members of the array by specifying their values. Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Number = new double[2, 3, 5] { { { 12.44, 525.38, -6.28, 2448.32, 632.04 }, {-378.05, 48.14, 634.18, 762.48, 83.02 }, { 64.92, -7.44, 86.74, -534.60, 386.73 } }, { { 48.02, 120.44, 38.62, 526.82, 1704.62 }, { 56.85, 105.48, 363.31, 172.62, 128.48 }, { 906.68, 47.12, -166.07, 4444.26, 408.62 } }, }; return 0; }

}

Access to Members of a Multidimensional Array C# 3.0 Practical Learning

572

To access a member of a multidimensional array, type the name of the array followed by the opening square bracket, followed by the 0-based first dimension, followed by a comma. Continue with each dimension and end with the closing square bracket. You can use this technique to initialize the array if you had only created it. Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Number = new double[2, 3, 5]; Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, }

0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,

0] 1] 2] 3] 4] 0] 1] 2] 3] 4] 0] 1] 2] 3] 4] 0] 1] 2] 3] 4] 0] 1] 2] 3] 4] 0] 1] 2] 3] 4]

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

12.44; 525.38; -6.28; 2448.32; 632.04; -378.05; 48.14; 634.18; 762.48; 83.02; 64.92; -7.44; 86.74; -534.60; 386.73; 48.02; 120.44; 38.62; 526.82; 1704.62; 56.85; 105.48; 363.31; 172.62; 128.48; 906.68; 47.12; -166.07; 4444.26; 408.62;

return 0;

}

This is the same approach you can use to access each member of the array to check or retrieve its value. Here are examples: using System; public static class Exercise { static int Main(string[] args) { double[, ,] number = new double[2, 3, 5]

C# 3.0 Practical Learning

573

{ {

{

12.44, 525.38, -6.28, 2448.32, 632.04 }, {-378.05, 48.14, 634.18, 762.48, 83.02 }, { 64.92, -7.44, 86.74, -534.60, 386.73 }

}, { { },

{

48.02, 120.44, 38.62, 526.82,1704.62 }, 56.85, 105.48, 363.31, 172.62, 128.48 }, { 906.68, 47.12,-166.07, 4444.26, 408.62 }

};

}

Console.WriteLine("Number[0][0][0] Console.WriteLine("Number[0][0][1] Console.WriteLine("Number[0][0][2] Console.WriteLine("Number[0][0][3] Console.WriteLine("Number[0][0][4]

= = = = =

{0}", number[0, 0, 0]); {0}", number[0, 0, 1]); {0}", number[0, 0, 2]); {0}", number[0, 0, 3]); {0}\n", number[0, 0, 4]);

Console.WriteLine("Number[0][1][0] Console.WriteLine("Number[0][1][1] Console.WriteLine("Number[0][1][2] Console.WriteLine("Number[0][1][3] Console.WriteLine("Number[0][1][4]

= = = = =

{0}", number[0, 1, 0]); {0}", number[0, 1, 1]); {0}", number[0, 1, 2]); {0}", number[0, 1, 3]); {0}\n", number[0, 1, 4]);

Console.WriteLine("Number[0][2][0] Console.WriteLine("Number[0][2][1] Console.WriteLine("Number[0][2][2] Console.WriteLine("Number[0][2][3] Console.WriteLine("Number[0][2][4]

= = = = =

{0}", number[0, 2, 0]); {0}", number[0, 2, 1]); {0}", number[0, 2, 2]); {0}", number[0, 2, 3]); {0}\n", number[0, 2, 4]);

Console.WriteLine("Number[1][0][0] Console.WriteLine("Number[1][0][1] Console.WriteLine("Number[1][0][2] Console.WriteLine("Number[1][0][3] Console.WriteLine("Number[1][0][4]

= = = = =

{0}", number[1, 0, 0]); {0}", number[1, 0, 1]); {0}", number[1, 0, 2]); {0}", number[1, 0, 3]); {0}\n", number[1, 0, 4]);

Console.WriteLine("Number[1][1][0] Console.WriteLine("Number[1][1][1] Console.WriteLine("Number[1][1][2] Console.WriteLine("Number[1][1][3] Console.WriteLine("Number[1][1][4]

= = = = =

{0}", number[1, 1, 0]); {0}", number[1, 1, 1]); {0}", number[1, 1, 2]); {0}", number[1, 1, 3]); {0}\n", number[1, 1, 4]);

Console.WriteLine("Number[1][2][0] Console.WriteLine("Number[1][2][1] Console.WriteLine("Number[1][2][2] Console.WriteLine("Number[1][2][3] Console.WriteLine("Number[1][2][4]

= = = = =

{0}", number[1, 2, 0]); {0}", number[1, 2, 1]); {0}", number[1, 2, 2]); {0}", number[1, 2, 3]); {0}\n", number[1, 2, 4]);

return 0;

}

This would produce: Number[0][0][0] Number[0][0][1] Number[0][0][2] Number[0][0][3] Number[0][0][4]

= = = = =

12.44 525.38 -6.28 2448.32 632.04

C# 3.0 Practical Learning

574

Number[0][1][0] Number[0][1][1] Number[0][1][2] Number[0][1][3] Number[0][1][4]

= = = = =

-378.05 48.14 634.18 762.48 83.02

Number[0][2][0] Number[0][2][1] Number[0][2][2] Number[0][2][3] Number[0][2][4]

= = = = =

64.92 -7.44 86.74 -534.6 386.73

Number[1][0][0] Number[1][0][1] Number[1][0][2] Number[1][0][3] Number[1][0][4]

= = = = =

48.02 120.44 38.62 526.82 1704.62

Number[1][1][0] Number[1][1][1] Number[1][1][2] Number[1][1][3] Number[1][1][4]

= = = = =

56.85 105.48 363.31 172.62 128.48

Number[1][2][0] Number[1][2][1] Number[1][2][2] Number[1][2][3] Number[1][2][4]

= = = = =

906.68 47.12 -166.07 4444.26 408.62

Press any key to continue . . .

Since the lists are nested, if you want to use loops to access the members of the array, you can nest the for loops to incrementally access the values. Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Number = new double[2, 3, 5]; Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0, Number[0,

0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,

0] 1] 2] 3] 4] 0] 1] 2] 3] 4] 0] 1] 2] 3] 4]

= = = = = = = = = = = = = = =

12.44; 525.38; -6.28; 2448.32; 632.04; -378.05; 48.14; 634.18; 762.48; 83.02; 64.92; -7.44; 86.74; -534.60; 386.73;

C# 3.0 Practical Learning

575

Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1, Number[1,

0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,

0] 1] 2] 3] 4] 0] 1] 2] 3] 4] 0] 1] 2] 3] 4]

= = = = = = = = = = = = = = =

48.02; 120.44; 38.62; 526.82; 1704.62; 56.85; 105.48; 363.31; 172.62; 128.48; 906.68; 47.12; -166.07; 4444.26; 408.62;

for(int Outside = 0; Outside < 2; Outside++) for(int Inside = 0; Inside < 3; Inside++) for(int Value = 0; Value < 5; Value++) Console.WriteLine("Number = {0}", Number[Outside, Inside, Value]); return 0; }

}

This would produce: Number = 12.44 Number = 525.38 Number = -6.28 Number = 2448.32 Number = 632.04 Number = -378.05 Number = 48.14 Number = 634.18 Number = 762.48 Number = 83.02 Number = 64.92 Number = -7.44 Number = 86.74 Number = -534.6 Number = 386.73 Number = 48.02 Number = 120.44 Number = 38.62 Number = 526.82 Number = 1704.62 Number = 56.85 Number = 105.48 Number = 363.31 Number = 172.62 Number = 128.48 Number = 906.68 Number = 47.12 Number = -166.07 Number = 4444.26 Number = 408.62 Press any key to continue . . .

C# 3.0 Practical Learning

576

To make the result easier to read, we could use code as follows: using System; public static class Exercise { static int Main(string[] args) { var Number = new double[2, 3, 5]; . . . No Change for(int Outside = 0; Outside < 2; Outside++) for(int Inside = 0; Inside < 3; Inside++) for (int Value = 0; Value < 5; Value++) { Console.WriteLine("Number[{0}][{1}][{2}] = {3}", Outside, Inside, Value, Number[Outside, Inside,

Value]);

}

if (Value % 5 == 0) Console.WriteLine();

return 0; }

}

To use a foreach operator, access only each member to get to it. Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Numbers = new double[2, 3, 5]; . . . No Change foreach (var Value in Numbers) Console.WriteLine("Number: {0}", Value); }

return 0;

}

Multidimensional Arrays and Classes Introduction Like an array of a primitive type, a multidimensional array can be made a field of a class. You can primarily declare it without initializing it. Here is an example: public class TriangleInCoordinateSystem

C# 3.0 Practical Learning

577

{ }

private int[,] Points;

This indicates a two-dimensional array field: the array will contain two lists but we don't know (yet) how many members each array will contain. Therefore, if you want, when creating the array, you can specify its dimension by assigning it a second pair of square brackets using the new operator and the data type. Here is an example: public class TriangleInCoordinateSystem { private int[,] Points = new int[3, 2]; }

You can also use a method of the class or a constructor to indicate the size of the array. Here is an example: public class TriangleInCoordinateSystem { private int[,] Points; public TriangleInCoordinateSystem() { Points = new int[3, 2]; } }

To initialize the array, you can access each member using the square brackets as we saw in the previous sections. Here is an example: public class TriangleInCoordinateSystem { private int[,] Points; public TriangleInCoordinateSystem() { Points = new int[3, 2];

}

Points[0, Points[0, Points[1, Points[1, Points[2, Points[2,

0] 1] 0] 1] 0] 1]

= -2; // A(x, ) = -3; // A( , y) = 5; // B(x, ) = 1; // B( , y) = 4; // C(x, ) = -2; // C( , y)

}

After initializing the array, you can use it as you see fit. For example, you can display its values to the user. Here is an example: using System; public class TriangleInCoordinateSystem { private int[,] Points; public TriangleInCoordinateSystem() { Points = new int[3, 2];

C# 3.0 Practical Learning

578

Points[0, Points[0, Points[1, Points[1, Points[2, Points[2,

0] 1] 0] 1] 0] 1]

= -2; // A(x, ) = -3; // A( , y) = 5; // B(x, ) = 1; // B( , y) = 4; // C(x, ) = -2; // C( , y)

}

}

public void ShowPoints() { Console.WriteLine("Coordinates of the Triangle"); Console.WriteLine("A({0}, {1})", Points[0, 0], Points[0, 1]); Console.WriteLine("B({0}, {1})", Points[1, 0], Points[1, 1]); Console.WriteLine("C({0}, {1})", Points[2, 0], Points[2, 1]); }

public static class Exercise { static int Main(string[] args) { var Triangle = new TriangleInCoordinateSystem(); Triangle.ShowPoints(); return 0; }

}

This would produce: Coordinates of the Triangle A(-2, -3) B(5, 1) C(4, -2) Press any key to continue . . .

A Multidimensional Array as Argument A multidimensional array can be passed as argument. When creating the method, in its parentheses, enter the data type followed by the square brackets. In the square brackets, enter one comma for a two-dimensional array, two or more commas, as necessary, for a three-dimensional arrays as necessary. Here is an example: public class TriangleInCoordinateSystem { public void ShowPoints(int[,] Coords) { } }

When defining the method, in its body, you can use the array as you see fit, such as displaying its values. Here is an example: public class TriangleInCoordinateSystem { public void ShowPoints(int[,] Coords)

C# 3.0 Practical Learning

579

{ Console.WriteLine("Coordinates of the Triangle"); Console.WriteLine("A({0}, {1})", Coords[0, 0], Coords[0, 1]); Console.WriteLine("B({0}, {1})", Coords[1, 0], Coords[1, 1]); Console.WriteLine("C({0}, {1})", Coords[2, 0], Coords[2, 1]); }

}

To call this type of method, pass only the name of the array. As indicated with one-dimensional arrays, when passing an multi-dimensional array argument, the array is treated as a reference. This makes it possible for the method to modify the array and return it changed. If you want to indicate that the array is passed by reference, you can precede its name in the parentheses by the the ref keyword. Here is an example: using System; public class TriangleInCoordinateSystem { private int[,] Points; public void CreateTriangle(ref int[,] Points) { Points[0, Points[0, Points[1, Points[1, Points[2, Points[2,

0] 1] 0] 1] 0] 1]

= -2; // A(x, ) = -3; // A( , y) = 5; // B(x, ) = 1; // B( , y) = 4; // C(x, ) = -2; // C( , y)

}

}

public void ShowPoints(int[,] Coords) { Console.WriteLine("Coordinates of the Triangle"); Console.WriteLine("A({0}, {1})", Coords[0, 0], Coords[0, 1]); Console.WriteLine("B({0}, {1})", Coords[1, 0], Coords[1, 1]); Console.WriteLine("C({0}, {1})", Coords[2, 0], Coords[2, 1]); }

public static class Exercise { static int Main(string[] args) { var Coordinates = new int[3, 2]; var Triangle = new TriangleInCoordinateSystem(); Triangle.CreateTriangle(ref Coordinates); Triangle.ShowPoints(Coordinates); }

return 0;

}

Returning a Multi-Dimensional Array C# 3.0 Practical Learning

580

You can return a multi-dimensional array from a method. When creating the method, before its name, specify the data type followed by square brackets. In the square brackets, enter the necessary number of commas. Here is an example: using System; public class TriangleInCoordinateSystem { public int[,] CreateTriangle() { } }

In the body of the method, you can do what you want but, before exiting it, you must return an array of the same type that was created. When calling the method, you can assign it to an array of the same type it returns. Here is an example: using System; public class TriangleInCoordinateSystem { public int[,] CreateTriangle() { var Points = new int[3,2]; Points[0, Points[0, Points[1, Points[1, Points[2, Points[2, }

0] 1] 0] 1] 0] 1]

= = = = = =

6; 1; 2; 3; 1; 4;

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

A(x, A( , B(x, B( , C(x, C( ,

) y) ) y) ) y)

return Points;

public void ShowPoints(int[,] Coords) { Console.WriteLine("Coordinates of the Triangle"); Console.WriteLine("A({0}, {1})", Coords[0, 0], Coords[0, 1]); Console.WriteLine("B({0}, {1})", Coords[1, 0], Coords[1, 1]); Console.WriteLine("C({0}, {1})", Coords[2, 0], Coords[2, 1]); } } public static class Exercise { static int Main(string[] args) { var Coordinates = new int[3, 2]; var Triangle = new TriangleInCoordinateSystem(); Coordinates = Triangle.CreateTriangle(); Triangle.ShowPoints(Coordinates); return 0; }

C# 3.0 Practical Learning

581

}

This would produce: Coordinates of the Triangle A(6, 1) B(2, 3) C(1, 4) Press any key to continue . . .

A Multidimensional Array of Objects A Variable of a Multidimensional Array of Objects As done for primitive data types, you can create a multi-dimensional array where each member is of a class type. Of course you can use an existing class or you must first create a class. Here is an example: public class Point { private int XCoord; private int YCoord; public int x { get { return XCoord; } set { XCoord = value; } }

}

public int y { get { return YCoord; } set { YCoord = value; } }

To create a multidimensional array of objects without initializing it, you can use the following formula: ClassName[,] VariableName;

If you know the number of instances of the class that the array will use, you can use the following formula: ClassName[,] VariableName = new ClassName[Number1,Number2];

Or you can use the var keyword in the following formula: var VariableName = new DataType[Number1,Number2];

The ClassName factor is the name of the class that will make up each member of the array. The other sections follow the same rules we reviewed for the primitive types. For example, you can create an array without allocating memory for it as follows: public static class Exercise

C# 3.0 Practical Learning

582

{ static int Main(string[] args) { Point[,] Line; }

return 0;

}

If you know the number of members that the array will contain, you can use the right pair of square brackets, in which case you can specify the name of the class or use the var keyword and omit the left square brackets. Here is an example: public static class Exercise { static int Main(string[] args) { var Line = new Point[2, 2]; }

return 0;

}

This declaration creates a two-dimensional array of two Point objects: The array contains two lists and each list contains two Points. To initialize a multidimensional array of objects, you can access each array member using its index, allocate memory for it using the new operator. After allocating memory for the member, you can then access its fields or properties to initialize it. Here is an example: using System; public class Point { private int XCoord; private int YCoord; public int x { get { return XCoord; } set { XCoord = value; } }

}

public int y { get { return YCoord; } set { YCoord = value; } }

public static class Exercise { static int Main(string[] args) { var Line = new Point[2, 2]; Line[0, 0] = new Point(); // First Point A

C# 3.0 Practical Learning

583

Line[0, Line[0, Line[0, Line[0, Line[0,

0].x 0].y 1] = 1].x 1].y

= -3; = 8; new Point(); = 4; = -5;

// // // // //

A(x, ) A( , y) Second Point B B(x, ) B( , y)

return 0; }

}

You can also initialize the array when creating it. Before doing this, you would need a constructor of the class and the constructor must take the argument(s) that would be used to initialize each member of the array. To actually initialize the array, you would need a pair of external curly brackets for the main array. Inside of the external curly brackets, create a pair of curly brackets for each sub-dimension of the array. Inside the last curly brackets, use the new operator to access an instance of the class and call its constructor to specify the values of the instance of the class. Here is an example: public class Point { private int XCoord; private int YCoord; public Point() { } public Point(int X, int Y) { XCoord = X; YCoord = Y; } public int x { get { return XCoord; } set { XCoord = value; } }

}

public int y { get { return YCoord; } set { YCoord = value; } }

public static class Exercise { static int Main(string[] args) { var Line = new Point[,] { { new Point(-3, 8), new Point(4, -5) } };

C# 3.0 Practical Learning

584

return 0; }

}

Accessing the Members of a Multidimensional Array of Objects To access the members of a multidimensional array of objects, apply the square brackets to a particular member of the array and access the desired field or property of the class. Here is an example: public static class Exercise { public static int Main(string[] args) { var Line = new Point[,] { { new Point(-3, 8), new Point(4, -5) } }; Console.WriteLine("Line =-="); Console.WriteLine("From A({0}, {1}) to B({2}, {3})", Line[0, 0].x, Line[0, 0].y, Line[0, 1].x, Line[0, 1].y); return 0; }

}

This would produce: Line =-= From A(-3, 8) to B(4, -5) Press any key to continue . . .

You can also use a loop to access the members of the array. To do this, create a first for loop that stops at the first dimension of the array - 1. Then, inside of a first for loop, nest a for loop for each subsequent dimension. Here is an example: public static class Exercise { public static int Main(string[] args) { var Line = new Point[,] { { new Point(-3, 8), new Point(4, -5) } }; Console.WriteLine("The points of the line are:"); for(int i = 0; i < 1; i++) for(int j = 0; j < 2; j++) Console.Write("({0}, {1})", Line[i, j].x, Line[i, j].y); return 0; }

}

C# 3.0 Practical Learning

585

This would produce: The points of the line are: (-3, 8) (4, -5) Press any key to continue . . .

To apply a foreach operator, access only each member of the internal list. Here is an example: public static class Exercise { static int Main(string[] args) { var Line = new Point[,] { { new Point(-3, 8), new Point(4, -5) } }; Console.WriteLine("The points of the line are:"); foreach (Point pt in Line) Console.WriteLine("({0}, {1})", pt.x, pt.y); return 0; }

}

Multidimensional Arrays of Objects and Classes Introduction As done for primitive types, a multidimensional array of objects can be made a field of a class. You can declare the array without specifying its size. Here is an example: public class Triangle { public Point[,] Vertices; }

If you know the dimensions that the array will have, you can specify them using the new operator at the same time you are creating the field. Here is an example: public class Triangle { public Point[,] Vertices = new Point[3,2]; }

This creation signals a multidimensional array of Point objects. It will consist of three lists and each list will contain two Point objects To initialize the array, access each member by its index to allocate memory for it. Once you get the member, you access each one of its fields or properties and initialize it with the desired value. Here is an example: 586 C# 3.0 Practical Learning

public class Triangle { public Point[,] Vertices = new Point[3, 2];

}

public Triangle() { Vertices[0, 0] = Vertices[0, 0].x Vertices[0, 0].y Vertices[1, 0] = Vertices[1, 0].x Vertices[1, 0].y Vertices[2, 0] = Vertices[2, 0].x Vertices[2, 0].y }

new Point(); = -2; = -4; new Point(); = 3; = 5; new Point(); = 6; = -2;

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

Point A(x, y) A(x, ) A( , y) Point B(x, y) B(x, ) B( , y) Point C(x, y) C(x, ) C( , y)

If the class is equipped with the right constructor, you can use it to initialize each member of the array. Once the array is ready, you can access each members using its index and manipulate it. For example you can display its value(s) to the user. Here is an example: using System; public class Point { private int XCoord; private int YCoord; public Point() { } public Point(int X, int Y) { XCoord = X; YCoord = Y; } public int x { get { return XCoord; } set { XCoord = value; } } public int y { get { return YCoord; } set { YCoord = value; } } } public class Triangle { public Point[,] Vertices = new Point[3, 2]; public Triangle()

C# 3.0 Practical Learning

587

{

}

}

Vertices[0, Vertices[0, Vertices[0, Vertices[1, Vertices[1, Vertices[1, Vertices[2, Vertices[2, Vertices[2,

0] = 0].x 0].y 0] = 0].x 0].y 0] = 0].x 0].y

new Point(); = -2; = -4; new Point(); = 3; = 5; new Point(); = 6; = -2;

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

Point A(x, y) A(x, ) A( , y) Point B(x, y) B(x, ) B( , y) Point C(x, y) C(x, ) C( , y)

public void Identify() { Console.Write("Triangle Vertices: "); Console.WriteLine("A({0}, {1}), B({2}, {3}), and C({4}, {5})", Vertices[0, 0].x, Vertices[0, 0].y, Vertices[1, 0].x, Vertices[1, 0].y, Vertices[2, 0].x, Vertices[2, 0].y); }

public static class Exercise { static int Main(string[] args) { Triangle Tri = new Triangle(); Tri.Identify(); }

return 0;

}

This would produce: Triangle Vertices: A(-2, -4), B(3, 5), and C(6, -2) Press any key to continue . . .

Passing a Multidimensional Array of Objects You can pass a multidimensional array of objects as arguments. To do this, in the parentheses of the method, enter the class name followed by the square brackets. In the square brackets, type the appropriate number of commas. Here is an example: public class Triangle { public void Create(Point[,] Points) { } }

In the body of the method, use the array as you we have done so far. You can access its members to get to its values. Here are examples: public class Triangle { public void Create(Point[,] Points) {

C# 3.0 Practical Learning

588

Points[0, Points[0, Points[0, Points[1, Points[1, Points[1, Points[2, Points[2, Points[2,

0] = 0].x 0].y 0] = 0].x 0].y 0] = 0].x 0].y

new Point(); = -2; = -4; new Point(); = 3; = 5; new Point(); = 6; = -2;

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

Point A(x, y) A(x, ) A( , y) Point B(x, y) B(x, ) B( , y) Point C(x, y) C(x, ) C( , y)

} public void Identify(Point[,] Coordinate) { Console.Write("Triangle Vertices: "); Console.WriteLine("A({0}, {1}), B({2}, {3}), and C({4}, {5})", Coordinate[0, 0].x, Coordinate[0, 0].y, Coordinate[1, 0].x, Coordinate[1, 0].y, Coordinate[2, 0].x, Coordinate[2, 0].y); } } public static class Exercise { static int Main(string[] args) { Triangle Tri = new Triangle(); Point[,] Vertices = new Point[3, 2]; Tri.Create(Vertices); Tri.Identify(Vertices); }

return 0;

}

Remember that an array passed as argument is in fact passed by reference. You can indicate this by preceding it with the ref keyword.

Returning a Multidimensional Array of Objects A method can return a multidimensional array of objects. If you are creating the method, before its name, type the name of the class followed by square brackets. Inside the square brackets, type the desired number of commas to indicate the dimension of the returned value. Here is an example: public class Triangle { public Point[,] Create() { } }

After implementing the method, before exiting it, make sure it returns the type of array that it was indicated to produce. Here is an example: using System; public class Point

C# 3.0 Practical Learning

589

{ private int XCoord; private int YCoord; public Point() { } public Point(int X, int Y) { XCoord = X; YCoord = Y; } public int x { get { return XCoord; } set { XCoord = value; } } public int y { get { return YCoord; } set { YCoord = value; } } } public class Triangle { public Point[,] Create() { var Points = new Point[3, 2]; Points[0, Points[0, Points[0, Points[1, Points[1, Points[1, Points[2, Points[2, Points[2, }

}

0] = 0].x 0].y 0] = 0].x 0].y 0] = 0].x 0].y

new Point(); = -2; = -4; new Point(); = 3; = 5; new Point(); = 6; = -2;

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

Point A(x, y) A(x, ) A( , y) Point B(x, y) B(x, ) B( , y) Point C(x, y) C(x, ) C( , y)

return Points;

public void Identify(Point[,] Coordinate) { Console.Write("Triangle Vertices: "); Console.WriteLine("A({0}, {1}), B({2}, {3}), and C({4}, {5})", Coordinate[0, 0].x, Coordinate[0, 0].y, Coordinate[1, 0].x, Coordinate[1, 0].y, Coordinate[2, 0].x, Coordinate[2, 0].y); }

public static class Exercise { static int Main(string[] args) {

C# 3.0 Practical Learning

590

Triangle Tri = new Triangle(); Point[,] Vertices = Tri.Create(); Tri.Identify(Vertices); return 0; }

}

Introduction to Jagged Arrays Introduction A jagged array is an array of arrays, or an array of arrays of arrays, etc. To create a jagged array, use a combination of square brackets for each dimension. The formula used is: DataType[][] VariableName;

Each of the square brackets is used in any of the ways we have introduced arrays so far. This means that the first square bracket can be used as its own one-dimensional array or as a multi-dimensional array. Here is an example: string[2][5] Members;

This declares a variable that represents two arrays and each array internally contains 5 arrays. Because each pair of square brackets is its own array, it can be used to create its own array with its own multidimensional array. Here is an example that creates a multidimensional array in the first dimension: string[2,4][5] Members;

In the same way, the second square bracket can be used as a single or a multidimensional array. Here is an example: string[2,4][5,12,8] Members;

Practical Learning: Introducing Jagged Arrays 1. Create a new Console Application named DepartmentStore4 2. Change the Program.cs file as follows: using using using using

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

namespace DepartmentStore4 { public class Program { static int Main(string[] args) { long ItemID = 0; string Description = "Unknown";

C# 3.0 Practical Learning

591

double Price = 0.00D;

} }

Console.WriteLine("Receipt"); Console.WriteLine("Item Number: {0}", ItemID); Console.WriteLine("Description: {0}", Description); Console.WriteLine("Unit Price: {0:C}\n", Price);

}

3. Execute the application to see the result. This would produce: Receipt Item Number: 0 Description: Unknown Unit Price: $0.00

4. Close the DOS window

Initialization of a Jagged Array When declaring a jagged array, you can allocate memory for it using the new operator followed by the data type of the array and the same combination of square brackets used to the left of the assignment operator. The first pair of square brackets on the right side of the assignment operator must contain the external dimension of the array. The second pair of square brackets must be left empty. Here is an example: using System; public class Exercise { static int Main(string[] args) { string[][] Members = new string[2][]; return 0; } }

To initialize a jagged array, when declaring the variable, on the right side of the second pair of square brackets, provide an opening and a closing curly brackets, then create each list in its own pair of curly brackets. At the beginning of each list, you must allocate memory for the list with the new operator. Here is an example: using System; public class Exercise { static int Main(string[] args) { string[][] Members = new string[2][]{ new string[]{"Celeste", "Mathurin", "Alex", "Germain"}, new string[]{"Jeremy", "Mathew", "Anselme", "Frederique"} }; return 0;

C# 3.0 Practical Learning

592

} }

If you initialize the array this way, you can omit specifying the dimension of the external array. With a jagged array, you can also initialize its internal array individually. To do this, access each internal array by its zero-based index. Here is an example: public class Exercise { static int Main(string[] args) { string[][] Members = new string[2][]; Members[0] = new string[]{"Celeste", "Mathurin", "Alex", "Germain"}; Members[1] = new string[]{"Jeremy", "Mathew", "Anselme", "Frederique"}; }

return 0;

}

Practical Learning: Initializing a Jagged Array 1. To declare and initialize jagged arrays, change the file as follows: using using using using

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

namespace DepartmentStore4 { public class Program { static int Main(string[] args) { long ItemID = 0; string Description = "Unknown"; double Price = 0.00D; // // // // // // // // // // // // // // // //

Each of the following variable arrays is structured as [2][2][4]. Each variable represents: A/ Two major lists: The first major list represents women items, the second major list represents men items, B/ Two minor lists. Each of the major lists contains two minor lists: a/ The first minor list of the first major list contains adult women items The second minor list of the first major list contains girls items b/ The first minor list of the second major list contains adult men items The second minor list of the second major list contains boys items

C# 3.0 Practical Learning

593

// C/ Each minor list contains four items long[][][] ItemNumber = new long[][][] { new long[][] { new long[]{947783, 934687, 973947, 987598, 974937}, new long[]{743765, 747635, 765473, 754026, 730302} }, new long[][] { new long[]{209579, 267583, 248937, 276057, 267945}, new long[]{ 409579, 467583, 448937, 476057, 467945} } }; string[][][] ItemName = new string[][][] { new string[][] { new string[] { "Double-faced wool coat", "Floral Silk Tank Blouse", "Push Up Bra", "Chiffon Blouse", "Bow Belt Skirtsuit" }, new string[] { "Cable-knit Sweater", "Jeans with Heart Belt", "Fashionable mini skirt", "Double Dry Pants", "Romantic Flower Dress" } }, new string[][] { new string[] { "Cotton Polo Shirt", "Pure Wool Cap", "Striped Cotton Shirt", "Two-Toned Ribbed Crewneck", "Chestnut Italian Shoes" }, new string[] { "Under Collar and Placket Jacket", "Country Coat Rugged Wear", "Carpenter Jeans", "Double-Cushion Tennis Shoes", "Stitched Center-Bar Belt" } } };

C# 3.0 Practical Learning

594

double[][][] UnitPrice = new double[2][][] { new double[][] { new double[] { 275.25, 180.00, 50.00, 265.00, 245.55 }, new double[] { 45.55, 25.65, 34.55, 28.55, 24.95 } }, new double[][] { new double[] { 45.75, 25.00, 65.55, 9.75, 165.75 }, new double[] { 265.15, 35.55, 24.95, 48.75, 32.50 } } }; Console.WriteLine("Receipt"); Console.WriteLine("Item Number: {0}", ItemID); Console.WriteLine("Description: {0}", Description); Console.WriteLine("Unit Price: {0:C}\n", Price); }

}

}

2. Save the file

Access to Members of a Jagged Array As done for a multidimensional array, each member of a jagged array can be accessed with a multiple index, depending on how the array was created. Both the external and the internal lists are zero-based. Here is an example: using System; public class Exercise { static int Main(string[] args) { string[][] Members = new string[2][]; Members[0] = new string[]{"Celeste", "Mathurin", "Alex", "Germain"}; Members[1] = new string[]{"Jeremy", "Mathew", "Anselme", "Frederique"}; Console.WriteLine("Member Console.WriteLine("Member Console.WriteLine("Member Console.WriteLine("Member Console.WriteLine("Member Console.WriteLine("Member Console.WriteLine("Member Console.WriteLine("Member

1: 2: 3: 4: 5: 6: 7: 8:

{0}", Members[0][0]); {0}", Members[0][1]); {0}", Members[0][2]); {0}", Members[0][3]); {0}", Members[0][0]); {0}", Members[1][1]); {0}", Members[1][2]); {0}\n", Members[1][3]);

return 0; }

C# 3.0 Practical Learning

595

}

This would produce: Member Member Member Member Member Member Member Member

1: 2: 3: 4: 5: 6: 7: 8:

Celeste Mathurin Alex Germain Celeste Mathew Anselme Frederique

Press any key to continue . . .

You can also use some loops to access each member of the array. Here is an example: using System; public static class Exercise { static int Main(string[] args) { string[][] Members = new string[2][]; Members[0] = new string[] { "Celeste", "Mathurin", "Alex", "Germain" }; Members[1] = new string[] { "Jeremy", "Mathew", "Anselme", "Frederique" }; for (int External = 0; External < 2; External++) for (int Internal = 0; Internal < 4; Internal++) Console.WriteLine("Name: {0}", Members[External] [Internal]); }

return 0;

}

If you want to use a foreach operator, you must access each array by its index. The external array can be accessed using a-zero based index and remember that you are accessing a whole array. Here is an example: using System; public static class Exercise { static int Main(string[] args) { string[][] Members = new string[2][]; Members[0] = new string[] { "Celeste", "Mathurin", "Alex", "Germain" }; Members[1] = new string[] { "Jeremy", "Mathew", "Anselme", "Frederique" }; foreach (string Name in Members[0]) Console.WriteLine("Member: {0}", Name);

C# 3.0 Practical Learning

596

return 0; }

}

This would produce: Member: Celeste Member: Mathurin Member: Alex Member: Germain Press any key to continue . . .

To access the second array, apply its index as ArrayName[1].

Practical Learning: Using a Jagged Array 1. To process the members of a jagged array, make the following changes to the file: using using using using

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

namespace DepartmentStore4 { public class Program { static int Main(string[] args) { long ItemID = 0; string Description = "Unknown"; double Price = 0.00D; string Category = "Category"; // // // // // // // // // // // // // // // // //

Each of the following variable arrays is structured as [2][2][4]. Each variable represents: A/ Two major lists: The first major list represents women items, the second major list represents men items, B/ Two minor lists. Each of the major lists contains two minor lists: a/ The first minor list of the first major list contains adult women items The second minor list of the first major list contains girls items b/ The first minor list of the second major list contains adult men items The second minor list of the second major list contains boys items C/ Each minor list contains four items

long[][][] ItemNumber = new long[][][] { new long[][] {

C# 3.0 Practical Learning

597

new long[]{947783, 934687, 973947, 987598, 974937}, new long[]{743765, 747635, 765473, 754026, 730302} }, new long[][] { new long[]{209579, 267583, 248937, 276057, 267945}, new long[]{ 409579, 467583, 448937, 476057, 467945} } }; string[][][] ItemName = new string[][][] { new string[][] { new string[] { "Double-faced wool coat", "Floral Silk Tank Blouse", "Push Up Bra", "Chiffon Blouse", "Bow Belt Skirtsuit" }, new string[] { "Cable-knit Sweater", "Jeans with Heart Belt", "Fashionable mini skirt", "Double Dry Pants", "Romantic Flower Dress" } }, new string[][] { new string[] { "Cotton Polo Shirt", "Pure Wool Cap", "Striped Cotton Shirt", "Two-Toned Ribbed Crewneck", "Chestnut Italian Shoes" }, new string[] { "Under Collar and Placket Jacket", "Country Coat Rugged Wear", "Carpenter Jeans", "Double-Cushion Tennis Shoes", "Stitched Center-Bar Belt" } } }; double[][][] UnitPrice = new double[2][][] { new double[][] { new double[] { 275.25, 180.00, 50.00, 265.00, 245.55 },

C# 3.0 Practical Learning

598

new double[] { 45.55, 25.65, 34.55, 28.55, 24.95 } }, new double[][] { new double[] { 45.75, 25.00, 65.55, 9.75, 165.75 }, new double[] { 265.15, 35.55, 24.95, 48.75, 32.50 } } }; // Order Processing try { Console.Write("Enter Item Number: "); ItemID = long.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine( "Invalid Number - The program will terminate\n"); } for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { for (int k = 0; k < 5; k++) { if (ItemID == ItemNumber[i][j][k]) { Description = ItemName[i][j][k]; Price = UnitPrice[i][j][k]; if (ItemID >= 900000) Category = "Women"; else if (ItemID >= 700000) Category = "Girls"; else if (ItemID >= 400000) Category = "Boys"; else Category = "Men"; } }

} }

}

}

Console.WriteLine("Receipt"); Console.WriteLine("Item Number: {0}", ItemID); Console.WriteLine("Description: {0}", Description); Console.WriteLine("Unit Price: {0:C}\n", Price);

}

2. Execute the application and test it. Here is an example: Enter Item Number: 448937

C# 3.0 Practical Learning

599

Receipt Item Number: Category: Description: Unit Price:

448937 Boys Carpenter Jeans $24.95

Press any key to continue . . .

3. Close the DOS window

C# 3.0 Practical Learning

600

The Array Class Introduction to the Array Class Overview In the previous lessons, we saw how to create and initialize arrays. To assist with the use and management of arrays, you can combine the array features of the C# language and support from the .NET Framework. To support arrays, the .NET Framework provides a class of the same name. The Array class is defined in the System namespace of the System.dll assembly. When you create an array, you are in fact declaring a variable of type Array. Based on this, since an array variable is an object of a class type, you can use the characteristics of the Array class to create an array and/or to manipulate the values stored in the variable. You can create an array using any of the techniques we saw in the previous lessons, or you can use the Array class.

To assist you with creating an array, the Array class is equipped with the CreateInstance() method that comes in various versions. To create a onedimensional array whose members are zero-based, you can use the following version: public static Array CreateInstance(Type elementType, int length);

The first argument is used to specify the type of array you want to create. Since it is declared as Type, you can use the typeof operator to cast your type. The second argument specifies the number of members of the array. Using the Array class, you can create an array as follows: using System; public class Exercise { static int Main(string[] args) { Array Numbers = Array.CreateInstance(typeof(double), length); }

return 0;

}

You can also use the var keyword to declare the variable: using System;

C# 3.0 Practical Learning

601

public class Exercise { static int Main(string[] args) { var Numbers = Array.CreateInstance(typeof(double), length); }

return 0;

}

The Length of an Array We saw that if you declare a variable for an array but don't initialize it, you must specify the number of elements of the array. This number is passed inside the second pair of square brackets, as a constant integer. Here is an example: using System; public class Exercise { static int Main(string[] args) { var Numbers = new double[5]; return 0; }

}

If you use the Array class to create an array, you must pass this constant integer as the second argument of the CreateInstance() method from the the above version. Here is an example: using System; public class Exercise { static int Main(string[] args) { var Numbers = Array.CreateInstance(typeof(double), 5); }

return 0;

}

If the array exists already, that is, if you have already created the array or you are using an array created by someone else, to find out the number of items it contains, you can access its Length property. Therefore, the length of an array is the number of elements it contains. Alternatively, you can call the Array.GetLength() method. Its syntax is: public int GetLength(int dimension);

For a one-dimensional array, you must pass the argument as 0. This method returns a 32-bit integer that represents the number of items in the array. C# 3.0 Practical Learning

602

The Rank of an Array We have seen that the square brackets are used to specify that you are declaring an array. If you are creating a one-dimensional array, we saw that you could type a number in the square bracket. If you are creating a twodimensional array, you type two numbers separated by a comma in the second pair of square brackets. Each number, whether it is one, two, or more is a placeholder for what is referred to a dimension. In other words, a one dimensional array has a dimension of one. A two-dimensional array has a dimension of 2. To find out the dimension of an array, the Array class provides the Rank property. Therefore, to know the dimension of an existing array, you can access its Rank.

Fundamental Operations on an Array Adding Items to an Array Before using a class, it must have values or members in it. In the previous lesson, we saw that, to initialize an array, you open the curly brackets and list its members separated by commas, or you could access each member and assign it the desired value. To support the ability to add members to an array, the Array is equipped with a method named SetValue() that comes in different versions. To add a new item to a the type of array we have used so far, you can call the following version of the Array.SetValue() method: public void SetValue(object value, int index);

The first argument is the value to add to the list. The second argument is the index of the member to be added. The first item has index 1; the second item has index 2, and so on. Here is an example: using System; public class Exercise { static int Main(string[] args) { var Numbers = Array.CreateInstance(typeof(double), 5); Numbers.SetValue(7628.937, 0); Numbers.SetValue(6.48, 1); Numbers.SetValue(574.9, 2); Numbers.SetValue(293749.064, 3); Numbers.SetValue(0.70257, 4); }

return 0;

}

C# 3.0 Practical Learning

603

We indicated that whenever you create an array, you are in fact declaring an instance of the Array class. Therefore, even if you create an array using the square bracket formula we used in the previous lesson, you can call the SetValue() method to specify any member of the array. Here is an example: using System; public class Exercise { static int Main(string[] args) { var Numbers = new double[5]; Numbers.SetValue(7628.937, 0); Numbers.SetValue(6.48, 1); Numbers.SetValue(574.9, 2); Numbers.SetValue(293749.064, 3); Numbers.SetValue(0.70257, 4); return 0; }

}

The Array class provides a SetValue() version for each corresponding CreateInstance() method we reviewed earlier.

Accessing the Members of an Array Once the array is initialized, you can access its members and do what you want with their values. To support the ability to retrieve the value of a member of an array, the Array class is equipped with a method named GetValue that is overloaded with a version corresponding to each version of the CreateInstance() and the SetValue() methods. For example, to access the values stored in a one-dimensional array, you can call call this version: public object GetValue(int index);

The index argument is the zero-based index of the member whose value you want to access. Here is an example: using System; public class Exercise { static int Main(string[] args) { var Numbers = new double[5]; Numbers.SetValue(7628.937, 0); Numbers.SetValue(6.48, 1); Numbers.SetValue(574.9, 2); Numbers.SetValue(293749.064, 3); Numbers.SetValue(0.70257, 4); Console.WriteLine("Number: {0}", Numbers.GetValue(0)); }

return 0;

C# 3.0 Practical Learning

604

}

When calling the Array.GetValue() method, if you pass an invalid value, the compiler would throw an IndexOutOfRangeException exception. Just as you can access one member of the array, you can access any member using its index. Here is an example that uses a for loop and the Length property to know the number of members of an array: using System; public class Exercise { static int Main(string[] args) { //var Numbers = Array.CreateInstance(typeof(double), 5); var Numbers = new double[5]; Numbers.SetValue(7628.937, 0); Numbers.SetValue(6.48, 1); Numbers.SetValue(574.9, 2); Numbers.SetValue(293749.064, 3); Numbers.SetValue(0.70257, 4); for(int i = 0; i < Numbers.Length; i++) Console.WriteLine("Number: {0}", Numbers.GetValue(i)); return 0; }

}

If using the foreach operator, you don't need the GetValue() method. Here is an example: using System; public class Exercise { static int Main(string[] args) { var Numbers = new double[5]; Numbers.SetValue(7628.937, 0); Numbers.SetValue(6.48, 1); Numbers.SetValue(574.9, 2); Numbers.SetValue(293749.064, 3); Numbers.SetValue(0.70257, 4); foreach(var Number in Numbers) Console.WriteLine("Number: {0}", Number); }

return 0;

}

Multidimensional Arrays

C# 3.0 Practical Learning

605

Two-Dimensional Arrays The Array class supports the creation of any of the types of arrays we saw in the previous lessons. In the previous lesson, we saw that a two-dimensional array was an array made of two lists: using System; public static class Exercise { public static int Main(string[] args) { var Members = new string[List1Length, List2Length]; }

return 0;

}

To create such an array using the Array class, you can use the following version of the Array.CreateInstance() method: public static Array CreateInstance(Type elementType, int length1, int length2)

The first argument is the type of array you want to create. The second argument is the length of the first list. The third argument is the length of the second list. Here is an example of using it: using System; public static class Exercise { public static int Main(string[] args) { var Members = Array.CreateInstance(typeof(string), 2, 4); }

return 0;

}

To specify the values of a two-dimensional array, you can use the following version of the Array.SetValue() method: public void SetValue(object value, int index1, int index2)

The first argument is the value you want to add. The second argument is the index of the list. The second argument is the index of the element that is being added. Here is an example: using System; public static class Exercise { public static int Main(string[] args) { var Members = Array.CreateInstance(typeof(string), 2, 4); Members.SetValue("Celeste", 0, 0); // 1st List - 1st Element Members.SetValue("Mathurin", 0, 1); // 1st List - 2nd Element

C# 3.0 Practical Learning

606

Members.SetValue("Alex", 0, 2); Members.SetValue("Germain",0, 3);

// 1st List - 3rd Element // 1st List - 4th Element

Members.SetValue("Jeremy", 1, 0); // 2nd List - 1st Element Members.SetValue("Mathew", 1, 1); // 1st List - 2nd Element Members.SetValue("Anselme", 1, 2); // 1st List - 3rd Element Members.SetValue("Frederique", 1, 3);// 1st List - 4th Element return 0; }

}

Just as mentioned for the one-dimensional array, you can use the square brackets to create the array but call the SetValue() method to specify the value of each element. To access a member of a two-dimensional array created with the Array.SetValue() method, you use the following version of the Array.GetValue() method: public Object GetValue(int index1, int index2)

This method takes two arguments. The first argument is the index of the list where the desired member resides. The second argument is the index of the element itself. Here is an example: using System; public static class Exercise { public static int Main(string[] args) { var Members = Array.CreateInstance(typeof(string), 2, 4); Members.SetValue("Celeste", 0, 0); Members.SetValue("Mathurin", 0, 1); Members.SetValue("Alex", 0, 2); Members.SetValue("Germain",0, 3);

// // // //

1st 1st 1st 1st

List List List List

-

1st 2nd 3rd 4th

Element Element Element Element

Members.SetValue("Jeremy", 1, 0); // 2nd List - 1st Element Members.SetValue("Mathew", 1, 1); // 1st List - 2nd Element Members.SetValue("Anselme", 1, 2); // 1st List - 3rd Element Members.SetValue("Frederique", 1, 3);// 1st List - 4th Element Console.WriteLine("Member: {0}", Members.GetValue(0, 2)); return 0; }

}

To access each member of the list, you can use two for loops. Use the first loop to access each list. Nest a second loop to it to access each member. To get the dimension of the main list, you can call the Array.GetLength() method and specify its argument as 0. For the internal loop, pass 1 as the argument to the Array.GetLength() method. Here is an example: using System; public static class Exercise {

C# 3.0 Practical Learning

607

public static int Main(string[] args) { var Members = Array.CreateInstance(typeof(string), 2, 4); Members.SetValue("Celeste", 0, 0); Members.SetValue("Mathurin", 0, 1); Members.SetValue("Alex", 0, 2); Members.SetValue("Germain",0, 3);

// // // //

1st 1st 1st 1st

List List List List

-

1st 2nd 3rd 4th

Element Element Element Element

Members.SetValue("Jeremy", 1, 0); // 2nd List - 1st Element Members.SetValue("Mathew", 1, 1); // 1st List - 2nd Element Members.SetValue("Anselme", 1, 2); // 1st List - 3rd Element Members.SetValue("Frederique", 1, 3);// 1st List - 4th Element for(int List = 0; List < Members.GetLength(0); List++) for(int Element = 0; Element < Members.GetLength(1); Element+

+)

Console.WriteLine("Member: {0}", Members.GetValue(List , Element )); return 0; }

}

You can also use a foreach operator to access each member of the array. When using it, there is no need for a counter. Here is an example: using System; public static class Exercise { public static int Main(string[] args) { var Members = Array.CreateInstance(typeof(string), 2, 4); Members.SetValue("Celeste", 0, 0); Members.SetValue("Mathurin", 0, 1); Members.SetValue("Alex", 0, 2); Members.SetValue("Germain",0, 3);

// // // //

1st 1st 1st 1st

List List List List

-

1st 2nd 3rd 4th

Element Element Element Element

Members.SetValue("Jeremy", 1, 0); // 2nd List - 1st Element Members.SetValue("Mathew", 1, 1); // 1st List - 2nd Element Members.SetValue("Anselme", 1, 2); // 1st List - 3rd Element Members.SetValue("Frederique", 1, 3);// 1st List - 4th Element foreach (string Member in Members) Console.WriteLine("Member: {0}", Member); return 0; }

}

Three-Dimensional Arrays Instead of two dimensions, you may want to create a three-dimensional arrays. A 3-D array is an array that, if created with the square brackets, would use two commas. Here is an example: using System;

C# 3.0 Practical Learning

608

public static class Exercise { static int Main(string[] args) { double[,,] Number; }

return 0;

}

To create such an array using the Array class, you can use the following version of its CreateInstance() method: public static Array CreateInstance(Type elementType, int length1, int length2, int length3)

Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Number = Array.CreateInstance(typeof(double), 2, 3, 5); return 0; }

}

To specify the value of each member of the three-dimensional array, you can call the following version of the Array.SetValue() method: public void SetValue ( Object value, int index1, int index2, int index3 )

Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Number = Array.CreateInstance(typeof(double), 2, 3, 5); Number.SetValue( 12.44, Number.SetValue( 525.38, Number.SetValue( -6.28, Number.SetValue(2448.32, Number.SetValue( 632.04, Number.SetValue(-378.05, Number.SetValue( 48.14, Number.SetValue( 634.18,

0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 1, 1, 1,

0); 1); 2); 3); 4); 0); 1); 2);

C# 3.0 Practical Learning

609

Number.SetValue( 762.48, Number.SetValue( 83.02, Number.SetValue( 64.92, Number.SetValue( -7.44, Number.SetValue( 86.74, Number.SetValue(-534.60, Number.SetValue( 386.73, Number.SetValue( 48.02, Number.SetValue( 120.44, Number.SetValue( 38.62, Number.SetValue( 526.82, Number.SetValue(1704.62, Number.SetValue( 56.85, Number.SetValue(105.48, Number.SetValue( 363.31, Number.SetValue( 172.62, Number.SetValue( 128.48, Number.SetValue( 906.68, Number.SetValue( 47.12, Number.SetValue(-166.07, Number.SetValue(4444.26, Number.SetValue( 408.62, }

0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,

3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4);

return 0;

}

To get the value of each member of the three-dimensional array, you can call the following version of the Array.GetValue() method: public Object GetValue ( int index1, int index2, int index3 )

Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Number = Array.CreateInstance(typeof(double), 2, 3, 5); Number.SetValue( 12.44, Number.SetValue( 525.38, Number.SetValue( -6.28, Number.SetValue(2448.32, Number.SetValue( 632.04, Number.SetValue(-378.05, Number.SetValue( 48.14, Number.SetValue( 634.18, Number.SetValue( 762.48, Number.SetValue( 83.02, Number.SetValue( 64.92, Number.SetValue( -7.44, Number.SetValue( 86.74, Number.SetValue(-534.60,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2,

0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3);

C# 3.0 Practical Learning

610

Number.SetValue( 386.73, Number.SetValue( 48.02, Number.SetValue( 120.44, Number.SetValue( 38.62, Number.SetValue( 526.82, Number.SetValue(1704.62, Number.SetValue( 56.85, Number.SetValue(105.48, Number.SetValue( 363.31, Number.SetValue( 172.62, Number.SetValue( 128.48, Number.SetValue( 906.68, Number.SetValue( 47.12, Number.SetValue(-166.07, Number.SetValue(4444.26, Number.SetValue( 408.62,

0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

2, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,

4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4);

Console.WriteLine("Number: {0}\n", Number.GetValue(0, 2, 4)); }

return 0;

}

This would produce: Number: 386.73 Press any key to continue . . .

To access each member of the array, you can use three for loops. Here is an example: using System; public static class Exercise { static int Main(string[] args) { var Number = Array.CreateInstance(typeof(double), 2, 3, 5); Number.SetValue( 12.44, Number.SetValue( 525.38, Number.SetValue( -6.28, Number.SetValue(2448.32, Number.SetValue( 632.04, Number.SetValue(-378.05, Number.SetValue( 48.14, Number.SetValue( 634.18, Number.SetValue( 762.48, Number.SetValue( 83.02, Number.SetValue( 64.92, Number.SetValue( -7.44, Number.SetValue( 86.74, Number.SetValue(-534.60, Number.SetValue( 386.73, Number.SetValue( 48.02, Number.SetValue( 120.44, Number.SetValue( 38.62, Number.SetValue( 526.82, Number.SetValue(1704.62,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,

0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0,

0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4);

C# 3.0 Practical Learning

611

Number.SetValue( 56.85, Number.SetValue(105.48, Number.SetValue( 363.31, Number.SetValue( 172.62, Number.SetValue( 128.48, Number.SetValue( 906.68, Number.SetValue( 47.12, Number.SetValue(-166.07, Number.SetValue(4444.26, Number.SetValue( 408.62,

1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

1, 1, 1, 1, 1, 2, 2, 2, 2, 2,

0); 1); 2); 3); 4); 0); 1); 2); 3); 4);

for(int External = 0; External < Number.GetLength(0); External++) for(int Internal = 0; Internal < Number.GetLength(1); Internal++) for(int Element = 0; Element < Number.GetLength(2); Element++) Console.WriteLine("Number: {0}", Number.GetValue(External, Internal, Element)); return 0; }

}

This would produce: Number: 12.44 Number: 525.38 Number: -6.28 Number: 2448.32 Number: 632.04 Number: -378.05 Number: 48.14 Number: 634.18 Number: 762.48 Number: 83.02 Number: 64.92 Number: -7.44 Number: 86.74 Number: -534.6 Number: 386.73 Number: 48.02 Number: 120.44 Number: 38.62 Number: 526.82 Number: 1704.62 Number: 56.85 Number: 105.48 Number: 363.31 Number: 172.62 Number: 128.48 Number: 906.68 Number: 47.12 Number: -166.07 Number: 4444.26 Number: 408.62 Press any key to continue . . .

You can also use a foreach loop to access each member of the array. Here is an example: C# 3.0 Practical Learning

612

using System; public static class Exercise { static int Main(string[] args) { var Number = Array.CreateInstance(typeof(double), 2, 3, 5); Number.SetValue( 12.44, Number.SetValue( 525.38, Number.SetValue( -6.28, Number.SetValue(2448.32, Number.SetValue( 632.04, Number.SetValue(-378.05, Number.SetValue( 48.14, Number.SetValue( 634.18, Number.SetValue( 762.48, Number.SetValue( 83.02, Number.SetValue( 64.92, Number.SetValue( -7.44, Number.SetValue( 86.74, Number.SetValue(-534.60, Number.SetValue( 386.73, Number.SetValue( 48.02, Number.SetValue( 120.44, Number.SetValue( 38.62, Number.SetValue( 526.82, Number.SetValue(1704.62, Number.SetValue( 56.85, Number.SetValue(105.48, Number.SetValue( 363.31, Number.SetValue( 172.62, Number.SetValue( 128.48, Number.SetValue( 906.68, Number.SetValue( 47.12, Number.SetValue(-166.07, Number.SetValue(4444.26, Number.SetValue( 408.62,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,

0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4); 0); 1); 2); 3); 4);

foreach(double n in Number) Console.WriteLine("Number: {0}", n); return 0; }

}

Multidimensional Arrays The Array class supports all dimensions of arrays beyond three. To create a multidimensional array, the class is equipped with the following version of its CreateInstance() method: public static Array CreateInstance(Type elementType, params int[] lengths)

To add elements to the list, you can use the following equivalent version of the SetValue() method: public void SetValue(object value, params int[] indices)

C# 3.0 Practical Learning

613

To get the value of an element, you would call the following version of the GetValue() method: public Object GetValue(params int[] indices)

Arranging the List Arranging the Items in Alphabetical or Numerical Order When you initialize an array, you add the members in an order of your choice. At one point, when accessing the members of an array, you may want them to be arranged in alphabetical, in numerical, or in chronological order. To assist you with re-arranging the elements in an array, the Array class is equipped with a method named Sort that is overloaded with as many versions as you can possibly need. To arrange an array of the type we have used so far, you can call the following version of the Array.Sort() method: public static void Sort(Array array);

This is a static method that takes as argument the name of the array you want to re-arrange. Here is an example: using System; public class Exercise { static int Main(string[] args) { var Numbers = new double[] { 7628.937, 6.48, 574.9, 293749.064, 0.70257, 314.905, 80458.01 }; Console.WriteLine("List of Numbers"); foreach(var Number in Numbers) Console.WriteLine("Number: {0}", Number); Array.Sort(Numbers); Console.WriteLine("\nList of Numbers"); foreach (var Number in Numbers) Console.WriteLine("Number: {0}", Number); }

return 0;

}

This would produce: List of Numbers Number: 7628.937 Number: 6.48

C# 3.0 Practical Learning

614

Number: Number: Number: Number: Number:

574.9 293749.064 0.70257 314.905 80458.01

List of Numbers Number: 0.70257 Number: 6.48 Number: 314.905 Number: 574.9 Number: 7628.937 Number: 80458.01 Number: 293749.064 Press any key to continue . . .

Notice that the numbers are arranged in in ascending order. In the same way, if the array is made of strings, you can call the Array.Sort() method to arrange it in alphabetical order. If the array is made of dates, you can arrange them in chronological order.

Reversing the Arrangement To arrange the members in reverse order, you can call the Array.Reverse() method. Its syntax is: public static void Reverse(Array array);

Locating an Element in an Array Locating the Index of an Element One of the most routine operations you can perform on an array is to find out whether it contains this or that value. For example, if the array contains a certain member, you may want to retrieve the index of that member. To assist you with this, the Array class is equipped with a method named IndexOf() method that comes in various versions. To apply it on the type of array we have used so far, you can use the following syntax: public static int IndexOf(Array array, object value);

This method visits each member of the array, looking for the value. Once it finds value in the array, it stops and returns the index where the first occurrence of value was found. Here is an example of calling it: using System; public class Exercise { static int Main(string[] args) { var Numbers = new double[] { 7628.937, 6.48, 574.9, 293749.064,

C# 3.0 Practical Learning

615

0.70257, 314.905, 80458.01 }; Console.WriteLine("List of Numbers"); foreach(var Number in Numbers) Console.WriteLine("Number: {0}", Number); Console.WriteLine(); int Index = Array.IndexOf(Numbers, 314.905); Console.WriteLine("The index of 314.905 is {0}", Index); return 0; }

}

If the Array.IndexOf() method finds the value in the array, it returns its position. The above program produces: List of Number: Number: Number: Number: Number: Number: Number:

Numbers 7628.937 6.48 574.9 293749.064 0.70257 314.905 80458.01

The index of 314.905 is 5 Press any key to continue . . .

If the array is not found, the method may return -1. The IndexOf() method actually looks for the first occurrence of an item in an array. If you prefer to get the last occurrence of that item in the array, you can call the Array.LastIndexOf() method. It also is overloaded in three versions.

The Bounds of an Array To better manage an array, the compiler must always be able to locate its highest and its lowest members. This is particularly important because an array must have a size. The

lowest

member of an array can Array.GetLowerBound() method. Its syntax is:

be

located

using

the

be

located

using

the

public int GetLowerBound(int dimension);

The

highest

member of an array can Array.GetUpperBound() method. Its syntax is: public int GetUpperBound(int dimension);

In both cases, the dimension argument is the rank of the array. For a singledimensional array, as those we have always used so far, this parameter must have the value of 0. C# 3.0 Practical Learning

616

C# 3.0 Practical Learning

617

Strings The Characters of a String Introduction To represent the values of an application, we primarily use characters, letters, and symbols from the alphabet or out of the alphabet. To recognize these symbols, the C# language provides the char data type. The char data type is identified in the .NET Framework by the Char structure, which gets represented with a 16-bit value. To declare a variable that can hold one character, a letter, or a symbol, user the char data type or the var keyword if you are also initializing the variable. To initialize the variable, include its value between two single-quotes. Here are examples:

using System; public static class Exercise { public static int Main(string[] args) { var Gender = 'm'; var MoneySymbol = '$'; var Multiplication = '*'; var NumberOne = '1'; Console.WriteLine("A few characters"); Console.WriteLine("Gender: {0}", Console.WriteLine("Money Symbol: {0}", Console.WriteLine("Multiplication: {0}", Console.WriteLine("Number One: {0}",

Gender); MoneySymbol); Multiplication); NumberOne);

return 0; }

}

This would produce: A few characters Gender: m Money Symbol: $ Multiplication: * Number One: 1 Press any key to continue...

C# 3.0 Practical Learning

618

Practical Learning: Introducing Strings 1. Start Microsoft Visual C# and create a new Console Application named RealEstate4

2. To create a new class, on the main menu, click Project -> Add Class... 3. Set the Name to Property and press Enter 4. Change the file as follows: using using using using

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

namespace RealEstate4 { public enum PropertyCondition { Unknown, Excellent, Good, NeedsRepair, BadShape } public class Property { private string propNbr; private PropertyCondition cond; private short beds; private float baths; private int yr; private decimal val; public Property() { } public string PropertyNumber { get { return propNbr; } set { if (propNbr == "") propNbr = "N/A"; else propNbr = value; } } public PropertyCondition Condition { get { return cond; } set { cond = value; } }

C# 3.0 Practical Learning

619

public short Bedrooms { get { if (beds <= 1) return 1; else return beds; } set { beds = value; } } public float Bathrooms { get { return (baths <= 0) ? 0.00f : baths; } set { baths = value; } } public int YearBuilt { get { return yr; } set { yr = value; } } public decimal Value { get { return (val <= 0) ? 0.00M : val; } set { val = value; } } }

}

5. In the Class View, right-click RealEstate4 -> Add -> Class... 6. Set the Name to HouseType and press Enter 7. To derive a class, change the file as follows: using using using using

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

namespace RealEstate4 { public class HouseType : Property { private short nbrOfStories; private bool basement; private bool garage; public short Stories { get { return nbrOfStories; } set { nbrOfStories = value; } } public bool FinishedBasement {

C# 3.0 Practical Learning

620

}

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

public bool IndoorGarage { get { return garage; } set { garage = value; } } }

}

8. To create a new class, in the Solution Explorer, right-click RealEstate4, position the mouse on Add and click Class... 9. Set the Name to Condominium and click Add 10. To create another class based on the Property class, change the file as follows: using using using using

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

namespace RealEstate4 { public class Condominium : Property { private bool handicap; public bool HandicapAccessible { get { return handicap; } set { handicap = value; } } }

}

11. 12.

In the Solution Explorer, right- click RealEstate4 -> Add -> Class...

13. Set the Name to PropertyListing and press Enter 14. using using using using

Change the file as follows: System; System.Collections.Generic; System.Linq; System.Text;

namespace RealEstate4 { public enum PropertyType { Unknown, SingleFamily,

C# 3.0 Practical Learning

621

}

Townhouse, Condominium

public class PropertyListing { private Property prop; private HouseType hse; private Condominium cond; private PropertyType tp; public Property ListProperty { get { return prop; } set { prop = value; } } public HouseType House { get { return hse; } set { hse = value; } } public Condominium Condo { get { return cond; } set { cond = value; } } public PropertyType Type { get { return tp; } set { tp = value; } } public PropertyListing() { prop = new Property(); hse = new HouseType(); cond = new Condominium(); } public void CreateListing() { char answer = 'n'; short propType = 1; short condition = 1; Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("-=- Property Creation -=-"); try { Console.WriteLine("\nTypes of Properties"); Console.WriteLine("1. Single Family"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Condominium"); Console.WriteLine("4. Don't Know"); Console.Write("Enter Type of Property: "); propType = short.Parse(Console.ReadLine()); }

C# 3.0 Practical Learning

622

catch (FormatException) { Console.WriteLine("The value you entered for " + "the type of property is invalid"); } catch (Exception) { Console.WriteLine("A bad behavior has been detectedd"); } Console.Write("\nEnter Property #: "); ListProperty.PropertyNumber = Console.ReadLine(); try { Console.WriteLine("\nProperties Conditions"); Console.WriteLine("1. Excellent"); Console.WriteLine("2. Good (may need minor repair)"); Console.WriteLine("3. Needs Repair"); Console.WriteLine("4. In Bad Shape (property needs "); Console.WriteLine("major repair or rebuild)"); Console.Write("Enter Property Condition: "); condition = short.Parse(Console.ReadLine());

happened");

} catch (FormatException) { Console.WriteLine("The value you entered for the " + "condition of the property is not valid"); } catch (Exception) { Console.WriteLine("An unacceptable event has just } if (condition == 1) ListProperty.Condition else if (condition == 2) ListProperty.Condition else if (condition == 3) ListProperty.Condition else if (condition == 4) ListProperty.Condition else ListProperty.Condition

= PropertyCondition.Excellent; = PropertyCondition.Good; = PropertyCondition.NeedsRepair; = PropertyCondition.BadShape; = PropertyCondition.Unknown;

switch ((PropertyType)propType) { case PropertyType.SingleFamily: Type = PropertyType.SingleFamily; try { Console.Write("\nHow many stories (levels)? "); House.Stories = short.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine( "The number of stories you entered is not allowed"); }

C# 3.0 Practical Learning

623

catch (Exception) { Console.WriteLine("An abnormal behavior has occurred");

} try {

Console.Write( "Does it have an indoor car garage (y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else House.IndoorGarage = false;

} catch (FormatException) { Console.WriteLine("Invalid Indoor Car Garage Answer");

} try { Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false; } catch (FormatException) { Console.WriteLine("Invalid Basement Answer"); } break; case PropertyType.Townhouse: Type = PropertyType.Townhouse; try { Console.Write("\nHow many stories (levels)? "); House.Stories = short.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The number of stories " + "you entered is not valid"); } catch (Exception) { Console.WriteLine("This is one of " + "those abnormal behaviors"); } Console.Write("Does it have an indoor car garage

(y/n): ");

answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else

C# 3.0 Practical Learning

624

House.IndoorGarage = false; Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false; break; case PropertyType.Condominium: Type = PropertyType.Condominium; Console.Write("\nIs the building accessible " + "to handicapped (y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) Condo.HandicapAccessible = true; else Condo.HandicapAccessible = false; break; default: Type = PropertyType.Unknown; break; } try { Console.Write("\nHow many bedrooms? "); ListProperty.Bedrooms = short.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The value you entered for " + "the number of bedrooms is not good"); } catch (Exception) { Console.WriteLine("The program has decided to stop"); } try {

error");

Console.Write("How many bathrooms? "); ListProperty.Bathrooms = float.Parse(Console.ReadLine());

} catch (Exception) { Console.WriteLine("The computer has encountered an } try {

Console.Write("Year built: "); ListProperty.YearBuilt = int.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The house cannot have built in that year");

C# 3.0 Practical Learning

625

problem");

} catch (Exception) { Console.WriteLine("The application is experiencing a } try { Console.Write("Property Value: "); ListProperty.Value = decimal.Parse(Console.ReadLine()); } catch (Exception) { Console.WriteLine("This is where the application " + "draws the line: it stops!"); }

} public void ShowListing() { Console.WriteLine("=================================="); Console.WriteLine(" =//=//= Altair Realty =//=//="); Console.WriteLine("-=-=-=- Properties Listing -=-=-=-"); Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", ListProperty.PropertyNumber); Console.WriteLine("Property Type: {0}", Type); switch (Type) { case PropertyType.SingleFamily: case PropertyType.Townhouse: Type = PropertyType.SingleFamily; Console.WriteLine("Stories: {0}", House.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", House.IndoorGarage); Console.WriteLine("Finished Basement: {0}", House.FinishedBasement); break; case PropertyType.Condominium: Console.WriteLine("Handicapped Accessible Building:

{0}",

Condo.HandicapAccessible); break; } Console.WriteLine("Condition: ListProperty.Condition); Console.WriteLine("Bedrooms: ListProperty.Bedrooms); Console.WriteLine("Bathrooms: ListProperty.Bathrooms); Console.WriteLine("Year Built: ListProperty.YearBuilt); Console.WriteLine("Market Value: ListProperty.Value);

{0}", {0}", {0:F}", {0}", {0:C}",

}

C# 3.0 Practical Learning

626

} }

15. using using using using

Access the Program.cs file and change it as follows: System; System.Collections.Generic; System.Linq; System.Text;

namespace RealEstate4 { public class Program { static void Main(string[] args) { PropertyListing Listing = new PropertyListing();

} }

Listing.CreateListing(); Console.WriteLine("\n"); Listing.ShowListing();

}

16.

Execute the application and test it. Here is an example:

=//= Altair Realty =//= -=- Property Creation -=Types of Properties 1. Single Family 2. Townhouse 3. Condominium 4. Don't Know Enter Type of Property: 1 Enter Property #: 793742 Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 3 How many stories (levels)? 3 Does it have an indoor car garage (y/n): p Is the basement finished(y/n): t How many bedrooms? How many bathrooms? Year built: Property Value:

4 3.5 1994 658225.85

================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=-

C# 3.0 Practical Learning

627

---------------------------------Property #: 793742 Property Type: SingleFamily Stories: 3 Has Indoor Car Garage: False Finished Basement: False Condition: NeedsRepair Bedrooms: 4 Bathrooms: 3.50 Year Built: 1994 Market Value: $658,225.85 Press any key to continue . . .

17.

Close the DOS window

The String: An Array of Characters In different programs so far, when we needed a string object, we would declare a variable of type String. To support strings, the .NET Framework provides the String class. This class is defined in the C# language as the string data type. Here is an example of declaring, initializing, and using a string object: using System; public class Exercise { static int Main(string[] args) { var gender = "Female"; Console.WriteLine("Gender:

{0}\n", gender);

return 0; }

}

This would produce: Gender:

Female

Press any key to continue . . .

From what we have studied about arrays, if you observe a value such as "Female", you may see that it primarily resembles a collection of characters. A string is a group of characters. This also means that a string is an array of characters. After declaring and initializing a string, it is considered an array of values where each character occupies a specific position. The positioned are numbered so that the most left character of the string occupies index 0; the second character is at index 1, and so on. To support this idea of an array of characters, the String class is equipped with an indexed property named Chars. This is also how you can retrieve the character at a specific index in the string, using the [] operator of arrays. Here is an example: using System;

C# 3.0 Practical Learning

628

public class Exercise { static int Main(string[] args) { var gender = "Female"; var gdr = gender[2]; Console.WriteLine("Gender: {0}", gender); Console.WriteLine("Character: {0}", gdr); Console.WriteLine(); return 0; }

}

This would produce: Gender: Female Character: m Press any key to continue . . .

Once (and because) a string is considered a collection of items, you can use the foreach operator to access each member of the collection. Here is an example: using System; class Exercise { static int Main(string[] args) { var gender = "Female"; Console.WriteLine("Gender: {0}", gender); Console.WriteLine("\nIndividual Characters"); foreach(char c in gender) Console.WriteLine("Character: {0}", c); return 0; }

}

This would produce: Gender: Female Individual Characters Character: F Character: e Character: m Character: a Character: l Character: e Press any key to continue . . .

Converting Characters to the Opposite Case

C# 3.0 Practical Learning

629

The English language uses two character representations: lowercase and uppercase. The characters in lowercase are: a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, and z. The equivalent characters in uppercase are represented as A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, and Z. Characters used for counting are called numeric characters; each one of them is called a digit. They are 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9. There are other characters used to represent things in computer applications, mathematics, and others. Some of these characters, also called symbols are ~ , ! @ # $ % ^ & * ( ) _ + { } ` | = [ ] \ : " ; ' < > ? , . / These characters are used for various reasons and under different circumstances. For example, some of them are used as operators in mathematics or in computer programming. Regardless of whether a character is easily identifiable or not, all these symbols are character types and can be declared using the char data type followed by a name. An alphabetic character, for any reason judged necessary, can be converted from one case to another. The other characters, non-alphabetic symbols, and the numbers, do not have a case and therefore cannot be converted in cases. To convert a string from lowercase to uppercase, you can call use the ToUpper() method of the String class. It is overloaded with two versions. One of the versions of this method uses the following syntax: public string ToUpper();

This method takes no argument. This method considers each character of the string that called it. If the character is already in uppercase, it would not change. If the character is a lowercase alphabetic character, it would be converted to uppercase. If the character is not an alphabetic character, it would be kept “as-is”. Here is an example: using System; public class Program { static int Main(string[] args) { var strFullName = "Alexander Patrick Katts"; var strConversion = strFullName.ToUpper(); Console.WriteLine("Full Name: " + strFullName); Console.WriteLine("Full Name: " + strConversion); }

return 0;

}

This would produce: Full Name: Alexander Patrick Katts Full Name: ALEXANDER PATRICK KATTS Press any key to continue . . .

To convert a string to lowercase, you can call the String.ToLower() method. Its syntax is: public string ToLower();

C# 3.0 Practical Learning

630

This method follows the same logic as its counterpart: it scans the string that called it, visiting each character. If the character is not an alphabetic character, it would be kept “as-is”. If the character is an uppercase alphabetic character, it would be converted to lowercase. If it is in lowercase, it would not be converted.

Replacing a Character If you have a string that contains a wrong character, you can either delete that character or replace it with another character of your choice. To support this operation, the String class is equipped with the Replace() method that is overloaded with two versions. One of the versions of the String.Replace() method uses the following syntax: public string Replace(char oldChar, char newChar);

The first argument of this method is used to identify the sought character. If and everywhere that character is found in the string, it would be replaced by the character passed as the second argument. Here is an example that received a telephone number from the user and it stripped that phone number with various things to end up with only the digits: using System; public class Program { static int Main(string[] args) { var PhoneNumber = ""; Console.Write("Enter Phone Number: "); PhoneNumber = Console.ReadLine(); // Get a telephone number from the user Console.WriteLine("\nPhone Number: " + PhoneNumber); // Remove the spaces PhoneNumber = PhoneNumber.Replace(" ", ""); Console.WriteLine("\nPhone Number: " + PhoneNumber); // Remove the left parenthesis, if any PhoneNumber = PhoneNumber.Replace("(", ""); // Remove the right parenthesis, if any PhoneNumber = PhoneNumber.Replace(")", ""); // Remove the dash, if any PhoneNumber = PhoneNumber.Replace("-", ""); Console.WriteLine("\nPhone Number: " + PhoneNumber + "\n"); return 0; }

}

Here is an example of running the program: Enter Phone Number: (303) 826-4603 Phone Number: (303) 826-4603 Phone Number: (303)826-4603

C# 3.0 Practical Learning

631

Phone Number: 3038264603 Press any key to continue . . .

Working With Strings The Length of a String In many operations, you will need to know the number of characters a string consists of. To get the size of a string, The String class provides the Length member variable. Here is an example of using it: using System; public class Exercise { static int Main(string[] args) { var gender = "Female"; Console.WriteLine("Gender: {0}", gender); Console.WriteLine("Length: {0} Characters\n", gender.Length); }

return 0;

}

This would produce: Gender: Female Length: 6 Characters Press any key to continue . . .

In the same way, you can access the Length property when processing the individual characters of a string. Here is an example: using System; public class Exercise { static int Main(string[] args) { var gender = "Female"; Console.WriteLine("Gender: {0}", gender); Console.WriteLine("Length: {0} Characters", gender.Length); Console.WriteLine("\nIndividual Characters"); for (int c = 0; c < gender.Length; c++) Console.WriteLine("Index[{0}]: {1}", c, gender[c]); }

return 0;

}

C# 3.0 Practical Learning

632

This would produce: Gender: Female Length: 6 Characters Individual Characters Index[0]: F Index[1]: e Index[2]: m Index[3]: a Index[4]: l Index[5]: e Press any key to continue . . .

Practical Learning: Using Characters of a String 1. To create a new file, on the main menu, click Project -> Add New Item... 2. In the Templates list, click Code File 3. Set the Name to NumericExceptions and click Add 4. Change the file as follows: using System; // This exception is used to check and validate an integer public class IntegerException : Exception { public IntegerException() { } public override string Message { get { return "The value you entered is not a valid integer"; } } } // This exception can be used to check and/or validate a decimal number public class FloatingPointException : Exception { public FloatingPointException() { } public override string Message { get { return "The value you entered is not a valid decimal number"; } } }

C# 3.0 Practical Learning

633

5. Access the PropertyListing.cs file and change it as follows: using using using using

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

namespace RealEstate4 { public enum PropertyType { Unknown, SingleFamily, Townhouse, Condominium } public class PropertyListing { . . . No Change public void CreateListing() { . . . No Change try { Console.Write("How many bathrooms? "); string strBathrooms = Console.ReadLine(); for (int c = 0; c < strBathrooms.Length; c++) { if ((strBathrooms[c] != '0') && (strBathrooms[c] != '1') && (strBathrooms[c] != '2') && (strBathrooms[c] != '3') && (strBathrooms[c] != '4') && (strBathrooms[c] != '5') && (strBathrooms[c] != '6') && (strBathrooms[c] != '7') && (strBathrooms[c] != '8') && (strBathrooms[c] != '9') && (strBathrooms[c] != '.')) throw new FloatingPointException(); } ListProperty.Bathrooms = float.Parse(strBathrooms); } catch (FloatingPointException ex) { Console.WriteLine(ex.Message); } catch (Exception) { Console.WriteLine("The computer has encountered an error");

} try {

Console.Write("Year built:

C# 3.0 Practical Learning

"); 634

ListProperty.YearBuilt = int.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The house cannot have " + "been built in that year"); } catch (Exception) { Console.WriteLine("The application is " + "experiencing a problem"); } try { Console.Write("Property Value: "); string strValue = Console.ReadLine(); for (int c = 0; c < strValue.Length; c++) { if ((strValue[c] != '0') && (strValue[c] != '1') && (strValue[c] != '2') && (strValue[c] != '3') && (strValue[c] != '4') && (strValue[c] != '5') && (strValue[c] != '6') && (strValue[c] != '7') && (strValue[c] != '8') && (strValue[c] != '9') && (strValue[c] != '.')) throw new FloatingPointException(); } ListProperty.Value = decimal.Parse(strValue); } catch (FloatingPointException ex) { Console.WriteLine(ex.Message); } catch (Exception) { Console.WriteLine("This is where the application " + "draws the line: it stops!"); } } }

. . . No Change

}

6. Execute the application and test it. Here is an example: =//= Altair Realty =//= -=- Property Creation -=Types of Properties 1. Single Family 2. Townhouse 3. Condominium 4. Don't Know

C# 3.0 Practical Learning

635

Enter Type of Property: 1 Enter Property #: 284866 Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 3 How many stories (levels)? 3 Does it have an indoor car garage (y/n): m Is the basement finished(y/n): u How many bedrooms? How many bathrooms? Year built: Property Value:

4 3.50 1995 735000

================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 284866 Property Type: SingleFamily Stories: 3 Has Indoor Car Garage: False Finished Basement: False Condition: NeedsRepair Bedrooms: 4 Bathrooms: 3.50 Year Built: 1995 Market Value: $735,000.00 Press any key to continue . . .

7. Close the DOS window 8. Execute the application again. Here is an example: =//= Altair Realty =//= -=- Property Creation -=Types of Properties 1. Single Family 2. Townhouse 3. Condominium 4. Don't Know Enter Type of Property: 1 Enter Property #: 284866 Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs

C# 3.0 Practical Learning

636

major repair or rebuild) Enter Property Condition: 3 How many stories (levels)? 3 Does it have an indoor car garage (y/n): N Is the basement finished(y/n): Y How many bedrooms? 4 How many bathrooms? 3.r0 The value you entered is not a valid decimal number Year built: 1995 Property Value: 7.35e5 The value you entered is not a valid decimal number ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 284866 Property Type: SingleFamily Stories: 3 Has Indoor Car Garage: False Finished Basement: True Condition: NeedsRepair Bedrooms: 4 Bathrooms: 0.00 Year Built: 1995 Market Value: $0.00 Press any key to continue . . .

9. Close the DOS window

Replacing a Sub-String Inside of a string, if you have a combination of consecutive character you don't want to keep, you can either remove that sub-string or replace it with an new combination of consecutive characters of your choice. To support this operation, the String class provides anopther version of the the Replace() method whose syntax is: public string Replace(string oldStr, string newStr);

The oldStr argument is the sub-string to look for in the string. Whenever that sub-string is found in the string, it is replaced by the newStr argument.

Formatting a String Formatting a string consists of specifying how it would be presented as an object. To support this operation, the String class is equipped with a static method named Format. The String.Format() method is overloaded in various versions; the syntax of the simplest is: public static string Format(string format, Object arg0);

This method takes two arguments and it follows the same techniques we reviewed in Lesson 5 for data formatting. This means that the first argument C# 3.0 Practical Learning

637

can contain one or a combination of {} operators that include incrementing numbers. The second argument contains one or a combination of values that would be added to the {} operators of the first argument. Here is an example: using System; public class Exercise { static int Main(string[] args) { var wage = 22.45; var strDisplay = string.Format("Hourly Salary: {0}", wage); Console.WriteLine(strDisplay); }

return 0;

}

This would produce: Side: 25.85 Hourly Salary: 22.45 Press any key to continue . . .

Copying a String After declaring and initializing one String variable, you can assign it to another String variable using the assignment operator. Here is an example: using System; public class Exercise { static int Main(string[] args) { var strPerson = "Charles Stanley";

var strSomebody = strPerson; Console.WriteLine("Full Name: " + strPerson); Console.WriteLine("Full Name: " + strSomebody); }

return 0;

}

This would produce: Full Name: Charles Stanley Full Name: Charles Stanley Press any key to continue . . .

Assigning one variable to another is referred to as copying it. To formally support this operator, the String class is equipped with the Copy() method. Its syntax is: C# 3.0 Practical Learning

638

public static string Copy(string str);

This method takes as argument an existing String object and copies it, producing a new string. Here is an example: using System; class Program { static int Main(string[] args) { var strPerson = "Charles Stanley";

var strSomebody = string.Copy(strPerson); Console.WriteLine("Full Name: " + strPerson); Console.WriteLine("Full Name: " + strSomebody); return 0; }

}

The string.Copy() method is used to copy all characters of one string into another another. If you want to copy only a few characters, use the string.CopyTo() method. Its syntax is: public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count);

Operations on Strings String Concatenation One of the routine operations you can perform on two strings consists of adding one to another, that is, putting one string to the right of another string, to produce a new string made of both. There are two techniques you can use. To add one string to another, you can use the addition operator as done in arithmetic. Here is an example: using System; public class Exercise { static int Main(string[] args) { var strNeed = "Needs"; var strRepair = "Repair"; var strAddition = strNeed + strRepair; Console.WriteLine(strAddition);

C# 3.0 Practical Learning

639

return 0; }

}

This would produce: NeedsRepair Press any key to continue . . .

In the same way, you can add as many strings as necessary using +. Here is an example: using System; public class Exercise { static int Main(string[] args) { var strFirstName = "Alexander"; var strMiddleName = "Patrick"; var strLastName = "Katts"; var strFullName = strFirstName + " " + strMiddleName + " " + strLastName; Console.WriteLine("First Name: Console.WriteLine("Middle Name: Console.WriteLine("Last Name: Console.WriteLine("Full Name: }

" " " "

+ + + +

strFirstName); strMiddleName); strLastName); strFullName + "\n");

return 0;

}

This would produce: First Name: Middle Name: Last Name: Full Name:

Alexander Patrick Katts Alexander Patrick Katts

Press any key to continue . . .

Besides the addition operator, to formally support string concatenation, the String class provides the Concat() method that is overloaded in various versions. One of the versions of this method takes two String arguments. Its syntax is: public static string Concat(string str1, string str2);

This versions takes two strings that should be concatenated. The method returns a new string as the first added to the second. Two imitations of this version use the following versions: public static string Concat(string str0, string str1, string str2); public static string Concat(string str0, string str1, string str2,

C# 3.0 Practical Learning

640

string str3);

In each case, the method takes the number of strings and adds them.

Strings Comparisons Introduction String comparison consists of examining the characters of two strings with a character of one string compared to a character of the other string with both characters at the same positions. To support this operation, the String class is equipped with the Compare() method that is overloaded in many versions. One of the versions uses the following syntax: public static int Compare(string String1, string

String2);

This method is declared static and it takes two arguments. When it starts, the first character of the first argument is compared to the first character of the second string. Alphabetically, if the first character of the first string has a lower alphabetical index than the first character of the second, this method returns a negative value. If the first character of the first string has a higher alphabetical index than the first character of the second, this method returns a positive value. If the first characters of both strings are the same, the method continues with the second character of each string. If both strings have the exact same characters, the method returns 0. This can be resumed as follows. The method returns •

A negative value if string1 is less than string2



0 if string1 and string2 are equal



A positive value if string1 is greater than string2

Here is an example: using System; public class Exercise { static int Main(string[] args) { var FirstName1 = "Andy"; var LastName1 = "Stanley"; var FirstName2 = "Charles"; var LastName2 = "Stanley"; var Value1 = string.Compare(FirstName1, FirstName2); var Value2 = string.Compare(FirstName2, FirstName1); var Value3 = string.Compare(LastName1, LastName2); Console.WriteLine("The result of comparing " + FirstName1 + " and " + FirstName2 + " is\t" + Value1.ToString()); Console.WriteLine("The result of comparing " + FirstName2 + " and " + FirstName1 + " is\t" + Value2.ToString());

C# 3.0 Practical Learning

641

Console.WriteLine("The result of comparing " + LastName1 + " and " + LastName2 + " is\t" + Value3.ToString() + "\n"); return 0; }

}

This would produce: The result of comparing Andy and Charles is The result of comparing Charles and Andy is The result of comparing Stanley and Stanley is

-1 1 0

Press any key to continue...

When using this version of the string.Compare() method, the case (upper or lower) of each character is considered. If you don't want to consider this factor, the String class proposes another version of the method. Its syntax is: public static int Compare(string String1, string String2, bool ignoreCase);

The third argument allows you to ignore the case of the characters when performing the comparison.

String Equality In the previous section, we saw that the indexed-equivalent characters of two strings can be compared to know whether one is lower or higher than the other's. If you are only interested to know whether two strings are equivalent, you can call the Equals() method of the String class. It is overloaded with various versions. Two versions use the following syntaxes: public override bool Equals(object obj); public bool Equals(string value);

When calling one of these versions, use an Object object or a String variable that calls it. The method takes one argument. The variable that calls the method is compared to the value passed as argument. If both values are the exact same, the method returns true. The comparison is performed considering the case of each character. If you don't want to consider the case, use the following version of the method: public bool Equals(string value, StringComparison comparisonType);

An alternative to the second syntax is to use a static version of this method whose syntax is: public static bool Equals(string a, string b);

This method takes two String arguments and compares them. If they are the same, the method returns true. This method considers the cases of the characters. If you don't want this factor taken into consideration, use the following version of the method: public static bool Equals(string a, string b, StringComparison comparisonType);

C# 3.0 Practical Learning

642

Working With Sub-Strings Introduction A sub-string is a section or part of a string. To create a sub-string, you first need a string and can retrieve one or more values from it. To support this, the String class is equipped with the Substring() method that is overloaded in two versions. The syntax of one is: public string Substring(int startIndex);

The integer argument specifies the position of the first character from the variable that called the method. The return value is a new String that is made of the characters from startIndex to the end of the string.

Sub-String Creation Probably the most consistent way to create a string is to control the beginning and end retrieved from the original string. To support this, the String class is equipped with another version of the Substring() method. Its syntax is: public string

Substring(int startIndex, int length);

The first argument specifies the index of the character to start from the String variable that calls this method. The second argument specifies the length of the string.

C# 3.0 Practical Learning

643

Introduction to Indexers A Property Can Be Indexed Introduction In the previous sections, we learned how to create an array, how to assign values to its elements, and how to get the value of each element. Here is an example: using System; public class Exercise { static int Main(string[] args) { double[] Numbers = new double[5]; Numbers[0] Numbers[1] Numbers[2] Numbers[3] Numbers[4]

= = = = =

927.93; 45.155; 2.37094; 73475.25; 186.72;

for (int i = 0; i < Numbers.Length; i++) Console.WriteLine("Number {0}: {1}", i+1, Numbers[i]);

}

Console.WriteLine(); return 0;

}

This would produce: Number Number Number Number Number

1: 2: 3: 4: 5:

927,93 45,155 2,37094 73475,25 186,72

Press any key to continue . . .

In the same way, if we declared an array as a member variable of a class, to access the elements of that member, we had to use an instance of the class, followed by the period operator, followed by the member variable applied with the square brackets. Instead of accessing each element through its member variable, you can create a type of property referred to as an indexer. C# 3.0 Practical Learning

644

Practical Learning: Introducing Indexed Properties 1. Start a new Console Application named PropertyRental1 2. To create a new class, on the main menu, click Project -> Add Class... 3. Set the Name to Property and press Enter 4. Change the file as follows: using using using using using

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

namespace PropertyRental1 { public enum Condition { Excellent, Good, NeedsRepair, Unknown } public class Property { private long propCode; private Condition cond; private short beds; private float baths; private decimal val; public long PropertyCode { get { return propCode; } set { propCode = value; } } public Condition PropertyCondition { get { return cond; } set { cond = value; } } public short Bedrooms { get { return beds; } set { beds = value; } } public float Bathrooms { get { return (baths <= 0) ? 0.00f : baths; } set { baths = value; } }

C# 3.0 Practical Learning

645

public decimal MonthlyRent { get { return (val <= 0) ? 0.00M : val; } set { val = value; } } public Property() { Random rnd = new Random(); propCode = rnd.Next(100000, 999999); cond = Condition.Unknown; beds = 0; baths = 0.0f; val = 0.00M; } }

}

5. To create a new class, on the main menu, click Project -> Add Class... 6. Set the Name to PropertyListing and press Enter 7. Change the file as follows: using using using using

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

namespace PropertyRental1 { public class PropertyListing { public Property[] props; public PropertyListing() { Random rnd = new Random(); props = new Property[40]; // Create a few properties ready to be rented props[0] = new Property(); props[0].PropertyCode = rnd.Next(100000, 999999); props[0].PropertyCondition = Condition.Excellent; props[0].Bedrooms = 5; props[0].Bathrooms = 3.5f; props[0].MonthlyRent = 2650; props[1] = new Property(); props[1].PropertyCode = rnd.Next(100000, 999999); props[1].PropertyCondition = Condition.Excellent; props[1].Bedrooms = 3; props[1].Bathrooms = 2.5f; props[1].MonthlyRent = 1750; props[2] = new Property(); props[2].PropertyCode = rnd.Next(100000, 999999); props[2].PropertyCondition = Condition.Good; props[2].Bedrooms = 4;

C# 3.0 Practical Learning

646

props[2].Bathrooms = 2.5f; props[2].MonthlyRent = 2450; props[3] = new Property(); props[3].PropertyCode = rnd.Next(100000, 999999); props[3].PropertyCondition = Condition.Excellent; props[3].Bedrooms = 1; props[3].Bathrooms = 1.0f; props[3].MonthlyRent = 880; props[4] = new Property(); props[4].PropertyCode = rnd.Next(100000, 999999); props[4].PropertyCondition = Condition.Excellent; props[4].Bedrooms = 3; props[4].Bathrooms = 2.5f; props[4].MonthlyRent = 1880; props[5] = new Property(); props[5].PropertyCode = rnd.Next(100000, 999999); props[5].PropertyCondition = Condition.Good; props[5].Bedrooms = 2; props[5].Bathrooms = 1.0f; props[5].MonthlyRent = 1050;

} }

// Since we don't yet have a complete list of properties // Create some empty ones for (int i = 6; i < 40; i++) { props[i] = new Property(); }

}

8. Access the Program.cs file and change it as follows: using using using using

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

namespace PropertyRental1 { public class Program { static void Main(string[] args) { var properties = new PropertyListing(); var prop = new Property();

",

for (int i = 0; i < 6; i++) { Console.WriteLine("{0}.---------------------------------i + 1); Console.WriteLine("Property #: {0}", properties .props[i].PropertyCode); Console.WriteLine("Condition: {0}", properties .props[i].PropertyCondition);

C# 3.0 Practical Learning

647

Console.WriteLine("Bedrooms: {0}", properties .props[i].Bedrooms); Console.WriteLine("Bathrooms: {0}", properties .props[i].Bathrooms); Console.WriteLine("Market Value: {0}\n", properties .props[i].MonthlyRent.ToString("C"));

} }

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

}

9. Press Ctrl + F5 to execute the application. This would produce: 1.---------------------------------Property #: 920119 Condition: Excellent Bedrooms: 5 Bathrooms: 3.5 Market Value: $2,650.00 2.---------------------------------Property #: 587917 Condition: Excellent Bedrooms: 3 Bathrooms: 2.5 Market Value: $1,750.00 3.---------------------------------Property #: 904376 Condition: Good Bedrooms: 4 Bathrooms: 2.5 Market Value: $2,450.00 4.---------------------------------Property #: 421662 Condition: Excellent Bedrooms: 1 Bathrooms: 1 Market Value: $880.00 5.---------------------------------Property #: 305196 Condition: Excellent Bedrooms: 3 Bathrooms: 2.5 Market Value: $1,880.00 6.---------------------------------Property #: 503836 Condition: Good Bedrooms: 2 Bathrooms: 1 Market Value: $1,050.00 ====================================== Press any key to continue . . .

C# 3.0 Practical Learning

648

10.

Close the DOS window

An Indexer An indexer, also called an indexed property, is a class's property that allows you to access a member variable of a class using the features of an array. To create an indexed property, start the class like any other. In the body of the class, create a field that is an array. Here is an example: public class Number { double[] Numbers = new double[5]; }

Then, in the body of the class, create a property named this with its accessor(s). The this property must be the same type as the field it will refer to. The property must take a parameter as an array. This means that it must have square brackets. Inside of the brackets, include the parameter you will use as index to access the members of the array. Traditionally, and as we have seen so far, you usually access the members of an array using an integer-based index. Therefore, you can use an int type as the index of the array. Of course, the index' parameter must have a name, such as i. This would be done as follows: public class Number { double[] Numbers = new double[5];

}

public double this[int i] { }

If you want the property to be read-only, include only a get accessor. In the get accessor, you should return an element of the array field the property refers to, using the parameter of the property. This would be done as follows: public class Number { double[] Numbers = new double[5]; public double this[int i] { get { return Numbers[i]; } } }

Once you have created the indexed property, the class can be used. To start, you can declare a variable of the class. To access its arrayed field, you can apply the square brackets directly to it. Here is an example: using System; public class Number { double[] Numbers;

C# 3.0 Practical Learning

649

public double this[int i] { get { return Numbers[i]; } }

}

public Number() { Numbers = new double[5]; Numbers[0] = 927.93; Numbers[1] = 45.155; Numbers[2] = 2.37094; Numbers[3] = 73475.25; Numbers[4] = 186.72; }

public class Exercise { static int Main(string[] args) { var nbr = new Number(); for (int i = 0; i < 5; i++) Console.WriteLine("Number {0}: {1}", i + 1, nbr[i]); Console.WriteLine(); return 0; }

}

Based on this, a type of formula to create and use a basic indexed property is: class ClassName { DataType[] ArrayName = new DataType[Length]; public DataType this[int i] { get { return ArrayName[i]; } } }

Indexed Properties of Other Primitive Types In the above example, we created a property that produced double-precision values. When creating an indexed property, you will decide what type of value the property must produce or the type it can have. As opposed to an int or a double, you can also create a property that takes or produces a string. To do this, you can use the above class template with the desired data type, such as string. Here is an example of a string-based indexed property: using System; public class Philosopher { string[] phil = new string[8];

C# 3.0 Practical Learning

650

public string this[int i] { get { return phil[i]; } }

}

public Philosopher() { phil[0] = "Aristotle"; phil[1] = "Emmanuel Kant"; phil[2] = "Tom Huffman"; phil[3] = "Judith Jarvis Thompson"; phil[4] = "Thomas Hobbes"; phil[5] = "Cornell West"; phil[6] = "Jane English"; phil[7] = "James Rachels"; }

public class Exercise { static int Main(string[] args) { var thinker = new Philosopher(); for (int i = 0; i < 8; i++) Console.WriteLine("Philosopher: {0}", thinker[i]); Console.WriteLine(); return 0; }

}

This would produce: Philosopher: Philosopher: Philosopher: Philosopher: Philosopher: Philosopher: Philosopher: Philosopher:

Aristotle Emmanuel Kant Tom Huffman Judith Jarvis Thompson Thomas Hobbes Cornell West Jane English James Rachels

Press any key to continue . . .

In the same way, you can created a Boolean-based indexed property by simply making it return a bool type. Here is an example: using System; public class DrivingWhileIntoxicated { bool[] dwi = new bool[7]; public bool this[int i] { get { return dwi[i]; } } public DrivingWhileIntoxicated()

C# 3.0 Practical Learning

651

{ dwi[0] dwi[1] dwi[2] dwi[3] dwi[5] dwi[6] }

= = = = = =

false; true; true; false; false; false;

}

public class Exercise { static int Main(string[] args) { var driving = new DrivingWhileIntoxicated(); Console.WriteLine("Police Report"); Console.WriteLine("-------------------------------"); for(int i = 0; i < 7; i++) Console.WriteLine("Driver Was Intoxicated: {0}", driving[i]); Console.WriteLine(); return 0; }

}

This would produce: Police Report ------------------------------Driver Was Intoxicated: False Driver Was Intoxicated: True Driver Was Intoxicated: True Driver Was Intoxicated: False Driver Was Intoxicated: False Driver Was Intoxicated: False Driver Was Intoxicated: False Press any key to continue . . .

Using a Non-Integer-Based Index In previous lessons, we saw how to create different arrays that are numeric or string based. Here is an example of a float array: using System; public class Exercise { static int Main(string[] args) { float[] ages = new float[5]; ages[0] ages[1] ages[2] ages[3] ages[4]

= = = = =

14.50f; 12.00f; 16.50f; 14.00f; 15.50f;

C# 3.0 Practical Learning

652

Console.WriteLine("Student Age: {0}", ages[2]); Console.WriteLine(); return 0; }

}

When we think of arrays, we usually consider passing an integer-based parameter to the square brackets of the variable, as done for the above ages array: float[] ages = new float[5];

When using an indexed property, you can use almost any type of index, such as a real value or a string. To do this, in the square brackets of the this property, pass the desired type as the index. Here is an example: public class StudentAge { public float this[string name] { } }

When defining the indexed property, there are two rules you must follow and you are aware of them already because an indexed property is like a method that takes a parameter and doesn't return void. Therefore, when implementing an indexed property, make sure you return the right type of value and make sure you pass the appropriate index to the return value of the this property. Here is an example: public class StudentAge { public float this[string name] { get { if( name == "Ernestine Jonas" ) return 14.50f; else if( name == "Paul Bertrand Yamaguchi" ) return 12.50f; else if( name == "Helene Jonas" ) return 16.00f; else if( name == "Chrissie Hanson" ) return 14.00f; else if( name == "Bernard Hallo" ) return 15.50f; else return 12.00f; } } }

Once you have defined the property, you can use it. To access any of its elements, you must pass the appropriate type of index. In this case, the index must be passed as a string and not an integer. You can then do whatever you want with the value produced by the property. For example, you can display it to the user. Here is an example: C# 3.0 Practical Learning

653

using System; public class StudentAge { public float this[string name] { get { if( name == "Ernestine Jonas" ) return 14.50f; else if( name == "Paul Bertrand Yamaguchi" ) return 12.50f; else if( name == "Helene Jonas" ) return 16.00f; else if( name == "Chrissie Hanson" ) return 14.00f; else if( name == "Bernard Hallo" ) return 15.50f; else return 12.00f; } } } public class Exercise { static int Main(string[] args) { var sa = new StudentAge(); var age = sa["Paul Bertrand Yamaguchi"]; Console.WriteLine("Student Age: {0}", age); Console.WriteLine(); return 0; }

}

This would produce: Student Age: 12.5 Press any key to continue . . .

You can also pass an enumeration as an index. To do this, after defining the enumerator, type its name and a parameter name in the square brackets of the this member, then define the property as you see fit. To access the property outside, apply an enumeration member to the square brackets on an instance of the class. Here is an example: using System; public enum CategoryFee { Children, Adult, Senior, Unknown }

C# 3.0 Practical Learning

654

public class GolfClubMembership { double[] fee = new double[4]; public GolfClubMembership() { fee[0] = 150.95d; fee[1] = 250.75d; fee[2] = 85.65d; fee[3] = 350.00d; }

}

public double this[CategoryFee cat] { get { if (cat == CategoryFee.Children) return fee[0]; else if (cat == CategoryFee.Adult) return fee[1]; else if (cat == CategoryFee.Senior) return fee[2]; else return fee[3]; } }

public class Exercise { static int Main(string[] args) { var mbr = new GolfClubMembership(); Console.WriteLine("Membership Fee: {0}", mbr[CategoryFee.Senior]); Console.WriteLine(); return 0; }

}

This would produce: Membership Fee: 85.65 Press any key to continue . . .

Practical Learning: Creating an Indexer 1. To create an indexer, access the PropertyListing.cs file and change it as follows: using using using using

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

C# 3.0 Practical Learning

655

namespace PropertyRental1 { public class PropertyListing { public Property[] props; public string this[long code] { get { for(int i = 0; i < props.Length; i++) if( code == props[i].PropertyCode ) return "Property #: " + props[i].PropertyCode + "\nCondition: " + props[i].PropertyCondition + "\nBedrooms: " + props[i].Bedrooms + "\nBathrooms: " + props[i].Bathrooms + "\nMonthly Rent: " + props[i].MonthlyRent.ToString("C"); return "Unidentifiable Property"; } } public PropertyListing() { . . . No Change }

} }

2. Access the Program.cs file and change it as follows: using using using using

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

namespace PropertyRental1 { public class Program { static void Main(string[] args) { var properties = new PropertyListing(); var lngCode = 0L; Console.WriteLine("Here is a list of our properties by code");

for (int i = 0; i < 6; i++) Console.WriteLine("Property Code: {0}", properties.props[i].PropertyCode); try {

");

Console.Write("Enter Property Code: "); lngCode = long.Parse(Console.ReadLine()); Console.WriteLine("====================================== Console.WriteLine("Property Information");

C# 3.0 Practical Learning

656

Console.WriteLine("-------------------------------------");

Console.WriteLine(properties[lngCode]); Console.WriteLine("======================================

");

} catch (FormatException) { Console.WriteLine("=- Invalid Property Code -="); } }

}

}

3. Press Ctrl + F5 to execute the application. Here is an example: Here is a list of our properties by code Property Code: 355443 Property Code: 653004 Property Code: 800118 Property Code: 839375 Property Code: 148561 Property Code: 697001 Enter Property Code: 697001 ====================================== Property Information -------------------------------------Property #: 697001 Condition: Good Bedrooms: 2 Bathrooms: 1 Monthly Rent: $1,050.00 ====================================== Press any key to continue . . .

4. Close the DOS window

Topics on Indexed Properties Multi-Parameterized Indexed Properties The indexed properties we have used so far were taking only one parameter. You can create an indexed property whose array uses more than one dimension. To start an indexed property that would use various parameters, first declare the array as we saw in Lesson 24. After declaring the array, create a this property that takes the parameters. Here is an example for an indexed property that relates to a two-dimensional array: public class Numbers { double[,] nbr; public double this[int x, int y]

C# 3.0 Practical Learning

657

}

{ }

In the body of an accessor (get or set), use the parameter as appropriately as you see fit. At a minimum, for a get accessor, you can return the value of the array using the parameters based on the rules of a two-dimensional array. This can be done as follows: public class Numbers { double[,] nbr; public double this[int x, int y] { get { return nbr[x, y]; } } }

After creating the property, you can access each element of the array by applying the square brackets to an instance of the class. Here is an example: using System; public class Numbers { double[,] nbr; public double this[int x, int y] { get { return nbr[x, y]; } } public Numbers() { nbr = new double[2,4]; nbr[0, 0] = 927.93; nbr[0, 1] = 45.155; nbr[0, 2] = 2.37094; nbr[0, 3] = 73475.25; nbr[1, 0] = 186.72; nbr[1, 1] = 82.350; nbr[1, 2] = 712734.95; nbr[1, 3] = 3249.0057; } } public class Exercise { static int Main(string[] args) { var nbr = new Numbers(); for (int i = 0; i < 2; i++) { for (int j = 0; j < 4; j++) { double value = nbr[i, j]; Console.WriteLine("Number [{0}][{1}]: {2}", i, j, value); } 658 C# 3.0 Practical Learning

}

}

Console.WriteLine(); return 0;

}

Remember that one of the most valuable features of an indexed property is that, when creating it, you can make it return any primitive type and you can make it take any parameter of your choice. Also, the parameters of a multiparameter indexed property don't have to be the same type. One can be a character while the other is a bool type; one can be a double while the other is a short, one can be an integer while the other is a string. When defining the property, you must apply the rules of both the methods and the arrays. Here is an example of a property that takes an integer and a string: using System; public class Catalog { long[] nbrs; string[] names; public double this[long nbr, string name] { get { if ((nbr == nbrs[0]) && (name == names[0])) return 275.25; else if ((nbr == nbrs[1]) && (name == names[1])) return 18.75; else if ((nbr == nbrs[2]) && (name == names[2])) return 50.00; else if ((nbr == nbrs[3]) && (name == names[3])) return 65.35; else if ((nbr == nbrs[4]) && (name == names[4])) return 25.55; else return 0.00; } } public Catalog() { nbrs = new long[5]; nbrs[0] = 273974; nbrs[1] = 539759; nbrs[2] = 710234; nbrs[3] = 220685; nbrs[4] = 192837; names = new string[5]; names[0] = "Women Double-faced wool coat"; names[1] = "Men Cotton Polo Shirt"; names[2] = "Children Cable-knit Sweater"; names[3] = "Women Floral Silk Tank Blouse";

C# 3.0 Practical Learning

659

names[4] = "Girls Jeans with Heart Belt"; }

}

public class Exercise { static int Main(string[] args) { var cat = new Catalog(); var itemNumber = 539759; var itemDescription = "Men Cotton Polo Shirt"; var price = cat[itemNumber, itemDescription]; Console.WriteLine("Item #: {0}", itemNumber); Console.WriteLine("Description: {0}", itemDescription); Console.WriteLine("Unit Price: {0}", price);

}

Console.WriteLine(); return 0;

}

This would produce: Item #: 539759 Description: Men Cotton Polo Shirt Unit Price: 18.75 Press any key to continue . . .

In the above example, we first declared the variables to be passed as parameters to the indexed property. You can also pass the parameter(s) directly on the instance of the class. Here is an example: public class Exercise { static int Main(string[] args) { var cat = new Catalog(); var price = cat[220685, "Women Floral Silk Tank Blouse"]; Console.WriteLine("Item #: 220685"); Console.WriteLine("Description: Women Floral Silk Tank Blouse"); Console.WriteLine("Unit Price: {0}", price); Console.WriteLine(); return 0; }

}

Just as you can create a two-dimensional indexed property, you can also create a property that takes more than two parameters. Once again, it is up to you to decide what type of parameter would be positioned where in the square brackets. Here is an example of an indexed property that takes three parameters: using System;

C# 3.0 Practical Learning

660

public class Catalog { public string this[long nbr, { get { return "Item #: "Description: "Unit Price: } } }

string name, double price]

" + nbr.ToString() + "\n" + " + name + "\n" + " + price.ToString("C");

public class Exercise { static int Main(string[] args) { var cat = new Catalog(); Console.WriteLine("Item Description"); Console.WriteLine(cat[220685, "Women Floral Silk Tank Blouse", 50.00]); Console.WriteLine(); return 0; }

}

Overloading an Indexed Property An indexer borrows various characteristics of a method. One of them is the ability to create various indexers in the same class but all of them must have the same name: this. Still, the various indexers of a class can return the same type of value. Because of this, when creating the indexers, you must find a way to distinguish them. One way you can do this, as seen with method overloading, consists of passing a different type of parameter to each indexer. This is referred to as overloading. To overload the this property, if two indexed properties take only one parameter, each must take a different (data) type of parameter than the other. Here is an example: using System; public class StudentIdentifications { int[] studentIDs; string[] fullnames; // This property takes a student ID, as an integer, // and it produces his/her name public string this[int id] { get { for (int i = 0; i < studentIDs.Length; i++) if (id == studentIDs[i]) return fullnames[i];

C# 3.0 Practical Learning

661

}

return "Unknown Student";

} // This property takes a student name, as a string, // and it produces his/her student ID public int this[string name] { get { for (int i = 0; i < fullnames.Length; i++) if (name == fullnames[i]) return studentIDs[i]; }

return 0;

} public StudentIdentifications() { studentIDs = new int[6]; studentIDs[0] = 39472; studentIDs[1] = 13957; studentIDs[2] = 73957; studentIDs[3] = 97003; studentIDs[4] = 28947; studentIDs[5] = 97395;

}

fullnames = new string[6]; fullnames[0] = "Paul Bertrand Yamaguchi"; fullnames[1] = "Ernestine Ngovayang"; fullnames[2] = "Patricia L Katts"; fullnames[3] = "Helene Mukoko"; fullnames[4] = "Joan Ursula Hancock"; fullnames[5] = "Arlette Mimosa";

} public class Exercise { static int Main(string[] args) { var std = new StudentIdentifications(); Console.WriteLine("Student Identification"); Console.WriteLine("Student ID: 39472"); Console.WriteLine("Full Name: {0}\n", std[39472]); Console.WriteLine("Student Identification"); Console.WriteLine("Full Name: Joan Ursula Hancock"); Console.WriteLine("Student ID: {0}\n", std["Joan Ursula Hancock"]); return 0; }

}

This would produce: C# 3.0 Practical Learning

662

Student Identification Student ID: 39472 Full Name: Paul Bertrand Yamaguchi Student Identification Full Name: Joan Ursula Hancock Student ID: 28947 Press any key to continue . . .

An indexer combines the features of an array and those of a method that takes one or more parameters. As an array, an indexer can use one or more dimensions as we have seen so far. Borrowing the features of a method, an indexer can take one or more parameters and it can return a value. Besides passing different types of parameters to various indexers, you can create some of them that take more than one parameter. Here is an example: using System; public class Catalog { //double[] item; long[] nbrs; string[] names; double[] prices; // This property produces the name of an item, as a string, // if it is given the item #, as a number public string this[long nbr] { get { for (int i = 0; i < nbrs.Length; i++) if (nbr == nbrs[i]) return names[i]; return "Unknown Item"; }

}

// This property produces the price of the item, as a number, // if it is given the item name and its number public double this[string name, long nbr] { get { for (int i = 0; i < 5; i++) if ((nbr == nbrs[i]) && (name == names[i])) return prices[i]; return 0.00; }

}

public Catalog() { nbrs = new long[5]; nbrs[0] = 273974; nbrs[1] = 539759;

C# 3.0 Practical Learning

663

nbrs[2] = 710234; nbrs[3] = 220685; nbrs[4] = 192837; names = new string[5]; names[0] = "Women Double-faced wool coat"; names[1] = "Men Cotton Polo Shirt"; names[2] = "Children Cable-knit Sweater"; names[3] = "Women Floral Silk Tank Blouse"; names[4] = "Girls Jeans with Heart Belt"; prices = new double[5]; prices[0] = 275.25; prices[1] = 18.75; prices[2] = 50.00; prices[3] = 65.35; prices[4] = 25.55; }

}

public class Exercise { static int Main(string[] args) { var cat = new Catalog(); Console.WriteLine("Item Identification"); Console.WriteLine("Item #: 539759"); Console.WriteLine("Unit Price: {0}\n", cat[539759]); Console.WriteLine("Item Identification"); Console.WriteLine("Item #: 192837"); Console.WriteLine("Description: Girls Jeans with Heart Belt"); Console.WriteLine("Unit Price: {0}\n", cat["Girls Jeans with Heart Belt", 192837]); return 0; }

}

This would produce: Item Identification Item #: 539759 Unit Price: Men Cotton Polo Shirt Item Identification Item #: 192837 Description: Girls Jeans with Heart Belt Unit Price: 25.55 Press any key to continue . . .

Read/Write Indexed Properties

C# 3.0 Practical Learning

664

Introduction So far, we have purposely used indexed properties that only produced a value. This type is used when you are (always) in charge of specifying the values of the elements of the array: the only action you would expect from the user is to retrieve the value of the property. This is referred to as a readonly property. In some cases, you will use a property created by someone else. You may want to specify the value of an element of the array. In the same way, you may create an indexed property and you want the users of that property to be able to specify the value of the array. If you want an indexed property to be read/write, besides the get accessor as we have been using it so far, you should also include a set accessor.

A Read/Write Property of a Primitive Type To create a read/write indexed property, you should include a set accessor for the property. In the set accessor, assign the value contextual keyword to the field indexed with the this parameter. Here is an example of a read/write indexed property that includes a set accessor: public class Number { double[] Numbers; public double this[int i] { get { return Numbers[i]; } set { Numbers[i] = value; } } }

After creating the read/write property, you can assign its values outside of the class. In other words, clients of the class can change the values to its elements. Remember that the advantage of an indexed property is that each element of the arrayed field can be accessed from the instance of the class by directly applying the square brackets and the (appropriate) index to it. Here is an example: using System; public class Number { double[] Numbers = new double[5]; public double this[int i] { get { return Numbers[i]; } set { Numbers[i] = value; } } } public class Program { static int Main(string[] args) { var nbr = new Number();

C# 3.0 Practical Learning

665

nbr[2] = 2.37094; for (int i = 0; i < 5; i++) Console.WriteLine("Number {0}: {1}", i + 1, nbr[i]);

}

Console.WriteLine(); return 0;

}

This would produce: Number Number Number Number Number

1: 2: 3: 4: 5:

0 0 2.37094 0 0

Press any key to continue . . .

Based on this, a type of formula to create and use a basic indexed property is: class ClassName { DataType[] ArrayName = new DataType[Index];

}

public DataType this[int i] { get { return ArrayName[i]; } set { ArrayName[i] = value; } }

class Program { static int Main(string[] args) { ClassName Variable = new ClassName(); Variable[Low-Index] = Value1; . . . Variable[High-Index] = Value_n; return 0; }

}

We saw that the index of a property could be a value other than an integerbased. For example, we created an index that was a string type. For such a property, if you make it read/write, you can assign its values outside of the class. Here is an example of a read/write string-based indexed property: using System; public class Philosopher { string[] phil = new string[8];

C# 3.0 Practical Learning

666

public string this[int i] { get { return phil[i]; } set { phil[i] = value; } } } public class Program { static int Main(string[] args) { var thinker = new Philosopher(); thinker[5] = "Stuart Rachels"; for (int i = 0; i < 8; i++) Console.WriteLine("Philosopher: {0}", thinker[i]);

}

Console.WriteLine(); return 0;

}

This would produce: Philosopher: Philosopher: Philosopher: Philosopher: Philosopher: Philosopher: Stuart Rachels Philosopher: Philosopher: Press any key to continue . . .

The same rules would apply to a read/write indexed property that can receive Boolean or decimal values.

C# 3.0 Practical Learning

667

Classes and Indexers Fundamentals of Indexed Properties and Classes Introduction In the previous lesson, we learned to create and use indexer that were taking parameters of primitive types. Just as we did with primitive types, you can create an indexer that is of a class type. For example, you can create a class so that one of the its fields declared as an array can be accessed with an index directly applied to an instance of the class.

Practical Learning: Introducing Indexers and Classes

1. Start a new Console Application named PropertyRental2 2. To create a new class, on the main menu, click Project -> Add Class... 3. Set the Name to Property and press Enter 4. Change the file as follows:

C# 3.0 Practical Learning

668

using using using using

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

namespace PropertyRental2 { public enum Condition { Excellent, Good, NeedsRepair, Unknown } public class Property { private long propCode; private Condition cond; private short beds; private float baths; private decimal val; public long PropertyCode { get { return propCode; } set { propCode = value; } } public Condition PropertyCondition { get { return cond; } set { cond = value; } } public short Bedrooms { get { return beds; } set { beds = value; } } public float Bathrooms { get { return (baths <= 0) ? 0.00f : baths; } set { baths = value; } } public decimal MonthlyRent { get { return (val <= 0) ? 0.00M : val; } set { val = value; } } public Property() { Random rnd = new Random(); propCode = rnd.Next(100000, 999999); cond = Condition.Unknown; beds = 0; baths = 0.0f;

C# 3.0 Practical Learning

669

val = 0.00M; } public override string ToString() { return "Property #: " + PropertyCode + "\nCondition: " + PropertyCondition + "\nBedrooms: " + Bedrooms + "\nBathrooms: " + Bathrooms + "\nMonthly Rent: " + MonthlyRent.ToString("C"); } }

}

5. To create a new class, on the main menu, click Project -> Add Class... 6. Set the Name to PropertyListing and press Enter 7. Change the file as follows: using using using using

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

namespace PropertyRental2 { public class PropertyListing { public Property[] props; public string this[long code] { get { for (int i = 0; i < props.Length; i++) if (code == props[i].PropertyCode) return "Property #: " + props[i].PropertyCode + "\nCondition: " + props[i].PropertyCondition + "\nBedrooms: " + props[i].Bedrooms + "\nBathrooms: " + props[i].Bathrooms + "\nMonthly Rent: " + props[i].MonthlyRent.ToString("C"); return "Unidentifiable Property"; } } public PropertyListing() { Random rnd = new Random(); props = new Property[40]; // Create a few properties ready to be rented props[0] = new Property(); props[0].PropertyCode = rnd.Next(100000, 999999); props[0].PropertyCondition = Condition.Excellent; props[0].Bedrooms = 5; props[0].Bathrooms = 3.5f;

C# 3.0 Practical Learning

670

props[0].MonthlyRent = 2650; props[1] = new Property(); props[1].PropertyCode = rnd.Next(100000, 999999); props[1].PropertyCondition = Condition.Excellent; props[1].Bedrooms = 3; props[1].Bathrooms = 2.5f; props[1].MonthlyRent = 1750; props[2] = new Property(); props[2].PropertyCode = rnd.Next(100000, 999999); props[2].PropertyCondition = Condition.Good; props[2].Bedrooms = 4; props[2].Bathrooms = 2.5f; props[2].MonthlyRent = 2450; props[3] = new Property(); props[3].PropertyCode = rnd.Next(100000, 999999); props[3].PropertyCondition = Condition.Excellent; props[3].Bedrooms = 1; props[3].Bathrooms = 1.0f; props[3].MonthlyRent = 880; props[4] = new Property(); props[4].PropertyCode = rnd.Next(100000, 999999); props[4].PropertyCondition = Condition.Excellent; props[4].Bedrooms = 3; props[4].Bathrooms = 2.5f; props[4].MonthlyRent = 1880; props[5] = new Property(); props[5].PropertyCode = rnd.Next(100000, 999999); props[5].PropertyCondition = Condition.Good; props[5].Bedrooms = 2; props[5].Bathrooms = 1.0f; props[5].MonthlyRent = 1050; // Since we don't yet have a complete list of properties // Create some empty ones for (int i = 6; i < 40; i++) { props[i] = new Property(); } }

}

}

8. Access the Program.cs file and change it as follows: using using using using

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

namespace PropertyRental2 { public class Program { static void Main(string[] args)

C# 3.0 Practical Learning

671

{ PropertyListing properties = new PropertyListing(); long lngCode; Console.WriteLine("Here is a list of our properties by code");

for (int i = 0; i < 6; i++) Console.WriteLine("Property Code: {0}", properties.props[i].PropertyCode); try {

Console.Write("Enter Property Code: "); lngCode = long.Parse(Console.ReadLine()); Console.WriteLine("======================================

");

Console.WriteLine("Property Information"); Console.WriteLine("-------------------------------------");

Console.WriteLine(properties[lngCode]); Console.WriteLine("======================================

");

} catch (FormatException) { Console.WriteLine("=- Invalid Property Code -="); } }

}

}

9. Press Ctrl + F5 to execute the application. Here is an example: Here is a list of our properties by code Property Code: 355443 Property Code: 653004 Property Code: 800118 Property Code: 839375 Property Code: 148561 Property Code: 697001 Enter Property Code: 697001 ====================================== Property Information -------------------------------------Property #: 697001 Condition: Good Bedrooms: 2 Bathrooms: 1 Monthly Rent: $1,050.00 ====================================== Press any key to continue . . .

10.

Close the DOS window

An Integer-Based Indexed Property C# 3.0 Practical Learning

672

Before designing an indexer that is class-based, first create the class that will be used as the data type. The class can be simple or complex as you judge it necessary. Here is an example of a simple class: public class Student { public string FirstName; public string LastName; public int Gender; }

When creating the class that will host the indexed property, declare an array field for the class. Then, create the this property with the desired accessor(s). Here is an example: public class Student { public string FirstName; public string LastName; public int Gender; } public class SchoolRegistration { Student[] std = new Student[5];

}

public Student this[int i] { get { return std[i]; } }

After creating the indexing class, you can use it and access the indexer; for example, you can retrieve its value(s). Here is an example: using System; public class Student { public string FirstName; public string LastName; public int Gender; } public class SchoolRegistration { Student[] std = new Student[5]; public Student this[int i] { get { return std[i]; } } public SchoolRegistration() { std[0] = new Student(); std[0].FirstName = "Alfredo"; std[0].LastName = "Olmos"; std[0].Gender = 2;

C# 3.0 Practical Learning

673

std[1] = new Student(); std[1].FirstName = "Patricia"; std[1].LastName = "Katts"; std[1].Gender = 1; std[2] = new Student(); std[2].FirstName = "Josiane"; std[2].LastName = "Euler"; std[2].Gender = 1; std[3] = new Student(); std[3].FirstName = "Joan"; std[3].LastName = "Jones"; std[3].Gender = 3; std[4] = new Student(); std[4].FirstName = "George"; std[4].LastName = "Paulson"; std[4].Gender = 2; }

}

public class Exercise { static int Main(string[] args) { var pupils = new SchoolRegistration(); for (var i = 0; i < 5; i++) { Student pupil = pupils[i]; Console.WriteLine("Student Information"); Console.WriteLine("---------------------"); Console.WriteLine("First Name: {0}", pupil.FirstName); Console.WriteLine("Last Name: {0}", pupil.LastName); Console.WriteLine("Gender: {0}\n", (pupil.Gender == 1 ? "Female" : (pupil.Gender == 2 ? "Male" : "Unknown"))); } }

return 0;

}

This would produce: Student Information --------------------First Name: Alfredo Last Name: Olmos Gender: Male Student Information --------------------First Name: Patricia Last Name: Katts Gender: Female Student Information

C# 3.0 Practical Learning

674

--------------------First Name: Josiane Last Name: Euler Gender: Female Student Information --------------------First Name: Joan Last Name: Jones Gender: Unknown Student Information --------------------First Name: George Last Name: Paulson Gender: Male Press any key to continue . . .

Practical Learning: Using an Integer-Based Indexer 1. To create an indexer that takes an integer and returns an object, access the PropertyListing.cs file and change it as follows: using using using using

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

namespace PropertyRental1 { public class PropertyListing { public Property[] props; public Property this[int i] { get { return props[i]; } }

}

public PropertyListing() { . . . No Change }

}

2. Access the Program.cs file and change it as follows: using using using using

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

namespace PropertyRental2 { public class Program

C# 3.0 Practical Learning

675

{ static void Main(string[] args) { PropertyListing properties = new PropertyListing(); Console.WriteLine("Here is a list of our properties"); for (int i = 0; i < 6; i++) { Property prop = properties[i];

");

Console.WriteLine("Property Information"); Console.WriteLine("--------------------------------------

Console.WriteLine("Property #: {0}", prop.PropertyCode); Console.WriteLine("Condition: {0}", prop.PropertyCondition); Console.WriteLine("Bedrooms: {0}", prop.Bedrooms); Console.WriteLine("Bathrooms: {0}", prop.Bathrooms); Console.WriteLine("Monthly Rent: {0}", prop.MonthlyRent.ToString("C")); Console.WriteLine("====================================== "); } } } }

3. Press Ctrl + F5 to execute the application 4. Close the DOS window

An Indexed Property Using Another Primitive Type The above implementation of the SchoolRegistration class easily allowed us to locate an element of the array by specifying its integer-based index. As done for primitive types, an indexer can take a parameter other than an integer. In some cases, you may use your class or a class created by someone else and need to access an element of the array without information other than its index. Consider the following program: public enum Classification { Female, Male, Unknown } public class Student { public long StudentID; public string FirstName; public string LastName; public Classification Gender; public override string ToString() { string str = "Student ID: " + StudentID +

C# 3.0 Practical Learning

676

"\nFirst Name: " + FirstName + "\nLast Name: " + LastName + "\nGender: " + Gender; }

return str;

} public class SchoolRegistration { Student[] std = new Student[50];

}

public Student this[...] { }

Previously, we saw that you could create an indexer that takes a type than an integer. For example, we saw that a string could be used as an index. By now, we know that a basic indexed property produces (or all the indexed properties we have studied so far produce) only one value. If you have a class that has only one field, this would be enough. In reality, most of the time, a class has many fields. In such a case, when you create an indexer , you need to be able to refer to one exact element of the array. To make this possible, you must define a way to point to the particular element you want. One way you can do this is to use one field of the class as a reference. This is better if that field holds unique values among the other elements of the array. For our Student class, we could use the StudentID field (because we will make sure that each student has a unique ID). You can start the property as follows: public class SchoolRegistration { Student[] std = new Student[5];

}

public Student this[long id] { }

When a user uses this property, he or she must provide a value that uniquely identifies an element of the array. You in turn, when you get this value, you can search for it in the array. If you find it and the array has a get accessor, you can then return the desired but appropriate value. Here is how this can be done: public class SchoolRegistration { Student[] students = new Student[50]; public Student this[long id] { get { for (int i = 0; i < students.Length; i++) { if (students[i].StudentID == id) return students[i]; } // Unknown student or the number was not found

C# 3.0 Practical Learning

677

return null; }

}

}

After creating the indexer, you can use it. Once again, you must follow the rules of a method that takes an argument and returns a value other than void. In this case, the indexer must take a string and it must return a Student object. Here is an example: using System; public enum Classification { Female, Male, Unknown } public class Student { public long StudentID; public string FirstName; public string LastName; public Classification Gender; public override string ToString() { string str = "Student ID: " + "\nFirst Name: " "\nLast Name: " "\nGender: " return str; }

StudentID + + FirstName + + LastName + + Gender;

} public class SchoolRegistration { Student[] students = new Student[50]; public Student this[long id] { get { for (int i = 0; i < students.Length; i++) { if (students[i].StudentID == id) return students[i]; } // Unknown student or the number was not found return null; } } public SchoolRegistration() { students[0] = new Student(); students[0].StudentID = 917294; students[0].FirstName = "Helene"; students[0].LastName = "Mukoko";

C# 3.0 Practical Learning

678

students[0].Gender = Classification.Female; students[1] = new Student(); students[1].StudentID = 283764; students[1].FirstName = "Patrice"; students[1].LastName = "Katts"; students[1].Gender = Classification.Unknown; students[2] = new Student(); students[2].StudentID = 192046; students[2].FirstName = "Armand"; students[2].LastName = "Essono"; students[2].Gender = Classification.Male; students[3] = new Student(); students[3].StudentID = 618268; students[3].FirstName = "Bertrand"; students[3].LastName = "Yamaguchi"; students[3].Gender = Classification.Male; students[4] = new Student(); students[4].StudentID = 820648; students[4].FirstName = "Hortense"; students[4].LastName = "McNeal"; students[4].Gender = Classification.Female; }

}

public class Exercise { static int Main(string[] args) { var pupils = new SchoolRegistration(); var pupil = pupils[820648]; Console.WriteLine("Student Information"); Console.WriteLine("---------------------"); Console.WriteLine("First Name: {0}", pupil.FirstName); Console.WriteLine("Last Name: {0}", pupil.LastName); Console.WriteLine("Gender: {0}\n", pupil.Gender); pupil = pupils[192046]; Console.WriteLine("Student Information"); Console.WriteLine("---------------------"); Console.WriteLine("First Name: {0}", pupil.FirstName); Console.WriteLine("Last Name: {0}", pupil.LastName); Console.WriteLine("Gender: {0}\n", pupil.Gender); }

return 0;

}

This would produce: Student Information --------------------First Name: Hortense Last Name: McNeal Gender: Female

C# 3.0 Practical Learning

679

Student Information --------------------First Name: Armand Last Name: Essono Gender: Male Press any key to continue . . .

Topics on Indexed Properties and Classes A Class as Index As opposed to returning a class, an indexer can use a class as its index. When creating such a property, the primary action you must take is to include a class and its name as a parameter to the this property. You can start such a class as follows: using System; public enum Classification { Female, Male, Unknown } public class Student { public long StudentID; public string FirstName; public string LastName; public Classification Gender; } public class SchoolRegistration { public string this[Student std] { } }

When implementing the class, you should proceed the same way we have done so far following the rules of a method that takes an argument and returns a value other than void. Here is an example: public class SchoolRegistration { Student[] students = new Student[50]; public string this[Student std] { get { for (int i = 0; i < students.Length; i++)

C# 3.0 Practical Learning

680

{ if (std.StudentID == students[i].StudentID) return "Student ID: " "\nFirst Name: "\nLast Name: "\nGender:

+ " " "

students[i].StudentID + + students[i].FirstName + + students[i].LastName + + students[i].Gender;

} // Unknown student or the number was not found return ""; }

}

}

After creating the property, you can use it. To do this, you must pass an object that is the type of the index. You can then use the returned value as you see fit. Here is an example: using System; public enum Classification { Female, Male, Unknown } public class Student { public long StudentID; public string FirstName; public string LastName; public Classification Gender; } public class SchoolRegistration { Student[] students = new Student[50]; public string this[Student std] { get { for (int i = 0; i < students.Length; i++) { if (std.StudentID == students[i].StudentID) return "Student ID: " "\nFirst Name: "\nLast Name: "\nGender:

+ " " "

students[i].StudentID + + students[i].FirstName + + students[i].LastName + + students[i].Gender;

} // Unknown student or the number was not found return ""; }

}

public SchoolRegistration()

C# 3.0 Practical Learning

681

{ students[0] = new Student(); students[0].StudentID = 917294; students[0].FirstName = "Helene"; students[0].LastName = "Mukoko"; students[0].Gender = Classification.Female; students[1] = new Student(); students[1].StudentID = 283764; students[1].FirstName = "Patrice"; students[1].LastName = "Katts"; students[1].Gender = Classification.Unknown; students[2] = new Student(); students[2].StudentID = 192046; students[2].FirstName = "Armand"; students[2].LastName = "Essono"; students[2].Gender = Classification.Male; students[3] = new Student(); students[3].StudentID = 618268; students[3].FirstName = "Bertrand"; students[3].LastName = "Yamaguchi"; students[3].Gender = Classification.Male; students[4] = new Student(); students[4].StudentID = 820648; students[4].FirstName = "Hortense"; students[4].LastName = "McNeal"; students[4].Gender = Classification.Female; students[5] = new Student(); students[5].StudentID = 917394; students[5].FirstName = "Alfredo"; students[5].LastName = "Olmos"; students[5].Gender = Classification.Unknown; students[6] = new Student(); students[6].StudentID = 163864; students[6].FirstName = "Josiane"; students[6].LastName = "Euler"; students[6].Gender = Classification.Female;

}

students[7] = new Student(); students[7].StudentID = 826384; students[7].FirstName = "Joan"; students[7].LastName = "Jones"; students[7].Gender = Classification.Female ;

} public class Exercise { static int Main(string[] args) { var pupils = new SchoolRegistration(); var pupil = new Student(); pupil.StudentID = 820648;

C# 3.0 Practical Learning

682

var strStudent = pupils[pupil]; Console.WriteLine("====================="); Console.WriteLine("Student Information"); Console.WriteLine("---------------------"); Console.WriteLine(strStudent); //pupil = new Student(); pupil.StudentID = 192046; strStudent = pupils[pupil]; Console.WriteLine("====================="); Console.WriteLine("Student Information"); Console.WriteLine("---------------------"); Console.WriteLine(strStudent); Console.WriteLine("=====================\n"); return 0; }

}

This would produce: ===================== Student Information --------------------Student ID: 820648 First Name: Hortense Last Name: McNeal Gender: Female ===================== Student Information --------------------Student ID: 192046 First Name: Armand Last Name: Essono Gender: Male ===================== Press any key to continue . . .

You can also directly pass an instance of the class in the square brackets of the object that holds the indexed property, as long as you specify the object. Here is an example: using System; public enum Classification { Female, Male, Unknown } public class Student { public long StudentID; public string FirstName; public string LastName; public Classification Gender;

C# 3.0 Practical Learning

683

public Student() { }

}

public Student(long id) { this.StudentID = id; }

public class SchoolRegistration { Student[] students = new Student[50]; public string this[Student std] { . . . No Change } public SchoolRegistration() { . . . No Change } } public class Exercise { static int Main(string[] args) { var pupils = new SchoolRegistration(); var strStudent = pupils[new Student(618268)]; Console.WriteLine("====================="); Console.WriteLine("Student Information"); Console.WriteLine("---------------------"); Console.WriteLine(strStudent);

}

Console.WriteLine("=====================\n"); return 0;

}

This would produce: ===================== Student Information --------------------Student ID: 618268 First Name: Bertrand Last Name: Yamaguchi Gender: Male ===================== Press any key to continue . . .

Overloading a Class-Based Indexed Property

C# 3.0 Practical Learning

684

As mentioned for indexers that return primitive types, you can overload an indexed property that produces a class. You do this following the same rules applied to method overloading and arrays: •

If two indexed properties take only one parameter, each must take a different type of parameter than the other. The parameter can be a primitive type or a class. Here are examples:

using System; public enum Classification { Female, Male, Unknown } public class Major { public string Name; public int CreditsRequired; } public class Student { public long StudentNumber; public string FullName; public Classification Gender;

}

public override string ToString() { string str = "Student #: " + StudentNumber.ToString() + "\nFull Name: " + FullName + "\nGender: " + Gender; return str; }

public class StudentRegistration { private Student[] std = new Student[5]; public StudentRegistration() { std[0] = new Student(); std[0].StudentNumber = 304850; std[0].FullName = "Helene Mukoko"; std[0].Gender = Classification.Female; std[1] = new Student(); std[1].StudentNumber = 926304; std[1].FullName = "Patrice Katts"; std[1].Gender = Classification.Unknown; std[2] = new Student(); std[2].StudentNumber = 330647; std[2].FullName = "Armand Essono"; std[2].Gender = Classification.Male;

C# 3.0 Practical Learning

685

std[3] = new Student(); std[3].StudentNumber = 631846; std[3].FullName = "Bertrand Yamaguchi"; std[3].Gender = Classification.Male;

}

std[4] = new Student(); std[4].StudentNumber = 209374; std[4].FullName = "Anselme Bongos"; std[4].Gender = Classification.Male;

// This property takes a string and produces a Student object public Student this[string strFullName] { get { for (int i = 0; i < std.Length; i++) { if (std[i].FullName == strFullName) return std[i]; } return null; } } // This property takes a number and produces a Student object public Student this[long nbr] { get { for (int i = 0; i < std.Length; i++) { if( nbr == std[i].StudentNumber ) return std[i]; } return null; } }

}

// This property takes a major produces its definition public string this[Major maj] { get { return "Major: " + maj.Name + " - " + maj.CreditsRequired + " Credits Required"; } }

public class Exercise { static int Main(string[] args) { var pupils = new StudentRegistration(); var m1 = new Major(); m1.Name = "Computer Sciences";

C# 3.0 Practical Learning

686

m1.CreditsRequired = 120; var m2 = new Major(); m2.Name = "Informtation Technology"; m2.CreditsRequired = 120;

");

");

Console.WriteLine("=-= Student Identification =-="); Console.WriteLine(pupils["Helene Mukoko"]); Console.WriteLine(pupils[m1]); Console.WriteLine("-------------------------------------------------Console.WriteLine("=-= Student Identification =-="); Console.WriteLine(pupils[330647]); Console.WriteLine(pupils[m2]); Console.WriteLine("-------------------------------------------------Console.WriteLine(); }

return 0;

}

This would produce: =-= Student Identification =-= Student #: 304850 Full Name: Helene Mukoko Gender: Female Major: Computer Sciences - 120 Credits Required -------------------------------------------------=-= Student Identification =-= Student #: 330647 Full Name: Armand Essono Gender: Male Major: Information Technology - 120 Credits Required -------------------------------------------------Press any key to continue . . . •

If one property takes only one parameter, the other(s) can take more than one parameter. An indexed property can take different parameters of primitive types as seen in the previous lesson. An indexer can also take two or more classes as parameters. An indexed property can also take a mix of primitive and class types as parameters. Here are examples:

using System; public enum Classification { Female, Male, Unknown } public class Student { public long StudentID;

C# 3.0 Practical Learning

687

public string FirstName; public string LastName; public Classification Gender; public Student() { } public Student(long id) { this.StudentID = id; }

}

public override string ToString() { return "Student ID: " + StudentID + "\nFirst Name: " + FirstName + "\nLast Name: " + LastName + "\nGender: " + Gender; }

public enum CourseDelivery { FaceToFace, Online, Both // Student Choose } public class Course { public string ShortName; public string LongName; public string Description; public int Credits; public CourseDelivery DeliveryMode; public Course() { } public Course(string name) { ShortName = name; }

}

public override string ToString() { return "Course: " + ShortName + "\nFull Name: " + LongName + "\nCredits: " + Credits + "\nDescription: " + Description + "\nDelivery: " + DeliveryMode; }

public class SchoolRegistration { Student[] students = new Student[50]; Course[] classes = new Course[3];

C# 3.0 Practical Learning

688

// This indexer takes a student id and // returns the student information public Student this[long id] { get { for (int i = 0; i < students.Length; i++) { if (id == students[i].StudentID) return students[i]; } // Unknown student or the number was not found return null; } } // This indexer takes a course short name and // it produces a summary of the course information public Course this[string name] { get { for (int i = 0; i < classes.Length; i++) { if (name == classes[i].ShortName) return classes[i]; } // Unknown course return null; }

}

public string this[Course ToAttend, Student registrant] { get { // First check that the class exists for (int i = 0; i < classes.Length; i++) { if (ToAttend.ShortName == classes[i].ShortName) { // If the class exists, then check if the student exists for (int j = 0; j < students.Length; j++) { if (registrant.StudentID == students[j].StudentID) { return "Student Identification --\n " + "Student ID: " + students[j].StudentID + "\n Full Name: " + students[j].LastName + ", " + students[j].FirstName + "\nClass to Attend --\n Course: " + classes[i].ShortName + " - " + classes[i].LongName + " (" +

C# 3.0 Practical Learning

689

classes[i].Credits + ")" + "\n Delivery: " + classes[i].DeliveryMode; } }

}

}

return "Invalid Registration - You may have to start over"; }

}

// This property takes information used to register // a student to a course // It also specifies whether the student is willing // to get in the waiting list in case another students drops out public string this[Student stud, Course Class, bool WaitingList] { get { // Check that the student information is valie for (int j = 0; j < students.Length; j++) { if (stud.StudentID == students[j].StudentID) { // Now that the student information has been found, // check if the course information is correct for (int i = 0; i < classes.Length; i++) { if (Class.ShortName == classes[i].ShortName) { // If the class exists, then check // if the student exists return "Student Identification --\n " + "Student ID: " + students[j].StudentID + "\n Full Name: " + students[j].LastName + ", " + students[j].FirstName + "\nClass to Attend --\n Course: " + classes[i].ShortName + " - " + classes[i].LongName + " (" + classes[i].Credits + ")" + "\n Delivery: " + classes[i].DeliveryMode + "\nStudent is willing to get " + "on the waiting list: " + WaitingList; } } } } return "Invalid Registration - You may have to start over"; }

} public SchoolRegistration()

{

C# 3.0 Practical Learning

690

students[0] = new Student(); students[0].StudentID = 917294; students[0].FirstName = "Helene"; students[0].LastName = "Mukoko"; students[0].Gender = Classification.Female; students[1] = new Student(); students[1].StudentID = 283764; students[1].FirstName = "Patrice"; students[1].LastName = "Katts"; students[1].Gender = Classification.Unknown; students[2] = new Student(); students[2].StudentID = 192046; students[2].FirstName = "Armand"; students[2].LastName = "Essono"; students[2].Gender = Classification.Male; students[3] = new Student(); students[3].StudentID = 618268; students[3].FirstName = "Bertrand"; students[3].LastName = "Yamaguchi"; students[3].Gender = Classification.Male; students[4] = new Student(); students[4].StudentID = 820648; students[4].FirstName = "Hortense"; students[4].LastName = "McNeal"; students[4].Gender = Classification.Female; classes[0] = new Course(); classes[0].ShortName = "PHIL140"; classes[0].LongName = "Philosophy - Contemporary Moral Issues"; classes[0].Credits = 3; classes[0].Description = "An exploration of how " + "philosophical analysis can be " + "\n\t\ta foundation for thinking " + "clearly about moral issues. " + "\n\t\tProblems analyzed include such " +

+

"widely debated issues " + "\n\t\tas abortion, euthanasia, " + "the death penalty, " + "\n\t\thomosexuality, pornography, " + "reverse discrimination, " + "\n\t\tbusiness ethics, sexual " + "equality, and economic equity."; classes[1] = new Course(); classes[1].ShortName = "MATH140"; classes[1].LongName = "Calculus I"; classes[1].Credits = 4; classes[1].Description = "An introduction to calculus. " + "Topics include functions, " + "\n\t\tthe sketching of graphs of " + "functions, limits, continuity, " + "\n\t\tderivatives and applications of " "the derivative, definite " + "\n\t\tand indefinite integrals, " + "and calculation of area.";

C# 3.0 Practical Learning

691

classes[2] = new Course(); classes[2].ShortName = "ASTR100"; classes[2].LongName = "Introduction to Astronomy"; classes[2].Credits = 3; classes[2].Description = "A discussion of the major areas " + "of astronomy. Topics " + "\n\t\tinclude the solar system, " + "stars and stellar evolution, " + "\n\t\tand galaxies. Current topics " + "in astronomy are also " + "\n\t\tdiscussed."; }

}

public class Exercise { static int Main(string[] args) { var pupils = new SchoolRegistration(); Student std = new Student(917294); Course crs = new Course("MATH140"); Console.WriteLine("============================================== ==");

Console.WriteLine("Student Registration"); Console.WriteLine("------------------------------------------"); Console.WriteLine(pupils[crs, std]); std = new Student(820648); crs = new Course("PHIL140"); Console.WriteLine("==============================================

==");

Console.WriteLine("Student Registration"); Console.WriteLine("------------------------------------------"); Console.WriteLine(pupils[std, crs, true]);

Console.WriteLine("================================================\n "); }

return 0; }

This would produce: ================================================ Student Registration -----------------------------------------Student Identification -Student ID: 917294 Full Name: Mukoko, Helene Class to Attend -Course: MATH140 - Calculus I (4) Delivery: FaceToFace ================================================ Student Registration -----------------------------------------Student Identification -Student ID: 820648 Full Name: McNeal, Hortense Class to Attend --

C# 3.0 Practical Learning

692

Course: PHIL140 - Philosophy - Contemporary Moral Issues (3) Delivery: FaceToFace Student is willing to get on the waiting list: True ================================================ Press any key to continue . . .

Practical Learning: Overloading an Indexer 1. To overload the indexer, access the PropertyListing.cs file and change it as follows: using using using using

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

namespace PropertyRental1 { public class PropertyListing { public Property[] props; public Property this[int i] { get { if ((i >= 0) && (i < 40)) return props[i]; else return null; } } public Property this[long code] { get { for (int i = 0; i < props.Length; i++) if (code == props[i].PropertyCode) return props[i]; return null; } }

}

public PropertyListing() { . . . No Change }

}

2. Access the Program.cs file and change it as follows: using using using using

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

C# 3.0 Practical Learning

693

namespace PropertyRental2 { public class Program { static void Main(string[] args) { PropertyListing properties = new PropertyListing(); long lngCode; Console.WriteLine("Here is a list of our properties by code");

for (int i = 0; i < 6; i++) Console.WriteLine("Property Code: {0}", properties.props[i].PropertyCode); try {

Console.Write("Enter Property Code: "); lngCode = long.Parse(Console.ReadLine()); Console.WriteLine("======================================

");

Console.WriteLine("Property Information"); Console.WriteLine("-------------------------------------");

Console.WriteLine(properties[lngCode]); Console.WriteLine("======================================

");

} catch (FormatException) { Console.WriteLine("=- Invalid Property Code -="); } }

}

}

3. Press Ctrl + F5 to execute the application 4. Close the DOS window

Read/Write Indexed Properties As done for a primitive type, you can allow the clients of your indexer to assign values to the array's elements. Once again, when defining the property, you should include a set accessor to it. In the set accessor, you should assign the value keyword to an element of the array. Here is an example: public class SchoolRegistration { Student[] std = new Student[5]; public Student this[int i] { get { return std[i]; }

C# 3.0 Practical Learning

694

set { std[i] = value; } }

}

After doing this, you can create an element of the array by applying the square brackets to the instance of the class and assigning the desired value to it. The problem with the class is that, since it may have many fields (or properties), to completely define each element, you must provide a value to the member variables of the class itself. Here is an example: using System; public enum Classification { Female, Male, Unknown } public class Student { public long StudentID; public string FirstName; public string LastName; public Classification Gender; public override string ToString() { string str = "Student ID: " + "\nFirst Name: " "\nLast Name: " "\nGender: " return str; }

StudentID + + FirstName + + LastName + + Gender;

} public class SchoolRegistration { Student[] std = new Student[5];

}

public Student this[int i] { get { return std[i]; } set { std[i] = value; } }

public class Exercise { static int Main(string[] args) { var registration = new SchoolRegistration(); var stud = new Student(); stud.StudentID = 604057; stud.FirstName = "Gertrude"; stud.LastName = "Monayong"; stud.Gender = Classification.Female; registration[2] = stud;

C# 3.0 Practical Learning

695

Console.WriteLine("Student Information"); Console.WriteLine("---------------------"); Console.WriteLine("First Name: {0}", registration[2].FirstName); Console.WriteLine("Last Name: {0}", registration[2].LastName); Console.WriteLine("Gender: {0}\n",registration[2].Gender); return 0; }

}

This would produce: Student Information --------------------First Name: Gertrude Last Name: Monayong Gender: Female Press any key to continue . . .

C# 3.0 Practical Learning

696

Introduction to Collections Array-Based Lists Introduction A collection, also called a list, is many items of the same kind grouped into one entity. The collection can be based on simple numbers, basic symbols, dates, strings, times. The collection can also be made of objects that each is made of internal values. This means that a collection can be made of such objects as houses, people, cars, countries, electronic devices. The primary rule to observe is that all items included in a list must be described using the same characteristics. Based on this, if the collection is made of cars, it should contain only cars, not cars and countries.

There are various types of lists or collections. An array-based list is one whose number of items is known in advance. For example, an array-based collection of 10 cars contains 10 cars, may-be less but not more (in reality, the Array class of the .NET Frameword provides a method used to expand an array).

Setting Up a Collection To use a collection as an entity, you can create a class for it. This class would be used to add items in the collection, to remove items in the list, or to perform other necessary operations. You can start a simple class as follows: class Collection { public Collection() { } }

After creating the class for a collection, the collection becomes an object and its class can be used like any other. This means that, before using the collection, you can declare a variable for it. Here is an example: using System; class Collection { public Collection() { }

C# 3.0 Practical Learning

697

} public class Exercise { static int Main(string[] args) { var list = new Collection(); return 0; }

}

The Number of Items in a Collection For an array-based list, because you must specify the number of items that the list will contain, you can declare an array as a field. Here is an example: class Collection { // This collection will be a list of decimal numbers private double[] Item = new double[20];

}

// Our default constructor, used to initialize the collection public Collection() { }

Although you can initialize an array in a C# class, remember that you can also use a constructor to initialize it. Here is an example: class Collection { public int MaxCount = 20; // This collection will be a list of decimal numbers private double[] Item; #region This section is used to set up the collection // Our default constructor, used to initialize the collection public Collection() { this.Item = new double[MaxCount]; } #endregion }

A primary accessory you need when using a list is a count of the number of items in the list when/as they are added or deleted. This accessory is primarily a private field as a simple natural number. When the class is declared, this member variable should be set to 0 to indicate that the list is primarily empty: class Collection { public int MaxCount = 20; // This collection will be a list of decimal numbers private double[] Item;

C# 3.0 Practical Learning

698

// This is the size of the collection private int size; #region This section is used to set up the collection // Our default constructor, used to initialize the collection public Collection() { this.Item = new double[MaxCount]; this.size = 0; } #endregion }

Since the size field was declared private, if you plan to get the count of items in the list from outside the class, you should (must) provide a property to take care of this. This can simply be done as follows: using System; class Collection { public int MaxCount = 20; // This private // This private

collection will be a list of decimal numbers double[] Item; is the size of the collection int size;

#region This section is used to set up the collection // Our default constructor, used to initialize the collection public Collection() { this.Item = new double[MaxCount]; this.size = 0; } // This represents the number of items in the collection public int Count { get { return this.size; } } #endregion } public class Exercise { static int Main(string[] args) { var list = new Collection(); Console.WriteLine("Number of Items: {0}", list.Count); return 0; }

}

This would produce: Number of Items: 0 Press any key to continue . . .

C# 3.0 Practical Learning

699

Routine Operations on an Array-Based List Adding an Item Creating a collection consists of adding items to it. Items are usually added one at a time. The easiest way to do this is to add an item at the end of the existing collection. To add an item to the collection, because an array has (or is supposed to have) a fixed number of items, you should first check whether the list is already full. For an array-based list, the collection is full if its count of items is equal to the maximum number of items it can hold. If the collection can still receive at least one item, you can add the item at the end of the list and increase the count by one. Here is how this can be done: class Collection { public int MaxCount = 20; // This private // This private

collection will be a list of decimal numbers double[] Item; is the size of the collection int size;

#region This section is used to set up the collection // Our default constructor, used to initialize the collection public Collection() { this.Item = new double[MaxCount]; this.size = 0; } // This represents the number of items in the collection public int Count { get { return this.size; } } #endregion #region Operations on the collection // Adds a new item to the list if the list is not full // Increases the number of items in the list // Returns true if the item was added, otherwise returns false public bool Add(double item) { // Make sure the list is not yet full if (this.size < 20) { // Since the list is not full, add the item at the end this.Item[this.size] = item; // Increase the count and return the new position this.size++; // Indicate that the item was successfully added return true;

C# 3.0 Practical Learning

700

} // If the item was not added, return false; return false;

}

} #endregion

Once you have a means of adding items to the list, you can effectively create a list of items. Here is an example: public class Exercise { static int Main(string[] args) { var list = new Collection(); Console.WriteLine("Number of Items: {0}", list.Count); list.Add(224.52); list.Add(60.48); list.Add(1250.64); list.Add(8.86); list.Add(1005.36); Console.WriteLine("Number of Items: {0}", list.Count); return 0; }

}

This would produce: Number of Items: 0 Number of Items: 5 Press any key to continue . . .

Getting an Item From a List After adding items to a collection, you can retrieve them to do what you intended the list for. To retrieve an item, you can locate it by its position, the same way you would do for an array. Having this index, you can check whether the position specified is negative or higher than the current count of items. If it is, there is nothing much to do since the index would be wrong. If the index is in the right range, you can retrieve its corresponding item. The method to do this can be implemented as follows: using System; class Collection { public int MaxCount = 20; // This private // This private

collection will be a list of decimal numbers double[] Item; is the size of the collection int size;

#region This section is used to set up the collection

C# 3.0 Practical Learning

701

// Our default constructor, used to initialize the collection public Collection() { this.Item = new double[MaxCount]; this.size = 0; } // This represents the number of items in the collection public int Count { get { return this.size; } } #endregion #region Operations on the collection // Adds a new item to the list if the list is not full // Increases the number of items in the list // Returns true if the item was added, otherwise returns false public bool Add(double item) { // Make sure the list is not yet full if (size < MaxCount) { // Since the list is not full, add the "item" at the end this.Item[this.size] = item; // Increase the count and return the new position this.size++;

}

}

// Indicate that the item was successfully added return true;

// If the item was not added, return false; return false;

// Retrieves an item from the list based on the specified index public double Retrieve(int pos) { // Make sure the index is in the range if (pos >= 0 && pos <= size) return this.Item[pos]; // If the index was wrong, return 0 return 0; } #endregion } public class Exercise { static int Main(string[] args) { var list = new Collection(); Console.WriteLine("Number of Items: {0}", list.Count); list.Add(224.52); list.Add(60.48); list.Add(1250.64);

C# 3.0 Practical Learning

702

list.Add(8.86); list.Add(1005.36); for (int i = 0; i < list.Count; i++) Console.WriteLine("Item {0}: {1}\n", i + 1, list.Retrieve(i)); Console.WriteLine("Number of Items: {0}", list.Count); return 0; }

}

This would produce: Number of Items: 0 Item 1: 224.52 Item 2: 60.48 Item 3: 1250.64 Item 4: 8.86 Item 5: 1005.36 Number of Items: 5 Press any key to continue . . .

Inserting an Item in the List Inserting a new item in the collection allows you to add one at a position of your choice. To insert an item in the list, you must provide the new item and the desired position. Before performing this operation, you must check two things. First, the list must not be empty because if it is, then there is no way to insert an item (you insert something between two things, not something between nothing). Second, the specified position must be in the allowed range. The method can be implemented as follows: using System; class Collection { public int MaxCount = 20; // This private // This private

collection will be a list of decimal numbers double[] Item; is the size of the collection int size;

#region This section is used to set up the collection // Our default constructor, used to initialize the collection public Collection() { this.Item = new double[MaxCount]; this.size = 0; } // This represents the number of items in the collection public int Count

C# 3.0 Practical Learning

703

{ get { return this.size; } } #endregion #region Operations on the collection // Adds a new item to the list if the list is not full // Increases the number of items in the list // Returns true if the item was added, otherwise returns false public bool Add(double item) { // Make sure the list is not yet full if (size < MaxCount) { // Since the list is not full, add the "item" at the end this.Item[this.size] = item; // Increase the count and return the new position this.size++; // Indicate that the item was successfully added return true; } // If the item was not added, return false; return false; } // Retrieves an item from the list based on the specified index public double Retrieve(int pos) { // Make sure the index is in the range if (pos >= 0 && pos <= size) return this.Item[pos];

}

// If the index was wrong, return 0 return 0;

// Before performing this operation, check that // 1. The list is not full // 2. The specified position is in an allowable range // Insert a new item at a specified position in the list. // After the new item is inserted, the count is increased public bool Insert(double itm, int pos) { // Check that the item can be added to the list if (size < 20 && pos >= 0 && pos <= size) { // Since there is room, // starting from the end of the list to the new position, // push each item to the next or up // to create room for the new item for (int i = size; i > pos - 1; i--) this.Item[i + 1] = this.Item[i]; created

// Now that we have room, put the new item in the position this.Item[pos] = itm; // Since we have added a new item, increase the count

C# 3.0 Practical Learning

704

this.size++;

}

// Indicate that the operation was successful return true;

// Since the item could not be added, return false return false;

}

} #endregion

public class Exercise { static int Main(string[] args) { var list = new Collection(); Console.WriteLine("Number of Items: {0}", list.Count); list.Add(224.52); list.Add(60.48); list.Add(1250.64); list.Add(8.86); list.Add(1005.36); for (var i = 0; i < list.Count; i++) Console.WriteLine("Item {0}: {1}", i + 1, list.Retrieve(i)); Console.WriteLine("Number of Items: {0}\n", list.Count); list.Insert(-707.16, 2); for (var i = 0; i < list.Count; i++) Console.WriteLine("Item {0}: {1}", i + 1, list.Retrieve(i)); Console.WriteLine("Number of Items: {0}\n", list.Count); }

return 0;

}

This would produce: Number of Items: 0 Item 1: 224.52 Item 2: 60.48 Item 3: 1250.64 Item 4: 8.86 Item 5: 1005.36 Number of Items: 5 Item 1: 224.52 Item 2: 60.48 Item 3: -707.16 Item 4: 1250.64 Item 5: 8.86 Item 6: 1005.36 Number of Items: 6 Press any key to continue . . .

C# 3.0 Practical Learning

705

Removing an Item From the List Another operation you can perform on a collection consists of deleting an item. This is also referred to as removing the item. To delete an item from the collection, you can provide its position. Before performing the operation, you can (should/must) first check that the specified position is valid. The method to perform this operation can be implemented as follows: using System; class Collection { public int MaxCount = 20; // This private // This private

collection will be a list of decimal numbers double[] Item; is the size of the collection int size;

#region This section is used to set up the collection // Our default constructor, used to initialize the collection public Collection() { this.Item = new double[MaxCount]; this.size = 0; } // This represents the number of items in the collection public int Count { get { return this.size; } } #endregion #region Operations on the collection // Adds a new item to the list if the list is not full // Increases the number of items in the list // Returns true if the item was added, otherwise returns false public bool Add(double item) { // Make sure the list is not yet full if (size < MaxCount) { // Since the list is not full, add the "item" at the end this.Item[this.size] = item; // Increase the count and return the new position this.size++;

}

}

// Indicate that the item was successfully added return true;

// If the item was not added, return false; return false;

// Retrieves an item from the list based on the specified index public double Retrieve(int pos)

C# 3.0 Practical Learning

706

{ // Make sure the index is in the range if (pos >= 0 && pos <= size) return this.Item[pos]; // If the index was wrong, return 0 return 0; } // Before performing this operation, check that // 1. The list is not full // 2. The specified position is in an allowable range // Inserts a new item at a specified position in the list // After the new item is inserted, the count is increased public bool Insert(double itm, int pos) { // Check that the item can be added to the list if (size < 20 && pos >= 0 && pos <= size) { // Since there is room, // starting from the end of the list to the new position, // push each item to the next or up // to create room for the new item for (int i = size; i > pos - 1; i--) this.Item[i + 1] = this.Item[i]; // Now that we have room, put the new item in the position created

this.Item[pos] = itm; // Since we have added a new item, increase the count this.size++; // Indicate that the operation was successful return true; } // Since the item could not be added, return false return false;

} // Removes an item from the list // First check that the specified position is valid //-- Delete the item at that position and decrease the count --// public bool Delete(int pos) { // Make sure the position specified is in the range if (pos >= 0 && pos <= size) { // Since there is room, starting at the specified position, // Replace each item by the next for (int i = pos; i < this.size; i++) this.Item[i] = this.Item[i + 1]; // Since an item has been removed, decrease the count this.size--; // Indicate that the operation was successful return true; }

C# 3.0 Practical Learning

707

// Since the position was out of range, return false return false; } #endregion } public class Exercise { static int Main(string[] args) { var list = new Collection(); Console.WriteLine("Number of Items: {0}", list.Count); list.Add(224.52); list.Add(60.48); list.Add(1250.64); list.Add(8.86); list.Add(1005.36); for (var i = 0; i < list.Count; i++) Console.WriteLine("Item {0}: {1}", i + 1, list.Retrieve(i)); Console.WriteLine("Number of Items: {0}\n", list.Count); list.Insert(-707.16, 2); list.Insert(-369952.274, 4); for (var i = 0; i < list.Count; i++) Console.WriteLine("Item {0}: {1}", i + 1, list.Retrieve(i)); Console.WriteLine("Number of Items: {0}\n", list.Count); list.Delete(5); list.Delete(3); for (var i = 0; i < list.Count; i++) Console.WriteLine("Item {0}: {1}", i + 1, list.Retrieve(i)); Console.WriteLine("Number of Items: {0}\n", list.Count); return 0; }

}

This would produce: Number of Items: 0 Item 1: 224.52 Item 2: 60.48 Item 3: 1250.64 Item 4: 8.86 Item 5: 1005.36 Number of Items: 5 Item Item Item Item Item Item

1: 2: 3: 4: 5: 6:

224.52 60.48 -707.16 1250.64 -369952.274 8.86

C# 3.0 Practical Learning

708

Item 7: 1005.36 Number of Items: 7 Item 1: 224.52 Item 2: 60.48 Item 3: -707.16 Item 4: -369952.274 Item 5: 1005.36 Number of Items: 5 Press any key to continue . . .

A Collection of Items Introduction We have learned how to create an array as a list of items. Like an array, a collection is a series of items of the same type. The particularity with creating an array is that you must know in advance the number of items that will make up the list (in reality, in the .NET Framework, you just have to specify an initial count, such as 5; then, before adding a new item, you can check if there is room, if there is no room, you can provide room first, then add the new item). There are times when you don't know, you can't know, or you can't predict the number of items of the list. For this reason, you may want to create the list for which you don't specify the maximum number of items but you allow the user of the list to add, locate, or remove items at will. Before creating a list, you probably should first decide or define what the list would be made of. As different as collections are, one list can be made of numeric values, such as a list that will be made of numbers. You may want a list that is made of names. Such a list can be created from a class that includes a string member variable. Another type of list can contain complex objects.

Practical Learning: Introducing Collections 1. Start Microsoft Visual C# and create a new Console Application named FlowerShop4

2. To save the project, on the Standard toolbar, click the Save All button 3. Accept all defaults and click Save 4. To create a new class, in the Solution Explorer, right-click FlowerShop4 -> Add -> Class... 5. Set the Name of the class to Flower and click Add 6. Change the file as follows: using System; using System.Collections.Generic;

C# 3.0 Practical Learning

709

using System.Linq; using System.Text; namespace FlowerShop4 { public enum FlowerType { Roses = 1, Lilies, Daisies, Carnations, LivePlant, Mixed } public enum FlowerColor { Red = 1, White, Yellow, Pink, Orange, Blue, Lavender, Mixed } public enum FlowerArrangement { Bouquet = 1, Vase, Basket, Any } public sealed class Flower { private decimal pc; public FlowerType Type; public FlowerColor Color; public FlowerArrangement Arrangement; public Flower() { Type = FlowerType.Mixed; Color = FlowerColor.Mixed; Arrangement = FlowerArrangement.Vase; pc = 0.00M; } public Flower(FlowerType type, FlowerColor color, FlowerArrangement argn, decimal price) { Type = type; Color = color; Arrangement = argn;

C# 3.0 Practical Learning

710

pc = price; }

}

public decimal UnitPrice { get { return pc; } set { pc = value; } }

}

7. To create a new class, in the Solution Explorer, right-click FlowerShop4 -> Add -> Class... 8. Set the Name of the class to OrderProcessing and click Add 9. Complete the OrderProcessing.cs file as follows: using using using using

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

namespace FlowerShop4 { public class OrderProcessing { public Flower FlowerOrder; private int qty; public int Quantity { get { return qty; } set { qty = value; } } public OrderProcessing() { FlowerOrder = new Flower(); } public decimal TotalPrice { get { return Quantity * FlowerOrder.UnitPrice; } } internal void GetFlowerType() { int choice = 0; do {

try {

Console.WriteLine("Enter the Type of Flower Order"); Console.WriteLine("1. Roses"); Console.WriteLine("2. Lilies");

C# 3.0 Practical Learning

711

Console.WriteLine("3. Daisies"); Console.WriteLine("4. Carnations"); Console.WriteLine("5. Live Plant"); Console.WriteLine("6. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("You failed to enter an " + "appropriate number!"); } if ((choice < 1) || (choice > 6)) Console.WriteLine("Invalid Value: Please enter " + "a value between 1 and 6"); } while ((choice < 1) || (choice > 6)); switch (choice) { case 1: FlowerOrder.Type break; case 2: FlowerOrder.Type break; case 3: FlowerOrder.Type break; case 4: FlowerOrder.Type break; case 5: FlowerOrder.Type break; default: FlowerOrder.Type break; }

= FlowerType.Roses; = FlowerType.Lilies; = FlowerType.Daisies; = FlowerType.Carnations; = FlowerType.LivePlant; = FlowerType.Mixed;

} internal void GetFlowerColor() { int choice = 0; do { try { Console.WriteLine("Enter the Color"); Console.WriteLine("1. Red"); Console.WriteLine("2. White"); Console.WriteLine("3. Yellow"); Console.WriteLine("4. Pink"); Console.WriteLine("5. Orange"); Console.WriteLine("6. Blue"); Console.WriteLine("7. Lavender"); Console.WriteLine("8. Mixed");

C# 3.0 Practical Learning

712

Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("You didn't enter an " + "appropriate number!"); } if ((choice < 1) || (choice > 8)) Console.WriteLine("Invalid Value: Please " + "enter a value between 1 and 8"); } while ((choice < 1) || (choice > 8)); switch (choice) { case 1: FlowerOrder.Color break; case 2: FlowerOrder.Color break; case 3: FlowerOrder.Color break; case 4: FlowerOrder.Color break; case 5: FlowerOrder.Color break; case 6: FlowerOrder.Color break; case 7: FlowerOrder.Color break; default: FlowerOrder.Color break; }

= FlowerColor.Red; = FlowerColor.White; = FlowerColor.Yellow; = FlowerColor.Pink; = FlowerColor.Yellow; = FlowerColor.Blue; = FlowerColor.Lavender; = FlowerColor.Mixed;

} internal void GetFlowerArrangement() { int choice = 0; do { try { Console.WriteLine("Enter the Type of Arrangement"); Console.WriteLine("1. Bouquet"); Console.WriteLine("2. Vase"); Console.WriteLine("3. Basket"); Console.WriteLine("4. Mixed"); Console.Write("Your Choice: "); choice = int.Parse(Console.ReadLine());

} catch (FormatException)

C# 3.0 Practical Learning

713

{ Console.WriteLine("You didn't provide an " + "acceptable number!"); } if ((choice < 1) || (choice > 4)) Console.WriteLine("Invalid Value: Please enter " + "a value between 1 and 4"); } while ((choice < 1) || (choice > 4)); switch (choice) { case 1: FlowerOrder.Arrangement break; case 2: FlowerOrder.Arrangement break; case 3: FlowerOrder.Arrangement break; default: FlowerOrder.Arrangement break; }

= FlowerArrangement.Bouquet; = FlowerArrangement.Vase; = FlowerArrangement.Basket; = FlowerArrangement.Any;

} internal void ProcessOrder() { GetFlowerType(); GetFlowerColor(); GetFlowerArrangement(); try { Console.Write("Enter the Unit Price: "); FlowerOrder.UnitPrice = Math.Abs(decimal.Parse(Console.ReadLine()));

} catch (FormatException) { Console.WriteLine("You didn't specify a valid price!"); } try {

}

Console.Write("Enter Quantity: "); Quantity = Math.Abs(int.Parse(Console.ReadLine()));

} catch (FormatException) { Console.WriteLine("The quantity you entered " + "is not acceptable!"); }

internal void ShowOrder() { Console.WriteLine("======================="); Console.WriteLine("==-=-=Flower Shop=-=-==");

C# 3.0 Practical Learning

714

} }

Console.WriteLine("-----------------------"); Console.WriteLine("Flower Type: {0}", FlowerOrder.Type); Console.WriteLine("Flower Color: {0}", FlowerOrder.Color); Console.WriteLine("Arrangement: {0}", FlowerOrder.Arrangement); Console.WriteLine("Price: {0:C}", FlowerOrder.UnitPrice); Console.WriteLine("Quantity: {0}", Quantity); Console.WriteLine("Total Price: {0:C}", TotalPrice); Console.WriteLine("=======================");

}

10. using using using using

Access the Program.cs file and complete it as follows: System; System.Collections.Generic; System.Linq; System.Text;

namespace FlowerShop4 { public class Program { static void Main(string[] args) { var order = new OrderProcessing(); order.ProcessOrder(); Console.WriteLine(); order.ShowOrder(); Console.WriteLine(); }

}

}

11.

Execute the application and test it. Here is an example:

Enter the Type of Flower Order 1. Roses 2. Lilies 3. Daisies 4. Carnations 5. Live Plant 6. Mixed Your Choice: 3 Enter the Color 1. Red 2. White 3. Yellow 4. Pink 5. Orange 6. Blue 7. Lavender

C# 3.0 Practical Learning

715

8. Mixed Your Choice: 8 Enter the Type of Arrangement 1. Bouquet 2. Vase 3. Basket 4. Mixed Your Choice: 1 Enter the Unit Price: 45.50 Enter Quantity: 3 ======================= ==-=-=Flower Shop=-=-== ----------------------Flower Type: Daisies Flower Color: Mixed Arrangement: Bouquet Price: $45.50 Quantity: 3 Total Price: $136.50 ======================= Press any key to continue . . .

12.

Close the DOS window

Implementing a Collection After deciding what each item of the list would be made of, you can create a class that would manage the list. This class would be responsible for all operations that can be performed on the list. If the list will be made of primitive values, you can directly create a field of the desired type. Here is an example: using System; public class Numbers { public double Number; } public class Exercise { static int Main(string[] args) { Numbers nbrs = new Numbers(); return 0; }

}

If the list will be made of objects, you can first create a class that specifies those types of items and then declare its variable in the list class. Here is an example of a simple class that holds a double-precision value: C# 3.0 Practical Learning

716

using System; public class Number { public double Item; } public class Numbers { Number Sample; } public class Exercise { static int Main(string[] args) { Numbers nbrs = new Numbers(); return 0; }

}

When creating a list, one of the aspects you should pay attention to is to keep track of the number of items in the list. To do this, you can create a property that holds the number. The value of this property would increase as the items are added to the list and the value would decrease as the items are removed from the list. Here is how this can be done: using System; public class Number { public double Item; } public class Numbers { int size; Number Sample; public Numbers() { size = 0; }

}

public int Count { get { return size; } }

public class Exercise { static int Main(string[] args) { var nbrs = new Numbers(); Console.WriteLine("Number of Items: {0}", nbrs.Count); return 0;

C# 3.0 Practical Learning

717

} }

This would produce: Number of Items: 0 Press any key to continue . . .

Practical Learning: Creating a Class Collection 1. To create a new class, in the Class View, right-click FlowerShop4 -> Add -> Class... 2. Set the Name to FlowerInventory and click Add 3. Change the class as follows: using using using using

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

namespace FlowerShop4 { public abstract class AFlower { protected int items; public AFlower() { items = 0; }

}

public int Count { get { return items; } }

public class FlowerInventory : AFlower { public Flower Inventory; public FlowerInventory() { } }

}

4. Save the file

The Beginning of a Collection A good collection is a list that can grow or shrink as the user wishes. When creating the list, you don't need to predict the maximum number of items that will be added to the list. When a list starts, it is empty or at least it must C# 3.0 Practical Learning

718

be considered like that, before any item is added to it. To specify this, you should declare a primary member variable. Although you can call it anything, it is usually called Head:

The head member can be made private if you don't intend to access it outside of the class. If you want clients of the class to access it, you can make it public. Here is an example: public class Numbers { int listSize; Number Sample; public Numbers() { size = 0; Head = null; } public int Count { get { return listSize; } } public Number Head; }

Linking the Items of a Collection We saw that when using an array, each member could be accessed using its index. If the items of a collection are not indexed, you must provide a mechanism to locate an item. To do this, you can use a starting point that determines the beginning of the list. Then, to locate an item, you can check whether another item follows that starting point:

C# 3.0 Practical Learning

719

If no item follows an item, either you are at the end of the list or the list is empty. To be able to scan a list from one item to another, you can declare a field. Although this member variable can be called anything, for the sake of clarify, you should call it Next. The field is the same type as its class. Here is an example: public class Number { public double Item; public Number Next; }

Practical Learning: Creating a List's Monitor 1. Access the Flower.cs file and change it as follows: using using using using

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

namespace FlowerShop4 { . . . No Change public sealed class Flower { . . . No Change public decimal UnitPrice { get { return pc; } set { pc = value; } } }

public Flower Next;

}

2. Access the FlowerInventory.cs file and change it as follows: using using using using

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

namespace FlowerShop4 { public abstract class AFlower { protected int items; public AFlower() {

C# 3.0 Practical Learning

720

items = 0; } public int Count { get { return items; } } } public class FlowerInventory : AFlower { public Flower Head; public Flower Inventory;

}

public FlowerInventory() { Head = null; }

}

3. Save all

Operations on a Collection Adding an Item Since a list is fundamentally empty when it starts, the primary operation you can perform on a list is to add a new item to it. In order to indicate that you want to add an item to the list, you can create a method that receives an item as argument. For the return type, you have two main options. Because the main job of this method is to add a new item, which it hardly fails to do if you implement it right, it can be defined as void. Alternatively, you can make it return the position of the new item in the list. Here is an example: public class Numbers { int size; Number Sample; public Number Head; public Numbers() { size = 0; Head = null; } public int Count { get { return size; } } public int Add(Number NewItem) { Number Sample = new Number();

C# 3.0 Practical Learning

721

Sample = NewItem; Sample.Next = Head; Head = Sample; return size++; }

}

Practical Learning: Adding Items to a Collection 1. Change the FlowerInventory.cs file as follows: using using using using

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

namespace FlowerShop4 { public abstract class AFlower { protected int items; public AFlower() { items = 0; } public int Count { get { return items; } } public abstract int Add(Flower obj); } public class FlowerInventory : AFlower { public Flower Head; public Flower Inventory; public FlowerInventory() { Head = null; } public override int Add(Flower NewFlower) { Flower Sample = new Flower(); Sample = NewFlower; Sample.Next = Head; Head = Sample; return items++; }

}

}

C# 3.0 Practical Learning

722

2. Access the Program.cs and change it as follows: using using using using

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

namespace FlowerShop4 { public class Program { static void Main(string[] args) { var flowers = new FlowerInventory(); var nice = new Flower(); nice.Type = FlowerType.Lilies; nice.Color = FlowerColor.White; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 39.95M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Daisies; nice.Color = FlowerColor.Mixed; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 40.50M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Carnations; nice.Color = FlowerColor.Lavender; nice.Arrangement = FlowerArrangement.Any; nice.UnitPrice = 34.85M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Roses; nice.Color = FlowerColor.Pink; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 29.95M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Daisies; nice.Color = FlowerColor.Yellow; nice.Arrangement = FlowerArrangement.Vase; nice.UnitPrice = 29.95M; flowers.Add(nice); }

}

}

3. Save all

Retrieving an Item C# 3.0 Practical Learning

723

Once a list exists, the user can explore it. One of the operations performed on a collection is to locate and retrieve an item. To do this, you can create a method that takes as argument an index. The method would examine the argument with regards to the number of items in the list to make sure the argument's value is in the range of the current items of the list. If the number is too low or too high, the method can return null or 0. If the number is in the range, the method can return the item at that position. Here is an example: public class Numbers { int size; Number Sample; public Number Head; public Numbers() { size = 0; Head = null; } public int Count { get { return size; } } public int Add(Number NewItem) { Number Sample = new Number(); Sample = NewItem; Sample.Next = Head; Head = Sample; return size++; } public Number Retrieve(int Position) { Number Current = Head;

}

for (int i = Count - 1; i > Position && Current != null; i--) Current = Current.Next; return Current;

}

Practical Learning: Retrieving the Items of a Collection 1. Access the FlowerInventory.cs file and add the following method: using using using using

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

namespace FlowerShop4 { public abstract class AFlower

C# 3.0 Practical Learning

724

{ protected int items; public AFlower() { items = 0; } public int Count { get { return items; } } public abstract int Add(Flower obj); public abstract Flower Get(int index); } public class FlowerInventory : AFlower { public Flower Head; public Flower Inventory; public FlowerInventory() { Head = null; } public override int Add(Flower NewFlower) { Flower Sample = new Flower(); Sample = NewFlower; Sample.Next = Head; Head = Sample; return items++; } public override Flower Get(int index) { Flower Current = Head;

} }

for(int i = Count - 1; i > index && Current != null; i--) Current = Current.Next; return Current;

}

2. Access the Program.cs file and change it as follows: using using using using

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

namespace FlowerShop4 {

C# 3.0 Practical Learning

725

public class Program { static void Main(string[] args) { var flowers = new FlowerInventory(); var nice = new Flower(); nice.Type = FlowerType.Lilies; nice.Color = FlowerColor.White; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 39.95M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Daisies; nice.Color = FlowerColor.Mixed; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 40.50M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Carnations; nice.Color = FlowerColor.Lavender; nice.Arrangement = FlowerArrangement.Any; nice.UnitPrice = 34.85M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Roses; nice.Color = FlowerColor.Pink; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 29.95M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Daisies; nice.Color = FlowerColor.Yellow; nice.Arrangement = FlowerArrangement.Vase; nice.UnitPrice = 42.75M; flowers.Add(nice); //"); inventory",

Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//= Console.WriteLine("Total: {0} flower items in current flowers.Count); Console.WriteLine("------------------------------------------

--");

Console.WriteLine("Inventory Summary"); for (int i = 0; i < flowers.Count; i++) { Console.WriteLine("------------------------"); Console.WriteLine("Flower Information"); Console.WriteLine("Type: {0}", flowers.Get(i).Type); Console.WriteLine("Color: {0}", flowers.Get(i).Color); Console.WriteLine("Arrangement: {0}", flowers.Get(i).Arrangement); Console.WriteLine("Unit Price: {0:F}",

C# 3.0 Practical Learning

726

flowers.Get(i).UnitPrice); } Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//= //"); }

}

}

3. Execute the application to view the result: //=//=//=//=//=//=//=//=//=//=//=//=//=//=// Total: 5 flower items in current inventory -------------------------------------------Inventory Summary -----------------------Flower Information Type: Lilies Color: White Arrangement: Bouquet Unit Price: 39.95 -----------------------Flower Information Type: Daisies Color: Mixed Arrangement: Bouquet Unit Price: 40.50 -----------------------Flower Information Type: Carnations Color: Lavender Arrangement: Any Unit Price: 34.85 -----------------------Flower Information Type: Roses Color: Pink Arrangement: Bouquet Unit Price: 29.95 -----------------------Flower Information Type: Daisies Color: Yellow Arrangement: Vase Unit Price: 42.75 //=//=//=//=//=//=//=//=//=//=//=//=//=//=// Press any key to continue . . .

4. Close the DOS window

Removing an Item Deleting an item consists of removing it from the list. There are two main approaches you can use. You can simply ask the class to delete an item. In this case, it is usually the item at the end that gets deleted. If you do this, make sure you perform other routine operations such as decrementing the count of items in the list. Here is an example: public class Numbers

C# 3.0 Practical Learning

727

{ . . . No Change public bool Delete() { if (Head == null) { Console.WriteLine("The list is empty"); return false; } Number Current; Current = Head.Next; Head.Next = Current.Next; size--; return true; }

}

Another technique used to delete an item consists of specifying the position of the item to be deleted. To do this, you can pass an argument as the desired position. The method would check the range of values of the current list. If the specified position is beyond the appropriate range, the method can return false, 0, or null, depending on how you create it.

Practical Learning: Retrieving the Items of a Collection 1. Access the FlowerInventory.cs file and add the following method: using using using using

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

namespace FlowerShop4 { public abstract class AFlower { protected int items; public AFlower() { items = 0; } public int Count { get { return items; } } public abstract int Add(Flower obj); public abstract Flower Get(int index); public abstract bool Delete(); } public class FlowerInventory : AFlower

C# 3.0 Practical Learning

728

{ public Flower Head; public Flower Inventory; public FlowerInventory() { Head = null; } public override int Add(Flower NewFlower) { Flower Sample = new Flower(); Sample = NewFlower; Sample.Next = Head; Head = Sample; return items++; } public override Flower Get(int index) { Flower Current = Head;

}

for(int i = Count - 1; i > index && Current != null; i--) Current = Current.Next; return Current;

public override bool Delete() { if (Head == null) { Console.WriteLine("The inventory is empty"); return false; } Flower Current;

} }

Current = Head.Next; Head.Next = Current.Next; items--; return true;

}

2. Access the Program.cs file and change it as follows: using using using using

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

namespace FlowerShop4 { public class Program {

C# 3.0 Practical Learning

729

static void Main(string[] args) { var flowers = new FlowerInventory(); var nice = new Flower(); nice.Type = FlowerType.Lilies; nice.Color = FlowerColor.White; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 39.95M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Daisies; nice.Color = FlowerColor.Mixed; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 40.50M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Carnations; nice.Color = FlowerColor.Lavender; nice.Arrangement = FlowerArrangement.Any; nice.UnitPrice = 34.85M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Roses; nice.Color = FlowerColor.Pink; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 29.95M; flowers.Add(nice); nice = new Flower(); nice.Type = FlowerType.Daisies; nice.Color = FlowerColor.Yellow; nice.Arrangement = FlowerArrangement.Vase; nice.UnitPrice = 42.75M; flowers.Add(nice); //"); inventory",

Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//= Console.WriteLine("Total: {0} flower items in current flowers.Count); Console.WriteLine("------------------------------------------

--");

Console.WriteLine("Inventory Summary"); for (var i = 0; i < flowers.Count; i++) { Console.WriteLine("------------------------"); Console.WriteLine("Flower Information"); Console.WriteLine("Type: {0}", flowers.Get(i).Type); Console.WriteLine("Color: {0}", flowers.Get(i).Color); Console.WriteLine("Arrangement: {0}", flowers.Get(i).Arrangement); Console.WriteLine("Unit Price: {0:F}", flowers.Get(i).UnitPrice); }

C# 3.0 Practical Learning

730

Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//= //"); flowers.Delete(); flowers.Delete(); Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//= //");

Console.WriteLine("Total: {0} flower items in current

inventory", --");

Console.WriteLine("Inventory Summary"); for (var i = 0; i < flowers.Count; i++) { Console.WriteLine("------------------------"); Console.WriteLine("Flower Information"); Console.WriteLine("Type: {0}", flowers.Get(i).Type); Console.WriteLine("Color: {0}", flowers.Get(i).Color); Console.WriteLine("Arrangement: {0}", flowers.Get(i).Arrangement); Console.WriteLine("Unit Price: {0:F}", flowers.Get(i).UnitPrice); } Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=

//"); }

flowers.Count); Console.WriteLine("------------------------------------------

}

}

3. Execute the application to view the result: //=//=//=//=//=//=//=//=//=//=//=//=//=//=// Total: 5 flower items in current inventory -------------------------------------------Inventory Summary -----------------------Flower Information Type: Lilies Color: White Arrangement: Bouquet Unit Price: 39.95 -----------------------Flower Information Type: Daisies Color: Mixed Arrangement: Bouquet Unit Price: 40.50 -----------------------Flower Information Type: Carnations Color: Lavender Arrangement: Any Unit Price: 34.85 -----------------------Flower Information

C# 3.0 Practical Learning

731

Type: Roses Color: Pink Arrangement: Bouquet Unit Price: 29.95 -----------------------Flower Information Type: Daisies Color: Yellow Arrangement: Vase Unit Price: 42.75 //=//=//=//=//=//=//=//=//=//=//=//=//=//=// //=//=//=//=//=//=//=//=//=//=//=//=//=//=// Total: 3 flower items in current inventory -------------------------------------------Inventory Summary -----------------------Flower Information Type: Lilies Color: White Arrangement: Bouquet Unit Price: 39.95 -----------------------Flower Information Type: Daisies Color: Mixed Arrangement: Bouquet Unit Price: 40.50 -----------------------Flower Information Type: Daisies Color: Yellow Arrangement: Vase Unit Price: 42.75 //=//=//=//=//=//=//=//=//=//=//=//=//=//=// Press any key to continue . . .

4. Close the DOS window

Locating an Item One of the operations hardly performed on a list is to find an item. This is because if you ask a list to locate a particular item, you must provide as much information as possible. Probably the most expedient way you can do this is to completely define an item and pass it to the list. Only if the (exact) item is found in the list would it be recognized. Here is an example: using System; public class Number { public double Item; public Number Next; } public class Numbers {

C# 3.0 Practical Learning

732

int size; Number Sample; public Number Head; public Numbers() { size = 0; Head = null; } public int Count { get { return size; } } public int Add(Number NewItem) { Number Sample = new Number(); Sample = NewItem; Sample.Next = Head; Head = Sample; return size++; } public Number Retrieve(int Position) { Number Current = Head;

}

for (int i = Count - 1; i > Position && Current != null; i--) Current = Current.Next; return Current;

public bool Delete() { if (Head == null) { Console.WriteLine("The list is empty"); return false; } Number Current;

}

Current = Head.Next; Head.Next = Current.Next; size--; return true;

public bool Find(Number toFind) { Number Current = new Number(); if (toFind == null) return false; for (Current = Head; Current != null; Current = Current.Next) { if( Current.Item == toFind.Item )

C# 3.0 Practical Learning

733

return true; } }

return false;

} public class Exercise { static int Main(string[] args) { Number real; Numbers reals = new Numbers(); real = new Number(); real.Item = 2974.03; reals.Add(real); real = new Number(); real.Item = 748.25; reals.Add(real); real = new Number(); real.Item = 50883.82; reals.Add(real); real = new Number(); real.Item = 29.24; reals.Add(real); real = new Number(); real.Item = 772.85; reals.Add(real); real = new Number(); real.Item = 106628.06; reals.Add(real); Console.WriteLine("Number of items: {0}", reals.Count); for (int i = 0; i < reals.Count; i++) { Number nbr = reals.Retrieve(i); Console.WriteLine("Number[{0}] = {1}", i, nbr.Item); } reals.Delete(); Console.WriteLine("\nNumber of items: {0}", reals.Count); for (int i = 0; i < reals.Count; i++) { Number nbr = reals.Retrieve(i); Console.WriteLine("Number[{0}] = {1}", i, nbr.Item); } Number nbrToFind = new Number(); nbrToFind.Item = 26486.56; bool Found = reals.Find(nbrToFind);

C# 3.0 Practical Learning

734

if (Found == true) Console.WriteLine("\nThe number {0} was found in the list", nbrToFind.Item); else Console.WriteLine("\nThe number {0} was NOT found in the list",

nbrToFind.Item); nbrToFind = new Number(); nbrToFind.Item = 50883.82; Found = reals.Find(nbrToFind); if (Found == true) Console.WriteLine("The number {0} was found in the list\n", nbrToFind.Item); else Console.WriteLine("The number {0} was NOT found in the

list\n",

nbrToFind.Item); return 0;

}

}

This would produce: Number of Number[0] Number[1] Number[2] Number[3] Number[4] Number[5]

items: 6 = 2974.03 = 748.25 = 50883.82 = 29.24 = 772.85 = 106628.06

Number of Number[0] Number[1] Number[2] Number[3] Number[4]

items: 5 = 2974.03 = 748.25 = 50883.82 = 29.24 = 106628.06

The number 26486.56 was NOT found in the list The number 50883.82 was found in the list Press any key to continue . . .

C# 3.0 Practical Learning

735

Iterating Through a Collection Enumerating the Members of a Collection Introduction to System Collections When studying arrays, we saw that you could use a for loop to visit each member of an array. This was also done with the help of the [] operator. In previous lessons, we saw that, when creating a collection, you should provide a method that allows you to retrieve a member of the collection. In both cases, you can list the members of an array or a collection through a technique called an enumeration. Enumerating a collection consists of visiting each member of the list, for any reason judged necessary. For example, you can enumerate a collection to display a list of its members. You can enumerate a collection when looking for a member that responds to a certain criterion.

Besides, or instead of, a for loop, the .NET Framework provides another and better support for enumeration. In the C# language, you can enumerate a collection using the foreach operator, but the collection must be prepared for it: you cannot just use foreach for any collection. This support is provided through two main interfaces: IEnumerator and IEnumerable. These two interfaces are defined in the System.Collection namespace. Therefore, if you intend to use them, you can include this namespace in your source file.

Practical Learning: Introducing Built-In Collections 1. Start Microsoft Visual C# and create a new Console Application named FlowerShop5

2. To create a new file, on the main menu, click Project -> Add New Item... 3. In the Templates list, click Code File 4. Set the Name to FlowerAccessories and click Add 5. In the empty file, type the following: public enum FlowerType { Roses = 1, Lilies = 102,

// Why // these

C# 3.0 Practical Learning

736

Daisies Carnations LivePlant Orchids Tulips Iris Mixed Other

}

= = = = = = = =

104, 112, 220, 234, 242, 250, 462, 464

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

fancy numbers? Just for the fun of it

public enum FlowerColor { Red = 1, White, Yellow, Pink, Orange, Blue, Lavender, Mixed } public enum FlowerArrangement { Bouquet = 1, Balloon, Vase, Basket, Bundle, Any }

6. To create a new class, in the Solution Explorer, right-click FlowerShop5 -> Add -> Class... 7. Set the Name to Flower and press Enter 8. Change the file as follows: using using using using

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

namespace FlowerShop5 { public class Flower { private decimal pc; public Flower Next; public FlowerType Type;

C# 3.0 Practical Learning

737

public FlowerColor Color; public FlowerArrangement Arrangement; public Flower() { Type = FlowerType.Mixed; Color = FlowerColor.Mixed; Arrangement = FlowerArrangement.Vase; pc = 0.00M; } public Flower(FlowerType type, FlowerColor color, FlowerArrangement argn, decimal price) { Type = type; Color = color; Arrangement = argn; pc = price; } public decimal UnitPrice { get { return pc; } set { pc = value; } } }

}

9. To create a new class, in the Class View, right-click FlowerShop5 -> Add -> Class... 10. Set the Name to FlowerInventory and click Add 11. using using using using

Change the class as follows: System; System.Collections.Generic; System.Linq; System.Text;

namespace FlowerShop5 { public abstract class AFlower { protected int items; public AFlower() { items = 0; } public int Count { get { return items; } } public abstract int Add(Flower obj); public abstract Flower Get(int index);

C# 3.0 Practical Learning

738

public abstract bool Delete(); } public class FlowerInventory : AFlower { public Flower Head; public Flower Inventory; public FlowerInventory() { Head = null; } public override int Add(Flower NewFlower) { Flower Sample = NewFlower;

}

Sample.Next = Head; Head = Sample; return items++;

public override Flower Get(int index) { Flower Current = Head; for(int i = Count - 1; i > index && Current != null; i--) Current = Current.Next; return Current; } public override bool Delete() { if (Head == null) { Console.WriteLine("The inventory is empty"); return false; } Flower Current; Current = Head.Next; Head.Next = Current.Next; items--; return true; }

}

}

12.

Save all

Introduction to the IEnumerator Interface The IEnumerator interface provides the means of identifying the class that holds a sample of the items that will be enumerated. This interface is equipped with one property and two methods. To use the functionalities C# 3.0 Practical Learning

739

provided by the IEnumerator interface, you must create a class that implements it. You can start the class as follows: public class Enumerator : IEnumerator { }

If your collection is an array-based list, you can start by declaring the base array in the class: Here is an example: public class Enumerator : IEnumerator { private double[] numbers; }

If the collection is not array-based, you can declare a variable for the class that would be enumerated. The role of the enumerator is to act on a collection. For this reason, the class should be prepared to receive an external collection. This can be done by passing it to a constructor of the enumerator. Here is an example: public class Enumerator : IEnumerator { private double[] numbers; public Enumerator(double[] list) { } }

The internal collection would be used in the enumerator class. The external collection would be the source of the values of the list that would be enumerated. For these reasons, you can/should initialize the internal collection with the values of the external list. This can be done as follows: public class Enumerator : IEnumerator { private double[] numbers;

}

public Enumerator(double[] list) { this.numbers = list; }

Practical Learning: Introducing Enumerations 1. To create a new class, in the Class View, right-click FlowerShop5 -> Add -> Class... 2. Set the Name of the class to FlowerIdentifier and click Add 3. Change the file as follows: using System; using System.Collections.Generic; using System.Linq;

C# 3.0 Practical Learning

740

using System.Text; using System.Collections; namespace FlowerShop5 { public class FlowerIdentifier : IEnumerator { public FlowerInventory counts; public void Identify(FlowerInventory list) { this.counts = list; } }

}

4. Save the file

The Current Item of an Enumeration In the previous lesson, when introducing some techniques of creating a list, we saw that you should have a type of tag, as a field, that allows you to monitor the item that is being currently accessed or used in the list. This is particularly valuable when visiting the members of the collection. The IEnumerator interface provides a property that is used to identify the current member of the list. This property is called Current. Because the current item is meant to be viewed only, the Current property is a read-only member. Based on the rules of abstract classes, remember that you must implement all members of an interface in the class that is based on it. To implement the Current property, you can define its get accessor to return the item at the current position. This can be done as follows: public class Enumerator : IEnumerator { private double[] numbers; private int cur; public Enumerator(double[] list) { this.numbers = list; } public object Current { get { return numbers[cur]; } } }

Practical Learning: Getting to the Current Item 1. In the FlowerIdentifier.cs file, implement the IEnumerator.Current property as follows: using System;

C# 3.0 Practical Learning

741

using using using using

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

namespace FlowerShop5 { public class FlowerIdentifier : IEnumerator { private int curPosition = -1; public FlowerInventory counts; public void Identify(FlowerInventory list) { this.counts = list; }

}

public object Current { get { return this.counts.Get(this.curPosition); } }

}

2. Save the file

Resetting the Tag of the Current Item Although you should be able to identify the current item at any time, when the application starts, before the collection can be enumerated, the tag that is used to monitor the current item should be set to a value before the beginning of the count. This can be done by setting the tag to -1. Here is an example: public class Enumerator : IEnumerator { private double[] numbers; private int cur; public Enumerator(double[] list) { this.numbers = list; cur = -1; } public Object Current { get { return numbers[cur]; } } }

While the collection is being used, at one moment you may want to reset the tag of the current item to its original position. To support this operation, the IEnumerator interface is equipped with a method named Reset. Its syntax is: C# 3.0 Practical Learning

742

void Reset();

When implementing this method, simply assign a non-existing value, which is usually -1, to the monitoring tag of the current item. This can be done as follows: public class Enumerator : IEnumerator { private double[] numbers; private int cur; public Enumerator(double[] list) { this.numbers = list; cur = -1; } public object Current { get { return numbers[cur]; } } public void Reset() { cur = -1; } }

When using the implementer of the IEnumerator interface, if you try accessing an item beyond the maximum number of items, the compiler would throw an IndexOutOfRangeException exception. For this reason, when anticipating a bad behavior, you should catch this exception when implementing the Current property.

Practical Learning: Resetting the Tag of the Current Item 1. In the FlowerIdentifier.cs file, implement the IEnumerator.Reset() method as follows: using using using using using

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

namespace FlowerShop5 { public class FlowerIdentifier : IEnumerator { private int curPosition = -1; public FlowerInventory counts; public void Identify(FlowerInventory list) { this.counts = list; }

C# 3.0 Practical Learning

743

public Object Current { get { try { return this.counts.Get(this.curPosition); } catch (IndexOutOfRangeException) { Console.WriteLine("The current item must be accessed " +

"within the range of available

items");

} }

}

}

public void Reset() { this.curPosition = -1; }

}

2. Save the file

Moving to the Next Item in the Enumerator In the previous lesson, we saw that, when using the items of a collection, one way you could locate one item from another was to be able to jump from one item to the next. This operation is also very important when enumerating a collection. To support this operation, the IEnumerator interface is quipped with the MoveNext() method. Its syntax is: bool MoveNext();

When implementing this method, first increment the tag that monitors the current item of the collection. After incrementing the tag, check whether it is lower than the total number of items. If it is, return true. Otherwise, return false. This can be done as follows: public class Enumerator : IEnumerator { private double[] numbers; private int cur; public Enumerator(double[] list) { this.numbers = list; cur = -1; } public Object Current { get { return numbers[cur]; } }

C# 3.0 Practical Learning

744

public void Reset() { cur = -1; } public bool MoveNext() { cur++; if (cur < numbers.Length) return true; else return false; } }

Practical Learning: Moving to the Next Item in the Enumerator 1. Implement the IEnumerator.MoveNext() method as follows: using using using using using

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

namespace FlowerShop5 { public class FlowerIdentifier : IEnumerator { private int curPosition = -1; public FlowerInventory counts; public void Identify(FlowerInventory list) { this.counts = list; } public Object Current { get { try { return this.counts.Get(this.curPosition); } catch (IndexOutOfRangeException) { Console.WriteLine("The current item must be accessed " +

"within the range of available

items");

} return null; }

}

public void Reset()

C# 3.0 Practical Learning

745

{ }

this.curPosition = -1;

public bool MoveNext() { this.curPosition++;

} }

if (this.curPosition < counts.Count) return true; else return false;

}

2. Save the file

An Enumerable Collection Introduction The IEnumerator interface is used to set up a collection for enumeration. The IEnumerator does not provide the functionality necessary to use foreach. The next step is to implement another interface called IEnumerable. While the IEnumerator interface is used to identify the class that holds each value that will be visited, the IEnumerable interface is used to communicate with the collection whose items will be enumerated. For this reason, when implementing this class, you should provide the means of accessing the external collection. This can be done by passing a collection of the class that holds the values, to a constructor of the IEnumerable implementer.

Getting the Enumerator To implement the IEnumerable interface, start by deriving a class from it. While the class implemented by the IEnumerator interface represents an object, the class that implements the IEnumerable interface is a collection. Here is an example: public class Enumerable : IEnumerable { }

The new class does not know what collection it will be asked to enumerate. For this reason, in the new class, you should declare a member variable of the class that holds the values that will be enumerated. If the collection is array-based, you can create the field as follows: public class Enumerable : IEnumerable { private double[] numbers; }

C# 3.0 Practical Learning

746

Eventually, when instantiating the IEnumerable implementer, you will need to pass it a collection of values. To make this possible, you can create a method in the new class and pass that collection of objects. Here is an example: public class Enumerable : IEnumerable { private double[] numbers;

}

public void Identify(double[] values) { }

In this method, you can assign the member variable to the argument. You should also assign each member of the argument to its equivalent of the member of the argument. This can be done with a for loop as follows: public class Enumerable : IEnumerable { private double[] numbers;

}

public void Identify(double[] values) { numbers = values; for (int i = 0; i < values.Length; i++) numbers[i] = values[i]; }

To support the use of the foreach loop, the IEnumerable interface is equipped with (only) a method named GetEnumerator that you must implement. The IEnumerable.GetEnumerator() method returns an IEnumerator object. When implementing this method, you can return an object of the class that implements the IEnumerator interface, passing it the collection that was declared in the IEnumerable implementer. This can be done as follows: public class Enumerable : IEnumerable { private double[] numbers; public void Identify(double[] values) { numbers = values; for (int i = 0; i < values.Length; i++) numbers[i] = values[i]; } public IEnumerator GetEnumerator() { return new Enumerator(numbers); } }

Practical Learning: Getting the Enumerator 1. To create a new class, in the Class View, right-click FlowerShop5 -> Add -> Class... C# 3.0 Practical Learning

747

2. Set the Name of the class to Flowers and click Add 3. Change the file as follows: using using using using using

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

namespace FlowerShop5 { public class Flowers : IEnumerable { private FlowerInventory items; public void Locate(FlowerInventory list) { items = new FlowerInventory();

}

for (int i = 0; i < list.Count; i++) this.items.Add(list.Get(i));

public IEnumerator GetEnumerator() { FlowerIdentifier fid = new FlowerIdentifier();

} }

fid.Identify(items); return fid;

}

4. Save the file

Using foreach After implementing the IEnumerator and the IEnumerable interfaces, you can then use the foreach loop. To start, you must prepare the collection and its items for processing. Here is an example: public class Exercise { static int Main(string[] args) { double[] numbers = new double[5]; numbers[0] = 224.52; numbers[1] = 60.48; numbers[2] = 1250.64; numbers[3] = 8.86; numbers[4] = 1005.36; return 0; }

}

C# 3.0 Practical Learning

748

To enumerate the collection, declare a variable based on the implementer of the IEnumerable and pass the collection to its constructor. Once this is done, you can then use the foreach. Here is an example: using System; using System.Collections; public class Enumerator : IEnumerator { private double[] numbers; private int cur; public Enumerator(double[] list) { this.numbers = list; cur = -1; } public Object Current { get { return numbers[cur]; } } public void Reset() { cur = -1; }

}

public bool MoveNext() { cur++; if (cur < numbers.Length) return true; else return false; }

public class Enumerable : IEnumerable { private double[] numbers; public void Identify(double[] values) { numbers = values; for (int i = 0; i < values.Length; i++) numbers[i] = values[i]; } public IEnumerator GetEnumerator() { return new Enumerator(numbers); } } public class Exercise { static int Main(string[] args) {

C# 3.0 Practical Learning

749

double[] numbers = new double[5]; numbers[0] = 224.52; numbers[1] = 60.48; numbers[2] = 1250.64; numbers[3] = 8.86; numbers[4] = 1005.36; Enumerable coll = new Enumerable(); coll.Identify(numbers); foreach (double d in coll) Console.WriteLine("Item {0}", d); ; }

return 0;

}

Practical Learning: Using foreach on an Enumerator 1. Access the Program.cs file and change it as follows: using using using using

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

namespace FlowerShop5 { public class Program { static void Main(string[] args) { FlowerInventory fls = new FlowerInventory(); Flower nice; nice = new Flower(); nice.Type = FlowerType.Lilies; nice.Color = FlowerColor.White; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 39.95M; fls.Add(nice); nice = new Flower(); nice.Type = FlowerType.Daisies; nice.Color = FlowerColor.Mixed; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 40.50M; fls.Add(nice); nice = new Flower(); nice.Type = FlowerType.Carnations; nice.Color = FlowerColor.Lavender; nice.Arrangement = FlowerArrangement.Any; nice.UnitPrice = 34.85M; fls.Add(nice); nice = new Flower(); nice.Type = FlowerType.Roses;

C# 3.0 Practical Learning

750

nice.Color = FlowerColor.Pink; nice.Arrangement = FlowerArrangement.Bouquet; nice.UnitPrice = 29.95M; fls.Add(nice); nice = new Flower(); nice.Type = FlowerType.Daisies; nice.Color = FlowerColor.Yellow; nice.Arrangement = FlowerArrangement.Vase; nice.UnitPrice = 29.95M; fls.Add(nice); Flowers collection = new Flowers(); collection.Locate(fls); ");

Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//

Console.WriteLine("Total: {0} flower items in current inventory", fls.Count); Console.WriteLine("-------------------------------------------"); Console.WriteLine("Inventory Summary"); foreach (Flower flr in collection) { Console.WriteLine("------------------------"); Console.WriteLine("Flower Information"); Console.WriteLine("Type: {0}", flr.Type); Console.WriteLine("Color: {0}", flr.Color); Console.WriteLine("Arrangement: {0}", flr.Arrangement); Console.WriteLine("Unit Price: {0:F}", flr.UnitPrice); } Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=// "); } } }

2. Execute the application to see the result: //=//=//=//=//=//=//=//=//=//=//=//=//=//=// Total: 5 flower items in current inventory -------------------------------------------Inventory Summary -----------------------Flower Information Type: Lilies Color: White Arrangement: Bouquet Unit Price: 39.95 -----------------------Flower Information Type: Daisies Color: Mixed Arrangement: Bouquet Unit Price: 40.50 -----------------------Flower Information Type: Carnations

C# 3.0 Practical Learning

751

Color: Lavender Arrangement: Any Unit Price: 34.85 -----------------------Flower Information Type: Roses Color: Pink Arrangement: Bouquet Unit Price: 29.95 -----------------------Flower Information Type: Daisies Color: Yellow Arrangement: Vase Unit Price: 29.95 //=//=//=//=//=//=//=//=//=//=//=//=//=//=// Press any key to continue . . .

3. Close the DOS window

C# 3.0 Practical Learning

752

Introduction to Built-In Collection Classes Overview of .NET Collections The ICollection Interface To provide a common abstract techniques of creating and using lists, the .NET Framework provides the ICollection interface. This interface is equipped with a property to keep track of the number of items in a list: the Count property. It is also equipped with a method to copy the items from a list to an array.

Introduction to the ArrayList Class To support the creation of any kind of list, the Microsoft .NET Framework provides the ArrayList class. The ArrayList class implements the ICollection interface. This class can be used to add, locate, or remove an item from a list. The class provides many other valuable operations routinely done on a list.

Because of its flexibility, ArrayList is the most used class to create lists of items of any kind in a .NET application. Besides the ability to handle any type of list, ArrayList is a good class to study the theory of a collection. The routine operations found in the ArrayList class are the same found in many other collection-based classes you would use when creating commercial or graphical applications. Besides the ability to create a collection, the ArrayList class has the built-in mechanism for serialization. The ArrayList class is defined in the System.Collections namespace. Therefore, in order to use the ArrayList class in your application, you can first include the System.Collections namespace in the file that would perform ArrayList operations.

Practical Learning: Introducing the ArrayList Class 1. Start Microsoft Visual C# and create a new Console Application named RealEstate5

C# 3.0 Practical Learning

753

2. To save the project, on the Standard toolbar, click the Save All button 3. Accept the suggestions and click Save 4. To create a new class, in the Solution Explorer, right-click RealEstate5 -> Add -> Class... 5. Set the Name to Property and click Add 6. Change the file as follows: using using using using

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

namespace RealEstate5 { public enum PropertyCondition { Unknown, Excellent, Good, NeedsRepair, BadShape } [Serializable] public class Property { private string propNbr; private PropertyCondition cond; private short beds; private float baths; private int yr; private decimal val; public string PropertyNumber { get { return propNbr; } set { if (propNbr == "") propNbr = "N/A"; else propNbr = value; } } public string PropertyType; public PropertyCondition Condition { get { return cond; } set { cond = value; } }

C# 3.0 Practical Learning

754

public short Bedrooms { get { if (beds <= 1) return 1; else return beds; } set { beds = value; } } public float Bathrooms { get { return (baths <= 0) ? 0.00f : baths; } set { baths = value; } } public int YearBuilt { get { return yr; } set { yr = value; } } public decimal Value { get { return (val <= 0) ? 0.00M : val; } set { val = value; } } }

}

7. To create a new class, in the Class View, right-click RealEstate5 -> Add -> Class... 8. Set the Name to Condominium and press Enter 9. Change the file as follows: using using using using

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

namespace RealEstate5 { [Serializable] public class Condominium : Property { private bool handicap; public Condominium() { this.PropertyType = "Condominium"; } public bool HandicapAccessible { get { return handicap; }

C# 3.0 Practical Learning

755

set { handicap = value; } }

}

}

10. To create a new class, on the main menu, click Project -> Add Class... 11. Set the Name to HouseType and click Add 12. using using using using

Change the file as follows: System; System.Collections.Generic; System.Linq; System.Text;

namespace RealEstate5 { [Serializable] public class HouseType : Property { private short nbrOfStories; private bool basement; private bool garage; public short Stories { get { return nbrOfStories; } set { nbrOfStories = value; } } public bool FinishedBasement { get { return basement; } set { basement = value; } } public bool IndoorGarage { get { return garage; } set { garage = value; } } }

}

13. To create a new class, in the Solution Explorer, right-click RealEstate5 -> Add -> Class... 14. Set the Name to Townhouse and press Enter 15.

Change the file as follows:

using System; using System.Collections.Generic; using System.Linq;

C# 3.0 Practical Learning

756

using System.Text; namespace RealEstate5 { [Serializable] public class Townhouse : HouseType { private bool comm; public Townhouse() { this.PropertyType = "Townhouse"; } public bool IsCommunityManaged { get { return this.comm; } set { this.comm = value; } } }

}

16. To create a new class, in the Class View, right-click RealEstate5 -> Add -> Class... 17. Set the Name to SingleFamily and click Add 18. using using using using

Change the file as follows: System; System.Collections.Generic; System.Linq; System.Text;

namespace RealEstate5 { [Serializable] public class SingleFamily : HouseType { public SingleFamily() { this.PropertyType = "Single Family"; } } }

19.

Save all

The Capacity of a List After declaring an ArrayList variable, it is empty. As objects are added to it, the list grows. The list can grow tremendously as you wish. The number of items of the list is managed through the memory it occupies and this memory grows as needed. The number of items that the memory allocated is currently using is represented by the ArrayList.Capacity property. This will usually be the least of your concerns. C# 3.0 Practical Learning

757

If for some reason, you want to intervene and control the number of items that your ArrayList list can contain, you can manipulate the Capacity property. For example, you can assign it a constant to set the maximum value that the list can contain. Once again, you will hardly have any reason to use the Capacity property: the compiler knows what to do with it. If you set a fixed size on an ArrayList list, you may not be able to add a new item beyond the limit. In fact, if you attempt to do this, you may receive an error. A safe way is to check whether the list is fixed before performing a related operation. To find out whether a list is fixed, you can check the ArrayList variable's IsFixedSize property.

A Read-Only List One of the reason for creating a list is to be able to add items to it, edit its items, retrieve an items, or delete items from it. These are the default operations. You can still limit these operations as you judge them unnecessary. For example, you may create a list and then initialize it with the items that you want the list to only have. If you don't intend to have the user adding items to it, you can create the list as read-only. To do this, you can call the ArrayList.ReadOnly() method. It is overloaded with two versions as follows: public static ArrayList ReadOnly(ArrayList); public static IList ReadOnly(IList);

This method is static. This means that you don't need to declare an instance of ArrayList to call them. Instead, to make the list read-only, call the ArrayList.ReadOnly() method and pass your ArrayList variable to it. As we will see in the next sections, some operations cannot be performed on a read-only list. To perform such operations, you can first find out whether an ArrayList list is read-only. This is done by checking its IsReadOnly property.

Item Addition The primary operation performed on a list is to create one. One of the biggest advantages of using a linked list is that you don't have to specify in advance the number of items of the list as done for an array. You can just start adding items. The ArrayList class makes this possible with the Add() method. Its syntax is: public virtual int Add(object value);

The argument of this method is the value to add to the list. If the method succeeds with the addition, it returns the position where the value was added in the list. This is usually the last position in the list. If the method fails, the compiler would throw an error. One of the errors that could result from failure of this operation would be based on the fact that either a new item cannot be added to the list because the list is read-only, or the list was already full prior to adding the new item. Normally, a list can be full only if you had specified the maximum number of items it can contain using the ArrayList.Capacity property. As mentioned above, the list can be made read-only by passing its variable to the ArrayList.ReadOnly() method. 758 C# 3.0 Practical Learning

Practical Learning: Adding Items to an ArrayList List 1. To create an inventory, on the main menu, click Project -> Add Class... 2. Set the Name to PropertyManagement and press Enter 3. Change the file as follows: using using using using using using using

System; System.Collections.Generic; System.Linq; System.Text; System.IO; System.Collections; System.Runtime.Serialization.Formatters.Binary;

namespace RealEstate5 { public class PropertyManagement { private Condominium Condo; private Townhouse TownHome; private SingleFamily House; private ArrayList Condominiums; private ArrayList Townhouses; private ArrayList SingleFamilies; private string strPropertyNumber; private string strPropertiesDirectory; public PropertyManagement() { Condo = new Condominium(); TownHome = new Townhouse(); House = new SingleFamily(); Condominiums = new ArrayList(); Townhouses = new ArrayList(); SingleFamilies = new ArrayList(); strPropertyNumber = "000000"; strPropertiesDirectory = @"C:\Altair Realty\Properties"; try { // If a directory for the properties has not yet // been created, then create them Directory.CreateDirectory(strPropertiesDirectory);

}

} catch (DirectoryNotFoundException) { Console.WriteLine("The directory could " + "not be created"); }

public PropertyCondition GetPropertyCondition() {

C# 3.0 Practical Learning

759

short condition = 0; try {

Console.WriteLine("\nProperties Conditions"); Console.WriteLine("1. Excellent"); Console.WriteLine("2. Good (may need minor repair)"); Console.WriteLine("3. Needs Repair"); Console.Write("4. In Bad Shape (property needs "); Console.WriteLine("major repair or rebuild)"); Console.Write("Enter Property Condition: "); condition = short.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The value you entered for " + "the condition of the property is not valid"); } if (condition == 1) return PropertyCondition.Excellent; else if (condition == 2) return PropertyCondition.Good; else if (condition == 3) return PropertyCondition.NeedsRepair; else if (condition == 4) return PropertyCondition.BadShape; else return PropertyCondition.Unknown; } public void CreateProperty() { char propType = '0'; Console.WriteLine("\n======================="); Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("-=- Property Creation -=-"); Console.WriteLine("------------------------"); // We will make sure that no two // properties have the same number Console.Write("\nEnter Property #: "); this.strPropertyNumber = Console.ReadLine(); try { Console.WriteLine("\nTypes of Properties"); Console.WriteLine("1. Condominium"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Single Family"); Console.Write("Enter Type of Property: "); propType = char.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The value you entered for " + "the type of property is invalid"); }

C# 3.0 Practical Learning

760

switch (propType) { case '1': CreateCondominium(); break; case '2': CreateTownhouse(); break; case '3': CreateSingleFamily(); break; default: Console.WriteLine("Invalid Choice!!!"); break; } } public void CreateCondominium() { char answer = 'n'; Condo.PropertyNumber = strPropertyNumber; Condo.Condition = GetPropertyCondition(); try {

Console.Write("\nHow many bedrooms? "); Condo.Bedrooms = short.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The value you entered for " + "the number of bedrooms is not good"); } try { Console.Write("How many bathrooms? "); Condo.Bathrooms = float.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid value"); } try {

Console.Write("Year built: "); Condo.YearBuilt = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The house cannot have " + "built in that year"); } Console.Write("\nIs the building " + "accessible to handicapped (y/n): ");

C# 3.0 Practical Learning

761

answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) Condo.HandicapAccessible = true; else Condo.HandicapAccessible = false; try {

Console.Write("Condominium Value: "); Condo.Value = decimal.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid Property Value"); }

}

Condominiums.Add(Condo); ShowTitle(); ShowCondominium(); SaveCondominium();

public void CreateTownhouse() { char answer = 'n'; this.TownHome.PropertyNumber = strPropertyNumber; this.TownHome.Condition = GetPropertyCondition(); try { Console.Write("\nHow many stories (levels)? "); this.TownHome.Stories = short.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The number of stories " + "you entered is not valid"); } try { Console.Write("How many bedrooms? "); this.TownHome.Bedrooms = short.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The value you entered for " + "the number of bedrooms is not good"); } try { Console.Write("How many bathrooms? "); this.TownHome.Bathrooms = float.Parse(Console.ReadLine());

} catch (FormatException)

C# 3.0 Practical Learning

762

{ }

Console.WriteLine("Invalid bathroom number.");

Console.Write("Does it have an indoor " + "car garage (y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) this.TownHome.IndoorGarage = true; else this.TownHome.IndoorGarage = false; Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) this.TownHome.FinishedBasement = true; else this.TownHome.FinishedBasement = false; try {

Console.Write("Year built: "); this.TownHome.YearBuilt = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The house cannot have " + "built in that year"); } try {

Console.Write("Is it community managed (y/n)? "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) this.TownHome.IsCommunityManaged = true; else this.TownHome.IsCommunityManaged = false;

} catch (FormatException) { Console.WriteLine("Invalid Answer"); } try {

Console.Write("Property Value: "); this.TownHome.Value = decimal.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid Property Value"); }

}

Townhouses.Add(this.TownHome); ShowTitle(); ShowTownhouse(); SaveTownhouse();

C# 3.0 Practical Learning

763

public void CreateSingleFamily() { char answer = 'n'; Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("-=- Property Creation -=-"); this.House.PropertyNumber = strPropertyNumber; House.Condition = GetPropertyCondition(); try {

Console.Write("\nHow many stories (levels)? "); House.Stories = short.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The number of stories you " + "entered is not allowed"); } try { Console.Write("How many bedrooms? "); House.Bedrooms = short.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The value you entered for " + "the number of bedrooms is not good"); } try { Console.Write("How many bathrooms? "); House.Bathrooms = float.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid number of bathrooms"); } try {

Console.Write("Does it have an indoor " + "car garage (y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else House.IndoorGarage = false;

} catch (FormatException) { Console.WriteLine("Invalid Indoor Car Garage Answer"); } try {

C# 3.0 Practical Learning

764

Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false;

} catch (FormatException) { Console.WriteLine("Invalid Basement Answer"); } try { Console.Write("Year built: "); House.YearBuilt = int.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The house cannot have " + "built in that year"); } try {

Console.Write("House Value: "); House.Value = decimal.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("Invalid Property Value"); } SingleFamilies.Add(House); ShowTitle(); ShowSingleFamily(); SaveSingleFamily(); } public void ShowTitle() { Console.WriteLine("=================================="); Console.WriteLine(" =//=//= Altair Realty =//=//="); Console.WriteLine("-=-=-=- Properties Listing -=-=-=-"); } public void ShowCondominium() { Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", Condo.PropertyNumber); Console.WriteLine("Property Type: {0}", Condo.PropertyType); Console.WriteLine("Condition: {0}", Condo.Condition); Console.WriteLine("Bedrooms: {0}", Condo.Bedrooms); Console.WriteLine("Bathrooms: {0:F}", Condo.Bathrooms); Console.WriteLine("Year Built: {0}",

C# 3.0 Practical Learning

765

}

Condo.YearBuilt); Console.WriteLine("Handicapped Accessible Building: {0}", Condo.HandicapAccessible); Console.WriteLine("Market Value: {0:C}", Condo.Value); Console.WriteLine("----------------------------------");

public void ShowTownhouse() { Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", TownHome.PropertyNumber); Console.WriteLine("Property Type: {0}", TownHome.PropertyType); Console.WriteLine("Stories: {0}", TownHome.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", TownHome.IndoorGarage); Console.WriteLine("Finished Basement: {0}", TownHome.FinishedBasement); Console.WriteLine("Condition: {0}", TownHome.Condition); Console.WriteLine("Bedrooms: {0}", TownHome.Bedrooms); Console.WriteLine("Bathrooms: {0:F}", TownHome.Bathrooms); Console.WriteLine("Year Built: {0}", TownHome.YearBuilt); Console.WriteLine("Community Managed? {0}", TownHome.IsCommunityManaged); Console.WriteLine("Market Value: {0:C}", TownHome.Value); Console.WriteLine("----------------------------------"); } public void ShowSingleFamily() { Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", House.PropertyNumber); Console.WriteLine("Property Type: {0}", House.PropertyType); Console.WriteLine("Stories: {0}", House.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", House.IndoorGarage); Console.WriteLine("Finished Basement: {0}", House.FinishedBasement); Console.WriteLine("Condition: {0}", House.Condition); Console.WriteLine("Bedrooms: {0}", House.Bedrooms); Console.WriteLine("Bathrooms: {0:F}", House.Bathrooms); Console.WriteLine("Year Built: {0}", House.YearBuilt); Console.WriteLine("Market Value: {0:C}", House.Value); Console.WriteLine("----------------------------------");

C# 3.0 Practical Learning

766

} public void SaveCondominium() { FileStream fsCondo = null; BinaryFormatter bfCondo = new BinaryFormatter(); string strFilename = strPropertiesDirectory + @"\Condominiums.alr"; try {

fsCondo = new FileStream(strFilename, FileMode.Create, FileAccess.Write); bfCondo.Serialize(fsCondo, Condominiums);

} finally { fsCondo.Close(); } }

public void SaveTownhouse() { FileStream fsTown = null; BinaryFormatter bfTown = new BinaryFormatter(); string strFilename = strPropertiesDirectory + @"\Townhouses.alr"; try {

fsTown = new FileStream(strFilename, FileMode.Create, FileAccess.Write); bfTown.Serialize(fsTown, Townhouses);

} finally { fsTown.Close(); } }

public void SaveSingleFamily() { FileStream fsHouse = null; BinaryFormatter bfHouse = new BinaryFormatter(); string strFilename = strPropertiesDirectory + @"\SingleFamilies.alr"; try { fsHouse = new FileStream(strFilename, FileMode.Create, FileAccess.Write); bfHouse.Serialize(fsHouse, SingleFamilies);

C# 3.0 Practical Learning

767

} finally { fsHouse.Close(); } }

}

}

4. Access the Program.cs file and change it as follows: using using using using

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

namespace RealEstate5 { public class Program { static void Main(string[] args) { var answer = 'q'; var listing = new PropertyManagement(); // Display the title Console.WriteLine("================================="); Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("----------------------------------"); do { // Ask the user to select an option try { Console.WriteLine("What do you want to do?"); Console.WriteLine("1. Create a property"); Console.WriteLine("0. Quit"); Console.Write("Your Choice? "); answer = char.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("Invalid Choice!!!"); } switch (answer) { case '1': listing.CreateProperty(); break; default: break; } } while(answer == '1'); Console.WriteLine(); }

}

}

C# 3.0 Practical Learning

768

5. Execute the application and continually create the following properties: ================================= =//= Altair Realty =//= ---------------------------------What do you want to do? 1. Create a property 0. Quit Your Choice? 1 ======================= =//= Altair Realty =//= -=- Property Creation -=-----------------------Enter Property #: 000001 Types of Properties 1. Condominium 2. Townhouse 3. Single Family Enter Type of Property: 1 Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 1 How many bedrooms? 1 How many bathrooms? 1 Year built: 1960 Is the building accessible to handicapped (y/n): n Condominium Value: 10000 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 000001 Property Type: Condominium Condition: Excellent Bedrooms: 1 Bathrooms: 1.00 Year Built: 1960 Handicapped Accessible Building: False Market Value: $10,000.00 ---------------------------------What do you want to do? 1. Create a property 0. Quit Your Choice? 1 ======================= =//= Altair Realty =//= -=- Property Creation -=-

C# 3.0 Practical Learning

769

-----------------------Enter Property #: 000002 Types of Properties 1. Condominium 2. Townhouse 3. Single Family Enter Type of Property: 2 Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 1 How many stories (levels)? 1 How many bedrooms? 1 How many bathrooms? 1 Does it have an indoor car garage (y/n): n Is the basement finished(y/n): n Year built: 1960 Is it community managed (y/n)? n Property Value: 20000 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 000002 Property Type: Townhouse Stories: 1 Has Indoor Car Garage: False Finished Basement: False Condition: Excellent Bedrooms: 1 Bathrooms: 1.00 Year Built: 1960 Community Managed? False Market Value: $20,000.00 ---------------------------------What do you want to do? 1. Create a property 0. Quit Your Choice? 1 ======================= =//= Altair Realty =//= -=- Property Creation -=-----------------------Enter Property #: 000003 Types of Properties 1. Condominium 2. Townhouse 3. Single Family Enter Type of Property: 3 =//= Altair Realty =//=

C# 3.0 Practical Learning

770

-=- Property Creation -=Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 1 How many stories (levels)? 1 How many bedrooms? 1 How many bathrooms? 1 Does it have an indoor car garage (y/n): n Is the basement finished(y/n): n Year built: 1960 House Value: 30000 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 000003 Property Type: Single Family Stories: 1 Has Indoor Car Garage: False Finished Basement: False Condition: Excellent Bedrooms: 1 Bathrooms: 1.00 Year Built: 1960 Market Value: $30,000.00 ---------------------------------What do you want to do? 1. Create a property 0. Quit Your Choice? 0 Press any key to continue . . .

6. Close the DOS window

The Number of Items in the List When using a list, at any time, you should be able to know the number of items that the list contains. This information is provided by the ArrayList.Count property. The Capacity and the Count have this in common: the value of each increases as the list grows and the same value decreases if the list shrinks. It is important to know that, although they look alike, there are various differences between the capacity of a list and the number of items it contains. Capacity is a read/write property. This means that, as we saw above, you can assign a value to the capacity to fix the number of items that the list can contain. You can also retrieve the value of the Capacity. The Count is read-only because it is used by the compiler to count the current number of items of the items and this counting is performed without your intervention.

Item Retrieval C# 3.0 Practical Learning

771

Once a list is ready, you can perform different types of operations on it. Besides adding items, one of the most regular operations performed on a list consists of locating and retrieving its items. You have various options. To retrieve a single item based on its position, you can apply the square brackets of arrays to the variable. Like a normal array, an ArrayList list is zero-based. Another issue to keep in mind is that the ArrayList[] returns an Object value. Therefore, you may have to cast this value to your type of value to get it right. Besides using the index to access an item from the list, ArrayList class implements the IEnumerable.GetEnumerator() method. For this reason, you can use the foreach loop to access each member of the collection.

Practical Learning: Retrieving Items From an ArrayList List 1. Change the PropertyManagement.cs file as follows: using using using using using using using

System; System.Collections.Generic; System.Linq; System.Text; System.IO; System.Collections; System.Runtime.Serialization.Formatters.Binary;

namespace RealEstate5 { public class PropertyManagement { private Condominium Condo; private Townhouse TownHome; private SingleFamily House; ArrayList Condominiums; ArrayList Townhouses; ArrayList SingleFamilies; string strPropertyNumber; string strPropertiesDirectory; public PropertyManagement() { Condo = new Condominium(); TownHome = new Townhouse(); House = new SingleFamily(); Condominiums = new ArrayList(); Townhouses = new ArrayList(); SingleFamilies = new ArrayList(); strPropertyNumber = "000000"; strPropertiesDirectory = @"C:\Altair Realty\Properties"; try {

// If a directory for the properties has not yet

C# 3.0 Practical Learning

772

// been created, then create them Directory.CreateDirectory(strPropertiesDirectory);

} catch (DirectoryNotFoundException) { Console.WriteLine("The directory could not be created"); } } public PropertyCondition GetPropertyCondition() { short condition = 0; try { Console.WriteLine("\nProperties Conditions"); Console.WriteLine("1. Excellent"); Console.WriteLine("2. Good (may need minor repair)"); Console.WriteLine("3. Needs Repair"); Console.Write("4. In Bad Shape (property needs "); Console.WriteLine("major repair or rebuild)"); Console.Write("Enter Property Condition: "); condition = short.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The value you entered for " + "the condition of the property is not

valid");

} if (condition == 1) return PropertyCondition.Excellent; else if (condition == 2) return PropertyCondition.Good; else if (condition == 3) return PropertyCondition.NeedsRepair; else if (condition == 4) return PropertyCondition.BadShape; else return PropertyCondition.Unknown; } public void CreateProperty() { char propType = '0'; bool found = false; FileStream fsProperties = null; BinaryFormatter bfProperties = new BinaryFormatter(); Console.WriteLine("\n======================="); Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("-=- Property Creation -=-"); Console.WriteLine("------------------------"); // We will make sure that no two // properties have the same number Console.Write("\nEnter Property #: "); this.strPropertyNumber = Console.ReadLine();

C# 3.0 Practical Learning

773

try {

fsProperties = new FileStream(strPropertiesDirectory + @"\Condominiums.alr", FileMode.Open, FileAccess.Read); Condominiums = (ArrayList)bfProperties.Deserialize(fsProperties); foreach (Condominium c in Condominiums) { if (c.PropertyNumber == this.strPropertyNumber) { found = true; } }

} catch (FileNotFoundException) { Console.WriteLine("The Condominiums list was not found"); } finally { fsProperties.Close(); } try {

fsProperties = new FileStream(strPropertiesDirectory + @"\Townhouses.alr", FileMode.Open, FileAccess.Read); Townhouses = (ArrayList)bfProperties.Deserialize(fsProperties); foreach (Townhouse t in Townhouses) { if (t.PropertyNumber == this.strPropertyNumber) { found = true; } }

} finally { fsProperties.Close(); } try {

fsProperties = new FileStream(strPropertiesDirectory + @"\SingleFamilies.alr", FileMode.Open, FileAccess.Read); SingleFamilies = (ArrayList)bfProperties.Deserialize(fsProperties); foreach (SingleFamily s in SingleFamilies) { if (s.PropertyNumber == this.strPropertyNumber)

C# 3.0 Practical Learning

774

{ }

found = true;

} } finally { fsProperties.Close(); } if (found == true) { Console.WriteLine("A property with that " + "number exists already"); return; } try { Console.WriteLine("\nTypes of Properties"); Console.WriteLine("1. Condominium"); Console.WriteLine("2. Townhouse"); Console.WriteLine("3. Single Family"); Console.Write("Enter Type of Property: "); propType = char.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The value you entered for " + "the type of property is invalid"); } switch (propType) { case '1': CreateCondominium(); break; case '2': CreateTownhouse(); break; case '3': CreateSingleFamily(); break; default: Console.WriteLine("Invalid Choice!!!"); break; } } public void CreateCondominium() { char answer = 'n'; Condo.PropertyNumber = strPropertyNumber; Condo.Condition = GetPropertyCondition(); try {

Console.Write("\nHow many bedrooms? "); Condo.Bedrooms = short.Parse(Console.ReadLine());

C# 3.0 Practical Learning

775

} catch (FormatException) { Console.WriteLine("The value you entered for " + "the number of bedrooms is not good"); } try { Console.Write("How many bathrooms? "); Condo.Bathrooms = float.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid value"); } try {

Console.Write("Year built: "); Condo.YearBuilt = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The house cannot have " + "built in that year"); } Console.Write("\nIs the building " + "accessible to handicapped (y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) Condo.HandicapAccessible = true; else Condo.HandicapAccessible = false; try {

Console.Write("Condominium Value: "); Condo.Value = decimal.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid Property Value"); }

}

Condominiums.Add(Condo); ShowTitle(); ShowCondominium(); SaveCondominium();

public void CreateTownhouse() { char answer = 'n'; this.TownHome.PropertyNumber = strPropertyNumber; this.TownHome.Condition = GetPropertyCondition();

C# 3.0 Practical Learning

776

try { Console.Write("\nHow many stories (levels)? "); this.TownHome.Stories = short.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The number of stories " + "you entered is not valid"); } try { Console.Write("How many bedrooms? "); this.TownHome.Bedrooms = short.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The value you entered for " + "the number of bedrooms is not good"); } try { Console.Write("How many bathrooms? "); this.TownHome.Bathrooms = float.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid bathroom number."); } Console.Write("Does it have an indoor " + "car garage (y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) this.TownHome.IndoorGarage = true; else this.TownHome.IndoorGarage = false; Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) this.TownHome.FinishedBasement = true; else this.TownHome.FinishedBasement = false; try {

Console.Write("Year built: "); this.TownHome.YearBuilt = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("The house cannot have " + "built in that year");

C# 3.0 Practical Learning

777

} try {

Console.Write("Is it community managed (y/n)? "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) this.TownHome.IsCommunityManaged = true; else this.TownHome.IsCommunityManaged = false;

} catch (FormatException) { Console.WriteLine("Invalid Answer"); } try {

Console.Write("Property Value: "); this.TownHome.Value = decimal.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid Property Value"); } Townhouses.Add(this.TownHome); ShowTitle(); ShowTownhouse(); SaveTownhouse(); } public void CreateSingleFamily() { char answer = 'n'; Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("-=- Property Creation -=-"); this.House.PropertyNumber = strPropertyNumber; House.Condition = GetPropertyCondition(); try { Console.Write("\nHow many stories (levels)? "); House.Stories = short.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The number of stories you " + "entered is not allowed"); } try {

Console.Write("How many bedrooms? "); House.Bedrooms = short.Parse(Console.ReadLine());

}

C# 3.0 Practical Learning

778

catch (FormatException) { Console.WriteLine("The value you entered for " + "the number of bedrooms is not good"); } try {

Console.Write("How many bathrooms? "); House.Bathrooms = float.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid number of bathrooms"); } try { Console.Write("Does it have an indoor " + "car garage (y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.IndoorGarage = true; else House.IndoorGarage = false;

} catch (FormatException) { Console.WriteLine("Invalid Indoor Car Garage Answer"); } try { Console.Write("Is the basement finished(y/n): "); answer = char.Parse(Console.ReadLine()); if ((answer == 'y') || (answer == 'Y')) House.FinishedBasement = true; else House.FinishedBasement = false; } catch (FormatException) { Console.WriteLine("Invalid Basement Answer"); } try { Console.Write("Year built: "); House.YearBuilt = int.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The house cannot have " + "built in that year"); } try {

Console.Write("House Value: "); House.Value = decimal.Parse(Console.ReadLine());

C# 3.0 Practical Learning

779

} catch (FormatException) { Console.WriteLine("Invalid Property Value"); }

}

SingleFamilies.Add(House); ShowTitle(); ShowSingleFamily(); SaveSingleFamily();

public void ShowTitle() { Console.WriteLine("=================================="); Console.WriteLine(" =//=//= Altair Realty =//=//="); Console.WriteLine("-=-=-=- Properties Listing -=-=-=-"); } public void ShowCondominium() { Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", Condo.PropertyNumber); Console.WriteLine("Property Type: {0}", Condo.PropertyType); Console.WriteLine("Condition: {0}", Condo.Condition); Console.WriteLine("Bedrooms: {0}", Condo.Bedrooms); Console.WriteLine("Bathrooms: {0:F}", Condo.Bathrooms); Console.WriteLine("Year Built: {0}", Condo.YearBuilt); Console.WriteLine("Handicapped Accessible Building: {0}", Condo.HandicapAccessible); Console.WriteLine("Market Value: {0:C}", Condo.Value); Console.WriteLine("----------------------------------"); } public void ShowTownhouse() { Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", TownHome.PropertyNumber); Console.WriteLine("Property Type: {0}", TownHome.PropertyType); Console.WriteLine("Stories: {0}", TownHome.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", TownHome.IndoorGarage); Console.WriteLine("Finished Basement: {0}", TownHome.FinishedBasement); Console.WriteLine("Condition: {0}", TownHome.Condition); Console.WriteLine("Bedrooms: {0}", TownHome.Bedrooms); Console.WriteLine("Bathrooms: {0:F}", TownHome.Bathrooms);

C# 3.0 Practical Learning

780

Console.WriteLine("Year Built: {0}", TownHome.YearBuilt); Console.WriteLine("Community Managed? {0}", TownHome.IsCommunityManaged); Console.WriteLine("Market Value: {0:C}", TownHome.Value); Console.WriteLine("----------------------------------"); } public void ShowSingleFamily() { Console.WriteLine("----------------------------------"); Console.WriteLine("Property #: {0}", House.PropertyNumber); Console.WriteLine("Property Type: {0}", House.PropertyType); Console.WriteLine("Stories: {0}", House.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", House.IndoorGarage); Console.WriteLine("Finished Basement: {0}", House.FinishedBasement); Console.WriteLine("Condition: {0}", House.Condition); Console.WriteLine("Bedrooms: {0}", House.Bedrooms); Console.WriteLine("Bathrooms: {0:F}", House.Bathrooms); Console.WriteLine("Year Built: {0}", House.YearBuilt); Console.WriteLine("Market Value: {0:C}", House.Value); Console.WriteLine("----------------------------------"); } public void SaveCondominium() { FileStream fsCondo = null; BinaryFormatter bfCondo = new BinaryFormatter(); string strFilename = strPropertiesDirectory + @"\Condominiums.alr"; try { fsCondo = new FileStream(strFilename, FileMode.Create, FileAccess.Write); bfCondo.Serialize(fsCondo, Condominiums);

}

} finally { fsCondo.Close(); }

public void SaveTownhouse() { FileStream fsTown = null; BinaryFormatter bfTown = new BinaryFormatter();

C# 3.0 Practical Learning

781

string strFilename = strPropertiesDirectory + @"\Townhouses.alr"; try {

fsTown = new FileStream(strFilename, FileMode.Create, FileAccess.Write); bfTown.Serialize(fsTown, Townhouses);

} finally { fsTown.Close(); } }

public void SaveSingleFamily() { FileStream fsHouse = null; BinaryFormatter bfHouse = new BinaryFormatter(); string strFilename = strPropertiesDirectory + @"\SingleFamilies.alr"; try {

}

fsHouse = new FileStream(strFilename, FileMode.Create, FileAccess.Write); bfHouse.Serialize(fsHouse, SingleFamilies);

} finally { fsHouse.Close(); }

public void ShowProperties() { int choice = 0; Console.WriteLine(); ShowTitle(); try { Console.WriteLine("What properties do you want to see?"); Console.WriteLine("1. One Particular Property"); Console.WriteLine("2. Condominiums Only"); Console.WriteLine("3. Townhouses Only"); Console.WriteLine("4. Single Families Only"); Console.WriteLine("5. All properties"); Console.WriteLine("6. None"); Console.Write("Your Choice? "); choice = int.Parse(Console.ReadLine());

} catch (FormatException)

C# 3.0 Practical Learning

782

{ }

}

Console.WriteLine("Invalid Selection");

switch (choice) { case 1: ShowParticularProperty(); break; case 2: ShowCondominiums(); break; case 3: ShowTownhouses(); break; case 4: ShowSingleFamilies(); break; case 5: ShowCondominiums(); ShowTownhouses(); ShowSingleFamilies(); break; default: break; }

public void ShowParticularProperty() { bool found = false; FileStream fsProperty = null; BinaryFormatter bfProperty = new BinaryFormatter(); Console.WriteLine("\n======================="); Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("------------------------"); Console.Write("\nEnter Property #: "); this.strPropertyNumber = Console.ReadLine(); try { fsProperty = new FileStream(strPropertiesDirectory + @"\Condominiums.alr", FileMode.Open, FileAccess.Read); Condominiums = (ArrayList)bfProperty.Deserialize(fsProperty); foreach (Condominium c in Condominiums) { if (c.PropertyNumber == this.strPropertyNumber) { found = true; Condo = c; ShowCondominium(); return; } }

C# 3.0 Practical Learning

783

} finally { fsProperty.Close(); } try {

fsProperty = new FileStream(strPropertiesDirectory + @"\Townhouses.alr", FileMode.Open, FileAccess.Read); Townhouses = (ArrayList)bfProperty.Deserialize(fsProperty); foreach (Townhouse t in Townhouses) { if (t.PropertyNumber == this.strPropertyNumber) { found = true; TownHome = t; ShowTownhouse(); return; } }

} finally { fsProperty.Close(); } try { fsProperty = new FileStream(strPropertiesDirectory + @"\SingleFamilies.alr", FileMode.Open, FileAccess.Read); SingleFamilies = (ArrayList)bfProperty.Deserialize(fsProperty); foreach (SingleFamily s in SingleFamilies) { if (s.PropertyNumber == this.strPropertyNumber) { found = true; House = s; ShowSingleFamily(); return; } }

} finally { fsProperty.Close(); }

if (found == false) { Console.WriteLine("No property with that " + "number was found in the database");

C# 3.0 Practical Learning

784

return; }

}

public void ShowCondominiums() { FileStream fsProperty = null; BinaryFormatter bfProperty = new BinaryFormatter(); try { fsProperty = new FileStream(strPropertiesDirectory + @"\Condominiums.alr", FileMode.Open, FileAccess.Read); Condominiums = (ArrayList)bfProperty.Deserialize(fsProperty); Console.WriteLine("\n================================="); Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("----------------------------------"); Console.WriteLine("Condominiums Listing"); Console.WriteLine("----------------------------------"); foreach (Condominium c in Condominiums) { Console.WriteLine("Property #: {0}", c.PropertyNumber); Console.WriteLine("Condition: {0}", c.Condition); Console.WriteLine("Bedrooms: {0}", c.Bedrooms); Console.WriteLine("Bathrooms: {0:F}", c.Bathrooms); Console.WriteLine("Year Built: {0}", c.YearBuilt); Console.WriteLine("Handicapped Accessible Building:

{0}",

Condo.HandicapAccessible); Console.WriteLine("Market Value: {0:C}", c.Value); Console.WriteLine("---------------------------------");

}

} } finally { fsProperty.Close(); }

public void ShowTownhouses() { FileStream fsProperty = null; BinaryFormatter bfProperty = new BinaryFormatter(); try { fsProperty = new FileStream(strPropertiesDirectory + @"\Townhouses.alr", FileMode.Open,

C# 3.0 Practical Learning

785

FileAccess.Read); Townhouses = (ArrayList)bfProperty.Deserialize(fsProperty); Console.WriteLine("\n================================="); Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("----------------------------------"); Console.WriteLine("Townhouses Listing"); Console.WriteLine("----------------------------------"); foreach (Townhouse t in Townhouses) { Console.WriteLine("Property #: {0}", t.PropertyNumber); Console.WriteLine("Stories: {0}", t.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", t.IndoorGarage); Console.WriteLine("Finished Basement: {0}", t.FinishedBasement); Console.WriteLine("Condition: {0}", t.Condition); Console.WriteLine("Bedrooms: {0}", t.Bedrooms); Console.WriteLine("Bathrooms: {0:F}", t.Bathrooms); Console.WriteLine("Year Built: {0}", t.YearBuilt); Console.WriteLine("Community Managed? {0}", t.IsCommunityManaged); Console.WriteLine("Market Value: {0:C}", t.Value); Console.WriteLine("----------------------------------

");

} } finally { fsProperty.Close(); } } public void ShowSingleFamilies() { FileStream fsProperty = null; BinaryFormatter bfProperty = new BinaryFormatter(); try {

fsProperty = new FileStream(strPropertiesDirectory + @"\SingleFamilies.alr", FileMode.Open, FileAccess.Read); SingleFamilies = (ArrayList)bfProperty.Deserialize(fsProperty); Console.WriteLine("\n================================"); Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("----------------------------------"); Console.WriteLine("Single Families Listing"); Console.WriteLine("----------------------------------");

C# 3.0 Practical Learning

786

foreach (SingleFamily s in SingleFamilies) { Console.WriteLine("Property #: {0}", s.PropertyNumber); Console.WriteLine("Stories: {0}", s.Stories); Console.WriteLine("Has Indoor Car Garage: {0}", s.IndoorGarage); Console.WriteLine("Finished Basement: {0}", s.FinishedBasement); Console.WriteLine("Condition: {0}", s.Condition); Console.WriteLine("Bedrooms: {0}", s.Bedrooms); Console.WriteLine("Bathrooms: {0:F}", s.Bathrooms); Console.WriteLine("Year Built: {0}", s.YearBuilt); Console.WriteLine("Market Value: {0:C}", s.Value); Console.WriteLine("---------------------------------");

} }

} } finally { fsProperty.Close(); }

}

2. Access the Program.cs file and change it as follows: using using using using

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

namespace RealEstate5 { public class Program { static void Main(string[] args) { var answer = 'q'; var listing = new PropertyManagement(); // Display the title Console.WriteLine("\n================================"); Console.WriteLine(" =//= Altair Realty =//="); Console.WriteLine("----------------------------------"); do { // Ask the user to select an option try { Console.WriteLine("What do you want to do?"); Console.WriteLine("1. Create a property");

C# 3.0 Practical Learning

787

Console.WriteLine("2. Show the properties"); Console.WriteLine("3. Delete a property"); Console.WriteLine("0. Quit"); Console.Write("Your Choice? "); answer = char.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("Invalid Choice!!!"); } switch (answer) { case '1': listing.CreateProperty(); Console.WriteLine("\n"); break; case '2': listing.ShowProperties(); break; case '3': break; default: break; } } while ((answer == '1') || (answer == '2') || (answer == '3')); } }

Console.WriteLine();

}

3. Execute the application and test it. Here is an example: ================================ =//= Altair Realty =//= ---------------------------------What do you want to do? 1. Create a property 2. Show the properties 3. Delete a property 0. Quit Your Choice? 1 ======================= =//= Altair Realty =//= -=- Property Creation -=-----------------------Enter Property #: 246185 Types of Properties 1. Condominium 2. Townhouse 3. Single Family Enter Type of Property: 1

C# 3.0 Practical Learning

788

Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 2 How many bedrooms? 2 How many bathrooms? 2 Year built: 1996 Is the building accessible to handicapped (y/n): n Condominium Value: 285660 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 246185 Property Type: Condominium Condition: Good Bedrooms: 2 Bathrooms: 2.00 Year Built: 1996 Handicapped Accessible Building: False Market Value: $285,660.00 ---------------------------------What do you want to do? 1. Create a property 2. Show the properties 3. Delete a property 0. Quit Your Choice? 1 ======================= =//= Altair Realty =//= -=- Property Creation -=-----------------------Enter Property #: 512664 Types of Properties 1. Condominium 2. Townhouse 3. Single Family Enter Type of Property: 2 Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 1 How many stories (levels)? 3 How many bedrooms? 3 How many bathrooms? 2.5 Does it have an indoor car garage (y/n): n Is the basement finished(y/n): y Year built: 1992

C# 3.0 Practical Learning

789

Is it community managed (y/n)? y Property Value: 435660 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 512664 Property Type: Townhouse Stories: 3 Has Indoor Car Garage: False Finished Basement: True Condition: Excellent Bedrooms: 3 Bathrooms: 2.50 Year Built: 1992 Community Managed? True Market Value: $435,660.00 ---------------------------------What do you want to do? 1. Create a property 2. Show the properties 3. Delete a property 0. Quit Your Choice? 1 ======================= =//= Altair Realty =//= -=- Property Creation -=-----------------------Enter Property #: 802664 Types of Properties 1. Condominium 2. Townhouse 3. Single Family Enter Type of Property: 3 =//= Altair Realty =//= -=- Property Creation -=Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 1 How many stories (levels)? 3 How many bedrooms? 4 How many bathrooms? 3.5 Does it have an indoor car garage (y/n): y Is the basement finished(y/n): y Year built: 1995 House Value: 755820 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 802664

C# 3.0 Practical Learning

790

Property Type: Single Family Stories: 3 Has Indoor Car Garage: True Finished Basement: True Condition: Excellent Bedrooms: 4 Bathrooms: 3.50 Year Built: 1995 Market Value: $755,820.00 ---------------------------------What do you want to do? 1. Create a property 2. Show the properties 3. Delete a property 0. Quit Your Choice? 1 ======================= =//= Altair Realty =//= -=- Property Creation -=-----------------------Enter Property #: 693524 Types of Properties 1. Condominium 2. Townhouse 3. Single Family Enter Type of Property: 3 =//= Altair Realty =//= -=- Property Creation -=Properties Conditions 1. Excellent 2. Good (may need minor repair) 3. Needs Repair 4. In Bad Shape (property needs major repair or rebuild) Enter Property Condition: 3 How many stories (levels)? 2 How many bedrooms? 3 How many bathrooms? 2.5 Does it have an indoor car garage (y/n): n Is the basement finished(y/n): n Year built: 1964 House Value: 515665 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=---------------------------------Property #: 693524 Property Type: Single Family Stories: 2 Has Indoor Car Garage: False Finished Basement: False Condition: NeedsRepair Bedrooms: 3 Bathrooms: 2.50 Year Built: 1964

C# 3.0 Practical Learning

791

Market Value: $515,665.00 ---------------------------------What do you want to do? 1. Create a property 2. Show the properties 3. Delete a property 0. Quit Your Choice? 0 Press any key to continue . . .

4. Close the DOS window 5. Execute the application again and test different options. Here are examples: ================================ =//= Altair Realty =//= ---------------------------------What do you want to do? 1. Create a property 2. Show the properties 3. Delete a property 0. Quit Your Choice? 2 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=What properties do you want to see? 1. One Particular Property 2. Condominiums Only 3. Townhouses Only 4. Single Families Only 5. All properties 6. None Your Choice? 1 ======================= =//= Altair Realty =//= -----------------------Enter Property #: 802664 ---------------------------------Property #: 802664 Property Type: Single Family Stories: 3 Has Indoor Car Garage: True Finished Basement: True Condition: Excellent Bedrooms: 4 Bathrooms: 3.50 Year Built: 1995 Market Value: $755,820.00 ---------------------------------What do you want to do? 1. Create a property 2. Show the properties

C# 3.0 Practical Learning

792

3. Delete a property 0. Quit Your Choice? 2 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=What properties do you want to see? 1. One Particular Property 2. Condominiums Only 3. Townhouses Only 4. Single Families Only 5. All properties 6. None Your Choice? 3 ================================= =//= Altair Realty =//= ---------------------------------Townhouses Listing ---------------------------------Property #: 000002 Stories: 1 Has Indoor Car Garage: False Finished Basement: False Condition: Excellent Bedrooms: 1 Bathrooms: 1.00 Year Built: 1960 Community Managed? False Market Value: $20,000.00 ---------------------------------Property #: 512664 Stories: 3 Has Indoor Car Garage: False Finished Basement: True Condition: Excellent Bedrooms: 3 Bathrooms: 2.50 Year Built: 1992 Community Managed? True Market Value: $435,660.00 ---------------------------------What do you want to do? 1. Create a property 2. Show the properties 3. Delete a property 0. Quit Your Choice? 2 ================================== =//=//= Altair Realty =//=//= -=-=-=- Properties Listing -=-=-=What properties do you want to see? 1. One Particular Property 2. Condominiums Only 3. Townhouses Only 4. Single Families Only 5. All properties 6. None

C# 3.0 Practical Learning

793

Your Choice? 4 ================================ =//= Altair Realty =//= ---------------------------------Single Families Listing ---------------------------------Property #: 000003 Stories: 1 Has Indoor Car Garage: False Finished Basement: False Condition: Excellent Bedrooms: 1 Bathrooms: 1.00 Year Built: 1960 Market Value: $30,000.00 ---------------------------------Property #: 802664 Stories: 3 Has Indoor Car Garage: True Finished Basement: True Condition: Excellent Bedrooms: 4 Bathrooms: 3.50 Year Built: 1995 Market Value: $755,820.00 ---------------------------------Property #: 693524 Stories: 2 Has Indoor Car Garage: False Finished Basement: False Condition: NeedsRepair Bedrooms: 3 Bathrooms: 2.50 Year Built: 1964 Market Value: $515,665.00 ---------------------------------What do you want to do? 1. Create a property 2. Show the properties 3. Delete a property 0. Quit Your Choice? 0 Press any key to continue . . .

6. Close the DOS window

Item Location Instead of the square brackets that allow you to retrieve an item based on its position, you can look for an item based on its complete definition. You have various options. You can first "build" an item and ask the compiler to check whether any item in the list matches your definition. To perform this search, you can call the ArrayList.Contains() method. Its syntax is: public virtual bool Contains(object item);

C# 3.0 Practical Learning

794

The item to look for is passed as argument to the method. The compiler would look for exactly the item, using its definition, in the list. If any detail of the argument fails to match any item of the ArrayList list, the method would return false. If all characteristics of the argument correspond to an item of the list, the method returns true. Another option to look for an item in a list consists of calling the ArrayList.BinarySearch() method. It is overloaded in three versions and one of them uses the following syntax: public virtual int BinarySearch(object value);

The item to look for is passed argument to the method.

Item Deletion As opposed to adding an item to a list, you may want to remove one. To perform this operation, you have various options. You can ask the compiler to look for an item in the list and if, or once, the compile finds it, it would delete the item. To perform this type of deletion, you can call the ArrayList.Remove() method. Its syntax is: public virtual void Remove(object obj);

This method accepts as argument the item that you want to delete from the list. To perform this operation, the list must not be read-only. The Remove() method allows you to specify the exact item you want to delete from a list. Another option you have consists of deleting an item based on its position. This is done using the RemoveAt() method whose syntax is: public virtual void RemoveAt(int index);

With this method, the position of the item is passed as argument. If the position is not valid because either it is lower or higher than the current Count, the compiler would throw an ArgumentOutOfRangeException exception. To remove all items from a list at once, you can call the ArrayList.Clear() method. Its syntax is: public virtual void Clear();

C# 3.0 Practical Learning

795

Generics Generic Methods Introduction As is usually done, imagine you want to pass different types of values to various methods of a class to primarily accomplish the same purpose. You may be tempted to overloaded a method in various versions as follows: using System; public class Generator {

// Display the value of an integer public void Show(int value) { Console.WriteLine(value); } // Display the value of a double-precesion value public void Show(double value) { Console.WriteLine(value); } // Display the value of a character public void Show(char value) { Console.WriteLine(value); }

}

public class Exercise { static int Main() { var exo = new Generator(); // Call the version of the method that displays an integer exo.Show(246); // Call the version of the method that displays a character exo.Show('G'); // Call the version of the method that displays a decimal

C# 3.0 Practical Learning

796

exo.Show(355.65); return 0; }

}

This would produce: 246 G 355.65 Press any key to continue . . .

We passed a constant value directly to the method when we called it. Remember that you can also first declare a variable, assign it a value, and then pass that variable to the method. Here are examples: public class Exercise { static int Main() { var exo = new Generator(); // Call the version of the method that displays an integer var Value1 = 246; exo.Show(Value1); // Call the version of the method that displays a character var Value2 = 'G'; exo.Show(Value2); // Call the version of the method that displays a decimal var Value3 = 355.65; exo.Show(Value3); }

return 0;

}

Although this is based on the concept of method overloading, another way you can solve this type of problem is to create one method that doesn't know the type of value that would be passed to it but the method is equipped to process the value appropriately. Based on the above program, you can create one method that takes an argument and it displays its value. To do this, at the time you are defining the method, you only let it know that it would receive an argument but you don't specify the type of value that it will process. Such a method is referred to as generic.

Practical Learning: Introducing Generics 1. Start Microsoft Visual C# and create a new Console Application named CommercialStore1

2. To create a new class, on the main menu, click Project -> Add Class... 3. Set the Name to StoreItem and press Enter

C# 3.0 Practical Learning

797

4. Change the file as follows: using using using using

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

namespace CommercialStore1 { public class StoreItem { public class CItem { public double Item; public CItem Next; } public CItem Head = null; public int Size; public int Count() { return Size; } public int Add(CItem NewItem) { CItem Sample = new CItem(); Sample = NewItem; Sample.Next = Head; Head = Sample; }

return Size++;

public CItem Retrieve(int Position) { CItem Current = Head; for (int i = Count() - 1; i > Position && Current != null; i--)

{ }

Current = Current.Next;

return Current; } public void ShowItem(double item) { Console.WriteLine("Item: {0}", item); } }

}

5. Access the Program.cs file and change it as follows: C# 3.0 Practical Learning

798

using System; namespace CommercialStore1 { public class Program { static void Main() { StoreItem exo = new StoreItem(); StoreItem.CItem Part; Part = new StoreItem.CItem(); Part.Item = 97.43; exo.Add(Part); Part = new StoreItem.CItem(); Part.Item = 274.87; exo.Add(Part); Part = new StoreItem.CItem(); Part.Item = 8.7873; exo.Add(Part); Part = new StoreItem.CItem(); Part.Item = 2764.4; exo.Add(Part); Part = new StoreItem.CItem(); Part.Item = 92.4662; exo.Add(Part); Part = new StoreItem.CItem(); Part.Item = 66800.85; exo.Add(Part); Console.WriteLine("-=- List of Items -=-"); for (int i = 0; i < exo.Count(); i++) { StoreItem.CItem One = exo.Retrieve(i); }

exo.ShowItem(One.Item);

Console.WriteLine("\nNumber of Items: {0}\n", exo.Count()); }

}

}

6. Execute the application to see the result -=- List of Items -=Item: 97.43 Item: 274.87 Item: 8.7873 Item: 2764.4 Item: 92.4662 Item: 66800.9

C# 3.0 Practical Learning

799

Number of Items: 6 Press any key to continue . . .

7. Close the DOS window

Generic Method Creation A generic method is a method that can process a value whose type is known only when the variable is accessed. To create a generic method, on the right side of the name of the method, type the <> operator. Inside of this operator, enter a letter or a name, which is referred to as parameter type. Here is an example: public class Generator { public void Show() { } }

One of the ways you can use the parameter type is to pass an argument to the method. You do this by preceding the name of the argument with the parameter type. Here is an example: public class Generator { public void Show(TypeOfValue value) { } }

In the body of the method, you can process the argument as you see fit. At a minimum, and based on our earlier program, you can simply display the value by passing it to the Console.WriteLine() method. Here is an example: public class Generator { public void Show(TypeOfValue value) { Console.WriteLine(value); } }

By tradition, most programmers and most documents use the letter T for the parameter type.

Practical Learning: Creating a Generic Method 1. To create a generic method, change the ShowItem() method as follows: public void ShowItem(T item) { Console.WriteLine("Item: {0}", item); }

C# 3.0 Practical Learning

800

2. Save the file

Calling a Generic Method As mentioned earlier, one of the particularities of a generic method is that, at the time it is defined, the method doesn't know the type of the parameter. This means that, when calling the method, you must make sure you clearly specify the type of value that will be processed. You can do this by directly passing (a constant of) the type of value that the method will process. Here are different examples of calling our Show() method: using System; public class Generator { public void Show(TypeOfValue value) { Console.WriteLine(value); } } public class Exercise { static int Main() { var exo = new Generator(); // Call the version of the function that displays an integer var Value1 = 246; exo.Show(Value1); // Call the version of the function that displays a character var Value2 = 'G'; exo.Show(Value2); // Call the version of the function that displays a decimal var Value3 = 355.65; exo.Show(Value3); return 0; }

}

When complied and executed, this program would produce: 246 G 355.65 Press any key to continue . . .

As an alternative, you can type the name of the method, followed by angle brackets. Inside of the brackets, enter the data type of the value that will be processed. After the angle brackets, open the parentheses and, inside of them, type the constant value that will be processed. Here are examples: using System; public class Generator

C# 3.0 Practical Learning

801

{ public void Show(TypeOfValue value) { Console.WriteLine(value); } } public class Program { static int Main() { var exo = new Generator(); // Call the version of the function that displays an integer var Value1 = 246; exo.Show(Value1); // Call the version of the function that displays a character var Value2 = 'G'; exo.Show(Value2); // Call the version of the function that displays a decimal var Value3 = 355.65; exo.Show<double>(Value3); }

return 0;

}

You can also declare the value as a constant before passing it to the method.

Practical Learning: Calling a Generic Method 1. To specify the parameter type of a generic method when calling it, change the Main() method as follows: class Program { static void Main() { . . . Console.WriteLine("-=- List of Items -=-"); for (int i = 0; i < exo.Count(); i++) { Exercise.CItem One = exo.Retrieve(i); exo.ShowItem<double>(One.Item); } }

Console.WriteLine("\nNumber of Items: {0}\n", exo.Count());

}

2. Execute the application and notice that it works fine 3. Close the DOS window C# 3.0 Practical Learning

802

A Generic Method With Various Parameters Introduction Just like a method can take one argument, it can take various generic parameters. You can pass one argument as a known type and the other as a generic type. Here is an example: using System; public class Generator { public void Show(string msg, TypeOfValue value) { Console.WriteLine("{0}: {1}", msg, value); } } public class Exercise { static int Main() { var exo = new Generator(); exo.Show("Integer", 246); exo.Show("Character", 'G'); exo.Show<double>("Decimal", 355.65); return 0; }

}

This would produce: Integer: 246 Character: G Decimal: 355.65 Press any key to continue . . .

Although we directly passed the values to the method when calling it, you can first declare a variable before passing it to the method. Here are examples: using System; public class Generator { public void Show(string msg, TypeOfValue value) { Console.WriteLine("{0}: {1}", msg, value); } } public class Exercise {

C# 3.0 Practical Learning

803

static int Main() { var exo = new Generator(); var message = "Integer"; const int iValue = 246; exo.Show(message, iValue); message = "Character"; const char cValue = 'G'; exo.Show(message, cValue); message = "Decimal"; const double dValue = 355.65; exo.Show<double>(message, dValue); return 0; }

}

Practical Learning: Using a Method With Various Parameters 1. Access the StoreItem.cs file 2. To create and use a method with various parameters, make the following changes: namespace CommercialStore1 { public class StoreItem { . . . public void ShowItem(string content, int index, T item) { Console.WriteLine("{0} {1}: {2}", content, index, item); } }

}

3. Access the Program.cs file and change it as follows: namespace CommercialStore1 { class Program { static void Main() { . . . for (int i = 0; i < exo.Count(); i++) { Exercise.CItem One = exo.Retrieve(i); exo.ShowItem<double>("Item", i+1, One.Item);

C# 3.0 Practical Learning

804

} Console.WriteLine("\nNumber of Items: {0}\n", exo.Count()); }

}

}

4. Execute the application -=- List of Items -=Item 1: 97.43 Item 2: 274.87 Item 3: 8.7873 Item 4: 2764.4 Item 5: 92.4662 Item 6: 66800.85 Number of Items: 6 Press any key to continue . . .

5. Close the DOS window

A Generic Method With Various Parameter Types As seen above, you can pass different arguments to a method. You can also pass different parameter types, in any appropriate order of your choice, to a method. To pass two parameter types to a method, inside its <> operator, enter the names of two parameter types separated by a comma. Here is an example: public class Generator { public void Show() { } }

If you want to use the parameter types, you can pass an argument for each to the method. Remember that each parameter type represents a data type; so you can use it as the type of an argument. Here are examples: public class Generator { public void Show(FirstType first, SecondType second) { } }

In the body of the method, you can then use the arguments as you see fit. For example, you can display their values by passing them to the Console.WriteLine() method. Here is an example: public class Generator { public void Show(FirstType first, SecondType second)

C# 3.0 Practical Learning

805

{ }

Console.WriteLine("First:

{0}\nSecond: {1}\n", first, second);

}

Calling a Generic Method With Various Parameter Types To call a method that takes various parameters, you can simply pass it the value of each argument. Here is an example: using System; public class Generator { public void Show(FirstType first, SecondType second) { Console.WriteLine("First: {0}\nSecond: {1}\n", first, second); } } public class Exercise { static int Main() { var exo = new Generator(); var iValue = 246; var message = "Some Message"; exo.Show(message, iValue); }

return 0;

}

This would produce: First: Some Message Second: 246 Press any key to continue . . .

An alternative is to specify the type of each argument. To do this, inside the <> operator on the right side of the name of the method, enter the data types separated by a comma. Here are examples: using System; public class Generator { public void Show(FirstType first, SecondType second) { Console.WriteLine("First: {0}\nSecond: {1}\n", first, second); } } public class Exercise {

C# 3.0 Practical Learning

806

static int Main() { var exo = new Generator(); var iValue = 246; var message = "Some Message"; exo.Show(message, iValue); iValue = 85; var cValue = 'G'; exo.Show(iValue, cValue); var weeklyHours = 42.50d; var hourlySalary = 25.05; exo.Show<double, double>(weeklyHours, hourlySalary); return 0; }

}

This would produce: First: Some Message Second: 246 First: 85 Second: G First: 42.5 Second: 25.05 Press any key to continue . . .

Notice that the arguments can be of the same type or different types. It is up to you to determine the type of a particular argument when calling the method.

Generic Classes Introduction Like a method, a class can be created as a generic. When a class is created as generic, it is asked to process a value wihtout knowing what type that value is. This means that the class will known the type of value only when it is called. To create a generic class, on the right side of the name of the class, type the <> operator and enter a name for the parameter type. Here is an example: public class Exercise { }

This parameter type is just a representative of a data type. As a data type, you can use it to declare a variable in the body of the class. Here is an example: C# 3.0 Practical Learning

807

public class Exercise { public TypeOfValue value; }

After declaring such a variable, you can use it in your application. For example, you can access it outside of the class using the period operator. Inside of the class, one way you can use the variable is to display its value using one of the methods of the class. Here is an example: public class Exercise { public TypeOfValue value;

}

public void Show() { Console.WriteLine("Value: }

{0}\n", value);

Practical Learning: Introducing Generic Classes 1. To start a new program, on the main menu, click the File -> New Project ... 2. Click Console Application. Set the Name to CommercialStore2 and press Enter 3. To create a new class, on the main menu, click Project -> Add Class... 4. Set the Name to ListOfItems and click OK 5. Change the file as follows: using using using using

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

namespace CommercialStore2 { public class ListOfItems { public class CItem { public double Item; public CItem Next; } public ListOfItems() { Head = null; Size = 0; } public CItem Head; public int Size;

C# 3.0 Practical Learning

808

public int Count() { return Size; } public int Add(CItem NewItem) { CItem Sample = new CItem(); Sample = NewItem; Sample.Next = Head; Head = Sample; return Size++; } public CItem Retrieve(int Position) { CItem Current = Head; for (int i = Count() - 1; i > Position && Current != null;

i--)

{

Current = Current.Next;

} } }

return Current;

}

6. Access the Program.cs file and change it as follows: using using using using

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

namespace CommercialStore2 { public class Program { static void Main() { ListOfItems exo = new ListOfItems(); ListOfItems.CItem Part; Part = new ListOfItems.CItem(); Part.Item = 97.43; exo.Add(Part); Part = new ListOfItems.CItem(); Part.Item = 274.87; exo.Add(Part); Part = new ListOfItems.CItem(); Part.Item = 8.7873; exo.Add(Part);

C# 3.0 Practical Learning

809

Part = new ListOfItems.CItem(); Part.Item = 2764.4; exo.Add(Part); Part = new ListOfItems.CItem(); Part.Item = 92.4662; exo.Add(Part); Part = new ListOfItems.CItem(); Part.Item = 66800.85; exo.Add(Part); Console.WriteLine("-=- List of Items -=-"); for (int i = 0; i < exo.Count(); i++) { ListOfItems.CItem One = exo.Retrieve(i); }

Console.WriteLine("Item: {0}", One.Item);

Console.WriteLine("\nNumber of Items: {0}\n", exo.Count()); }

}

}

7. Execute the application and test it: -=- List of Items -=Item: 97.43 Item: 274.87 Item: 8.7873 Item: 2764.4 Item: 92.4662 Item: 66800.85 Number of Items: 6 Press any key to continue . . .

8. Close the DOS window

Using a Generic Class After creating a generic class, you can use it. One way to do this, as we have learned in previous lessons, consists of declaring a variable for it. In previous lessons, to declare a variable of a class, we would write: Exercise exo = new Exercise();

If the class is generic, on the right side, type the <> operator. Inside of this operator, enter the data type that will be processed as the parameter type of the generic class. Here is an example: using System; public class Generator

C# 3.0 Practical Learning

810

{ public TypeOfValue value; public void Show() { Console.WriteLine("Value: }

{0}\n", value);

} public class Exercise { static int Main() { Generator exo = new Generator(); }

return 0;

}

You can also declare a variable of a generic type using the var keyword. To do this, use var on the left side of the variable name, omit the <> operator and the data type. This would be done as follows: public class Exercise { static int Main() { var exo = new Generator(); return 0; }

}

After declaring the variable, you can then access the member(s) of the class using the period operator. Here are examples: using System; public class Generator { public TypeOfValue value; public void Show() { Console.WriteLine("Value: }

{0}\n", value);

} public class Exercise { static int Main() { var exo = new Generator(); var iValue = 246; exo.value = iValue; exo.Show(); }

return 0;

C# 3.0 Practical Learning

811

}

Passing a Parameter Type to a Method We saw that you could declare a variable of a parameter type in the generic class. Another way you can use it is to pass it as an argument to a method and make the argument a parameter type. As seen previously, you can use the argument as you see fit. For example, you can display its value to the console. Here is an example: using System; public class Generator { public void Show(TypeOfValue value) { Console.WriteLine("Value: {0}\n", value); } } public class Exercise { static int Main() { var exo = new Generator(); var iValue = 246; exo.Show(iValue); return 0; }

}

In the same way, you can pass the parameter type to a constructor of the class. Here is an example: public class Generator { private TypeOfValue val; public Exercise(TypeOfValue v) { val = v; } }

Returning a Parameter Type Besides, or as opposed to, passing a parameter type, you can create a method that returns a parameter type. Once again, you can primarily observe the rules we reviewed for returning a value from a method. Here is an example: using System; public class Generator {

C# 3.0 Practical Learning

812

private TypeOfValue val; public Generator(TypeOfValue v) { val = v; } public TypeOfValue GetValue() { return val; } } public class Exercise { static int Main() { var exo = new Generator<double>(35.65); Console.WriteLine("Value: }

{0}\n", exo.GetValue());

return 0;

}

Practical Learning: Returning a Parameter Type 1. Open the ListOfItems.cs source file 2. To apply what we have reviewed, change the file as follows: using using using using

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

namespace CommercialStore2 { public class ListOfItems { public class CItem { public double Item; public CItem Next; } public ListOfItems() { Head = null; Size = 0; } public CItem<double> Head; public int Size; public int Count() { return Size;

C# 3.0 Practical Learning

813

} public int Add(CItem<double> NewItem) { CItem<double> Sample = new CItem<double>(); Sample = NewItem; Sample.Next = Head; Head = Sample; return Size++; } public CItem<double> Retrieve(int Position) { CItem<double> Current = Head; for (int i = Count() - 1; i > Position && Current != null;

i--)

{

Current = Current.Next;

} } }

return Current;

}

3. Access the Program file and change it as follows: using using using using

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

namespace CommercialStore2 { public class Program { static void Main() { ListOfItems exo = new ListOfItems(); ListOfItems.CItem<double> Part; Part = new ListOfItems.CItem<double>(); Part.Item = 97.43; exo.Add(Part); Part = new ListOfItems.CItem<double>(); Part.Item = 274.87; exo.Add(Part); Part = new ListOfItems.CItem<double>(); Part.Item = 8.7873; exo.Add(Part); Part = new ListOfItems.CItem<double>(); Part.Item = 2764.4; exo.Add(Part);

C# 3.0 Practical Learning

814

Part = new ListOfItems.CItem<double>(); Part.Item = 92.4662; exo.Add(Part); Part = new ListOfItems.CItem<double>(); Part.Item = 66800.85; exo.Add(Part); Console.WriteLine("-=- List of Items -=-"); for (int i = 0; i < exo.Count(); i++) { ListOfItems.CItem<double> One = exo.Retrieve(i); }

Console.WriteLine("Item: {0}", One.Item);

Console.WriteLine("\nNumber of Items: {0}\n", exo.Count()); }

}

}

4. Execute the application and test it 5. Close the DOS window

A Property of the Parameter Type You can create a property that is of the parameter type of the generic class. There is no significant rule to follow when creating the property, except that you should remember that, at the time you are creating the property, the class doesn't know the type of the parameter. Here is an example: using System; public class Generator { private TypeOfValue val; public TypeOfValue Value { get { return val; } set { val = value; } }

}

public void Show() { Console.WriteLine("Value: }

{0}\n", val);

public class Exercise { static int Main() { var exo = new Generator(); exo.Value = 246;

C# 3.0 Practical Learning

815

exo.Show(); return 0; }

}

A Generic Class With Multiple Parameters Using Multiple Type Parameters As done for generic methods, when creating a generic class, you can specify more than one parameter type. To do this, in the <> operator, after the first generic type, enter a comma and another generic type. Here is an example: public class Generator { }

If you know for sure that the parameters will be of the same type, you can use one method to process both. Otherwise, you can declare the necessary members for each type. You can also create a method that would take many arguments with each argument of a particular type. Here are examples: using System; public class Generator { private T t; private V v; public void SetTValue(T value) { t = value; } public T GetTValue() { return t; } public void SetVValue(V value) { v = value; } public V GetVValue() { return v; }

}

public void Show(T tValue, V vValue) { Console.WriteLine("First: {0}\nSecond: {1}", tValue, vValue); }

C# 3.0 Practical Learning

816

When declaring a variable for the class, make sure you appropriately specify the list of parameter types. Here are two examples: public class Exercise { static int Main() { Generator IntTypes = new Generator(); IntTypes.SetTValue(246); IntTypes.SetVValue(6088); IntTypes.Show(IntTypes.GetTValue(), IntTypes.GetVValue()); Generator<double, double> DoubleTypes = new Generator<double, double>(); DoubleTypes.SetTValue(355.65); DoubleTypes.SetVValue(1785.426); DoubleTypes.Show(DoubleTypes.GetTValue(), DoubleTypes.GetVValue()); Generator<short, decimal> Disparate = new Generator<short, decimal>(); DoubleTypes.SetTValue(42); DoubleTypes.SetVValue(245580.35); DoubleTypes.Show(DoubleTypes.GetTValue(), DoubleTypes.GetVValue()); }

return 0;

}

You can also declare the variable using the var keyword. To do this, on the left side of the assignment operator, type only the var keyword and the name of the operator. Here is an example: public class Exercise { static int Main() { var IntTypes = new Generator(); IntTypes.SetTValue(246); IntTypes.SetVValue(6088); IntTypes.Show(IntTypes.GetTValue(), IntTypes.GetVValue()); var DoubleTypes = new Generator<double, double>(); DoubleTypes.SetTValue(355.65); DoubleTypes.SetVValue(1785.426); DoubleTypes.Show(DoubleTypes.GetTValue(), DoubleTypes.GetVValue()); var Disparate = new Generator<short, decimal>(); DoubleTypes.SetTValue(42); DoubleTypes.SetVValue(245580.35); DoubleTypes.Show(DoubleTypes.GetTValue(), DoubleTypes.GetVValue()); }

return 0;

}

This would produce: C# 3.0 Practical Learning

817

First: 246 Second: 6088 First: 355.65 Second: 1785.426 First: 42 Second: 245580.35 Press any key to continue . . .

If a generic class has more than one parameter type, they don't have to be of the same type. At the time you are creating the class, you may not specify their types but you can anticipate that they would be different. It is when you declare the variable that you would need to determine their precise types. Even if the parameters are of primitive types, you can first declare the variables and pass them to the class.

A Class as a Parameter Type So far, in our examples, we treated the parameter type as a primitive data type. A parameter type can also be a formal class, either one that you created yourself or one that exists as part of the C# language. When creating the generic class, you must follow all the rules we have reviewed so far for generic classess. Here is such a simple class: public class Generator { public void Show(TypeOfValue val) { Console.WriteLine("{0}\n", val.ToString()); } }

As mentioned already, the class that would be processed by the generic one must have been previously created so it can be used as a parameter. When declaring a variable of the generic class, make sure you enter the name of the normal class in place of the parameter type. Everything else is as we have done so far. Here is an example: using System; public class FourSideGeometricFigure { private string nm; private double bs; private double hg; public string Name { get { return nm; } set { nm = value; } } public double Base { get { return bs; } set { bs = value; } }

C# 3.0 Practical Learning

818

public double Height { get { return hg; } set { hg = value; } } public double Area { get { return bs * hg; } } public override string ToString() { string result = "Type: " + nm + "\n" + "Base: " + bs.ToString() + "\n" + "Height: " + hg.ToString() + "\n" + "Area: " + Area.ToString(); return result; } } public class Generator { public void Show(TypeOfValue val) { Console.WriteLine("{0}\n", val.ToString()); } } public class Exercise { static int Main() { var sqr = new FourSideGeometricFigure(); sqr.Name = "Square"; sqr.Base = 36.82; sqr.Height = 36.82; Generator exoSquare = new Generator(); exoSquare.Show(sqr); FourSideGeometricFigure rect = new FourSideGeometricFigure(); rect.Name = "Rectangle"; rect.Base = 52.94; rect.Height = 27.58;

}

Generator exoRect = new Generator(); exoRect.Show(rect); return 0;

}

You can also declare the variable using the var keyword. Here are examples: public class Exercise { static int Main() { var sqr = new FourSideGeometricFigure();

C# 3.0 Practical Learning

819

sqr.Name = "Square"; sqr.Base = 36.82; sqr.Height = 36.82; var exoSquare = new Generator(); exoSquare.Show(sqr); FourSideGeometricFigure rect = new FourSideGeometricFigure(); rect.Name = "Rectangle"; rect.Base = 52.94; rect.Height = 27.58;

}

var exoRect = new Generator(); exoRect.Show(rect); return 0;

}

This would produce: Type: Base: Height: Area:

Square 36.82 36.82 1355.7124

Type: Base: Height: Area:

Rectangle 52.94 27.58 1460.0852

Press any key to continue . . .

In the same way, you can create a generic class that takes more than one parameter

Generic Classes and Inheritance Introduction Consider the following geometric figures:

Square

Rectangle

Trapezoid

Parallelogram

Notice that these are geometric figures with each having four sides. From what we know so far, we can create a base class to prepare it for inheritance. If the class is very general, we can make it a generic one. We can set a data C# 3.0 Practical Learning

820

type as an unknown type, anticipating that the dimensions of the figure can be considered as integer or double-precision types. Here is an example: using System; public class Quadrilateral { protected T _base; protected T _height; protected string _name; public virtual T Base { get { return _base; } set { _base = value; } } public virtual T Height { get { return _height; } set { _height = value; } } public virtual string Name { get { return _name; } set { _name = value; } } public Quadrilateral() { _name = "Quadrilateral"; } public Quadrilateral(string name) { _name = "Quadrilateral"; } public Quadrilateral(T bs, T height) { _name = "Quadrilateral"; _base = bs; _height = height; } public Quadrilateral(string name, T bs, T height) { _name = name; _base = bs; _height = height; }

sides";

public virtual string Describe() { return "A quadrilateral is a geometric figure with four }

C# 3.0 Practical Learning

821

public virtual void ShowCharacteristics() { Console.WriteLine("Geometric Figure: {0}", Console.WriteLine("Description: {0}", Console.WriteLine("Base: {0}", Console.WriteLine("Height: {0}", }

Name); Describe()); Base); Height);

} public class Exercise { static int Main() { // Trapezoid with equal sides var Kite = new Quadrilateral<double>("Beach Kite", 18.64, 18.64); Kite.ShowCharacteristics(); Console.WriteLine(); // Rectangle, in meters var BasketballStadium = new Quadrilateral(); BasketballStadium.Name = "Basketball Stadium"; BasketballStadium.Base = 15; BasketballStadium.Height = 28; BasketballStadium.ShowCharacteristics(); Console.WriteLine(); return 0; }

}

This would produce: Geometric Figure: Description: Base: Height:

Beach Kite A quadrilateral is a geometric figure with four sides 18.64 18.64

Geometric Figure: Description: Base: Height:

Basketball Stadium A quadrilateral is a geometric figure with four sides 15 28

Press any key to continue . . .

If you have a generic class that can serve as a foundation for another class, you can derive one class from the generic one. To do this, use the formula we apply when deriving a class but follow the name of each class with <>. Inside of the <> operator, enter the same identifier to indicate that the class is a generic type that is based on another generic class. Here is an example: public class Square : Quadrilateral { }

In the body of the new class, you can use the parameter type as you see fit. For example, you can declare some member variables of that type. You can create methods that return the parameter type or you can pass arguments of the parameter type. When implementing the methods of the new class, use the member variables of the parameter and the argument(s) based on the C# 3.0 Practical Learning

822

parameter type as you see fit. You can then declare a variable of the class and use it as we done so far for other generic classes. Here is an example: using System; public class Quadrilateral { protected T _base; protected T _height; protected string _name; public virtual T Base { get { return _base; } set { _base = value; } } public virtual T Height { get { return _height; } set { _height = value; } } public virtual string Name { get { return _name; } set { _name = value; } } public Quadrilateral() { _name = "Quadrilateral"; } public Quadrilateral(string name) { _name = "Quadrilateral"; } public Quadrilateral(T bs, T height) { _name = "Quadrilateral"; _base = bs; _height = height; } public Quadrilateral(string name, T bs, T height) { _name = name; _base = bs; _height = height; }

sides";

public virtual string Describe() { return "A quadrilateral is a geometric figure with four }

C# 3.0 Practical Learning

823

public virtual void ShowCharacteristics() { Console.WriteLine("Geometric Figure: {0}", Console.WriteLine("Description: {0}", Console.WriteLine("Base: {0}", Console.WriteLine("Height: {0}", }

Name); Describe()); Base); Height);

} public class Square : Quadrilateral { public Square() { _name = "Square"; } public Square(string name) { _name = "Square"; } public Square(T side) { _name = "Square"; _base = side; _height = side; } public Square(string name, T side) { _name = name; _base = side; _height = side; } public override string Describe() { return "A square is a quadrilateral with four equal sides"; } public override void ShowCharacteristics() { Console.WriteLine("Geometric Figure: {0}", Name); Console.WriteLine("Description: {0}", Describe()); Console.WriteLine(" {0}", Describe()); Console.WriteLine("Side: {0}", Base); } } public class Exercise { static int Main() { // Rectangle, in meters var plate = new Square(); plate.Name = "Plate"; plate.Base = 15; plate.Height = 28; plate.ShowCharacteristics();

}

Console.WriteLine(); return 0;

}

C# 3.0 Practical Learning

824

This would produce: Geometric Figure: Plate Description: A quadrilateral is a geometric figure with four sides A square is a quadrilateral with four equal sides Side: 15 Press any key to continue . . .

Generic Classes and Interfaces As done for a generic class, you can create a generic interface that would serve as the base for generic classes. To proceed, when creating the interface, follow its name with a <> declaration and, inside of the <> operator, enter an identifier for the parameter type. Here is an example: public interface IGeometry { string Name { get; set; } void Display(); }

Since this is a generic interface, like an interface class, when deriving a class from it, follow the formula we reviewed for inheriting from a generic class. Here is an example: using System; public interface IGeometry { string Name { get; set; } void Display(); } public class Round : IGeometry { }

When implementing the derived class, you must observe all rules that apply to interface derivation. Here is an example: using System; public interface IGeometry { string Name { get; set; } void Display(); } public class Round : IGeometry { private string _name; public Round() { _name = "Unknown"; } public Round(string name) {

C# 3.0 Practical Learning

825

_name = name; } public virtual string Name { get { return _name; } set { _name = value; } } public virtual void Display() { Console.WriteLine("Name: {0}", Name); } } public class Exercise { static int Main() { var rnd = new Round<decimal>(); rnd.Name = "General Round Shape"; rnd.Display();

}

Console.WriteLine(); return 0;

}

This would produce: Name: General Round Shape Press any key to continue . . .

In the same way, you can derive a generic class from another generic class that derived from a generic interface.

Constraining a Generic Class Imagine you create a regular interface such as the following: public interface IGeometry { string Name { get; set; } void Display(); }

Then imagine you derive a regular class from it. Here is an example: using System; public interface IGeometry { string Name { get; set; } void Display(); } public class Round : IGeometry

C# 3.0 Practical Learning

826

{ private string _name; private double _rad; public Round() { _name = "Unknown"; } public Round(string name) { _name = name; _rad = 0.00; } public Round(string name, double radius) { _name = name; _rad = radius; } public virtual string Name { get { return _name; } set { _name = value; } } public double Radius { get { return _rad; } set { _rad = (value <= 0) ? 0.00 : value; } } public virtual void Display() { Console.WriteLine("Name: {0}", Name); Console.WriteLine("Radius: {0}", Radius); } } public class Exercise { static int Main() { var rnd = new Round(); rnd.Name = "General Round Shape"; rnd.Radius = 38.24; rnd.Display(); Console.WriteLine(); return 0; }

}

You may be tempted to derive just any type of class from it. One of the features of generics is that you can create a class that must implement the functionality of a certain abstract class of your choice. For example, when C# 3.0 Practical Learning

827

creating a generic class, you can oblige it to implement the functionality of a certain interface or you can make sure that the class is derived from a specific base class. This would make sure that the generic class surely contains some useful functionality. To create a constraint on a generic class, after the operator, type where TypeName : followed by the rule that the class must follow. For example, you may want the generic class to implement the functionality of a pre-defined class. You can create the generic class as follows: public interface IGeometry { } public class Round : IGeometry { } public class Sphere where T : Round { }

After creating the class, you must implement the virtual members of the where class/interface, using the rules of generic classes, the way we have done it so far. When declaring a variable for the generic class, in its <> operator, you must enter an object of the base class. Here is an example: using System; public interface IGeometry { string Name { get; set; } void Display(); } public class Round : IGeometry { private string _name; private double _rad; public Round() { _name = "Unknown"; } public Round(string name) { _name = name; _rad = 0.00; } public Round(string name, double radius) { _name = name; _rad = radius; } public virtual string Name { get { return _name; }

C# 3.0 Practical Learning

828

set { _name = value; } } public double Radius { get { return _rad; } set { _rad = (value <= 0) ? 0.00 : value; } } public virtual void Display() { Console.WriteLine("Name: {0}", Name); Console.WriteLine("Radius: {0}", Radius); } } public class Sphere where T : Round { private T _t;

}

public Sphere() { } public Sphere(T fig) { _t = fig; } public T Figure { get { return _t; } set { _t = value; } }

public class Exercise { static int Main() { var rnd = new Round(); rnd.Name = "Circle"; rnd.Radius = 60.12; Sphere sph = new Sphere(); sph.Figure = rnd; Console.WriteLine("Circle Characteristics"); Console.WriteLine("Name: {0}", sph.Figure.Name); Console.WriteLine("Radius: {0}", sph.Figure.Radius); Console.WriteLine(); return 0; }

}

This would produce: Circle Characteristics Name: Circle

C# 3.0 Practical Learning

829

Radius: 60.12 Press any key to continue . . .

You can also create a constraint so that a generic class implements an interface.

C# 3.0 Practical Learning

830

Introduction to File Processing Overview of File Processing and Definitions Introduction In Lesson 2, we saw that a piece of information used in an application was primarily represented as a group of bits. So far, if we requested information from the user, when the application exited, we lost all information that the user had entered. This is because such information was only temporarily stored in the random access memory (RAM). In some cases, you will want to "keep" information that the user has entered so you can make the information available the next time the user opens the application. In some other cases, whether you request information from the user or inherently provide it to the user, you may want different people working from different computers to use or share the same data. In these and other scenarios, you must store the information somewhere and retrieve it when necessary. This is the basis of file processing.

Files A file is a series of bytes of data that are arranged in a particular manner to produce a usable document. For easy storage, location, and management, the bytes are stored on a medium such as a hard disc, a floppy disc, a compact disc, or any valid and supported type of storage. When these bytes belong to a single but common entity and hold values that are stored on a medium, the group is referred to as a file. For greater management, files can be stored in a parent object called a directory or a folder. Since a file is a unit of storage and it stores information, it has a size, which is the number of bits it uses to store its values. To manage it, a file has a location also called a path that specifies where and/or how the file can be retrieved. Also, for better management, a file has attributes (characteristics) that indicate what can be done on the file or that provide specific information that the programmer or the operating system can use when dealing with the file.

Streams C# 3.0 Practical Learning

831

File processing consists of creating, storing, and/or retrieving the contents of a file from a recognizable medium. For example, it is used to save wordprocessed files to a hard drive, to store a presentation on floppy disk, or to open a file from a CD-ROM. A stream is the technique or means of performing file processing. In order to manage files stored in a computer, each file must be able to provide basic pieces of information about itself. This basic information is specified when the file is created but can change during the lifetime of a file. To create a file, a user must first decide where it would be located: this is a requirement. A file can be located on the root drive. Alternatively, a file can be positioned inside of an existing folder. Based on security settings, a user may not be able to create a file just anywhere in the (file system of the) computer. Once the user has decided where the file would reside, there are various means of creating files that the users are trained to use. When creating a file, the user must give it a name following the rules of the operating system combined with those of the file system. The most fundamental piece of information a file must have is a name. Once the user has created a file, whether the file is empty or not, the operating system assigns basic pieces of information to it. Once a file is created, it can be opened, updated, modified, renamed, etc.

Streaming Prerequisites Introduction To support file processing, the .NET Framework provides the System.IO namespace that contains many different classes to handle almost any type of file operation you may need to perform. Therefore, to perform file processing, you can include the System.IO namespace in your project. The parent class of file processing is Stream. With Stream, you can store data to a stream or you can retrieve data from a stream. Stream is an abstract class, which means that you cannot use it to declare a variable in your application. As an abstract class, Stream is used as the parent of the classes that actually implement the necessary operations. You will usually use a combination of classes to perform a typical operation. For example, some classes are used to create a stream object while some others are used to write data to the created stream.

Practical Learning: Introducing Streaming 1. Start Microsoft Visual C# and create a new Console Application named IceCream3

2. To save the project, on the Standard toolbar, click the Save All button 3. Change the Solution Name to VendingMachine3 4. Accept the Name of the project as IceCream3 and click Save C# 3.0 Practical Learning

832

5. To create a new class, on the main menu, click Project -> Add Class... 6. Set the Name to IceCream and click Add 7. Change the file as follows: using using using using

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

namespace IceCream3 { delegate void Request(); // This class is used to create and // and to process an order public sealed class IceCream { // This is the base price of an // Optional values may be added public const double BasePrice =

manage an Ice Cream

Ice Cream to it 1.55D;

// These arrays are used to build the components // of various Ice Creams // In C#, we can allocate an array's memory in // the body of the class private string[] Flavor; private string[] Container; private string[] Ingredient; // Additional factor used to process an Ice Cream order private int Scoops; private double TotalPrice; // Variables that will hold the user's choice // These are declared "globally" so they can be // shared among methods int ChoiceFlavor; int ChoiceContainer; int ChoiceIngredient; // This default constructor is the best place for // us to initialize the array public IceCream() { Flavor = new string[10]; Flavor[0] = "Vanilla"; Flavor[1] = "Cream of Cocoa"; Flavor[2] = "Chocolate Chip"; Flavor[3] = "Organic Strawberry"; Flavor[4] = "Butter Pecan"; Flavor[5] = "Cherry Coke"; Flavor[6] = "Chocolate Brownies"; Flavor[7] = "Caramel Au Lait"; Flavor[8] = "Chunky Butter"; Flavor[9] = "Chocolate Cookie"; Ingredient = new string[4];

C# 3.0 Practical Learning

833

Ingredient[0] Ingredient[1] Ingredient[2] Ingredient[3]

= = = =

"No Ingredient"; "Peanuts"; "M & M"; "Cookies";

Container = new string[3]; Container[0] = "Cone"; Container[1] = "Cup"; Container[2] = "Bowl"; } // This method requests a flavor from the user and // returns the choice internal void ChooseFlavor() { // Make sure the user selects a valid number //that represents a flavor... do { // In case the user types a symbol that // is not a number try { Console.WriteLine("What type of flavor do you

want?");

for (int i = 0; i < Flavor.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Flavor[i]); Console.Write("Your Choice? "); ChoiceFlavor = int.Parse(Console.ReadLine()); } catch (FormatException) message

// display an appropriate

{ Console.WriteLine("You must enter a valid number " + "and no other character!"); } // // // if

If the user typed an invalid number out of the allowed range let him or her know and provide another chance (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length) Console.WriteLine("Invalid Choice - Try Again!\n"); } while (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length); } // This method allows the user to select a container internal void ChooseContainer() { // Make sure the user selects a valid number that // represents a container do { // If the user types a symbol that is not a number try { Console.WriteLine("What type of container do you

want?");

for (int i = 0; i < Container.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Container[i]);

C# 3.0 Practical Learning

834

Console.Write("Your Choice? "); ChoiceContainer = int.Parse(Console.ReadLine());

} catch (FormatException)

message

{ }

// display an appropriate

Console.WriteLine("You must enter a valid " + "number and no other character!");

// // // if

}

If the user typed an invalid number out of the allowed range let him or her know and provide another chance ((ChoiceContainer < 1) || (ChoiceContainer > Container.Length)) Console.WriteLine("Invalid Choice - Try Again!"); } while ((ChoiceContainer < 1) || (ChoiceContainer > Container.Length));

internal void ChooseIngredient() { do { try { Console.WriteLine("Do you want an ingredient or not");

for (int i = 0; i < Ingredient.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Ingredient[i]); Console.Write("Your Choice? "); ChoiceIngredient = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("You must enter a valid " + "number and no other character!"); }

}

if ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient.Length)) Console.WriteLine("Invalid Choice - Try Again!"); } while ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient.Length));

internal void SpecifyNumberOfScoops() { do { try { Console.Write("How many scoops(1, 2, or 3)? "); Scoops = int.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You must enter a valid number " +

C# 3.0 Practical Learning

835

"and no other character!"); }

}

if (Scoops < 1 || Scoops > 3) Console.WriteLine("Invalid Choice - Try Again!"); } while (Scoops < 1 || Scoops > 3);

// This method is used to process a customer order // It uses the values of the above methods internal void ProcessAnOrder() { var PriceIngredient = 0.00D; var PriceScoop = 0.00D; // Let the user know that this is a vending machine Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console.WriteLine("Ice Cream Vending Machine"); Console.WriteLine("-----------------------------------"); // Let the user select the components of the Ice Cream Request Get = new Request(ChooseFlavor); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(ChooseContainer); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(ChooseIngredient); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(SpecifyNumberOfScoops); Get(); Console.WriteLine("-----------------------------------"); // If the user selects an ingredient instead of "No Ingredient",

// add $0.50 to the order if ((ChoiceIngredient == 2) || (ChoiceIngredient == 3) || (ChoiceIngredient == 4)) PriceIngredient = 0.50D; else PriceIngredient = 0.00D; // // // if

Instead of multiplying a number scoops to a value, We will use an incremental value depending on the number of scoops (Scoops == 1) PriceScoop = 0.65D; else if (Scoops == 2) PriceScoop = 1.05D; else PriceScoop = 1.55D; // Calculate the total price of the Ice Cream TotalPrice = BasePrice + PriceScoop + PriceIngredient; // Create the Ice Cream... // And display a receipt to the user

C# 3.0 Practical Learning

836

DisplayReceipt(); } // This method is used to display a receipt to the user internal void DisplayReceipt() { Console.WriteLine("\n=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console.WriteLine("Ice Cream Order"); Console.WriteLine("-----------------------------------"); Console.WriteLine("Flavor: {0}", Flavor[ChoiceFlavor - 1]); Console.WriteLine("Container: {0}", Container[ChoiceContainer - 1]); Console.WriteLine("Ingredient: {0}", Ingredient[ChoiceIngredient - 1]); Console.WriteLine("Scoops: {0}", Scoops); Console.WriteLine("Total Price: {0:C}", TotalPrice); Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\n"); } }

}

8. Access the Program.cs file and change it as follows: using using using using

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

namespace IceCream3 { public class Program { static void Main(string[] args) { var ic = new IceCream(); var process = new Request(ic.ProcessAnOrder); } }

process();

}

9. Execute the project and test it. Here is an example: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Vending Machine ----------------------------------What type of flavor do you want? 1 - Vanilla 2 - Cream of Cocoa 3 - Chocolate Chip 4 - Organic Strawberry 5 - Butter Pecan 6 - Cherry Coke 7 - Chocolate Brownies 8 - Caramel Au Lait 9 - Chunky Butter

C# 3.0 Practical Learning

837

10 - Chocolate Cookie Your Choice? 3 ----------------------------------What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 5 Invalid Choice - Try Again! What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 3 ----------------------------------Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 8 Invalid Choice - Try Again! Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 4 ----------------------------------How many scoops(1, 2, or 3)? 3 ----------------------------------=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Order ----------------------------------Flavor: Chocolate Chip Container: Bowl Ingredient: Cookies Scoops: 3 Total Price: $3.60 =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Press any key to continue . . .

10.

Close the DOS window

The Name of a File Before performing file processing, one of your early decisions will consist of specifying the type of operation you want the user to perform. For example, the user may want to create a brand new file, open an existing file, or perform a routine operation on a file. In all or most cases, whether you are creating a new file or manipulating an existing one, you must specify the name of the file. You can do this by declaring a string variable but, as we will learn later on, most classes used to create a stream can take a string that represents the file. C# 3.0 Practical Learning

838

If you are creating a new file, there are certainly some rules you must observe. The name of a file follows the directives of the operating system. On MS DOS and Windows 3.X (that is, prior to Microsoft Windows 9X), the file had to use the 8.3 format. The actual name had to have a maximum of 8 characters with restrictions on the characters that could be used. The user also had to specify three characters after a period. The three characters, known as the file extension, were used by the operating system to classify the file. That was all necessary for those 8-bit and 16-bit operating systems. Various rules have changed. For example, the names of folders and files on Microsoft Windows >= 95 can have up to 255 characters. The extension of the file is mostly left to the judgment of the programmer but the files are still using extensions. Applications can also be configured to save different types of files; that is, files with different extensions. At the time of this writing, the rules for file names for Microsoft Windows were on the MSDN web site at Windows Development\Windows Base Services\Files and I/O\SDK Documentation\Storage\Storage Overview\File Management\Creating, Deleting, and Maintaining Files\Naming a File (because it is a web site and not a book, its pages can change anytime). Based on this, if you declare a string variable to hold the name of the file, you can simply initialize the variable with the necessary name and its extension. Here is an example: using System; public class Exercise { static int Main(string[] args) { var Filename = "Employees.spr"; }

return 0;

}

Practical Learning: Specifying the Name of a File 1. Access the IceCream.cs file and add a new internal method named SaveOrder of type void as follows: using using using using

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

namespace IceCream3 { // This class is used to create and manage an Ice Cream // and to process an order public sealed class IceCream {

C# 3.0 Practical Learning

839

. . . No Change // This method is used to display a receipt to the user internal void DisplayReceipt() { . . . No Change }

}

internal void SaveOrder() { Console.Write("Please enter your initials or the " + "name we will use to remember your order: "); var Filename = Console.ReadLine(); }

}

2. Access the Program.cs file and change it as follows: using using using using

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

namespace IceCream3 { public class Program { static void Main(string[] args) { var ic = new IceCream(); var process = new Request(ic.ProcessAnOrder); process(); Console.Write("Do you want us to remember this " + "order the next time you come to " + "get your Ice Cream (y/n)? "); var answer = char.Parse(Console.ReadLine()); if (answer == 'y' || answer == 'Y') ic.SaveOrder(); }

}

}

3. Execute the project and test it 4. Close the DOS window

The Path to a File If you declare a string as above, the file will be created in the folder as the application. Otherwise, you can create your new file anywhere in the hard drive or on another medium. To do that, you must provide a complete path where the file will reside. A path is a string that specifies the drive (such as A:, C:, or D:, etc). The sections of a complete path are separated by a C# 3.0 Practical Learning

840

backslash. For example, a path can be made of a folder followed by the name of the file. An example would be C:\Palermo.tde

A path can also consist of a drive followed by the name of the folder in which the file will be created. Here is an example: C:\Program Files\Palermo.tde

A path can also indicate that the file will be created in a folder that itself is inside of another folder. In this case, remember that the names of folders must be separated by backslashes. In Lesson 2, we saw that the backslash character is used to create or manage escape sequences and it can be included in a string value to make up an escape sequence. Because of this, every time you include a backslash in a string, the compiler thinks that you are trying to provide an escape sequence. In this case, if the combination of the backslash and the character that follows the backslash is not recognized as an escape sequence, you would get an error. To solve this problem, you have two alternatives. To indicate that the backslash must be considered as a character in its own right, you can double it. Here are examples: using System; public class Exercise { static int Main(string[] args) { var Filename = "C:\\Documents and " + "Settings\\Business Records\\Employees.spr"; }

return 0;

}

Alternative, you can keep one backslash in each placeholder but precede the value of the string with the @ symbol. Here is an example: using System; public class Exercise { static int Main(string[] args) { var Filename = @"C:\Documents and " + "Settings\Business Records\Employees.spr"; }

return 0;

}

In the same way, you can declare a string variable to represent the name of an existing file that you plan to use in your program. You can also represent its path. When providing a path to the file, if the drive you specify doesn't exist or cannot be read, the compiler would consider that the file doesn't exist. If you 841 C# 3.0 Practical Learning

provide folders that don't exist in the drive, the compiler would consider that the file doesn't exist. This also means that the compiler will not create the folder(s) (the .NET Framework provides all means to create a folder but you must ask the compiler to create it; simply specifying a folder that doesn't exist will not automatically create it, even if you are creating a new file). Therefore, it is your responsibility to make sure that either the file or the path to the file is valid. As we will see in the next section, the compiler can check the existence of a file or path.

The .NET Support for Files Introduction The primary support of a file as an object is provided by a .NET Framework class called File. This static class is equipped with various types of (static) methods to create, save, open, copy, move, delete, or check the existence of a file.

File Existence One of the valuable operations that the File class can perform is to check the existence of the file you want to use. For example, if you are creating a new file, you may want to make sure it doesn't exist already because if you try to create a file that exists already, the compiler may first delete the old file before creating the new one. This could lead to unpredictable result, especially because such a file is not sent to the Recycle Bin. On the other hand, if you are trying to open a file, you should first make sure the file exists, otherwise the compiler will not be able to open a file it cannot find. To check the existence of a file, the File class provides the Exists method. Its syntax is: public static bool Exists(string path);

If you provide only the name of the file, the compiler would check it in the folder of the application. If you provide the path to the file, the compiler would check its drive, its folder(s) and the file itself. In both cases, if the file exists, the method returns true. If the compiler cannot find the file, the method returns false. It's important to know that if you provided a complete path to the file, any slight mistake would produce a false result.

Practical Learning: Checking the Existence of a File 1. Access the IceCream.cs file and change it as follows: using using using using using

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

C# 3.0 Practical Learning

842

namespace IceCream3 { delegate void Request(); . . . No Change // This method is used to display a receipt to the user internal void DisplayReceipt() { . . . No Change } internal void SaveOrder() { Console.Write("Please enter your initials or the " + "name we will use to remember your order: "); var Filename = Console.ReadLine(); if( File.Exists(Filename) ) { Console.WriteLine("The file you entered exists already."); Console.Write("Do you want to replace it(y/n)?" ); var Answer = char.Parse(Console.ReadLine()); if( Answer == 'y' || Answer == 'Y' ) Console.WriteLine("The former order with the " + "same name will be replaced"); else if( Answer == 'n' || Answer == 'N' ) { Console.WriteLine("Please enter a name we will " + "use to remember this order: "); Filename = Console.ReadLine(); } else Console.WriteLine("Invalid Answer - We will close"); return;

} else

Console.WriteLine("Great");

} internal void OpenOrder() { Console.Write("Please enter the name you previously " + "gave to remember your order: "); var Filename = Console.ReadLine(); if (File.Exists(Filename)) Console.WriteLine("The file would have been opened"); else Console.WriteLine("The name you entered is not registered " +

"in our previous orders"); }

}

}

C# 3.0 Practical Learning

843

2. Access the Program.cs file and change it as follows: using System; namespace IceCream3 { public class Program { static void Main(string[] args) { var ic = new IceCream(); var process = new Request(ic.ProcessAnOrder); process(); Console.Write("Do you want us to remember this " + "order the next time you come to " + "get your Ice Cream (y/n)? "); var answer = char.Parse(Console.ReadLine()); if (answer == 'y' || answer == 'Y') ic.SaveOrder(); else Console.WriteLine("\nIt was nice serving you." + "\nCome Again!!!\n"); }

}

}

3. Save the file 4. Compile and execute it

File Creation Besides checking the existence of the file, the File class can be used to create a new file. To support this operation, the File class is equipped with the Create() method that is overloaded with two versions as follows: public static FileStream Create(string path); public static FileStream Create(string path, int buffersize);

In both cases, the File.Create() method returns a Stream value, in this case a FileStream value. As the File.Create() method indicates, it takes the name or path of the file as argument. If you know or want to specify the size, in bytes, of the file, you can use the second version. To provide the same operation of creating a file, you can use the Open() method of the File class. It is overloaded in three versions as follows: public static FileStream Open( string path, FileMode mode ); public static FileStream Open( string path, FileMode mode,

C# 3.0 Practical Learning

844

FileAccess access ); public static FileStream Open( string path, FileMode mode, FileAccess access, FileShare share );

Access to a File In order to perform an operation on a file, you must specify to the operating system how to proceed. One of the options you have is to indicate the type of access that will be granted on the file. This access is specified using the FileAccess enumerator. The members of the FileAccess enumerator are: •

FileAccess.Write: New data can be written to the file



FileAccess.Read: Existing data can be read from the file



FileAccess.ReadWrite: Existing data can be read from the file and new

data be written to the file

File Sharing In standalone workstations, one person is usually able to access and open a file then perform the necessary operations on it. In networked computers, you may create a file that different people can access at the same time or you may make one file access another file to retrieve information. For example, suppose you create an application for a fast food restaurant that has two or more connected workstations and all workstations save their customers orders to a common file. In this case, you must make sure that any of the computers can access the file to save an order. An employee from one of these workstations must also be able to open the file to retrieve a customer order for any necessary reason. You can also create a situation where one file holds an inventory of the items of a store and another file holds the customers orders. Obviously one file would depend on another. Based on this, when an operation must be performed on a file, you may have to specify how a file can be shared. This is done through the FileShare enumerator. The values of the FileShare enumerator are: •

FileShare.Inheritable: Allows other file handles to inherit from this file



FileShare.None: The file cannot be shared



FileShare.Read: The file can be opened and read from



FileShare.Write: The file can be opened and written to



FileShare.ReadWrite: The file can be opened to write to it or read from it

The Mode of a File

C# 3.0 Practical Learning

845

Besides the access to the file, another option you will most likely specify to the operating system is referred to as the mode of a file. It is specified through the FileMode enumerator. The members of the FileMode Enumerator are: •

FileMode.Append: If the file already exists, the new data will be added to

its end. If the file doesn't exist, it will be created and the new data will be added to it •

FileMode.Create: If the file already exists, it will be deleted and a new file

with the same name will be created. If the file doesn't exist, then it will be created •

FileMode.CreateNew: If the new already exists, the compiler will throw an

error. If the file doesn't exist, it will be created •

FileMode.Open: If the file exists, it will be opened. If the file doesn't exist,

an error would be thrown •

FileMode.OpenOrCreate: If the file already exists, it will be opened. If the

file doesn't exist, it will be created •

FileMode.Truncate: If the file already exists, its contents will be deleted

completely but the file will be kept, allowing you to write new data to it. If the file doesn't exist, an error would be thrown

Fundamentals of File Streaming Introduction File streaming consists of performing one of the routine operations on a file, such as creating it or opening it. This basic operation can be performed using a class called FileStream. You can use a FileStream object to get a stream ready for processing. As one of the most complete classes of file processing of the .NET Framework, FileStream is equipped with all necessary properties and methods. To use it, you must first declare a variable of it. The class is equipped with nine constructors. One of the constructors (the second) of the FileStream class has the following syntax: public FileStream(string path, FileMode mode);

This constructor takes as its first argument the name or the file or its path. The second argument specifies the type of operation to perform on the file. Here is an example: using System; using System.IO; public class Exercise { static int Main(string[] args) { var Filename = "Persons.spr";

C# 3.0 Practical Learning

846

FileStream fstPersons = new FileStream(Filename, FileMode.Create); return 0; }

}

Practical Learning: Creating a Stream 1. To create a new stream, change the SaveOrder() method in the IceCream.cs file and as follows: using using using using using

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

namespace IceCream3 { . . . No Change internal void SaveOrder() { Console.Write("Please enter your initials or the " + "name we will use to remember your order: "); var Filename = Console.ReadLine();

already.");

if( File.Exists(Filename) ) { Console.WriteLine("The file you entered exists Console.Write("Do you want to replace it(y/n)?" ); var Answer = char.Parse(Console.ReadLine()); FileStream stmIceCream = new FileStream(Filename, FileMode.Create); if( Answer == 'y' || Answer == 'Y' ) Console.WriteLine("The former order with the " + "same name will be replaced"); else if( Answer == 'n' || Answer == 'N' ) { Console.WriteLine("Please enter a name we will " + "use to remember this order: "); Filename = Console.ReadLine(); } else Console.WriteLine("Invalid Answer - We will close");

return; } else Console.WriteLine("Great"); } internal void OpenOrder() { . . . No Change

C# 3.0 Practical Learning

847

} }

}

2. Save the file

Stream Writing A streaming operation is typically used to create a stream. Once the stream is ready, you can write data to it. The writing operation is perform through various classes. One of these classes is BinaryWriter. The BinaryWriter class can be used to write values of primitive data types (char, int, float, double, etc). To use a BinaryWriter value, you can first declare its variable. To do this, you would use one of the class' three constructors. One of its constructors (the second) has the following syntax: public BinaryWriter(Stream output);

This constructor takes as argument a Stream value, which could be a FileStream variable. Here is an example: using System; using System.IO; public class Exercise { static int Main(string[] args) { var Filename = "Persons.spr"; FileStream fstPersons = new FileStream(Filename, FileMode.Create); BinaryWriter wrtPersons = new BinaryWriter(fstPersons); }

return 0;

}

If you are initializing a variable while you are creating it, remember that you can use the var keyword. Most classes that are used to add values to a stream are equipped with a method called Write. This is also the case for the BinaryWriter class. This method takes as argument the value that must be written to the stream. The method is overloaded so that there is a version for each primitive data type. Here is an example that adds strings to a newly created file: using System; using System.IO; public class Exercise { static int Main(string[] args) { var Filename = "Persons.spr"; var fstPersons = new FileStream(Filename, FileMode.Create); var wrtPersons = new BinaryWriter(fstPersons);

C# 3.0 Practical Learning

848

wrtPersons.Write("James Bloch"); wrtPersons.Write("Catherina Wallace"); wrtPersons.Write("Bruce Lamont"); wrtPersons.Write("Douglas Truth"); }

return 0;

}

Stream Closing When you use a stream, it requests resources from the operating system and uses them while the stream is available. When you are not using the stream anymore, you should free the resources and make them available again to the operating system so that other services can use them. This is done by closing the stream. To close a stream, you can can call the Close() method of the class(es) you were using. Here are examples: using System; using System.IO; public class Exercise { static int Main(string[] args) { var Filename = "Persons.spr"; var fstPersons = new FileStream(Filename, FileMode.Create); var wrtPersons = new BinaryWriter(fstPersons); wrtPersons.Write("James Bloch"); wrtPersons.Write("Catherina Wallace"); wrtPersons.Write("Bruce Lamont"); wrtPersons.Write("Douglas Truth"); wrtPersons.Close(); fstPersons.Close(); }

return 0;

}

Practical Learning: Writing to a Stream 1. To be able to complete a file, change the SaveOrder() method in the IceCream.cs file as follows: using using using using using

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

namespace IceCream3 {

C# 3.0 Practical Learning

849

. . . No Change internal void SaveOrder() { Console.Write("Please enter your initials or the name " + "we will use to remember your order: "); var Filename = Console.ReadLine(); Filename = Filename + ".icr"; // Find out if the user entered a name of a file // that is already in the machine if (File.Exists(Filename)) { var stmIceCream = new FileStream(Filename, FileMode.Create); var bnwIceCream = new BinaryWriter(stmIceCream); // If so, find out if the user wants to // replace the old file Console.WriteLine("The file you entered exists already.");

Console.Write("Do you want to replace it(y/n)?"); char answer = char.Parse(Console.ReadLine()); // If the customer wants to replace it... if (answer == 'y' || answer == 'Y') { // ... do so Console.WriteLine("The former order with the same " + "name will be replaced"); Console.WriteLine("\n=-= Ice Cream Vending Machine =-

=");

Console.WriteLine(" Saving Order: {0}", Filename); bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer - 1]); bnwIceCream.Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice);

} // If the customer wants to save the new order with // a different name else if (answer == 'n' || answer == 'N') { // Ask the user to enter a name to remember the order Console.Write("Please enter a name we will use " + "to remember this order: "); Filename = Console.ReadLine(); Filename = Filename + ".icr"; FileMode.Create);

stmIceCream = new FileStream(Filename, bnwIceCream = new BinaryWriter(stmIceCream);

=");

Console.WriteLine("\n=-= Ice Cream Vending Machine =Console.WriteLine(" Saving Order: {0}", Filename); bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer - 1]);

C# 3.0 Practical Learning

850

bnwIceCream.Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice); } else Console.WriteLine("Invalid Answer - We will close"); bnwIceCream.Close(); stmIceCream.Close();

} else {

var stmIceCream = new FileStream(Filename, FileMode.Create); var bnwIceCream = new BinaryWriter(stmIceCream); Console.WriteLine("\n=-= Ice Cream Vending Machine =-="); Console.WriteLine(" Saving Order: {0}", Filename); bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer - 1]); bnwIceCream.Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice);

}

bnwIceCream.Close(); stmIceCream.Close();

} public void OpenOrder() { . . . No Change } }

}

2. Execute the application and test it. Here is an example: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Vending Machine ----------------------------------What type of flavor do you want? 1 - Vanilla 2 - Cream of Cocoa 3 - Chocolate Chip 4 - Organic Strawberry 5 - Butter Pecan 6 - Cherry Coke 7 - Chocolate Brownies 8 - Caramel Au Lait 9 - Chunky Butter 10 - Chocolate Cookie Your Choice? 8 ----------------------------------What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 2

C# 3.0 Practical Learning

851

----------------------------------Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 3 ----------------------------------How many scoops(1, 2, or 3)? 2 ----------------------------------=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Order ----------------------------------Flavor: Caramel Au Lait Container: Cup Ingredient: M & M Scoops: 2 Total Price: $3.10 =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Do you want us to remember this order the next time you come to get your ice scream (y/n)? Y Please enter your initials or the name we will use to remember your order: LS =-= Ice Cream Vending Machine =-= Saving Order: LS.icr Press any key to continue . . .

3. Close the DOS window

Stream Reading As opposed to writing to a stream, you may want to read existing data from it. Before doing this, you can first specify your intent to the streaming class using the FileMode enumerator. This can be done using the FileStream class as follows: using System; using System.IO; public class Exercise { static int Main(string[] args) { var Filename = "Persons.spr"; /* var fstPersons = new FileStream(Filename, FileMode.Create); var wrtPersons = new BinaryWriter(fstPersons); wrtPersons.Write("James Bloch"); wrtPersons.Write("Catherina Wallace"); wrtPersons.Write("Bruce Lamont"); wrtPersons.Write("Douglas Truth"); wrtPersons.Close(); fstPersons.Close();

C# 3.0 Practical Learning

852

*/ var fstPersons = new FileStream(Filename, FileMode.Open); }

return 0;

}

Once the stream is ready, you can get prepared to read data from it. To support this, you can use the BinaryReader class. This class provides two constructors. One of the constructors (the first) has the following syntax: public BinaryReader(Stream input);

This constructor takes as argument a Stream value, which could be a FileStream object. After declaring a FileStream variable using this constructor, you can read data from it. To do this, you can call an appropriate method. This class provides an appropriate method for each primitive data type. After using the stream, you should close it to reclaim the resources it was using. This is done by calling the Close() method. Here is an example of using the mentioned methods: using System; using System.IO; public class Exercise { static int Main(string[] args) { var Filename = "Persons.spr"; /* var fstPersons = new FileStream(Filename, FileMode.Create); var wrtPersons = new BinaryWriter(fstPersons); wrtPersons.Write("James Bloch"); wrtPersons.Write("Catherina Wallace"); wrtPersons.Write("Bruce Lamont"); wrtPersons.Write("Douglas Truth");

*/

wrtPersons.Close(); fstPersons.Close(); var fstPersons = new FileStream(Filename, FileMode.Open); var rdrPersons = new BinaryReader(fstPersons); var strLine = ""; strLine = rdrPersons.ReadString(); Console.WriteLine(strLine); strLine = rdrPersons.ReadString(); Console.WriteLine(strLine); strLine = rdrPersons.ReadString(); Console.WriteLine(strLine); strLine = rdrPersons.ReadString(); Console.WriteLine(strLine); rdrPersons.Close(); fstPersons.Close();

C# 3.0 Practical Learning

853

}

return 0;

}

Practical Learning: Reading From a Stream 1. To be able to retrieve data from an existing file, change the IceCream.cs file as follows: using using using using using

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

namespace IceCream3 { delegate void Request(); // This class is used to create and // and to process an order public sealed class IceCream { // This is the base price of an // Optional values may be added public const double BasePrice =

manage an Ice Cream

Ice Cream to it 1.55D;

// These arrays are used to build the components // of various Ice Creams // In C#, we can allocate an array's memory in // the body of the class private string[] Flavor; private string[] Container; private string[] Ingredient; // Additional factor used to process an Ice Cream order private int Scoops; private double TotalPrice; // Variables that will hold the user's choice // These are declared "globally" so they can be // shared among methods int ChoiceFlavor; int ChoiceContainer; int ChoiceIngredient; // This default constructor is the best place for // us to initialize the array public IceCream() { Flavor = new string[10]; Flavor[0] = "Vanilla"; Flavor[1] = "Cream of Cocoa"; Flavor[2] = "Chocolate Chip"; Flavor[3] = "Organic Strawberry"; Flavor[4] = "Butter Pecan"; Flavor[5] = "Cherry Coke";

C# 3.0 Practical Learning

854

Flavor[6] Flavor[7] Flavor[8] Flavor[9]

= = = =

"Chocolate Brownies"; "Caramel Au Lait"; "Chunky Butter"; "Chocolate Cookie";

Ingredient = new string[4]; Ingredient[0] = "No Ingredient"; Ingredient[1] = "Peanuts"; Ingredient[2] = "M & M"; Ingredient[3] = "Cookies"; Container = new string[3]; Container[0] = "Cone"; Container[1] = "Cup"; Container[2] = "Bowl"; } // This method requests a flavor from the user and // returns the choice internal void ChooseFlavor() { // Make sure the user selects a valid number //that represents a flavor... do { // In case the user types a symbol that // is not a number try { Console.WriteLine("What type of flavor do you

want?");

for (int i = 0; i < Flavor.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Flavor[i]); Console.Write("Your Choice? "); ChoiceFlavor = int.Parse(Console.ReadLine()); } catch (FormatException) message

// display an appropriate

{ Console.WriteLine(@"You must enter a valid number and no other character!"); } // // // if

If the user typed an invalid number out of the allowed range let him or her know and provide another chance (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length) Console.WriteLine("Invalid Choice - Try Again!\n"); } while (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length); } // This method allows the user to select a container internal void ChooseContainer() { // Make sure the user selects a valid number that // represents a container do { // If the user types a symbol that is not a number try

C# 3.0 Practical Learning

855

{ Console.WriteLine("What type of container do you

want?");

for (int i = 0; i < Container.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Container[i]);

Console.Write("Your Choice? "); ChoiceContainer = int.Parse(Console.ReadLine());

} catch (FormatException)

message

{ }

// display an appropriate

Console.WriteLine(@"You must enter a valid number and no other character!");

// // // if

}

If the user typed an invalid number out of the allowed range let him or her know and provide another chance ((ChoiceContainer < 1) || (ChoiceContainer > Container.Length)) Console.WriteLine("Invalid Choice - Try Again!"); } while ((ChoiceContainer < 1) || (ChoiceContainer > Container.Length));

internal void ChooseIngredient() { do { try { Console.WriteLine("Do you want an ingredient or not");

for (int i = 0; i < Ingredient.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Ingredient[i]); Console.Write("Your Choice? "); ChoiceIngredient = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine(@"You must enter a valid number and no other character!"); }

}

if ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient.Length)) Console.WriteLine("Invalid Choice - Try Again!"); } while ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient.Length));

internal void SpecifyNumberOfScoops() { do { try {

C# 3.0 Practical Learning

856

Console.Write("How many scoops(1, 2, or 3)? "); Scoops = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("You must enter a valid number " + "and no other character!"); }

}

if (Scoops < 1 || Scoops > 3) Console.WriteLine("Invalid Choice - Try Again!"); } while (Scoops < 1 || Scoops > 3);

// This method is used to process a customer order // It uses the values of the above methods internal void ProcessAnOrder() { var PriceIngredient = 0.00D; var PriceScoop = 0.00D; // Let the user know that this is a vending machine Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console.WriteLine("Ice Cream Vending Machine"); Console.WriteLine("-----------------------------------"); // Let the user select the components of the Ice Cream Request Get = new Request(ChooseFlavor); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(ChooseContainer); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(ChooseIngredient); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(SpecifyNumberOfScoops); Get(); Console.WriteLine("-----------------------------------"); // If the user selects an ingredient instead of "No Ingredient",

// add $0.50 to the order if ((ChoiceIngredient == 2) || (ChoiceIngredient == 3) || (ChoiceIngredient == 4)) PriceIngredient = 0.50D; else PriceIngredient = 0.00D; // // // if

Instead of multiplying a number scoops to a value, We will use an incremental value depending on the number of scoops (Scoops == 1) PriceScoop = 0.65D; else if (Scoops == 2) PriceScoop = 1.05D; else PriceScoop = 1.55D;

C# 3.0 Practical Learning

857

// Calculate the total price of the Ice Cream TotalPrice = BasePrice + PriceScoop + PriceIngredient; // Create the Ice Cream... // And display a receipt to the user DisplayReceipt(); } // This method is used to display a receipt to the user internal void DisplayReceipt() { Console.WriteLine("\n=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console.WriteLine("Ice Cream Order"); Console.WriteLine("-----------------------------------"); Console.WriteLine("Flavor: {0}", Flavor[ChoiceFlavor - 1]); Console.WriteLine("Container: {0}", Container[ChoiceContainer - 1]); Console.WriteLine("Ingredient: {0}", Ingredient[ChoiceIngredient - 1]); Console.WriteLine("Scoops: {0}", Scoops); Console.WriteLine("Total Price: {0:C}", TotalPrice); Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\n"); } internal void SaveOrder() { Console.Write("Please enter your initials or the name " + "we will use to remember your order: "); var Filename = Console.ReadLine(); Filename = Filename + ".icr"; // Find out if the user entered a name of a file // that is already in the machine if (File.Exists(Filename)) { FileStream stmIceCream = new FileStream(Filename, FileMode.Create); BinaryWriter bnwIceCream = new BinaryWriter(stmIceCream); // If so, find out if the user wants to // replace the old file Console.WriteLine("The file you entered exists already.");

Console.Write("Do you want to replace it(y/n)?"); char answer = char.Parse(Console.ReadLine()); // If the customer wants to replace it... if (answer == 'y' || answer == 'Y') { // ... do so Console.WriteLine("The former order with the same " + "name will be replaced"); Console.WriteLine("\n=-= Ice Cream Vending Machine =-

=");

Console.WriteLine(" Saving Order: {0}", Filename); bnwIceCream.Write(Flavor[ChoiceFlavor - 1]);

C# 3.0 Practical Learning

858

bnwIceCream.Write(Container[ChoiceContainer - 1]); bnwIceCream.Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice);

} // If the customer wants to save the new order with // a different name else if (answer == 'n' || answer == 'N') { // Ask the user to enter a name to remember the order Console.Write("Please enter a name we will use " + "to remember this order: "); Filename = Console.ReadLine(); Filename = Filename + ".icr"; stmIceCream = new FileStream(Filename,

FileMode.Create);

bnwIceCream = new BinaryWriter(stmIceCream); Console.WriteLine("\n=-= Ice Cream Vending Machine =-

=");

Console.WriteLine(" Saving Order: {0}", Filename); bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer - 1]); bnwIceCream.Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice); } else Console.WriteLine("Invalid Answer - We will close"); bnwIceCream.Close(); stmIceCream.Close();

} else {

var stmIceCream = new FileStream(Filename, FileMode.Create); var bnwIceCream = new BinaryWriter(stmIceCream); Console.WriteLine("\n=-= Ice Cream Vending Machine =-="); Console.WriteLine(" Saving Order: {0}", Filename); bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer - 1]); bnwIceCream.Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice);

}

bnwIceCream.Close(); stmIceCream.Close();

} public void OpenOrder() { // Ask the user to enter a name of a previously saved order Console.Write("Please enter the name you previously " + "gave to remember your order: "); var Filename = Console.ReadLine(); Filename = Filename + ".icr";

C# 3.0 Practical Learning

859

var stmIceCream = new FileStream(Filename, FileMode.Open); var bnrIceCream = new BinaryReader(stmIceCream); // Find out if this order was previously saved in the machine if (File.Exists(Filename)) { // If so, open it var SelectedFlavor = bnrIceCream.ReadString(); var SelectedContainer = bnrIceCream.ReadString(); var SelectedIngredient = bnrIceCream.ReadString(); Scoops = bnrIceCream.ReadInt32(); TotalPrice = bnrIceCream.ReadDouble(); // And display it to the user Console.WriteLine("\n=-= Ice Cream Vending Machine =-="); Console.WriteLine(" Previous Order: {0}", Filename); Console.WriteLine("Flavor: {0}", SelectedFlavor); Console.WriteLine("Container: {0}", SelectedContainer); Console.WriteLine("Ingredient: {0}", SelectedIngredient); Console.WriteLine("Scoops: {0}", Scoops); Console.WriteLine("Total Price: {0:C}\n", TotalPrice); bnrIceCream.Close(); stmIceCream.Close();

} else } }

Console.WriteLine("The name you entered is not " + "registered in our previous orders");

}

2. Access the Program.cs file and change it as follows: using using using using

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

namespace IceCream3 { public class Program { static void Main(string[] args) { var ic = new IceCream(); var process = new Request(ic.ProcessAnOrder); Console.Write("Do you want to re-order a previously " + "saved order(y/n)? "); var answer = char.Parse(Console.ReadLine()); if (answer == 'y' || answer == 'Y') ic.OpenOrder(); else

C# 3.0 Practical Learning

860

{ process(); Console.Write("Do you want us to remember this " + "order the next time you come to " + "get your Ice Cream (y/n)? "); answer = char.Parse(Console.ReadLine()); if (answer == 'y' || answer == 'Y') ic.SaveOrder(); else Console.WriteLine("\nIt was nice serving you." + "\nCome Again!!!\n"); } }

}

}

3. Execute the application and test it. Here is an example: Do you want to re-order a previously saved order(y/n)? Y Please enter the name you previously gave to remember your order: LS =-= Ice Cream Vending Machine =-= Previous Order: LS.icr Flavor: Caramel Au Lait Container: Cup Ingredient: M & M Scoops: 2 Total Price: $3.10 Press any key to continue . . .

4. Close the DOS window 5. Execute the application again and test it. Here is an example: Do you want to re-order a previously saved order(y/n)? w =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Vending Machine ----------------------------------What type of flavor do you want? 1 - Vanilla 2 - Cream of Cocoa 3 - Chocolate Chip 4 - Organic Strawberry 5 - Butter Pecan 6 - Cherry Coke 7 - Chocolate Brownies 8 - Caramel Au Lait 9 - Chunky Butter 10 - Chocolate Cookie Your Choice? 5 ----------------------------------What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 2 -----------------------------------

C# 3.0 Practical Learning

861

Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 1 ----------------------------------How many scoops(1, 2, or 3)? 1 ----------------------------------=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Order ----------------------------------Flavor: Butter Pecan Container: Cup Ingredient: No Ingredient Scoops: 1 Total Price: $2.20 =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Do you want us to remember this order the next time you come to get your Ice Cream (y/n)? y Please enter your initials or the name we will use to remember your order: DIC =-= Ice Cream Vending Machine =-= Saving Order: DIC.icr Press any key to continue . . .

6. Close the DOS window 7. Execute the application again and test it. Here is an example: Do you want to re-order a previously saved order(y/n)? n =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Vending Machine ----------------------------------What type of flavor do you want? 1 - Vanilla 2 - Cream of Cocoa 3 - Chocolate Chip 4 - Organic Strawberry 5 - Butter Pecan 6 - Cherry Coke 7 - Chocolate Brownies 8 - Caramel Au Lait 9 - Chunky Butter 10 - Chocolate Cookie Your Choice? 9 ----------------------------------What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 3 ----------------------------------Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts

C# 3.0 Practical Learning

862

3 - M & M 4 - Cookies Your Choice? 4 ----------------------------------How many scoops(1, 2, or 3)? 3 ----------------------------------=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Order ----------------------------------Flavor: Chunky Butter Container: Bowl Ingredient: Cookies Scoops: 3 Total Price: $3.60 =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Do you want us to remember this order the next time you come to get your Ice Cream (y/n)? Y Please enter your initials or the name we will use to remember your order: LS The file you entered exists already. Do you want to replace it(y/n)?Y The former order with the same name will be replaced =-= Ice Cream Vending Machine =-= Saving Order: LS.icr Press any key to continue . . .

8. Close the DOS window

C# 3.0 Practical Learning

863

Details on File Processing Exception Handling in File Processing Finally So far, to handle exceptions, we were using the try, catch, and throw keywords. These allowed us to perform normal assignments in a try section and then handle an exception, if any, in a catch block. In the previous lesson, we mentioned that, when you create a stream, the operating system must allocate resources and dedicate them to the file processing operations. Additional resources may be provided for the object that is in charge of writing to, or reading from, the stream. We also saw that, when the streaming was over, we should free the resources and give them back to the operating system. To do this, we called the Close() method of the variable that was using resources.

More than any other assignment, file processing is in prime need of exception handling. As we will see in the next section, during file processing, there are many things that can go wrong. For this reason, the creation and/or management of streams should be performed in a try block to get ready to handle exceptions that would occur. Besides actually handling exceptions, the C# language provides a special keyword used free resources. This keyword is finally. The finally keyword is used to create a section of an exception. Like catch, a finally block cannot exist by itself. It can be created following a try section. The formula used would be: try { } finally { }

Based on this, the finally section has a body of its own, delimited by its curly brackets. Like catch, the finally section is created after the try section. Unlike catch, finally never has parentheses and never takes arguments. Unlike catch, the finally section is always executed. Because the finally clause always gets executed, you can include any type of code in it but it is usually appropriate to free the resources that were allocated earlier. Here is an example: C# 3.0 Practical Learning

864

using System; using System.IO; public class Program { static int Main(string[] args) { var Filename = "Members.clb"; var fstPersons = new FileStream(Filename, FileMode.Create); var wrtPersons = new BinaryWriter(fstPersons); try { wrtPersons.Write("James Bloch"); wrtPersons.Write("Catherina Wallace"); wrtPersons.Write("Bruce Lamont"); wrtPersons.Write("Douglas Truth"); } finally { wrtPersons.Close(); fstPersons.Close(); } return 0; }

}

In the same way, you can use a finally section to free resources used when reading from a stream: using System; using System.IO; public class Program { static int Main(string[] args) { /* var Filename = "Members.clb"; var fstPersons = new FileStream(Filename, FileMode.Create); var wrtPersons = new BinaryWriter(fstPersons); try {

wrtPersons.Write("James Bloch"); wrtPersons.Write("Catherina Wallace"); wrtPersons.Write("Bruce Lamont"); wrtPersons.Write("Douglas Truth");

} finally { wrtPersons.Close(); fstPersons.Close(); }*/ var var var var

strLine = ""; Filename = "Members.clb"; fstMembers = new FileStream(Filename, FileMode.Open); rdrMembers = new BinaryReader(fstMembers);

C# 3.0 Practical Learning

865

try {

strLine = rdrMembers.ReadString(); Console.WriteLine(strLine); strLine = rdrMembers.ReadString(); Console.WriteLine(strLine); strLine = rdrMembers.ReadString(); Console.WriteLine(strLine); strLine = rdrMembers.ReadString(); Console.WriteLine(strLine);

} finally { rdrMembers.Close(); fstMembers.Close(); } }

return 0;

}

Of course, since the whole block of code starts with a try section, it is used for exception handling. This means that you can add the necessary and appropriate catch section(s) but you don't have to.

Practical Learning: Finally Releasing Resources 1. Start Microsoft Visual C# and create a Console Application named IceCream4

2. To save the project, on the Standard toolbar, click the Save All button 3. Change the Solution Name to VendingMachine4 4. Accept the Name of the project as IceCream3 and click Save 5. To create a new class, on the main menu, click Project -> Add Class... 6. Set the Name to IceCream and click Add 7. Change the file as follows: using using using using using

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

namespace IceCream4 { delegate void Request(); // This class is used to create and manage an Ice Cream // and to process an order public sealed class IceCream { // This is the base price of an Ice Cream

C# 3.0 Practical Learning

866

// Optional values may be added to it public const decimal BasePrice = 1.55M; // These arrays are used to build the components // of various ice creams private string[] Flavor; private string[] Container; private string[] Ingredient; // Additional factor used to process an Ice Cream order private int Scoops; private decimal TotalPrice; // Variables that will hold the user's choice // These are declared "globally" so they can be // shared among methods int ChoiceFlavor; int ChoiceContainer; int ChoiceIngredient; // This default constructor is the best place for // us to initialize the array public IceCream() { Flavor = new string[10]; Flavor[0] = "Vanilla"; Flavor[1] = "Cream of Cocoa"; Flavor[2] = "Chocolate Chip"; Flavor[3] = "Organic Strawberry"; Flavor[4] = "Butter Pecan"; Flavor[5] = "Cherry Coke"; Flavor[6] = "Chocolate Brownies"; Flavor[7] = "Caramel Au Lait"; Flavor[8] = "Chunky Butter"; Flavor[9] = "Chocolate Cookie"; Ingredient = new string[4]; Ingredient[0] = "No Ingredient"; Ingredient[1] = "Peanuts"; Ingredient[2] = "M & M"; Ingredient[3] = "Cookies";

}

Container = new string[3]; Container[0] = "Cone"; Container[1] = "Cup"; Container[2] = "Bowl";

// This method requests a flavor from the user and // returns the choice internal void ChooseFlavor() { // Make sure the user selects a valid number //that represents a flavor... do { // In case the user types a symbol that // is not a number try {

C# 3.0 Practical Learning

867

Console.WriteLine("What type of flavor do you want?");

for (int i = 0; i < Flavor.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Flavor[i]); Console.Write("Your Choice? "); ChoiceFlavor = int.Parse(Console.ReadLine());

} catch (FormatException)

message

{ }

// display an appropriate

Console.WriteLine("You must enter a valid number " + "and no other character!");

// // // if

}

If the user typed an invalid number out of the allowed range let him or her know and provide another chance (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length) Console.WriteLine("Invalid Choice - Try Again!\n"); } while (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length);

// This method allows the user to select a container internal void ChooseContainer() { // Make sure the user selects a valid number that // represents a container do { // If the user types a symbol that is not a number try { Console.WriteLine("What type of container do you want?");

for (int i = 0; i < Container.Length; i++) Console.WriteLine("{0} - {1}", i + 1,

Container[i]);

Console.Write("Your Choice? "); ChoiceContainer = int.Parse(Console.ReadLine()); } catch (FormatException) message

// display an appropriate

{ Console.WriteLine("You must enter a valid " + "number and no other character!"); } // // // if

If the user typed an invalid number out of the allowed range let him or her know and provide another chance ((ChoiceContainer < 1) || (ChoiceContainer > Container.Length)) Console.WriteLine("Invalid Choice - Try Again!"); } while ((ChoiceContainer < 1) || (ChoiceContainer > Container.Length)); } internal void ChooseIngredient() { do

C# 3.0 Practical Learning

868

{ try { Console.WriteLine("Do you want an ingredient or

not");

for (int i = 0; i < Ingredient.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Ingredient[i]); Console.Write("Your Choice? "); ChoiceIngredient = int.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You must enter a valid " + "number and no other character!"); } if ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient.Length)) Console.WriteLine("Invalid Choice - Try Again!"); } while ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient.Length)); } internal void SpecifyNumberOfScoops() { do { try { Console.Write("How many scoops(1, 2, or 3)? "); Scoops = int.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You must enter a valid number " + "and no other character!"); } if (Scoops < 1 || Scoops > 3) Console.WriteLine("Invalid Choice - Try Again!"); } while (Scoops < 1 || Scoops > 3); } // This method is used to process a customer order // It uses the values of the above methods internal void ProcessAnOrder() { // int ChoiceFlavor; // int ChoiceContainer; // int ChoiceIngredient; decimal PriceIngredient, PriceScoop; // Let the user know that this is a vending machine Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console.WriteLine("Ice Cream Vending Machine"); Console.WriteLine("-----------------------------------"); // Let the user select the components of the Ice Cream

C# 3.0 Practical Learning

869

Request Get = new Request(ChooseFlavor); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(ChooseContainer); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(ChooseIngredient); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(SpecifyNumberOfScoops); Get(); Console.WriteLine("-----------------------------------"); // If the user selects an ingredient instead of "No

Ingredient",

// add $0.50 to the order if ((ChoiceIngredient == 2) || (ChoiceIngredient == 3) || (ChoiceIngredient == 4)) PriceIngredient = 0.50M; else PriceIngredient = 0.00M; // // // if

Instead of multiplying a number scoops to a value, We will use an incremental value depending on the number of scoops (Scoops == 1) PriceScoop = 0.65M; else if (Scoops == 2) PriceScoop = 1.05M; else PriceScoop = 1.55M; // Calculate the total price of the Ice Cream TotalPrice = BasePrice + PriceScoop + PriceIngredient; // Create the Ice Cream...

}

// And display a receipt to the user DisplayReceipt();

// This method is used to display a receipt to the user internal void DisplayReceipt() { Console.WriteLine("\n=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console.WriteLine("Ice Cream Order"); Console.WriteLine("-----------------------------------"); Console.WriteLine("Flavor: {0}", Flavor[ChoiceFlavor - 1]); Console.WriteLine("Container: {0}", Container[ChoiceContainer - 1]); Console.WriteLine("Ingredient: {0}", Ingredient[ChoiceIngredient - 1]); Console.WriteLine("Scoops: {0}", Scoops); Console.WriteLine("Total Price: {0:C}", TotalPrice); Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\n"); } internal void SaveOrder()

C# 3.0 Practical Learning

870

{ string strFilename; Console.Write("Please enter your initials or the name " + "we will use to remember your order: "); strFilename = Console.ReadLine(); strFilename = strFilename + ".icr"; // Find out if the user entered a name of a file // that is already in the machine if (File.Exists(strFilename)) { char answer; FileStream stmIceCream = new FileStream(strFilename, FileMode.Create); BinaryWriter bnwIceCream = new BinaryWriter(stmIceCream); try { // If so, find out if the user wants to // replace the old file Console.WriteLine("The file you entered exists already.");

" +

Console.Write("Do you want to replace it(y/n)?"); answer = char.Parse(Console.ReadLine()); // If the customer wants to replace it... if (answer == 'y' || answer == 'Y') { // ... do so Console.WriteLine("The former order with the same "name will be replaced");

Machine =-="); strFilename);

Console.WriteLine("\n=-= Ice Cream Vending Console.WriteLine(" Saving Order: {0}", bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer -

1]); 1]);

order +

bnwIceCream.Write(Ingredient[ChoiceIngredient bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice);

} // If the customer wants to save the new order with // a different name else if (answer == 'n' || answer == 'N') { // Ask the user to enter a name to remember the Console.Write("Please enter a name we will use " "to remember this order: "); strFilename = Console.ReadLine(); strFilename = strFilename + ".icr";

C# 3.0 Practical Learning

871

stmIceCream = new FileStream(strFilename, FileMode.Create); bnwIceCream = new BinaryWriter(stmIceCream); Console.WriteLine("\n=-= Ice Cream Vending

Machine =-=");

Console.WriteLine(" Saving Order: {0}",

strFilename);

bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer 1]);

bnwIceCream.Write(Ingredient[ChoiceIngredient -

1]);

bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice);

} else

Console.WriteLine("Invalid Answer - We will

close");

} finally { bnwIceCream.Close(); stmIceCream.Close(); }

} else {

FileStream stmIceCream = new FileStream(strFilename, FileMode.Create); BinaryWriter bnwIceCream = new BinaryWriter(stmIceCream); try { =");

Console.WriteLine("\n=-= Ice Cream Vending Machine =Console.WriteLine(" Saving Order: {0}", strFilename); bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer - 1]); bnwIceCream.Write(Ingredient[ChoiceIngredient - 1]); bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice);

}

} finally { bnwIceCream.Close(); stmIceCream.Close(); }

} internal void OpenOrder() { string strFilename; string SelectedFlavor; string SelectedContainer; string SelectedIngredient;

C# 3.0 Practical Learning

872

// Ask the user to enter a name of a previously saved order Console.Write("Please enter the name you previously " + "gave to remember your order: "); strFilename = Console.ReadLine(); strFilename = strFilename + ".icr"; FileStream stmIceCream = new FileStream(strFilename, FileMode.Open); BinaryReader bnrIceCream = new BinaryReader(stmIceCream); try {

// Find out if this order was previously saved in the

machine

if (File.Exists(strFilename)) { // If so, open it SelectedFlavor = bnrIceCream.ReadString(); SelectedContainer = bnrIceCream.ReadString(); SelectedIngredient = bnrIceCream.ReadString(); Scoops = bnrIceCream.ReadInt32(); TotalPrice = bnrIceCream.ReadDecimal(); // And display it to the user Console.WriteLine("\n=-= Ice Cream Vending Machine =-

=");

Console.WriteLine(" Previous Order: {0}",

strFilename);

Console.WriteLine("Flavor:

{0}",

Console.WriteLine("Container:

{0}",

Console.WriteLine("Ingredient:

{0}",

SelectedFlavor); SelectedContainer); SelectedIngredient);

Console.WriteLine("Scoops: {0}", Scoops); Console.WriteLine("Total Price: {0:C}\n",

TotalPrice); } else

Console.WriteLine("The name you entered is not " + "registered in our previous orders");

} }

} finally { bnrIceCream.Close(); stmIceCream.Close(); }

}

8. Access the Program.cs file and change it as follows: using System; using System.Collections.Generic; using System.Linq;

C# 3.0 Practical Learning

873

using System.Text; namespace IceCream4 { public class Program { static void Main(string[] args) { var answer = 'n'; var ic = new IceCream(); var process = new Request(ic.ProcessAnOrder); Console.Write("Do you want to re-order a previously " + "saved order(y/n)? "); answer = char.Parse(Console.ReadLine()); if (answer == 'y' || answer == 'Y') ic.OpenOrder(); else { process(); Console.Write("Do you want us to remember this " + "order the next time you come to " + "get your Ice Cream (y/n)? "); answer = char.Parse(Console.ReadLine()); if (answer == 'y' || answer == 'Y') ic.SaveOrder(); else Console.WriteLine("\nIt was nice serving you." + "\nCome Again!!!\n"); } }

}

}

9. Execute the application and test it. Here is an example: Do you want to re-order a previously saved order(y/n)? n =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Vending Machine ----------------------------------What type of flavor do you want? 1 - Vanilla 2 - Cream of Cocoa 3 - Chocolate Chip 4 - Organic Strawberry 5 - Butter Pecan 6 - Cherry Coke 7 - Chocolate Brownies 8 - Caramel Au Lait 9 - Chunky Butter 10 - Chocolate Cookie Your Choice? 6 ----------------------------------What type of container do you want? 1 - Cone 2 - Cup 3 - Bowl Your Choice? 2

C# 3.0 Practical Learning

874

----------------------------------Do you want an ingredient or not 1 - No Ingredient 2 - Peanuts 3 - M & M 4 - Cookies Your Choice? 1 ----------------------------------How many scoops(1, 2, or 3)? 2 ----------------------------------=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Ice Cream Order ----------------------------------Flavor: Cherry Coke Container: Cup Ingredient: No Ingredient Scoops: 2 Total Price: $2.60 =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Do you want us to remember this order the next time you come to get your Ice Cream (y/n)? n It was nice serving you. Come Again!!! Press any key to continue . . .

10.

Close the DOS window

11. Execute the application and test it. Indicate that you want to open an existing file 12. Enter a wrong file name such as Q4 and press Enter

Click Don't Send. Here is an example: C# 3.0 Practical Learning

875

Do you want to re-order a previously saved order(y/n)? y Please enter the name you previously gave to remember your order: Q4 Unhandled Exception: System.IO.FileNotFoundException: Could not find file 'C:\Do cuments and Settings\Administrator\My Documents\Visual Studio 2008\Projects\Vend ingMachine4\IceCream4\bin\Release\Q4.icr'. File name: 'C:\Documents and Settings\Administrator\My Documents\Visual Studio 2 008\Projects\VendingMachine4\IceCream4\bin\Release\Q4.icr' at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, I nt32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions o ptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) at System.IO.FileStream..ctor(String path, FileMode mode) at IceCream4.IceCream.OpenOrder() in C:\Documents and Settings\Administrator\ My Documents\Visual Studio 2008\Projects\VendingMachine4\IceCream4\IceCream.cs:l ine 362 at IceCream4.Program.Main(String[] args) in C:\Documents and Settings\Adminis trator\My Documents\Visual Studio 2008\Projects\VendingMachine4\IceCream4\Progra m.cs:line 21 Press any key to continue . . .

13.

Close the DOS window

.NET Framework Exception Handling for File Processing In the previous lesson as our introduction to file processing, we behaved as if everything was alright. Unfortunately, file processing can be very strict in its assignments. Based on this, the .NET Framework provides various Exceptionoriented classes to deal with almost any type of exception you can think of. One of the most important aspects of file processing is the name of the file that will be dealt with. In some cases you can provide this name to the application or document. In some other cases, you would let the user specify the name of the path. Regardless of how the name of the file would be provided to the operating system, when this name is acted upon, the compiler is asked to work on the file. If the file doesn't exist, the operation cannot be carried. Furthermore, the compiler would throw an error. There are many other exceptions that can be thrown as a result of something going bad during file processing: FileNotFoundException: The exception thrown when a file has not been found is of type FileNotFoundException. Here is an example of handling it: using System; using System.IO; public class Program {

C# 3.0 Practical Learning

876

/*

static int Main(string[] args) { var Filename = "Members.clb"; var fstPersons = new FileStream(Filename, FileMode.Create); var wrtPersons = new BinaryWriter(fstPersons); try { wrtPersons.Write("James Bloch"); wrtPersons.Write("Catherina Wallace"); wrtPersons.Write("Bruce Lamont"); wrtPersons.Write("Douglas Truth"); } finally { wrtPersons.Close(); fstPersons.Close(); }*/ var strLine = ""; var Filename = "Members.clc"; try {

var fstMembers = new FileStream(Filename, FileMode.Open); var rdrMembers = new BinaryReader(fstMembers); try {

strLine = rdrMembers.ReadString(); Console.WriteLine(strLine); strLine = rdrMembers.ReadString(); Console.WriteLine(strLine); strLine = rdrMembers.ReadString(); Console.WriteLine(strLine); strLine = rdrMembers.ReadString(); Console.WriteLine(strLine);

} finally { rdrMembers.Close(); fstMembers.Close(); }

} catch (FileNotFoundException ex) { Console.Write("Error: " + ex.Message); Console.WriteLine(" May be the file doesn't exist " + "or you typed it wrong!"); } return 0; }

}

Here is an example of what this would produce: C# 3.0 Practical Learning

877

Error: Could not find file 'C:\Documents and Settings\Administrator\Local Settings\Application Data\Temporary Projects\ConsoleApplication1\bin\Release\Members.clc'. May be the file doesn't exist or you typed it wrong! Press any key to continue . . . IOException: As mentioned already, during file processing, anything could go

wrong. If you don't know what caused an error, you can throw the IOException exception.

Practical Learning: Handling File Processing Exceptions 1. To throw exceptions, change the file processing methods from the IceCream.cs file as follows: using using using using using

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

namespace IceCream4 { delegate void Request(); // This class is used to create and manage an Ice Cream // and to process an order public sealed class IceCream { // This is the base price of an Ice Cream // Optional values may be added to it public const decimal BasePrice = 1.55M; // These arrays are used to build the components // of various Ice Creams // In C#, we can allocate an array's memory in // the body of the class private string[] Flavor; private string[] Container; private string[] Ingredient; // Additional factor used to process an Ice Cream order private int Scoops; private decimal TotalPrice; // Variables that will hold the user's choice // These are declared "globally" so they can be // shared among methods int ChoiceFlavor; int ChoiceContainer; int ChoiceIngredient; // This default constructor is the best place for // us to initialize the array public IceCream() { Flavor = new string[10];

C# 3.0 Practical Learning

878

Flavor[0] Flavor[1] Flavor[2] Flavor[3] Flavor[4] Flavor[5] Flavor[6] Flavor[7] Flavor[8] Flavor[9]

= = = = = = = = = =

"Vanilla"; "Cream of Cocoa"; "Chocolate Chip"; "Organic Strawberry"; "Butter Pecan"; "Cherry Coke"; "Chocolate Brownies"; "Caramel Au Lait"; "Chunky Butter"; "Chocolate Cookie";

Ingredient = new string[4]; Ingredient[0] = "No Ingredient"; Ingredient[1] = "Peanuts"; Ingredient[2] = "M & M"; Ingredient[3] = "Cookies"; Container = new string[3]; Container[0] = "Cone"; Container[1] = "Cup"; Container[2] = "Bowl"; } // This method requests a flavor from the user and // returns the choice internal void ChooseFlavor() { // Make sure the user selects a valid number //that represents a flavor... do { // In case the user types a symbol that // is not a number try { Console.WriteLine("What type of flavor do you

want?");

for (int i = 0; i < Flavor.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Flavor[i]); Console.Write("Your Choice? "); ChoiceFlavor = int.Parse(Console.ReadLine()); } catch (FormatException) message

// display an appropriate

{ Console.WriteLine("You must enter a valid number " + "and no other character!"); } // // // if

If the user typed an invalid number out of the allowed range let him or her know and provide another chance (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length) Console.WriteLine("Invalid Choice - Try Again!\n"); } while (ChoiceFlavor < 1 || ChoiceFlavor > Flavor.Length); } // This method allows the user to select a container internal void ChooseContainer() {

C# 3.0 Practical Learning

879

// Make sure the user selects a valid number that // represents a container do { // If the user types a symbol that is not a number try { Console.WriteLine("What type of container do you

want?");

for (int i = 0; i < Container.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Container[i]);

Console.Write("Your Choice? "); ChoiceContainer = int.Parse(Console.ReadLine());

} catch (FormatException)

message

{ }

// display an appropriate

Console.WriteLine("You must enter a valid " + "number and no other character!");

// // // if

}

If the user typed an invalid number out of the allowed range let him or her know and provide another chance ((ChoiceContainer < 1) || (ChoiceContainer > Container.Length)) Console.WriteLine("Invalid Choice - Try Again!"); } while ((ChoiceContainer < 1) || (ChoiceContainer > Container.Length));

internal void ChooseIngredient() { do { try { Console.WriteLine("Do you want an ingredient or not");

for (int i = 0; i < Ingredient.Length; i++) Console.WriteLine("{0} - {1}", i + 1, Ingredient[i]); Console.Write("Your Choice? "); ChoiceIngredient = int.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("You must enter a valid " + "number and no other character!"); }

}

if ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient.Length)) Console.WriteLine("Invalid Choice - Try Again!"); } while ((ChoiceIngredient < 1) || (ChoiceIngredient > Ingredient.Length));

C# 3.0 Practical Learning

880

internal void SpecifyNumberOfScoops() { do { try { Console.Write("How many scoops(1, 2, or 3)? "); Scoops = int.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You must enter a valid number " + "and no other character!"); }

}

if (Scoops < 1 || Scoops > 3) Console.WriteLine("Invalid Choice - Try Again!"); } while (Scoops < 1 || Scoops > 3);

// This method is used to process a customer order // It uses the values of the above methods public void ProcessAnOrder() { // int ChoiceFlavor; // int ChoiceContainer; // int ChoiceIngredient; decimal PriceIngredient, PriceScoop; // Let the user know that this is a vending machine Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console.WriteLine("Ice Cream Vending Machine"); Console.WriteLine("-----------------------------------"); // Let the user select the components of the Ice Cream Request Get = new Request(ChooseFlavor); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(ChooseContainer); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(ChooseIngredient); Get(); Console.WriteLine("-----------------------------------"); Get = new Request(SpecifyNumberOfScoops); Get(); Console.WriteLine("-----------------------------------"); // If the user selects an ingredient instead of "No Ingredient",

// add $0.50 to the order if ((ChoiceIngredient == 2) || (ChoiceIngredient == 3) || (ChoiceIngredient == 4)) PriceIngredient = 0.50M; else PriceIngredient = 0.00M; // Instead of multiplying a number scoops to a value, // We will use an incremental value depending on

C# 3.0 Practical Learning

881

// the number of scoops if (Scoops == 1) PriceScoop = 0.65M; else if (Scoops == 2) PriceScoop = 1.05M; else PriceScoop = 1.55M; // Calculate the total price of the Ice Cream TotalPrice = BasePrice + PriceScoop + PriceIngredient; // Create the Ice Cream... // And display a receipt to the user DisplayReceipt(); } // This method is used to display a receipt to the user internal void DisplayReceipt() { Console.WriteLine("\n=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*="); Console.WriteLine("Ice Cream Order"); Console.WriteLine("-----------------------------------"); Console.WriteLine("Flavor: {0}", Flavor[ChoiceFlavor - 1]); Console.WriteLine("Container: {0}", Container[ChoiceContainer - 1]); Console.WriteLine("Ingredient: {0}", Ingredient[ChoiceIngredient - 1]); Console.WriteLine("Scoops: {0}", Scoops); Console.WriteLine("Total Price: {0:C}", TotalPrice); Console.WriteLine("=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\n"); } internal void SaveOrder() { string strFilename; Console.Write("Please enter your initials or the name " + "we will use to remember your order: "); strFilename = Console.ReadLine(); strFilename = strFilename + ".icr"; try { // Find out if the user entered a name of a file // that is already in the machine if (File.Exists(strFilename)) { char answer; FileStream stmIceCream = new FileStream(strFilename, FileMode.Create); BinaryWriter bnwIceCream = new BinaryWriter(stmIceCream); try { // If so, find out if the user wants to

C# 3.0 Practical Learning

882

already.");

// replace the old file Console.WriteLine("The file you entered exists Console.Write("Do you want to replace it(y/n)?"); answer = char.Parse(Console.ReadLine()); // If the customer wants to replace it... if (answer == 'y' || answer == 'Y') { // ... do so Console.WriteLine("The former order with the

same " +

"name will be replaced"); Console.WriteLine("\n=-= Ice Cream " + "Vending Machine =-="); Console.WriteLine(" Saving Order: {0}",

strFilename);

bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer -

1]);

bnwIceCream.Write(Ingredient[ChoiceIngredient

- 1]);

bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice); } // If the customer wants to save the new order with

the order

// a different name else if (answer == 'n' || answer == 'N') { // Ask the user to enter a name to remember Console.Write("Please enter a name we will

use " +

"to remember this order: "); strFilename = Console.ReadLine(); strFilename = strFilename + ".icr"; try {

BinaryWriter(stmIceCream);

stmIceCream = new FileStream(strFilename, FileMode.Create); bnwIceCream = new Console.WriteLine("\n=-= Ice Cream " + "Vending Machine =-="); Console.WriteLine(" Saving Order: {0}", strFilename); bnwIceCream.Write(Flavor[ChoiceFlavor -

1]); 1]); - 1]);

bnwIceCream.Write(Container[ChoiceContainer bnwIceCream.Write(Ingredient[ChoiceIngredient bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice);

} catch (IOException)

C# 3.0 Practical Learning

883

{ Console.Write("\nThe file you wanted us

to " +

"create exists already. "); Console.WriteLine("In case it was registered " + }

"by a different customer, " + "we will not delete it.");

} else Console.WriteLine("Invalid Answer - We will

close");

} catch (IOException) { Console.Write("\nThat file exists already. "); Console.WriteLine("We need to preserve it just in

" +

"case another customer will require

it.");

} finally { bnwIceCream.Close(); stmIceCream.Close(); } } else {

FileStream stmIceCream = new FileStream(strFilename, FileMode.Create); BinaryWriter bnwIceCream = new BinaryWriter(stmIceCream); try {

Machine =-="); strFilename);

Console.WriteLine("\n=-= Ice Cream Vending Console.WriteLine(" Saving Order: {0}", bnwIceCream.Write(Flavor[ChoiceFlavor - 1]); bnwIceCream.Write(Container[ChoiceContainer -

1]); 1]);

bnwIceCream.Write(Ingredient[ChoiceIngredient bnwIceCream.Write(Scoops); bnwIceCream.Write(TotalPrice);

} finally { bnwIceCream.Close(); stmIceCream.Close(); }

} } catch (IOException ex) { Console.WriteLine("\nError: " + ex.Message);

C# 3.0 Practical Learning

884

Console.WriteLine("Operation Canceled: The file you want " +

"to create exists already."); }

}

internal void OpenOrder() { string strFilename; string SelectedFlavor; string SelectedContainer; string SelectedIngredient; // Ask the user to enter a name of a previously saved order Console.Write("Please enter the name you previously " + "gave to remember your order: "); strFilename = Console.ReadLine(); strFilename = strFilename + ".icr"; try {

FileStream stmIceCream = new FileStream(strFilename, FileMode.Open); BinaryReader bnrIceCream = new BinaryReader(stmIceCream); try { // Find out if this order was previously saved in the

machine

if (File.Exists(strFilename)) { // If so, open it SelectedFlavor = bnrIceCream.ReadString(); SelectedContainer = bnrIceCream.ReadString(); SelectedIngredient = bnrIceCream.ReadString(); Scoops = bnrIceCream.ReadInt32(); TotalPrice = bnrIceCream.ReadDecimal(); // And display it to the user Console.WriteLine("\n=-= Ice Cream Vending

Machine =-=");

Console.WriteLine(" Previous Order: {0}",

strFilename);

Console.WriteLine("Flavor:

{0}",

Console.WriteLine("Container:

{0}",

Console.WriteLine("Ingredient:

{0}",

SelectedFlavor); SelectedContainer); SelectedIngredient);

Console.WriteLine("Scoops: {0}", Scoops); Console.WriteLine("Total Price: {0:C}\n", TotalPrice);

} else

Console.WriteLine("The name you entered is not "

+

"registered in our previous

orders");

C# 3.0 Practical Learning

885

} finally { bnrIceCream.Close(); stmIceCream.Close(); }

} catch (FileNotFoundException ex) { Console.Write("\nError: " + ex.Message); Console.WriteLine("It is unlikely that the file exists in " +

"our machine's register."); }

}

}

}

2. Exercise the application and test it 3. Close the DOS window

File Information Introduction In its high level of support for file processing, the .NET Framework provides the FileInfo class. This class is equipped to handle all types of file-related operations including creating, copying, moving, renaming, or deleting a file. FileInfo is based on the FileSystemInfo class that provides information on characteristics of a file.

Practical Learning: Introducing File Information 1. Start a new Console Application named WattsALoan2 2. To take advantage of the Visual Basic rich library, in the Solution Explorer, under WattsALoan2, right-click References and click Add Reference 3. In the Add Reference dialog box, click the .NET tab and click Microsoft.VisualBasic

C# 3.0 Practical Learning

886

4. Click OK 5. Change the Program.cs file as follows: using using using using using

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

namespace WattsALoan1 { public class Program { static int Main(string[] args) { string EmployerName, ApplicantName; string HomePhone, WorkPhone; double LoanAmount = 0.00D, InterestRate = 0.0D; double MonthlyPayment = 0.00D, Periods = 0D; Console.WriteLine(" -=- Car Loan Application -=-"); Console.WriteLine("Enter the following pieces " + "of information\n"); Console.WriteLine("Applicant Information"); Console.Write("Full Name: "); ApplicantName = Console.ReadLine(); Console.Write("Employer Name: "); EmployerName = Console.ReadLine(); Console.Write("Home Phone: "); HomePhone = Console.ReadLine(); Console.Write("Work Phone: "); WorkPhone = Console.ReadLine(); Console.WriteLine("Loan Estimation");

C# 3.0 Practical Learning

887

try { Console.Write("Amount of Loan: "); LoanAmount = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("Invalid Loan Amount"); } try { Console.Write("Interest Rate(0 to 100): "); InterestRate = double.Parse(Console.ReadLine()) / 100; } catch (FormatException) { Console.WriteLine("Invalid Interest Rate"); } try { Console.Write("Number of Months: "); Periods = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("Invalid Number of Months"); } try { MonthlyPayment = Microsoft.VisualBasic.Financial.Pmt(InterestRate / 12, Periods, -LoanAmount, 0, Microsoft.VisualBasic.DueDate.BegOfPeriod); } catch (ArgumentException) { Console.WriteLine("Some invalid values were provided\n"); } Console.WriteLine(); Console.WriteLine(" -=-=-=-=-=-=-=-=-=-=-=-=-=-="); Console.WriteLine(" -=- Car Loan Application -=-"); Console.WriteLine(" -=-=-=-=-=-=-=-=-=-=-=-=-=-="); Console.WriteLine("Applicant Information"); Console.WriteLine("Full Name: {0}", ApplicantName); Console.WriteLine("Employer Name: {0}", EmployerName); Console.WriteLine("Home Phone: {0}", HomePhone); Console.WriteLine("Work Phone: {0}", WorkPhone); Console.WriteLine("Loan Estimation"); Console.WriteLine("Loan Amount: {0:C}", LoanAmount); Console.WriteLine("Interest Rate: {0:P}", InterestRate); Console.WriteLine("Number of Months: {0:F}", Periods); Console.WriteLine("Monthly Payment: {0:C}\n", MonthlyPayment); } } }

C# 3.0 Practical Learning

888

6. Execute the application and test it. Here is an example: -=- Car Loan Application -=Enter the following pieces of information Applicant Information Full Name: James Watts Employer Name: Wattson Enterprises Home Phone: (202) 374-4738 Work Phone: (301) 894-4789 Loan Estimation Amount of Loan: 12500 Interest Rate(0 to 100): 10.25 Number of Months: 48 -=-=-=-=-=-=-=-=-=-=-=-=-=-= -=- Car Loan Application -=-=-=-=-=-=-=-=-=-=-=-=-=-=-= Applicant Information Full Name: James Watts Employer Name: Wattson Enterprises Home Phone: (202) 374-4738 Work Phone: (301) 894-4789 Loan Estimation Loan Amount: $12,500.00 Interest Rate: 10.25 % Number of Months: 48.00 Monthly Payment: $315.84 Press any key to continue...

7. Close the DOS window

File Initialization The FileInfo class is equipped with one constructor whose syntax is: public FileInfo(string fileName);

This constructor takes as argument the name of a file or its complete path. If you provide only the name of the file, the compiler would consider the same directory of its project. Here is an example: FileInfo fleMembers = new FileInfo("First.txt");

Alternatively, if you want, you can provide any valid directory you have access to. In this case, you should provide the complete path.

File Creation The FileInfo constructor is mostly meant only to indicate that you want to use a file, whether it exists already or it would be created. Based on this, if you execute an application that has only a FileInfo object created using the constructor as done above, nothing would happen.

C# 3.0 Practical Learning

889

To create a file, you have various alternatives. If you want to create one without writing anything in it, which implies creating an empty file, you can call the FileInfo.Create() method. Its syntax is: public FileStream Create();

This method simply creates an empty file. Here is an example of calling it: using System; using System.IO; public class Program { static int Main(string[] args) { var fleMembers = new FileInfo("First.txt"); fleMembers.Create(); return 0; }

}

The FileInfo.Create() method returns a FileStream object. You can use this returned value to write any type of value into the file, including text. If you want to create a file that contains text, an alternative is to call the FileInfo.CreateText() method. Its syntax is: public StreamWriter CreateText();

This method directly returns a StreamWriter object. You can use this returned object to write text to the file.

File Existence When you call the FileInfo.Create() or the FileInfo.CreateText() method, if the file passed as argument, or as the file in the path of the argument, exists already, it would be deleted and a new one would be created with the same name. This can cause the right file to be deleted. Therefore, before creating a file, you may need to check whether it exists already. To do this, you can check the value of the Boolean FileInfo.Exists property. This property holds a true value if the file exists already and it holds a false value if the file doesn't exist or it doesn't exist in the path. Here is an example of checking the existence of a file: using System; using System.IO; public class Program { static int Main(string[] args) { var fleMembers = new FileInfo("First.txt"); if (fleMembers.Exists == true) return 0; else fleMembers.Create();

C# 3.0 Practical Learning

890

}

return 0;

}

Writing to a File As mentioned earlier, the FileInfo.Create() method returns a FileStream object. You can use this to specify the type of operation that would be allowed on the file. To write normal text to a file, you can first call the FileInfo.CreateText() method. This method returns a StreamWriter object. The StreamWriter class is based on the TextWriter class that is equipped with the Write() and the WriteLine() methods used to write values to a file. The Write() method writes text on a line and keeps the caret on the same line. The WriteLine() method writes a line of text and moves the caret to the next line. After writing to a file, you should close the StreamWriter object to free the resources it was using during its operation(s).

Practical Learning: Writing to a File 1. To allow the user to create a new employee, change the file as follows: using using using using using

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

namespace WattsALoan2 { class Program { private static void CreateNewEmployee() { string employeeNumber, employeeName; FileInfo fleEmployees = new FileInfo("Employees.txt"); StreamWriter swrEmployees = fleEmployees.CreateText(); try { Console.WriteLine("Hiring New Employee"); Console.Write("Enter Employee Number as 00-000: "); employeeNumber = Console.ReadLine(); Console.Write("Enter Employee Name: "); employeeName = Console.ReadLine(); swrEmployees.WriteLine(employeeNumber); swrEmployees.WriteLine(employeeName); } finally

C# 3.0 Practical Learning

891

{ swrEmployees.Flush(); swrEmployees.Close(); }

}

static int Main(string[] args) { try { Console.Write("Do you want to hire a new " + "employee(0=No/1=Yes)? "); int answer = int.Parse(Console.ReadLine()); if (answer == 1) CreateNewEmployee();

} catch (FormatException) { Console.WriteLine("That was an invalid answer!\n"); } string string double double

EmployerName, ApplicantName; HomePhone, WorkPhone; LoanAmount = 0.00D, InterestRate = 0.0D; MonthlyPayment = 0.00D, Periods = 0D;

. . . No Change } }

return 0;

}

2. Execute the application. Here is an example: Do you want to hire a new employee(0=No/1=Yes)? 1 Hiring New Employee Enter Employee Number as 00-000: 44-228 Enter Employee Name: Johnny Olney

3. Close the DOS window

Appending to a File You may have created a text-based file and written to it. If you open such a file and find out that a piece of information is missing, you can add that information to the end of the file. To do this, you can call the FileInfo.AppenText() method. Its syntax is: public StreamWriter AppendText();

When calling this method, you can retrieve the StreamWriter object that it returns, then use that object to add new information to the file.

Practical Learning: Appending to a File C# 3.0 Practical Learning

892

1. To allow the user to add more employees to the file that holds their names, change the file as follows: using using using using using

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

namespace WattsALoan2 { public class Program { private static void CreateNewEmployee() { string employeeNumber, employeeName; FileInfo fleEmployees = new FileInfo("Employees.txt"); StreamWriter swrEmployees = null; // If the file exists already, then add the new employee to it

if (fleEmployees.Exists == true) swrEmployees = fleEmployees.AppendText(); else // Otherwise, create a new file swrEmployees = fleEmployees.CreateText(); try { Console.WriteLine("Hiring New Employee"); Console.Write("Enter Employee Number as 00-000: "); employeeNumber = Console.ReadLine(); Console.Write("Enter Employee Name: "); employeeName = Console.ReadLine(); swrEmployees.WriteLine(employeeNumber); swrEmployees.WriteLine(employeeName);

}

}

} finally { swrEmployees.Flush(); swrEmployees.Close(); }

static void Main(string[] args) { . . . No Change }

}

2. Execute the application 3. Type y to create an employee. Here is an example: Do you want to hire a new employee(0=No/1=Yes)? 1 Hiring New Employee

C# 3.0 Practical Learning

893

Enter Employee Number as 00-000: 72-604 Enter Employee Name: Ernest Barzan

4. Close the DOS window

C# 3.0 Practical Learning

894

Files Operations Routine Operations on Files Opening a File As opposed to creating a file, probably the second most regular operation performed on a file consists of opening it to read or explore its contents. To support opening a file, the FileInfo class is equipped with the Open() method that is overloaded with three versions. If you have a text-based file StreamReader class that is methods. As done for the object, make sure you close

and want to directly read from it, you can use the equipped with the Read() and the ReadLine() StreamWriter class, after using a StreamReader it.

Deleting a File If you have an existing file you don't need anymore, you can delete it. This operation can be performed by calling the FileInfo.Delete() method. Its syntax is: public override void Delete();

Here is an example: using System; using System.IO; public class Program { static int Main(string[] args) { var fleMembers = new FileInfo("First.txt"); if (fleMembers.Exists == true) fleMembers.Delete(); return 0; }

}

Copying a File C# 3.0 Practical Learning

895

You can make a copy of a file from one directory to another. To do this, you can call the FileInfo.CopyTo() method that is overloaded with two versions. The first version has the following syntax: public FileInfo CopyTo(string destFileName);

When calling this method, specify the path or directory that will be the destination of the copied file. Here is an example: using System; using System.IO; public class Program { static int Main(string[] args) { var fleMembers = new FileInfo("Reality.txt"); var strMyDocuments = Environment.GetFolderPath(Environment.SpecialFolder.Personal) ; if (fleMembers.Exists == true) fleMembers.CopyTo(string.Concat(strMyDocuments, "\\Federal.txt")); return 0; }

}

In this example, a file named Reality.txt in the directory of the project would be retrieved and its content would be applied to a new file named Federal.txt created in the My Documents folder of the current user. When calling the first version of the FileInfo.CopyTo() method, if the file exists already, the operation would not continue and you would simply receive a message box. If you insist, you can overwrite the target file. To do this, you can use the second version of this method. Its syntax is: public FileInfo CopyTo(string destFileName, bool overwrite);

The first argument is the same as that of the first version of the method. The second argument specifies what action to take if the file exists already in the target directory. If you want to overwrite it, pass the argument as true; otherwise, pass it as false.

Moving a File If you copy a file from one directory to another, you would have two copies of the same file or the same contents in two files. Instead of copying, if you want, you can simply move the file from one directory to another. This operation can be performed by calling the FileInfo.MoveTo() method. Its syntax is: public void MoveTo(string destFileName);

C# 3.0 Practical Learning

896

The argument to this method is the same as that of the CopyTo() method. After executing this method, the FileInfo object would be moved to the destFileName path. Here is an example: using System; using System.IO; public class Program { static int Main(string[] args) { var fleMembers = new FileInfo("pop.txt"); var strMyDocuments = Environment.GetFolderPath(Environment.SpecialFolder.Personal) ; if (fleMembers.Exists == true) fleMembers.MoveTo(string.Concat(strMyDocuments, "\\Federal.txt")); return 0; }

}

Characteristics of a File The Date and Time a File Was Created To keep track of it, after a file has been created, the operating system makes a note of the date and the time the file was created. This information can be valuable in other operations such as search routines. You too are allowed to change this date and time values to those you prefer. As mentioned already, the OS makes sure to keep track of the date and time a file was created. To find out what those date and time values are, you can access the FileSystemInfo.CreationTime property. This would be done as follows: using System; using System.IO; public class Program { static int Main(string[] args) { var SomeFile = new FileInfo("First.txt"); DateTime dteCreationTime = SomeFile.CreationTime; if (SomeFile.Exists == true) Console.WriteLine("Date and Time Created: " + dteCreationTime.ToString()); return 0;

C# 3.0 Practical Learning

897

} }

Of course, by entering the appropriate format in the parentheses of the ToString() method, you can get only either the date or only the time. If you don't like the date, the time, or both, that the OS would have set when the file was created, you can change them. To change one or both of these values, you can assign a desired DateTime object to the FileSystemInfo.set_CreationTime() property.

The Date and Time a File Was Last Accessed Many applications allow a user to open an existing file and to modify it. When people work in a team or when a particular file is regularly opened, at one particular time, you may want to know the date and time that the file was last accessed. To get this information, you can access the FileSystemInfo.LastAccessTime property. If you are interested to know the last date and time a file was modified, you can get the value of its FileSystemInfo.LastWriteTime property.

The Name of a File The operating system requires that each file have a name. In fact, the name must be specified when creating a file. This allows the OS to catalogue the computer files. This also allows you to locate or identify a particular file you need. When reviewing or opening a file, to get its name, the FileInfo class is equipped with the Name property. Here is an example: using System; using System.IO; public class Program { static int Main(string[] args) { var SomeFile = new FileInfo("Persons.spr"); if (SomeFile.Exists == true) Console.WriteLine("The name of this file is: \"" + SomeFile.Name + "\""); return 0; }

}

This string simply identifies a file.

The Extension of a File With the advent of Windows 95 and later, the user doesn't have to specify the extension of a file when creating it. Because of the type of confusion that this C# 3.0 Practical Learning

898

can lead to, most applications assist the user with this detail. Some applications allow the user to choose among various extensions. For example, using Notepad, a user can open a text, a PHP, a script, or an HTML file. When you access a file or when the user opens one, to know the extension of the file, you can access the value of the FileSystemInfo.Extension property. Here is an example: using System; using System.IO; public class Program { static int Main(string[] args) { var SomeFile = new FileInfo("Persons.spr"); if (SomeFile.Exists == true) Console.WriteLine("File Extension: " + SomeFile.Extension); }

return 0;

}

This would produce: File Extension: .spr Press any key to continue . . .

The Size of a File One of the routine operations the operating system performs consists of calculating the sizes of files it holds. This information is provided in terms of bits, kilobits, or kilobytes. To get the size of a file, the FileInfo class is quipped with the Length property. Here is an example of accessing it: using System; using System.IO; public class Program { static int Main(string[] args) { var SomeFile = new FileInfo("Persons.spr"); if (SomeFile.Exists == true) Console.WriteLine("File Size: " + SomeFile.Length.ToString()); }

return 0;

}

Here is an example of what this would produce: File Size: 57 Press any key to continue . . .

C# 3.0 Practical Learning

899

The Path to a File Besides the name of the file, it must be located somewhere. The location of a file is referred to as its path or directory. The FileInfo class represents this path as the DirectoryName property. Therefore, if a file has already been created, to get its path, you can access the value of the FileInfo.DirectoryName property. Besides the FileInfo.Directoryname, to know the full path to a file, you can access its FileSystemInfo.FullName property.

The Attributes of a File Attributes are characteristics that apply to a file, defining what can be done or must be disallowed on it. The Attributes are primarily defined by, and in, the operating system, mostly when a file is created. When the user accesses or opens a file, to get its attributes, you can access the value of its FileSystemInfo.Attributes property. This property produces a FileAttributes object. When you create or access a file, you can specify or change some of the attributes. To do this, you can a FileAttributes object and assign it to the FileSystemInfo.Attributes property. FileAttributes is an enumerator with the following members: Archive, Compressed, Device, Directory, Encrypted, Hidden, Normal, NotContentIndexed, Offline, ReadOnly, ReparsePoint, SparseFile, System, and Temporary.

Directories Introduction A directory is a section of a medium used to delimit a group of files. Because it is a "physical" area, it can handle operations not available on files. In fact, there are many fundamental differences between both: •

A file is used to contain data. A directory doesn't contain data



A directory can contain one or more files and not vice-versa



A directory can contain other directories



A file can be moved from one directory to another. This operation is not possible vice-versa since a file cannot contain a directory

The similarities of both types are: •

A directory or a file can be created. One of the restrictions is that two files cannot have the same name inside of the same directory. Two directories cannot have the same name inside of the same parent directory. C# 3.0 Practical Learning

900



A directory or a file can be renamed. If a directory is renamed, the "path" of its file(s) changes



A directory or a file can be deleted. If a directory is deleted, its files are deleted also



A directory or a file can be moved. If a directory moves, it "carries" all of its files to the new location



A directory or a file can be copied. A file can be copied from one directory to another. If a directory is copied to a new location, all of its files are also copied to the new location

Practical Learning: Introducing Directories 1. Start Microsoft Visual C# and create a Console Application named GeorgetownCleaningServices6

2. To create a new class, in the Solution Explorer, right-click GeorgetownCleaningServices6 -> Add -> Class... 3. Set the Name to Customer and click OK 4. Change the file as follows: using using using using

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

namespace GeorgetownCleaningServices6 { public class Customer { public string Name; public string PhoneNumber; } }

5. To create a new class, on the main menu, click Project -> Add Class... 6. Set the Name to CleaningOrderDetails and press Enter 7. Change the file as follows: using using using using

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

namespace GeorgetownCleaningServices6 { public sealed class CleaningOrderDetails { // The date the cleaning items were deposited public DateTime OrderDate;

C# 3.0 Practical Learning

901

public DateTime OrderTime; // Numbers to represent cleaning items public uint NumberOfShirts; public uint NumberOfPants; public uint NumberOtherItems; // Price of items public decimal PriceOneShirt = 0.95M; public decimal PriceAPairOfPants = 2.95M; public decimal PriceOtherItems = 4.55M; public decimal TaxRate = 0.0575M; // 5.75% // Each of these sub totals will be used for cleaning items public decimal SubTotalShirts; public decimal SubTotalPants; public decimal SubTotalOtherItems; // Values used public decimal public decimal public decimal }

to process an order TotalOrder; TaxAmount; SalesTotal;

}

8. To save the project, on the Standard toolbar, click the Save All button 9. Accept all the defaults and click Save

Directory Creation Before using a directory, you must first have it. You can use an existing directory if the operating system or someone else had already created one. You can also create a new directory. Directories are created and managed by various classes but the fundamental class is Directory. Directory is a static class, which means all of its methods are static, which means you will never need to declare an instance of the Directory class in order to use it. Besides the Directory class, additional operations of folders and sub-folders can be performed using the DirectoryInfo class. To create a directory, you can call the CreateDirectory() method of the Directory class. This method is available in two versions. One of the versions uses the following syntax: public static DirectoryInfo CreateDirectry(string path);

This method takes as argument the (complete) path of the desired directory. Here is an example: E:\Programs\Business Orders\Customer Information

When this method is called: 1. It first checks the parent drive, in this case E. If the drive doesn't exist, because this method cannot create a drive, the compiler would throw a DirectoryNotFoundException exception C# 3.0 Practical Learning

902

2. If the drive (in this case E) exists, the compiler moves to the first directory part of the path; in this case this would be the Programs folder in the E drive. If the folder doesn't exist, the compiler would create it. If that first director doesn't exist, this means that the other directory(ies), if any, under the first don't exist. So, the compiler would create it/them 3. If the first directory exists and if there is no other directory under that directory, the compiler would stop and would not do anything further. 4. If the directory exists and there is a sub-directory specified under it, the compiler would check the existence of that directory. If the sub-directory exists, the compiler would not do anything further and would stop. If the sub-directory doesn't exist, the compiler would create it 5. The compiler would repeat step 4 until the end of the specified path The Directory.CreateDirectory() method returns a DirectoryInfo object that you can use as you see fit.

Checking for a Directory Existence Before using or creating a directory, you can first check if it exists. This is because, if a directory already exists in the location where you want to create it, you would be prevented from creating one with the same name. In the same way, if you just decide to directly use a directory that doesn't exist, the operation you want to perform may fail because the directory would not be found. Before using or creating a directory, to first check whether it exists or not, you can call the Directory.Exists() Boolean method. Its syntax is: public static bool Exists(string path);

This method receives the (complete) path of the directory. If the path exists, the method returns true. If the directory doesn't exist, the method returns false. To create a directory, you can call the CreateDirectory() method of the Directory class.

Locating a File One of the most routine operations performed in a directory consists of looking for a file. Both Microsoft Windows operating systems and the user's intuition have different ways of addressing this issue. The .NET Framework also provides its own means of performing this operation, through various techniques. You can start by checking the sub-directories and files inside of a main directory. To look for files in a directory, the DirectoryInfo class can assist you with its GetFiles() method, which is overloaded with three versions.

Practical Learning: Using Directories and Files C# 3.0 Practical Learning

903

1. To create a new class, in the Class View, right-click GeorgetownCleaningOrder6 -> Add -> Class... 2. Set the Name to CleaningDeposit and press Enter 3. Change the file as follows: using using using using using

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

namespace GeorgetownCleaningServices6 { public abstract class CustomerOrder { public abstract void ProcessOrder(); public abstract void ShowReceipt(); } public class CleaningDeposit : CustomerOrder { private Customer custInfo; public CleaningOrderDetails depot; private decimal AmountTended; private decimal Difference; public CleaningDeposit() { this.custInfo = new Customer(); this.depot = new CleaningOrderDetails(); } private Customer IdentifyCustomer() { string strCustomerName; string strTelephoneNumber, strPhoneFormatted; Console.Write("Enter Customer Phone Number: "); strTelephoneNumber = Console.ReadLine();

+ +

// Remove the spaces, parentheses, if any, and dashes, if any strTelephoneNumber = strTelephoneNumber.Replace(" ", ""); strTelephoneNumber = strTelephoneNumber.Replace("(", ""); strTelephoneNumber = strTelephoneNumber.Replace(")", ""); strTelephoneNumber = strTelephoneNumber.Replace("-", ""); if (strTelephoneNumber.Length != 10) { Console.WriteLine("Invalid telphone number: {0} " + "characters instead of 10 digits", strTelephoneNumber.Length); return null; } strPhoneFormatted = "(" + strTelephoneNumber.Substring(0, 3) ") " + strTelephoneNumber.Substring(3, 3)

C# 3.0 Practical Learning

904

"-" + strTelephoneNumber.Substring(6, 4); string strFilename = strTelephoneNumber + @".gcs"; string strPath = @"C:\Georgetown Cleaning Services\Customers\" + @"\" + strFilename; if (File.Exists(strPath)) { FileStream stmCustomer = File.Open(strPath, FileMode.Open, FileAccess.Read); BinaryReader bnrCustomer = new BinaryReader(stmCustomer); custInfo.Name = bnrCustomer.ReadString(); custInfo.PhoneNumber = bnrCustomer.ReadString(); Console.WriteLine("\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-");

Console.WriteLine("-/- Georgetown Cleaning Services

-/-");

Console.WriteLine("------------------------------------")

;

Console.WriteLine("Customer Name: {0}", custInfo.Name); Console.WriteLine("Phone Number: {0}", custInfo.PhoneNumber); Console.WriteLine("------------------------------------\n "); } else // If the customer information was not found in a file { Console.WriteLine("It looks like this is the first time you " + "are trusting us with your cleaning order"); Directory.CreateDirectory(@"C:\Georgetown Cleaning Services\Customers"); FileStream stmCustomer = File.Create(strPath); BinaryWriter bnwCustomer = new BinaryWriter(stmCustomer); Console.Write("Enter Customer Name: "); strCustomerName = Console.ReadLine(); bnwCustomer.Write(strCustomerName); bnwCustomer.Write(strPhoneFormatted); custInfo.Name = strCustomerName; custInfo.PhoneNumber = strTelephoneNumber; } }

return custInfo;

public override void ProcessOrder() { Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Customer client = this.IdentifyCustomer(); try { Console.Write("Enter the order date(mm/dd/yyyy): this.depot.OrderDate = DateTime.Parse(Console.ReadLine());

C# 3.0 Practical Learning

");

905

date");

} catch (FormatException) { Console.WriteLine("The value you entered is not a valid } try {

Console.Write("Enter the order time(hh:mm AM/PM): "); this.depot.OrderTime = DateTime.Parse(Console.ReadLine()); } catch { Console.WriteLine("The value you entered is not a valid time"); } // Request the quantity of each category of items try { Console.Write("Number of Shirts: "); this.depot.NumberOfShirts = uint.Parse(Console.ReadLine()); if (this.depot.NumberOfShirts < uint.MinValue) throw new OverflowException("Negative value not " + "allowed for shirts"); } catch (FormatException) { Console.WriteLine("The value you typed for the number of " +

"shirts is not a valid number"); } try {

Console.Write("Number of Pants: this.depot.NumberOfPants = uint.Parse(Console.ReadLine());

");

} catch (FormatException) { Console.WriteLine("The value you typed for the number of " +

"pair or pants is not a valid number"); } try {

Console.Write("Number of Other Items: "); this.depot.NumberOtherItems = uint.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("The value you typed for the number of " + "other items is not a valid number"); } // Perform the necessary calculations this.depot.SubTotalShirts =

C# 3.0 Practical Learning

906

this.depot.NumberOfShirts * this.depot.PriceOneShirt; this.depot.SubTotalPants = this.depot.NumberOfPants * this.depot.PriceAPairOfPants; this.depot.SubTotalOtherItems = this.depot.NumberOtherItems * this.depot.PriceOtherItems; // Calculate the "temporary" total of the order this.depot.TotalOrder = this.depot.SubTotalShirts + this.depot.SubTotalPants + this.depot.SubTotalOtherItems; // Calculate the tax amount using a constant rate this.depot.TaxAmount = this.depot.TotalOrder * this.depot.TaxRate; // Add the tax amount to the total order this.depot.SalesTotal = this.depot.TotalOrder + this.depot.TaxAmount; // Communicate the total to the user... Console.WriteLine("\nThe Total order is: {0:C}", this.depot.SalesTotal); // and request money for the order try { Console.Write("Amount Tended? "); AmountTended = decimal.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You were asked to enter an " + "amount of money but..."); } // Calculate the difference owed to the customer // or that the customer still owes to the store Difference = AmountTended - this.depot.SalesTotal; this.ShowReceipt(); this.Save(); } public override void ShowReceipt() { Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.WriteLine("Customer: {0}", this.custInfo.Name); Console.WriteLine("Home Phone: {0}", this.custInfo.PhoneNumber); Console.WriteLine("Order Date: {0:D}", this.depot.OrderDate); Console.WriteLine("Order Time: {0:t}", this.depot.OrderTime); Console.WriteLine("------------------------------------"); Console.WriteLine("Item Type Qty Unit/Price Sub-Total"); Console.WriteLine("------------------------------------"); Console.WriteLine("Shirts {0,3} {1,4} {2,6}", this.depot.NumberOfShirts, this.depot.PriceOneShirt, this.depot.SubTotalShirts);

C# 3.0 Practical Learning

907

Console.WriteLine("Pants {0,3} {1,4} {2,6}", this.depot.NumberOfPants, this.depot.PriceAPairOfPants, this.depot.SubTotalPants); Console.WriteLine("Other Items {0,3} {1,4} {2,6}", this.depot.NumberOtherItems, this.depot.PriceOtherItems, this.depot.SubTotalOtherItems); Console.WriteLine("------------------------------------"); Console.WriteLine("Total Order: {0,6}", this.depot.TotalOrder.ToString("C")); Console.WriteLine("Tax Rate: {0,6}", this.depot.TaxRate.ToString("P")); Console.WriteLine("Tax Amount: {0,6}", this.depot.TaxAmount.ToString("C")); Console.WriteLine("Net Price: {0,6}", this.depot.SalesTotal.ToString("C")); Console.WriteLine("------------------------------------"); Console.WriteLine("Amount Tended: {0,6}", AmountTended.ToString("C")); Console.WriteLine("Difference: {0,6}", Difference.ToString("C")); Console.WriteLine("===================================="); } public virtual void Save() { string strPhoneNumber = this.custInfo.PhoneNumber; // Remove the spaces, parentheses, and dashes strPhoneNumber = strPhoneNumber.Replace(" ", ""); strPhoneNumber = strPhoneNumber.Replace("(", ""); strPhoneNumber = strPhoneNumber.Replace(")", ""); strPhoneNumber = strPhoneNumber.Replace("-", ""); string strMonth = depot.OrderDate.Month.ToString(); if (depot.OrderDate.Month < 10) strMonth = "0" + strMonth; string strDay = depot.OrderDate.Day.ToString(); if (depot.OrderDate.Day < 10) strDay = "0" + strDay; string strYear = depot.OrderDate.Year.ToString(); string strFilename = strMonth + strDay + strYear + @".gcs"; Orders\" +

string strPath = @"C:\Georgetown Cleaning Services\Cleaning @"\" + strPhoneNumber + @"\" + strFilename;

Directory.CreateDirectory(@"C:\Georgetown Cleaning Services\Cleaning Orders\" + strPhoneNumber); FileStream stmCleaningOrder = File.Create(strPath); BinaryWriter bnwCleaningOrder = new BinaryWriter(stmCleaningOrder); bnwCleaningOrder.Write(this.custInfo.Name);

C# 3.0 Practical Learning

908

bnwCleaningOrder.Write(this.custInfo.PhoneNumber); bnwCleaningOrder.Write(this.depot.OrderDate.ToString()); bnwCleaningOrder.Write(this.depot.OrderTime.ToString()); bnwCleaningOrder.Write(this.depot.NumberOfShirts.ToString()); bnwCleaningOrder.Write(this.depot.NumberOfPants.ToString()); bnwCleaningOrder.Write(this.depot.NumberOtherItems.ToString()

);

bnwCleaningOrder.Write(this.depot.PriceOneShirt.ToString()); bnwCleaningOrder.Write(this.depot.PriceAPairOfPants.ToString( ));

bnwCleaningOrder.Write(this.depot.PriceOtherItems.ToString())

;

bnwCleaningOrder.Write(this.depot.TaxRate.ToString()); bnwCleaningOrder.Write(this.depot.SubTotalShirts.ToString()); bnwCleaningOrder.Write(this.depot.SubTotalPants.ToString()); bnwCleaningOrder.Write(this.depot.SubTotalOtherItems.ToString

());

} }

bnwCleaningOrder.Write(this.depot.TotalOrder.ToString()); bnwCleaningOrder.Write(this.depot.TaxAmount.ToString()); bnwCleaningOrder.Write(this.depot.SalesTotal.ToString());

}

4. To create a new class, in the Solution Explorer, right- click GeorgetownCleaningOrder6 -> Add -> Class... 5. Set the Name to CleaningRetrieval and press Enter 6. Change the file as follows: using using using using using

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

namespace GeorgetownCleaningServices6 { public class CleaningRetrieval { private Customer custInfo; private CleaningOrderDetails depot; private string strPhoneNumber; public CleaningRetrieval() { this.custInfo = new Customer(); this.depot = new CleaningOrderDetails(); } public virtual void Open() { Console.Write("Enter Receipt Number: "); string strFilename = Console.ReadLine(); string strPath = @"C:\Georgetown Cleaning Services\Cleaning Orders\" +

C# 3.0 Practical Learning

909

@"\" + strFilename + @"\" + strFilename + ".gcs"; DirectoryInfo di = new DirectoryInfo(@"C:\Georgetown Cleaning Services\Cleaning Orders");

FileInfo[] aryFiles = di.GetFiles("*", SearchOption.AllDirectories); string strFileFullname = ""; bool found = false; foreach (FileInfo fle in aryFiles) { if (fle.Name == (strFilename + ".gcs")) { found = true; strFileFullname = fle.FullName; } } if (found == true) { FileStream stmCleaningOrder = File.Open(strFileFullname, FileMode.Open, FileAccess.Read); BinaryReader bnrCleaningOrder = new BinaryReader(stmCleaningOrder); this.custInfo.Name = bnrCleaningOrder.ReadString(); this.custInfo.PhoneNumber = bnrCleaningOrder.ReadString(); this.depot.OrderDate = DateTime.Parse(bnrCleaningOrder.ReadString()); this.depot.OrderTime = DateTime.Parse(bnrCleaningOrder.ReadString()); this.depot.NumberOfShirts = uint.Parse(bnrCleaningOrder.ReadString()); this.depot.NumberOfPants = uint.Parse(bnrCleaningOrder.ReadString()); this.depot.NumberOtherItems = uint.Parse(bnrCleaningOrder.ReadString()); this.depot.PriceOneShirt = decimal.Parse(bnrCleaningOrder.ReadString()); this.depot.PriceAPairOfPants = decimal.Parse(bnrCleaningOrder.ReadString()); this.depot.PriceOtherItems = decimal.Parse(bnrCleaningOrder.ReadString()); this.depot.TaxRate = decimal.Parse(bnrCleaningOrder.ReadString()); this.depot.SubTotalShirts = decimal.Parse(bnrCleaningOrder.ReadString()); this.depot.SubTotalPants = decimal.Parse(bnrCleaningOrder.ReadString()); this.depot.SubTotalOtherItems = decimal.Parse(bnrCleaningOrder.ReadString()); this.depot.TotalOrder = decimal.Parse(bnrCleaningOrder.ReadString()); this.depot.TaxAmount = decimal.Parse(bnrCleaningOrder.ReadString());

C# 3.0 Practical Learning

910

this.depot.SalesTotal = decimal.Parse(bnrCleaningOrder.ReadString()); this.strPhoneNumber = "(" + this.custInfo.PhoneNumber.Substring(0, 3) +

") " + this.custInfo.PhoneNumber.Substring(3,

3) +

"-" + this.custInfo.PhoneNumber.Substring(6, 4);

this.ShowReceipt(); } else Console.WriteLine("No cleaning order of " + "that receipt number was found"); }

internal void ShowReceipt() { Console.WriteLine(); // Display the receipt Console.WriteLine("===================================="); Console.WriteLine("-/- Georgetown Cleaning Services -/-"); Console.WriteLine("===================================="); Console.WriteLine("Customer: {0}", this.custInfo.Name); Console.WriteLine("Home Phone: {0}", this.custInfo.PhoneNumber); Console.WriteLine("Order Date: {0:D}", this.depot.OrderDate); Console.WriteLine("Order Time: {0:t}", this.depot.OrderTime); Console.WriteLine("------------------------------------"); Console.WriteLine("Item Type Qty Unit/Price Sub-Total"); Console.WriteLine("------------------------------------"); Console.WriteLine("Shirts {0,3} {1,4} {2,6}", this.depot.NumberOfShirts, this.depot.PriceOneShirt, this.depot.SubTotalShirts); Console.WriteLine("Pants {0,3} {1,4} {2,6}", this.depot.NumberOfPants, this.depot.PriceAPairOfPants, this.depot.SubTotalPants); Console.WriteLine("Other Items {0,3} {1,4} {2,6}", this.depot.NumberOtherItems, this.depot.PriceOtherItems, this.depot.SubTotalOtherItems); Console.WriteLine("------------------------------------"); Console.WriteLine("Total Order: {0,6}", this.depot.TotalOrder.ToString("C")); Console.WriteLine("Tax Rate: {0,6}", this.depot.TaxRate.ToString("P")); Console.WriteLine("Tax Amount: {0,6}", this.depot.TaxAmount.ToString("C")); Console.WriteLine("Net Price: {0,6}", this.depot.SalesTotal.ToString("C")); Console.WriteLine("===================================="); } }

C# 3.0 Practical Learning

911

}

7. Access the Program.cs file and change it as follows: using using using using

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

namespace GeorgetownCleaningServices6 { public class Program { static void Main(string[] args) { char answer = 'q'; Console.WriteLine("Is this a new order or the customer is " + "retrieving items previously left for

cleaning?");

Console.WriteLine("0. Quit"); Console.WriteLine("1. This is a new order"); Console.WriteLine("2. The customer is retrieving an existing

order");

Console.Write("Your Choice: "); answer = char.Parse(Console.ReadLine()); switch (answer) { case '1': CleaningDeposit depotOrder = new CleaningDeposit(); depotOrder.ProcessOrder(); break; case '2': CleaningRetrieval previousOrder = new CleaningRetrieval(); previousOrder.Open(); break; default: break; } } }

Console.WriteLine();

}

8. Execute the application and test it. Here is an example: Is this a new order or the customer is retrieving items previously left for cleaning? 0. Quit 1. This is a new order 2. The customer is retrieving an existing order Your Choice: 0

C# 3.0 Practical Learning

912

Press any key to continue . . .

9. Close the DOS window 10. Execute the application and create a new order. Here is an example: Is this a new order or the customer is retrieving items previously left for cleaning? 0. Quit 1. This is a new order 2. The customer is retrieving an existing order Your Choice: 1 -/- Georgetown Cleaning Services -/Enter Customer Phone Number: 202 103 0443 It looks like this is the first time you are trusting us with your cleaning order Enter Customer Name: Arsene Cranston Enter the order date(mm/dd/yyyy): 11/20/2006 Enter the order time(hh:mm AM/PM): 08:12 AM Number of Shirts: 6 Number of Pants: 4 Number of Other Items: 2 The Total order is: $28.13 Amount Tended? 30 ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Arsene Cranston Home Phone: 2021030443 Order Date: Monday, November 20, 2006 Order Time: 8:12 AM -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 6 0.95 5.70 Pants 4 2.95 11.80 Other Items 2 4.55 9.10 -----------------------------------Total Order: $26.60 Tax Rate: 5.75 % Tax Amount: $1.53 Net Price: $28.13 -----------------------------------Amount Tended: $30.00 Difference: $1.87 ==================================== Press any key to continue . . .

11.

Remember the date you provided and close the DOS window

12. Execute the application and create a new order. Here is an example: Is this a new order or the customer is retrieving items previously left for cleaning? 0. Quit

C# 3.0 Practical Learning

913

1. This is a new order 2. The customer is retrieving an existing order Your Choice: 1 -/- Georgetown Cleaning Services -/Enter Customer Phone Number: 301-022-1077 It looks like this is the first time you are trusting us with your cleaning order Enter Customer Name: Helene Craft Enter the order date(mm/dd/yyyy): 11/21/2006 Enter the order time(hh:mm AM/PM): 9:25 Number of Shirts: 3 Number of Pants: 0 Number of Other Items: 5 The Total order is: $27.07 Amount Tended? 40 ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Helene Craft Home Phone: 3010221077 Order Date: Tuesday, November 21, 2006 Order Time: 9:25 AM -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 3 0.95 2.85 Pants 0 2.95 0.00 Other Items 5 4.55 22.75 -----------------------------------Total Order: $25.60 Tax Rate: 5.75 % Tax Amount: $1.47 Net Price: $27.07 -----------------------------------Amount Tended: $40.00 Difference: $12.93 ==================================== Press any key to continue . . .

13.

Remember the date you provided and close the DOS window

14. Execute the application and choose to open an existing order. Here is an example: Is this a new order or the customer is retrieving items previously left for cleaning? 0. Quit 1. This is a new order 2. The customer is retrieving an existing order Your Choice: 2 Enter Receipt Number: 11202006 ==================================== -/- Georgetown Cleaning Services -/==================================== Customer: Arsene Cranston

C# 3.0 Practical Learning

914

Home Phone: 2021030443 Order Date: Monday, November 20, 2006 Order Time: 8:12 AM -----------------------------------Item Type Qty Unit/Price Sub-Total -----------------------------------Shirts 6 0.95 5.70 Pants 4 2.95 11.80 Other Items 2 4.55 9.10 -----------------------------------Total Order: $26.60 Tax Rate: 5.75 % Tax Amount: $1.53 Net Price: $28.13 ==================================== Press any key to continue . . .

15.

Close the DOS window

C# 3.0 Practical Learning

915

Serialization Object Serialization and De-Serialization Introduction Consider the following program: using System; using using using using

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

public class Exercise

{ static int Main(string[] args) { var Make = "Ford"; var Model = "Escort"; var Year = 1998; var Color

= 1;

var stmCar = new FileStream("Car1.car", FileMode.Create); var bnwCar = new BinaryWriter(stmCar); try { bnwCar.Write(Make); bnwCar.Write(Model); bnwCar.Write(Year); bnwCar.Write(Color); } finally { bnwCar.Close(); stmCar.Close(); } return 0; }

}

This is an example of the techniques we have used in previous lessons to save individual data of primitive types: C# 3.0 Practical Learning

916

The values can be retrieved with the following code: using using using using using

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

public class Exercise { static int Main(string[] args) { var stmCar = new FileStream("Car1.car", FileMode.Open); var bnrCar = new BinaryReader(stmCar); try { Console.WriteLine("Make: {0}", bnrCar.ReadString()); Console.WriteLine("Model: {0}", bnrCar.ReadString()); Console.WriteLine("Year: {0}", bnrCar.ReadUInt32()); Console.Write("Color: "); byte clr = bnrCar.ReadByte(); switch (clr) { case 1: Console.WriteLine("Black"); break; case 2: Console.WriteLine("Gray"); break; case 3: Console.WriteLine("White"); break; case 4: Console.WriteLine("Red"); break; case 5: Console.WriteLine("Blue"); break; }

} finally { bnrCar.Close(); stmCar.Close(); } }

return 0;

}

C# 3.0 Practical Learning

917

This would produce: Make: Ford Model: Escort Year: 1998 Color: Black Press any key to continue . . .

In the same way, we learned to save the individual fields of a class:

Here is an example: using System; using System.IO; public class Car { public string public string public uint public byte }

Make Model Year Color

= = = =

"Toyota"; "Corolla"; 2002; 2;

public class Exercise { static int Main(string[] args) { var vehicle = new Car(); var stmCar = File.Create("Car2.car"); var bnwCar = new BinaryWriter(stmCar); try { bnwCar.Write(vehicle.Model); bnwCar.Write(vehicle.Year); bnwCar.Write(vehicle.Color);

} finally { bnwCar.Close(); stmCar.Close(); } return 0;

C# 3.0 Practical Learning

918

} }

When it comes to a class, the problem with saving individual fields is that you could forget to save one of the fields. For example, considering a Car class, if you don't save the Make information of a Car object and retrieve or open the saved object on another computer, the receiving user would miss some information and the car cannot be completely identifiable. An alternative is to save the whole Car object. Object serialization consists of saving a whole object as one instead of its individual fields:

In other words, a variable declared from a class can be saved to a stream and then the saved object can be retrieved later or on another computer. The .NET Framework supports two types of object serialization: binary and SOAP.

Practical Learning: Introducing Serialization 1. Start Microsoft Visual C# and create a Console Application named GeorgetownCleaningServices7

2. To save the project, on the Standard toolbar, click the Save All button 3. Accept all the defaults and click Save 4. To create a new class, in the Solution Explorer, right-click GeorgetownCleaningServices7 -> Add -> Class... 5. Set the Name to BusinessManagement and press Enter 6. Change the file as follows: using using using using using

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

namespace GeorgetownCleaningServices7 {

C# 3.0 Practical Learning

919

public static class BusinessManagement { public static void HireEmployee() { FileStream fsEmployee = null; BinaryWriter bwEmployee = null; // Ask the clerk to enter an employee number // using the format 00-000 Console.Write("Enter Employee Number (00-000): "); string emplNumber = Console.ReadLine(); string strPath = @"C:\Georgetown Cleaning Services\Employees\" + @"\" + emplNumber + ".gce"; if (File.Exists(strPath)) { Console.Write("\nEither the employee has already been hired, ");

Console.WriteLine("or there is already another " + "employee with that number."); return; } else // If no employee with that number was found, create it { try { // If there is not yet a directory // named Employees, then create it Directory.CreateDirectory(@"C:\Georgetown Cleaning "

+

"Services\\Employees"); } catch (DirectoryNotFoundException) { Console.WriteLine("The folder could not be created"); } try { fsEmployee = File.Create(strPath); bwEmployee = new BinaryWriter(fsEmployee); Console.Write("Enter Employee First Name: "); string emplFName = Console.ReadLine(); Console.Write("Enter Employee Last Name: "); string emplLName = Console.ReadLine(); Console.Write("Enter Hourly Salary: "); double emplSalary = double.Parse(Console.ReadLine()); // The minimum salary in this company is 7.50 if (emplSalary < 7.50D) emplSalary = 7.50D; bwEmployee.Write(emplNumber); bwEmployee.Write(emplFName); bwEmployee.Write(emplLName); bwEmployee.Write(emplSalary);

} finally

C# 3.0 Practical Learning

920

{ bwEmployee.Close(); fsEmployee.Close(); }

}

Console.WriteLine(); }

}

}

7. Access the Program.cs file and change it as follows: using System; namespace GeorgetownCleaningServices7 { public static class Program { static int Main(string[] args) { var answer = '0'; do {

try {

Console.WriteLine("What do you want to do?"); Console.WriteLine("0. Quit"); Console.WriteLine("1. Hire a new employee"); Console.WriteLine("2. Process a payroll"); Console.Write("Your Choice: "); answer = char.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("Invalid Answer!"); }

switch (answer) { case '1': BusinessManagement.HireEmployee(); break; case '2': break; default: break; } } while (answer == '1' || answer == '2'); Console.WriteLine(); return 0; }

}

}

C# 3.0 Practical Learning

921

8. Execute the application and test it. Here is an example: What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll Your Choice: 1 Enter Employee Number (00-000): 86-025 Enter Employee First Name: Anne Enter Employee Last Name: Harang Enter Hourly Salary: 6.75 What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll Your Choice: 1 Enter Employee Number (00-000): 42-713 Enter Employee First Name: Peter Enter Employee Last Name: Lansome Enter Hourly Salary: 12.45 What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll Your Choice: 1 Enter Employee Number (00-000): 29-368 Enter Employee First Name: Gertrude Enter Employee Last Name: Monay Enter Hourly Salary: 10.85 What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll Your Choice: 0 Press any key to continue . . .

9. Close the DOS window

Serialization Binary serialization works by processing an object rather than streaming its individual member variables. This means that, to use it, you define an object and initialize it, or "fill" it, with the necessary values and any information you judge necessary. This creates a "state" of the object. It is this state that you prepare to serialize. When you save the object, it is converted into a stream. To perform binary serialization, there are a few steps you must follow. When creating the class whose objects would be serialized, start it with the [Serializable] attribute. Here is an example: [Serializable] public class Car {

C# 3.0 Practical Learning

922

}

public public public public

Before

string string uint byte

Make; Model; Year; Color;

serializing

an

object,

you

should reference the System.Runtime.Serialization.Formatters.Binary namespace. The class responsible for binary serialization is called BinaryFormatter. This class is equipped with two constructors. The default constructor is used to simply create an object. After declaring the variable, to actually serialize an object, call the Serialize() method of the BinaryFormatter class. The method is overloaded with two versions. One of the versions of this method uses the following syntax: public void Serialize(Stream serializationStream, object graph);

The first argument to this method must be an object of a Stream-based class. In the previous lessons, we saw how to create Stream objects (for example using the FileStream class). The second argument must be the object to serialize. This means that, before calling this method, you should have built the object. Here is an example: using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; [Serializable] public class Car { public string public string public uint public byte }

Make; Model; Year; Color;

public class Exercise { static int Main(string[] args) { var vehicle = new Car(); vehicle.Make vehicle.Model vehicle.Year vehicle.Color

= = = =

"Lexus"; "LS"; 2007; 4;

var stmCar = new FileStream("Car3.car", FileMode.Create); var bfmCar = new BinaryFormatter(); bfmCar.Serialize(stmCar, vehicle); }

return 0;

}

C# 3.0 Practical Learning

923

Practical Learning: Serializing an Object 1. To create a new class, in the Class View, right-click GeorgetownCleaningServices7 -> Add -> Class... 2. Set the Name to PayrollInformation and click OK 3. Change the file as follows: using using using using

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

namespace GeorgetownCleaningServices7 { [Serializable] public class PayrollInformation { private string number; private string fname; private string lname; private double salary; private DateTime start; public string EmployeeNumber { get { return this.number; } set { this.number = value; } } public string FirstName { get { return this.fname; } set { this.fname = value; } } public string LastName { get { return this.lname; } set { this.lname = value; } } public double HourlySalary { get { return this.salary; } set { this.salary = value; } } public DateTime StartPeriod { get { return this.start; } set { this.start = value; } } public DateTime EndPeriod { get { return start.AddDays(13D); }

C# 3.0 Practical Learning

924

} public public public public public public public public public public

double double double double double double double double double double

Week1Monday; Week1Tuesday; Week1Wednesday; Week1Thursday; Week1Friday; Week2Monday; Week2Tuesday; Week2Wednesday; Week2Thursday; Week2Friday;

public public public public

double double double double

RegularHours; OvertimeHours; RegularAmount; OvertimeAmount;

public double TotalEarnings; }

}

4. Access the BusinessManagement.cs file and change it as follows: using using using using using using

System; System.Collections.Generic; System.Linq; System.Text; System.IO; System.Runtime.Serialization.Formatters.Binary;

namespace GeorgetownCleaningServices7 { public static class BusinessManagement { public static void HireEmployee() { FileStream fsEmployee = null; BinaryWriter bwEmployee = null; // Ask the clerk to enter an employee number // using the format 00-000 Console.Write("Enter Employee Number (00-000): "); string emplNumber = Console.ReadLine(); string strPath = @"C:\Georgetown Cleaning " + @"Services\Employees\" + @"\" + emplNumber + ".gce"; if (File.Exists(strPath)) { Console.Write("\nEither the employee has " + "already been hired, "); Console.WriteLine("or there is already another " + "employee with that number."); return; } // If no employee with that number // was found, create it

C# 3.0 Practical Learning

925

else {

try {

// If there is not yet a directory named // Employees, then create it Directory.CreateDirectory(@"C:\Georgetown " + @"Cleaning Services\Employees");

} catch (DirectoryNotFoundException) { Console.WriteLine("The folder could " + "not be created"); } try {

fsEmployee = File.Create(strPath); bwEmployee = new BinaryWriter(fsEmployee); Console.Write("Enter Employee First Name: "); string emplFName = Console.ReadLine(); Console.Write("Enter Employee Last Name: "); string emplLName = Console.ReadLine(); Console.Write("Enter Hourly Salary: "); double emplSalary = double.Parse(Console.ReadLine()); // The minimum salary in this company is 7.50 if (emplSalary < 7.50D) emplSalary = 7.50D; bwEmployee.Write(emplNumber); bwEmployee.Write(emplFName); bwEmployee.Write(emplLName); bwEmployee.Write(emplSalary);

}

} finally { bwEmployee.Close(); fsEmployee.Close(); }

Console.WriteLine(); } public static void CreatePayroll() { FileStream fsPayroll = null; BinaryReader brPayroll = null; DateTime dteStartDate; PayrollInformation payroll = new PayrollInformation(); double monday1 = 0.00D, tuesday1 = 0.00D, wednesday1 = 0.00D, thursday1 = 0.00D, friday1 = 0.00D, monday2 = 0.00D, tuesday2 = 0.00D, wednesday2 = 0.00D,

C# 3.0 Practical Learning

926

thursday2 = 0.00D, friday2 = 0.00D; double totalHoursWeek1 = 0.00D, totalHoursWeek2 = 0.00D; double regHours1 = 0.00D, regHours2 = 0.00D, ovtHours1 = 0.00, ovtHours2 = 0.00; double regAmount1 = 0.00D, regAmount2 = 0.00D, ovtAmount1 = 0.00D, ovtAmount2 = 0.00D; double regularHours = 0.00D, overtimeHours = 0.00D; double regularAmount = 0.00D, overtimeAmount = 0.00D, totalEarnings = 0.00D; Console.Write("Enter Employee Number: "); string emplNumber = Console.ReadLine(); string strEmployeePath = @"C:\Georgetown " + @"Cleaning Services\Employees\" + @"\" + emplNumber + ".gce"; if (!File.Exists(strEmployeePath)) { Console.WriteLine("There is no employee with " + "that number in our records"); return; } // If an employee with that number was found, // continue with the payroll else { try { fsPayroll = new FileStream(strEmployeePath, FileMode.Open, FileAccess.Read); brPayroll = new BinaryReader(fsPayroll); payroll.EmployeeNumber = brPayroll.ReadString(); payroll.FirstName = brPayroll.ReadString(); payroll.LastName = brPayroll.ReadString(); payroll.HourlySalary = brPayroll.ReadDouble(); Console.WriteLine("\n------------------------" + "------------------------"); Console.WriteLine("Employee #: {0}", payroll.EmployeeNumber); Console.WriteLine("Full Name: {0}, {1}", payroll.FirstName, payroll.LastName); Console.WriteLine("Hourly Salary: {0:C}", payroll.HourlySalary); Console.WriteLine("-------------------------" + "-----------------------\n");

} finally { brPayroll.Close(); fsPayroll.Close(); } try

C# 3.0 Practical Learning

927

{ do { Console.Write("Enter Payroll Start " + "Date (mm/dd/yyyy): "); dteStartDate = DateTime.Parse(Console.ReadLine()); if (dteStartDate.DayOfWeek != DayOfWeek.Sunday) { Console.WriteLine("Invalid Date Entry"); Console.WriteLine("Payrolls start " + "on a Sunday"); } } while (dteStartDate.DayOfWeek != DayOfWeek.Sunday); payroll.StartPeriod = dteStartDate; } catch (FormatException) { Console.WriteLine("Invalid Date Entry"); } } // Retrieve the value of each day worked Console.WriteLine("\nEnter the time worked " + "for each day (0.00)"); Console.WriteLine("=-= Week 1 =-="); try { Console.Write("{0}: ", payroll.StartPeriod.AddDays(1).ToString("D")); monday1 = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You typed an invalid value"); } try { Console.Write("{0}: ", payroll.StartPeriod.AddDays(2).ToString("D")); tuesday1 = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You typed an invalid value"); } try { Console.Write("{0}: ", payroll.StartPeriod.AddDays(3).ToString("D")); wednesday1 = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You typed an invalid value"); } try

C# 3.0 Practical Learning

928

{ Console.Write("{0}: ", payroll.StartPeriod.AddDays(4).ToString("D")); thursday1 = double.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("You typed an invalid value"); } try { Console.Write("{0}: ", payroll.StartPeriod.AddDays(5).ToString("D")); friday1 = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You typed an invalid value"); } Console.WriteLine("=-= Week 2 =-="); try { Console.Write("{0}: ", payroll.StartPeriod.AddDays(8).ToString("D")); monday2 = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You typed an invalid value"); } try { Console.Write("{0}: ", payroll.StartPeriod.AddDays(9).ToString("D")); tuesday2 = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You typed an invalid value"); } try { Console.Write("{0}: ", payroll.StartPeriod.AddDays(10).ToString("D")); wednesday2 = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You typed an invalid value"); } try { Console.Write("{0}: ", payroll.StartPeriod.AddDays(11).ToString("D")); thursday2 = double.Parse(Console.ReadLine()); } catch (FormatException) { Console.WriteLine("You typed an invalid value");

C# 3.0 Practical Learning

929

} try { Console.Write("{0}: ", payroll.StartPeriod.AddDays(12).ToString("D")); friday2 = double.Parse(Console.ReadLine());

} catch (FormatException) { Console.WriteLine("You typed an invalid value"); } // Calculate the total number of hours for each week totalHoursWeek1 = monday1 + tuesday1 + wednesday1 + thursday1 + friday1; totalHoursWeek2 = monday2 + tuesday2 + wednesday2 + thursday2 + friday2; // The overtime is paid time and half double ovtSalary = payroll.HourlySalary * 1.5D; // If the employee worked under 40 hours, // there is no overtime if (totalHoursWeek1 < 40) { regHours1 = totalHoursWeek1; regAmount1 = payroll.HourlySalary * regHours1; ovtHours1 = 0.00D; ovtAmount1 = 0.00D; } // If the employee worked over 40 hours, // calculate the overtime else if (totalHoursWeek1 >= 40) { regHours1 = 40; regAmount1 = payroll.HourlySalary * 40; ovtHours1 = totalHoursWeek1 - 40; ovtAmount1 = ovtHours1 * ovtSalary; } if (totalHoursWeek2 < 40) { regHours2 = totalHoursWeek2; regAmount2 = payroll.HourlySalary * regHours2; ovtHours2 = 0.00D; ovtAmount2 = 0.00D; } else if (totalHoursWeek2 >= 40) { regHours2 = 40; regAmount2 = payroll.HourlySalary * 40; ovtHours2 = totalHoursWeek2 - 40; ovtAmount2 = ovtHours2 * ovtSalary; } regularHours = regHours1 + regHours2; overtimeHours = ovtHours1 + ovtHours2; regularAmount = regAmount1 + regAmount2; overtimeAmount = ovtAmount1 + ovtAmount2; totalEarnings = regularAmount + overtimeAmount;

C# 3.0 Practical Learning

930

payroll.Week1Monday = monday1; payroll.Week1Tuesday = tuesday1; payroll.Week1Wednesday = wednesday1; payroll.Week1Thursday = thursday1; payroll.Week1Friday = friday1; payroll.Week2Monday = monday2; payroll.Week2Tuesday = tuesday2; payroll.Week2Wednesday = wednesday2; payroll.Week2Thursday = thursday2; payroll.Week2Friday = friday2; payroll.RegularHours = regularHours; payroll.OvertimeHours = overtimeHours; payroll.RegularAmount = regularAmount; payroll.OvertimeAmount = overtimeAmount; payroll.TotalEarnings = totalEarnings; ShowPayroll(payroll); Console.Write("Do you want to save " + "the payroll (y/n): "); string strAnswer = Console.ReadLine();

}

if (strAnswer.ToUpper() == "Y") SavePayroll(payroll);

public static void SavePayroll(PayrollInformation pay) { // We will need this value to create the // name of the payroll file string strMonth = "0", strDay = "0", strYear = "0"; // We want the month and day to include 0 if necessary strMonth = pay.StartPeriod.Month.ToString(); if (pay.StartPeriod.Month < 10) strMonth = "0" + pay.StartPeriod.Month.ToString(); strDay = pay.StartPeriod.Day.ToString(); if (pay.StartPeriod.Day < 10) strDay = "0" + pay.StartPeriod.Day.ToString(); strYear = pay.StartPeriod.Year.ToString(); string strPayrollFilename = @"C:\Georgetown " + @"Cleaning Services\Payrolls\" + @"\" + pay.LastName[0] + pay.FirstName[0] + strMonth + strDay + strYear + ".epr"; try { // If there is not yet a directory for the // payrolls, then create it Directory.CreateDirectory(@"C:\Georgetown Cleaning " + @"Services\Payrolls"); } catch (DirectoryNotFoundException) { Console.WriteLine("The employee payroll file " + "could not be created");

C# 3.0 Practical Learning

931

} if (File.Exists(strPayrollFilename)) { Console.WriteLine("The employee's payroll " + "for that period exists already"); } FileStream fsEmployeePayroll = new FileStream(strPayrollFilename, FileMode.Create); BinaryFormatter bfEmployeePayroll = new BinaryFormatter();

}

bfEmployeePayroll.Serialize(fsEmployeePayroll, pay); fsEmployeePayroll.Close();

public static void ViewPayroll() { } public static void ShowPayroll(PayrollInformation payed) { Console.WriteLine("\n=============================" + "==================="); Console.WriteLine("=$= Payroll summary =$="); Console.WriteLine("-------------------------------" + "-----------------"); Console.WriteLine("Employee #: {0}", payed.EmployeeNumber); Console.WriteLine("Full Name: {0}, {1}", payed.FirstName, payed.LastName); Console.WriteLine("Hourly Salary: {0:C}", payed.HourlySalary); Console.WriteLine("Start Period: {0:D}", payed.StartPeriod); Console.WriteLine("End Period: {0:D}", payed.EndPeriod); Console.WriteLine("--------------------------------" + "----------------"); Console.WriteLine(" Monday Tuesday Wednesday " + "Thursday Friday"); Console.WriteLine("Week 1: {0:F} {1:F} " + "{2:F} {3:F} {4:F}", payed.Week1Monday, payed.Week1Tuesday, payed.Week1Wednesday, payed.Week1Thursday, payed.Week1Friday); Console.WriteLine("Week 2: {0:F} {1:F} " + "{2:F} {3:F} {4:F}", payed.Week2Monday, payed.Week2Tuesday, payed.Week2Wednesday, payed.Week2Thursday, payed.Week2Friday); Console.WriteLine("-------------------------------" + "-----------------"); Console.WriteLine("Monetary Summary"); Console.WriteLine(" Hours Amount"); Console.WriteLine("Regular: {0,6} {1,6}", payed.RegularHours.ToString("F"),

C# 3.0 Practical Learning

932

} }

payed.RegularAmount.ToString("F")); Console.WriteLine("Overtime: {0,6} {1,6}", payed.OvertimeHours.ToString("F"), payed.OvertimeAmount.ToString("F")); Console.WriteLine("-------------------------------" + "-----------------"); Console.WriteLine("Net Pay: {0:F}", payed.TotalEarnings); Console.WriteLine("===============================" + "=================\n");

}

5. Access the Program.cs file and change it as follows: using using using using

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

namespace GeorgetownCleaningServices7 { public static class Program { static int Main(string[] args) { var answer = '0'; Console.WriteLine("========================" + "========================"); Console.WriteLine("Georgetown Cleaning Services"); Console.WriteLine("========================" + "========================"); do {

try {

Console.WriteLine("\nWhat do you want to do?"); Console.WriteLine("0. Quit"); Console.WriteLine("1. Hire a new employee"); Console.WriteLine("2. Process a payroll"); Console.WriteLine("3. View an employee's payroll"); Console.Write("Your Choice: "); answer = char.Parse(Console.ReadLine()); Console.WriteLine();

} catch (FormatException) { Console.WriteLine("Invalid Answer!"); }

switch (answer) { case '1': BusinessManagement.HireEmployee(); break; case '2':

C# 3.0 Practical Learning

933

BusinessManagement.CreatePayroll(); break; case '3': BusinessManagement.ViewPayroll(); break; default: break; } } while( (answer == '1') || (answer == '2') || (answer == '3') ); } }

return 0;

}

6. Execute the application and test it. Here is an example: ================================================ Georgetown Cleaning Services ================================================ What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll 3. View an employee's payroll Your Choice: 2 Enter Employee Number: 29-368 -----------------------------------------------Employee #: 29-368 Full Name: Gertrude, Monay Hourly Salary: $10.85 -----------------------------------------------Enter Payroll Start Date (mm/dd/yyyy): 11/12/05 Invalid Date Entry Payrolls start on a Sunday Enter Payroll Start Date (mm/dd/yyyy): 11/12/06 Enter the time worked for each day (0.00) =-= Week 1 =-= Monday, November 13, 2006: 8.00 Tuesday, November 14, 2006: 8.50 Wednesday, November 15, 2006: 9.50 Thursday, November 16, 2006: 8 Friday, November 17, 2006: 8.50 =-= Week 2 =-= Monday, November 20, 2006: 6.50 Tuesday, November 21, 2006: 7.00 Wednesday, November 22, 2006: 8 Thursday, November 23, 2006: 6.00 Friday, November 24, 2006: 7.00 ================================================

C# 3.0 Practical Learning

934

=$= Payroll summary =$= -----------------------------------------------Employee #: 29-368 Full Name: Gertrude, Monay Hourly Salary: $10.85 Start Period: Sunday, November 12, 2006 End Period: Saturday, November 25, 2006 -----------------------------------------------Monday Tuesday Wednesday Thursday Friday Week 1: 8.00 8.50 9.50 8.00 8.50 Week 2: 6.50 7.00 8.00 6.00 7.00 -----------------------------------------------Monetary Summary Hours Amount Regular: 74.50 808.33 Overtime: 2.50 40.69 -----------------------------------------------Net Pay: 849.01 ================================================ Do you want to save the payroll (y/n): Y What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll 3. View an employee's payroll Your Choice: 0 Press any key to continue . . .

7. Close the DOS window 8. Execute the application again and process another payroll. Here is an example: ================================================ Georgetown Cleaning Services ================================================ What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll 3. View an employee's payroll Your Choice: 2 Enter Employee Number: 86-025 -----------------------------------------------Employee #: 86-025 Full Name: Anne, Harang Hourly Salary: $7.50 -----------------------------------------------Enter Payroll Start Date (mm/dd/yyyy): 11/26/2006 Enter the time worked for each day (0.00) =-= Week 1 =-=

C# 3.0 Practical Learning

935

Monday, November 27, 2006: 8.00 Tuesday, November 28, 2006: 6.50 Wednesday, November 29, 2006: 8.50 Thursday, November 30, 2006: 8.00 Friday, December 01, 2006: 8.00 =-= Week 2 =-= Monday, December 04, 2006: 9.00 Tuesday, December 05, 2006: 8.50 Wednesday, December 06, 2006: 8.00 Thursday, December 07, 2006: 9.50 Friday, December 08, 2006: 8.00 ================================================ =$= Payroll summary =$= -----------------------------------------------Employee #: 86-025 Full Name: Anne, Harang Hourly Salary: $7.50 Start Period: Sunday, November 26, 2006 End Period: Saturday, December 09, 2006 -----------------------------------------------Monday Tuesday Wednesday Thursday Friday Week 1: 8.00 6.50 8.50 8.00 8.00 Week 2: 9.00 8.50 8.00 9.50 8.00 -----------------------------------------------Monetary Summary Hours Amount Regular: 79.00 592.50 Overtime: 3.00 33.75 -----------------------------------------------Net Pay: 626.25 ================================================ Do you want to save the payroll (y/n): y What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll 3. View an employee's payroll Your Choice: 0 Press any key to continue . . .

9. Close the DOS window

De-Serialization As serialization is the process of storing an object to a medium, the opposite, serialization is used to retrieve an object from a stream. To support this, the BinaryFormatter class is equipped with the Deserialize() method. Like Serialize(), the Deserialize() method is overloaded with two versions. One of them uses the following syntax: public object Deserialize(Stream serializationStream);

This method takes as argument a Stream-based object, such as a FileStream variable, that indicates where the file is located. The Deserialize() method C# 3.0 Practical Learning

936

returns an Object object. As a goal, you want the Deserialize() method to produce the type of object that was saved so you can retrieve the values that the returned object holds. Because the method returns an Object value, you must cast the returned value to the type of your class. Once the Deserialize() method has returned the desired object, you can access its values. Here is an example: using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; [Serializable] public class Car { public string Make; public string Model; public uint Year; public byte Color; } class Program { static int Main(string[] args) { var stmCar = new FileStream("Car3.car", FileMode.Open); var bfmCar = new BinaryFormatter(); var vehicle = (Car)bfmCar.Deserialize(stmCar); Console.WriteLine("Make: {0}", vehicle.Make); Console.WriteLine("Model: {0}", vehicle.Model); Console.WriteLine("Year: {0}", vehicle.Year); Console.Write("Color: "); byte clr = vehicle.Color; switch (clr) { case 1: Console.WriteLine("Black"); break; case 2: Console.WriteLine("Gray"); break; case 3: Console.WriteLine("White"); break; case 4: Console.WriteLine("Red"); break; case 5: Console.WriteLine("Blue"); break; } stmCar.Close(); }

return 0;

}

C# 3.0 Practical Learning

937

Practical Learning: De-Serializing an Object 1. Access the BusinessManagement.cs file and implement the ViewPayroll() method as follows: using using using using using using

System; System.Collections.Generic; System.Linq; System.Text; System.IO; System.Runtime.Serialization.Formatters.Binary;

namespace GeorgetownCleaningServices7 { public static class BusinessManagement { public static void HireEmployee() { . . . No Change } public static void CreatePayroll() { . . . No Change } public static void SavePayroll(PayrollInformation pay) { . . . No Change } public static void ViewPayroll() { string strEmplNumber, strFName, strLName; string strMonth, strDay, strYear; // Ask the clerk to enter an employee number // using the format 00-000 Console.Write("Enter Employee Number (00-000): "); strEmplNumber = Console.ReadLine(); string strFilename = @"C:\Georgetown Cleaning " + @"Services\Employees\" + @"\" + strEmplNumber + ".gce"; if (!File.Exists(strFilename)) { Console.Write("There is no employee " + "with that number."); } else { FileStream fsEmployee = null; BinaryReader brEmployee = null; try {

// We need to formally open the file

C# 3.0 Practical Learning

938

// because we need the employees initials fsEmployee = new FileStream(strFilename, FileMode.Open, FileAccess.Read); brEmployee = new BinaryReader(fsEmployee); // Read the file, mainly to get the // employee's name strEmplNumber = brEmployee.ReadString(); strFName = brEmployee.ReadString(); strLName = brEmployee.ReadString(); } finally { brEmployee.Close(); fsEmployee.Close(); } Console.Write("Enter the start date of the " + "payroll you want to see (mm/dd/yyyy): "); DateTime dteStartDate = DateTime.Parse(Console.ReadLine()); // We want the month and day to include 0 if necessary strMonth = dteStartDate.Month.ToString(); if (dteStartDate.Month < 10) strMonth = "0" + dteStartDate.Month.ToString(); strDay = dteStartDate.Day.ToString(); if (dteStartDate.Day < 10) strDay = "0" + dteStartDate.Day.ToString(); strYear = dteStartDate.Year.ToString(); strFilename = @"C:\Georgetown Cleaning " + @"Services\Payrolls\" + @"\" + strLName[0] + strFName[0] + strMonth + strDay + strYear + ".epr"; if (!File.Exists(strFilename)) { Console.Write("{0}, {1} doesn't have a " + "payroll in that time frame", strLName, strFName); } else { // Open the payroll and display it FileStream fsPayroll = new FileStream(strFilename, FileMode.Open); BinaryFormatter bfPayroll = new BinaryFormatter(); PayrollInformation pay = (PayrollInformation)bfPayroll.Deserialize(fsPayro ll); } }

ShowPayroll(pay);

}

C# 3.0 Practical Learning

939

}

public static void ShowPayroll(PayrollInformation payed) { . . . No Change }

}

2. Execute the application and test it. Here is an example: ================================================ Georgetown Cleaning Services ================================================ What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll 3. View an employee's payroll Your Choice: 3 Enter Employee Number (00-000): 29-368 Enter the start date of the payroll you want to see (mm/dd/yyyy): 11/12/2006 ================================================ =$= Payroll summary =$= -----------------------------------------------Employee #: 29-368 Full Name: Gertrude, Monay Hourly Salary: $10.85 Start Period: Sunday, November 12, 2006 End Period: Saturday, November 25, 2006 -----------------------------------------------Monday Tuesday Wednesday Thursday Friday Week 1: 8.00 8.50 9.50 8.00 8.50 Week 2: 6.50 7.00 8.00 6.00 7.00 -----------------------------------------------Monetary Summary Hours Amount Regular: 74.50 808.33 Overtime: 2.50 40.69 -----------------------------------------------Net Pay: 849.01 ================================================ What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll 3. View an employee's payroll Your Choice: 3 Enter Employee Number (00-000): 86-025 Enter the start date of the payroll you want to see (mm/dd/yyyy): 11/26/06 ================================================ =$= Payroll summary =$=

C# 3.0 Practical Learning

940

-----------------------------------------------Employee #: 86-025 Full Name: Anne, Harang Hourly Salary: $7.50 Start Period: Sunday, November 26, 2006 End Period: Saturday, December 09, 2006 -----------------------------------------------Monday Tuesday Wednesday Thursday Friday Week 1: 8.00 6.50 8.50 8.00 8.00 Week 2: 9.00 8.50 8.00 9.50 8.00 -----------------------------------------------Monetary Summary Hours Amount Regular: 79.00 592.50 Overtime: 3.00 33.75 -----------------------------------------------Net Pay: 626.25 ================================================ What do you want to do? 0. Quit 1. Hire a new employee 2. Process a payroll 3. View an employee's payroll Your Choice: 0 Press any key to continue . . .

3. Close the DOS window

SOAP Serialization Introduction The .NET Framework supports another technique of serialization referred to as SOAP (which stands for Simple Object Access Protocol). This technique is related to XML but, although we haven't studied XML, you don't need to know anything about it to use SOAP serialization.

Practical Learning: Introducing SOAP Serialization 1. Start a new Console Application named PropertyRental1 2. To create a new class, on the main menu, click Project -> Add Class 3. Set the Name to Property and press Enter 4. Change the file as follows: using using using using

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

C# 3.0 Practical Learning

941

namespace PropertyRental1 { public enum TypeOfProperty { Appartment, SingleFamily, Townhouse, Unknown } public enum Condition { Excellent, Good, NeedsRepair, Unknown } [Serializable] public class Property { private long propCode; private TypeOfProperty tp; private Condition cond; private short beds; private float baths; private int levels; private decimal val; public long PropertyCode { get { return propCode; } set { propCode = value; } } public TypeOfProperty PropertyType { get { return tp; } set { tp = value; } } public Condition PropertyCondition { get { return cond; } set { cond = value; } } public short Bedrooms { get { return beds; } set { beds = value; } } public float Bathrooms { get { return (baths <= 0) ? 0.00f : baths; } set { baths = value; } } public int Stories

C# 3.0 Practical Learning

942

{ get { return levels; } set { levels = value; } } public decimal MonthlyRent { get { return (val <= 0) ? 0.00M : val; } set { val = value; } }

}

public Property() { Random rnd = new Random(); propCode = rnd.Next(100000, 999999); tp = TypeOfProperty.Unknown; cond = Condition.Unknown; beds = 0; baths = 0.0f; levels = 0; val = 0.00M; }

}

5. To create a new class, on the main menu, click Project -> Add Class 6. Set the Name to PropertyListing and press Enter 7. Change the file as follows: using using using using

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

namespace PropertyRental1 { [Serializable] public class PropertyListing { private Property[] prop = new Property[100]; public Property this[int i] { get { return prop[i]; } set { prop[i] = value; } } }

}

8. Save all

Serialization With SOAP To serialize an object using SOAP, you follow the same steps we reviewed for the binary serialization with one addition that you must add a certain reference. 943 C# 3.0 Practical Learning

When creating the class whose objects would be serialized, mark it with the [Serializable] attribute. Here is an example: [Serializable] public class Car { public string Make; public string Model; public uint Year; public byte Color; }

To

support

SOAP

serialization,

the

.NET

Framework

provides

the

SoapFormatter class. This class is defined in the System.Runtime.Serialization.Formatters. Soap namespace that is part of the System.Runtime.Serialization.Formatters. Soap.dll assembly. In order to use The SoapFormatter class, you must reference this assembly. Then, you

can create an object and initialize it as you see fit. Before saving it, as always, create a Stream-based object that would indicate the name (and location) of the file and the type of action to perform. Then, declare a SoapFormatter variable using its default constructor. To actually save the object, call the Serialize() method of this class. This method uses the same syntax as that of the BinaryFormatter class: it takes two arguments. The first is a Streambased object. The second is the object that needs to be serialized. Here is an example: using System; using System.IO; using System.Runtime.Serialization.Formatters.Soap; [Serializable] public class Car { public string public string public uint public byte }

Make; Model; Year; Color;

public static class Program { public static int Main(string[] args) { var vehicle = new Car(); vehicle.Make vehicle.Model vehicle.Year vehicle.Color

= = = =

"Volvo"; "S40"; 2006; 3;

var stmCar = new FileStream("Car4.car", FileMode.Create); var sopCar = new SoapFormatter(); sopCar.Serialize(stmCar, vehicle); return 0;

C# 3.0 Practical Learning

944

} }

Practical Learning: Serializing With SOAP 1. To add SOAP support to your project, on the main menu, click Project -> Add Reference... 2. In the Add Reference dialog box and in the .NET tab, scroll down and select System.Runtime.Serialization.Formatters.Soap:

3. Click OK 4. Access the Program.cs file and change it as follows: using using using using using using

System; System.Collections.Generic; System.Linq; System.Text; System.IO; System.Runtime.Serialization.Formatters.Soap;

namespace PropertyRental1 { class Program { static PropertyListing CreateListing() { Random rnd = new Random(); Property prop = new Property(); PropertyListing listing = new PropertyListing(); prop = new Property();

C# 3.0 Practical Learning

945

// Create a few properties ready to be rented prop.PropertyCode = rnd.Next(100000, 999999); prop.PropertyType = TypeOfProperty.SingleFamily; prop.PropertyCondition = Condition.Excellent; prop.Bedrooms = 5; prop.Bathrooms = 3.5f; prop.Stories = 3; prop.MonthlyRent = 2650; listing[0] = prop; prop = new Property(); prop.PropertyCode = rnd.Next(100000, 999999); prop.PropertyType = TypeOfProperty.Townhouse; prop.PropertyCondition = Condition.Excellent; prop.Bedrooms = 3; prop.Bathrooms = 2.5f; prop.Stories = 3; prop.MonthlyRent = 1750; listing[1] = prop; prop = new Property(); prop.PropertyCode = rnd.Next(100000, 999999); prop.PropertyType = TypeOfProperty.SingleFamily; prop.PropertyCondition = Condition.Good; prop.Bedrooms = 4; prop.Bathrooms = 2.5f; prop.Stories = 2; prop.MonthlyRent = 2450; listing[2] = prop; prop = new Property(); prop.PropertyCode = rnd.Next(100000, 999999); prop.PropertyType = TypeOfProperty.Appartment; prop.PropertyCondition = Condition.Excellent; prop.Bedrooms = 1; prop.Bathrooms = 1.0f; prop.Stories = 1; prop.MonthlyRent = 880; listing[3] = prop; prop = new Property(); prop.PropertyCode = rnd.Next(100000, 999999); prop.PropertyType = TypeOfProperty.Townhouse; prop.PropertyCondition = Condition.Excellent; prop.Bedrooms = 3; prop.Bathrooms = 2.5f; prop.Stories = 2; prop.MonthlyRent = 1880; listing[4] = prop; prop = new Property(); prop.PropertyCode = rnd.Next(100000, 999999); prop.PropertyType = TypeOfProperty.Appartment; prop.PropertyCondition = Condition.Good; prop.Bedrooms = 2; prop.Bathrooms = 1.0f; prop.Stories = 1; prop.MonthlyRent = 1050; listing[5] = prop;

C# 3.0 Practical Learning

946

// Since we don't yet have a complete list of properties // Create some empty ones for (int i = 5; i < 100; i++) { prop = new Property(); listing[i] = prop; } return listing; } static int Main() { PropertyListing props = CreateListing(); Property prop = new Property(); FileStream prpStream = new FileStream("properties.rnt", FileMode.Create); SoapFormatter prpSoap = new SoapFormatter(); prpSoap.Serialize(prpStream, props); for (int i = 0; i < 16; i++) { prop = props[i]; Console.WriteLine("{0}.---------------------------------", i + 1);

Console.WriteLine("Property #: {0}", prop.PropertyCode); Console.WriteLine("Type: {0}", prop.PropertyType); Console.WriteLine("Condition: {0}", prop.PropertyCondition); Console.WriteLine("Bedrooms: {0}", prop.Bedrooms); Console.WriteLine("Bathrooms: {0}", prop.Bathrooms); Console.WriteLine("Stories: {0}", prop.Stories); Console.WriteLine("Market Value: {0}\n", prop.MonthlyRent); } Console.WriteLine("======================================"); return 0; }

}

}

5. Press Ctrl + F5 to execute the application

De-Serialization With SOAP De-serialization in soap is performed exactly as done for the binary deserialization. To support it, the SoapFormatter class is equipped with the Deserialize() method. This method uses the same syntax as its equivalent of the BinaryFormatter class. The approach to use it is also the same. Here is an example: C# 3.0 Practical Learning

947

using System; using System.IO; using System.Runtime.Serialization.Formatters.Soap; [Serializable] public class Car { public string public string public uint public byte }

Make; Model; Year; Color;

public static class Program { public static int Main(string[] args) { var stmCar = new FileStream("Car4.car", FileMode.Open); var sopCar = new SoapFormatter(); var vehicle = (Car)sopCar.Deserialize(stmCar); Console.WriteLine("Car Information"); Console.WriteLine("Make: {0}", vehicle.Make ); Console.WriteLine("Model: {0}", vehicle.Model); Console.WriteLine("Year: {0}", vehicle.Year); Console.Write("Color: "); switch (vehicle.Color) { case 1: Console.WriteLine("Black"); break; case 2: Console.WriteLine("Gray"); break; case 3: Console.WriteLine("White"); break; case 4: Console.WriteLine("Red"); break; case 5: Console.WriteLine("Blue"); break; } return 0; }

}

Practical Learning: Deserializing With SOAP 1. To deserialize, change the contents of the Program.cs file as follows: using using using using

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

C# 3.0 Practical Learning

948

using System.IO; using System.Runtime.Serialization.Formatters.Soap; namespace PropertyRental1 { class Program { static int Main() { Property prop = new Property(); // Open the list/collection of properties FileStream prpStream = new FileStream("properties.rnt", FileMode.Open); SoapFormatter prpSoap = new SoapFormatter(); PropertyListing props = (PropertyListing)prpSoap.Deserialize(prpStream); prpStream.Close(); for (int i = 0; i < 16; i++) { prop = props[i]; Console.WriteLine("{0}.----------------------------------", i +

1);

Console.WriteLine("Property #: {0}", prop.PropertyCode); Console.WriteLine("Type: {0}", prop.PropertyType); Console.WriteLine("Condition: {0}", prop.PropertyCondition); Console.WriteLine("Bedrooms: {0}", prop.Bedrooms); Console.WriteLine("Bathrooms: {0}", prop.Bathrooms); Console.WriteLine("Stories: {0}", prop.Stories); Console.WriteLine("Market Value: {0}\n", prop.MonthlyRent); } Console.WriteLine("======================================"); return 0; }

}

}

2. Press Ctrl + F5 to execute the application 3. After viewing the result, close the DOS window 4. To apply an example of updating the file, change the contents of the Program.cs file as follows: using using using using using using

System; System.Collections.Generic; System.Linq; System.Text; System.IO; System.Runtime.Serialization.Formatters.Soap;

namespace PropertyRental1 {

C# 3.0 Practical Learning

949

class Program { static int Main() { Property prop = new Property(); // Open the list/collection of properties FileStream prpStream = new FileStream("properties.rnt", FileMode.Open); SoapFormatter prpSoap = new SoapFormatter(); // Get the list of properties and store it in an array PropertyListing props = (PropertyListing)prpSoap.Deserialize(prpStream); // Close the stream while we are working on something else prpStream.Close(); // To add a few properties, we will actually replace // some "empty" properties whose placeholders we defined earlier

Random rnd = new Random(); prop = new Property(); prop.PropertyCode = rnd.Next(100000, 999999); prop.PropertyType = TypeOfProperty.Appartment; prop.PropertyCondition = Condition.Excellent; prop.Bedrooms = 2; prop.Bathrooms = 2.0f; prop.Stories = 1; prop.MonthlyRent = 1240; props[7] = prop; prop = new Property(); prop.PropertyCode = rnd.Next(100000, 999999); prop.PropertyType = TypeOfProperty.SingleFamily; prop.PropertyCondition = Condition.Excellent; prop.Bedrooms = 3; prop.Bathrooms = 2.5f; prop.Stories = 3; prop.MonthlyRent = 1750; props[8] = prop; prop = new Property(); prop.PropertyCode = rnd.Next(100000, 999999); prop.PropertyType = TypeOfProperty.SingleFamily; prop.PropertyCondition = Condition.Good; prop.Bedrooms = 5; prop.Bathrooms = 3.5f; prop.Stories = 3; prop.MonthlyRent = 3475; props[14] = prop; prop = new Property(); prop.PropertyType = TypeOfProperty.Appartment; prop.PropertyCondition = Condition.Excellent; prop.Bedrooms = 2; prop.Bathrooms = 1.0f; prop.Stories = 1; prop.MonthlyRent = 1275; props[28] = prop;

C# 3.0 Practical Learning

950

// Reopen the stream prpStream = new FileStream("properties.rnt", FileMode.Create); prpSoap = new SoapFormatter(); // Open the file and save it prpSoap.Serialize(prpStream, props); prpStream.Close(); // That's it for (int i = 0; i < 16; i++) { prop = props[i]; Console.WriteLine("{0}.----------------------------------", i + 1);

Console.WriteLine("Property #: {0}", prop.PropertyCode); Console.WriteLine("Type: {0}", prop.PropertyType); Console.WriteLine("Condition: {0}", prop.PropertyCondition); Console.WriteLine("Bedrooms: {0}", prop.Bedrooms); Console.WriteLine("Bathrooms: {0}", prop.Bathrooms); Console.WriteLine("Stories: {0}", prop.Stories); Console.WriteLine("Market Value: {0}\n", prop.MonthlyRent); } Console.WriteLine("======================================"); } }

return 0;

}

5. Press Ctrl + F5 to execute the application

Details on Serialization Partial Serialization In the examples we have used so far, we were saving the whole object. You can make it possible to save only some parts of the class. When creating a class, you can specify what fields would be serialized and which ones would not be. To specify that a member cannot be saved, you can mark it with the [NonSerialized] attribute. Here is an example: [Serializable] public class Car { public string Make; public string Model; // Because the value of a car can change, // there is no reason to save it [NonSerialized]

C# 3.0 Practical Learning

951

public decimal Value; public uint Year; public byte Color; }

After creating the class, you can declare a variable of it and serialize it, using either the binary or the SOAP approach. Here is an example: using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; [Serializable] public class Car { public string Make; public string Model;

}

// Because the value of a car can change, // there is no reason to save it [NonSerialized] public decimal Value; public uint Year; public byte Color;

public class Exercise { static int Main(string[] args) { var vehicle = new Car(); vehicle.Make = "Lexus"; vehicle.Model = "LS"; vehicle.Year = 2007; vehicle.Color = 4; vehicle.Value = 28640M; var stmCar = new FileStream("Car1.car", FileMode.Create); var bfmCar = new BinaryFormatter(); bfmCar.Serialize(stmCar, vehicle); return 0; }

}

You can then retrieve the object and its values, using any of the techniques we learned earlier. Here is an example: using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; [Serializable] public class Car { public string Make; public string Model;

C# 3.0 Practical Learning

952

// Because the value of a car can change, // there is no reason to save it [NonSerialized] public decimal Value; public uint Year; public byte Color; } public class Exercise { static int Main(string[] args) { var stmCar = new FileStream("Car1.car", FileMode.Open); var bfmCar = new BinaryFormatter(); var vehicle = (Car)bfmCar.Deserialize(stmCar); Console.WriteLine("Car Information"); Console.WriteLine("Make: {0}", vehicle.Make); Console.WriteLine("Model: {0}", vehicle.Model); Console.WriteLine("Year: {0}", vehicle.Year); Console.Write("Color: "); switch (vehicle.Color) { case 1: Console.WriteLine("Black"); break; case 2: Console.WriteLine("Gray"); break; case 3: Console.WriteLine("White"); break; case 4: Console.WriteLine("Red"); break; case 5: Console.WriteLine("Blue"); break; } Console.WriteLine("Value: {0}\n", vehicle.Value); return 0; }

}

This would produce: Car Information Make: Lexus Model: LS Year: 2007 Color: Red Value: 0 Press any key to continue . . .

Notice that the value of the Value field was not saved: it holds the default value of its data type. This indicates that, you can assign a value a C# 3.0 Practical Learning

953

[NonSerialized] field and save the object. The value of that field would not

be saved but the compiler would not throw an exception.

Implementing a Custom Serialized Class To support serialization, the .NET Framework provides the ISerializable interface. You can create a class that implements this interface to customize the serialization process. Even if you plan to use this interface, the class you create must be marked with the [Serializable] attribute.

.NET Built-In Serialized Classes The .NET Framework is filled with many classes ready for serialization. To know that a class is ready for serialization, when viewing its documentation either in the MSDN web site or in the help documentation, check that it is marked with the [SerializableAttribute]. Here is an example of such as class:

C# 3.0 Practical Learning

954

Some of these classes provide the properties and methods to create an object and directly save it. For some other classes, you must first create a class, mark it with the [Serializable] attribute, build an object of it, and then pass it to the .NET class.

C# 3.0 Practical Learning

955

Related Documents

C Practical
November 2019 7
C Learning
June 2020 1
Practical Fileof C
June 2020 9
Tool Engg I-practical
November 2019 22