Anda di halaman 1dari 84

C# 2005 Overview

Learning objective
After completing this topic, you should be able to recognize basic object-oriented programming procedures in C# 2005, given a scenario.

1. Introduction to C# 2005
C# 2005 is a programming language that enables programmers to develop a large range of components and applications, such as

Windows services, controls, and control libraries Windows and console mode applications web applications XML Web services .NET classes and namespaces web controls and libraries

C# 2005 provides several new features and enhancements on the C# 2003 version. For example, it includes

a Common Type System (CTS) a Framework Class Library (FCL) improved object orientation user-friendly naming conventions

a Common Type System (CTS) In the CTS, all data types are defined as classes or structures. This ensures that all .NET components are interoperable, irrespective of the language in which they're coded. a Framework Class Library (FCL) The new .NET Framework Class Library groups common system services such as classes, class members, and object-oriented programming (OOP) elements in a hierarchical structure. This makes managing application components easier. Essentially, the Framework Class Library consists of a large set of classes built on top of the smaller set of classes contained in the Base Class Library (BCL). improved object orientation C# 2005 is built on an object-oriented programming platform and provides better support for base class inheritance than previous versions. user-friendly naming conventions A new naming system supports checking names for elements such as classes, functions, constants, and variables based on their type. Following the new naming conventions makes it much easier for programmers to create reusable code. A variable that stores a

business address, for example, may be named businessAddress. C# 2005 uses two styles of casing:

camel casing, as in businessAddress, for names of private classes, variables, and arguments Pascal casing, which uses an initial uppercase letter as in MyOtherFunction, for names of public classes and global elements

Visual Studio is able to check the naming of your variables, in addition to making them easier to declare and initialize. Each variable in C# 2005 is associated with a

name address data type value scope lifetime

name A variable is identified in code by its name. Variable names begin with an alphabetical character or underscore, followed by additional alphanumeric characters. address A variable's address is the temporary location in memory in which the variable is stored. data type A variable's data type determines which sorts of values it can store. A variable of the String data type, for example, stores alphabetic sentence or word-based values, whereas a variable of the Integer type stores nondecimal numeric values. C# 2005 provides support for several new data types that were not supported in earlier versions. value A variable's value is the data value you use it to store the value that the variable holds at its memory address. scope A variable's scope determines which application code can access it. For example, a variable may be available only within a class, across an application, or to a particular method or function. lifetime A variable's lifetime determines the period of time for which the variable must exist when code runs. C# 2005 provides the following access modifiers, which allow you to specify scope:

makes code accessible to any other segment that has included the namespace it resides within
public

makes code accessible only to the class in which you declare it, or its derived subclasses. It cannot be used at the namespace level, or within interfaces, modules or structures internal makes code accessible to classes, structures and modules, but only within an assembly protected internal makes code accessible only within a class and it subclasses, or within an assembly, or both. It cannot be used at the namespace level, or within interfaces, modules or structures private makes code accessible only within the same class, structure or module. This cannot be used at the namespace level, or within an interface.
protected

The association between a variable name and a data type is called a variable declaration. For example, a variable declaration may create a string variable named createNewDecl.
string createNewDecl;

You can use a single statement to declare multiple variables of the same type. These can be single-value variables or arrays.
int x, grid[], y;

In C# 2005, you can declare and initialize a variable on the same line. For example, you can declare an int variable and then assign it a value of 2.
int startInitialization = 2;

You can also declare and initialize multiple variables using a single statement.
int one = 2, two = 6;

Question
Suppose you want to declare a variable that must be available in a class, structure, and module, but only within a specific assembly. Which access modifier do you use to declare the variable? Options: 1. 2. 3. 4.
internal protected protected internal public

Answer

You use the internal access modifier to declare a variable that can be used in a class, structure, and module, but only within a specific assembly. Option 1 is correct. internal variables are accessible within an assembly, and they can be used in classes, structures, and modules. Option 2 is incorrect. protected variables are accessible only to code within the class in which you declare them. They can't be used in modules and structures. Option 3 is incorrect. A protected internal variable is accessible not only within the assembly it is declared, but is also available in any subclasses of the class it is declared in. Option 4 is incorrect. public variables are accessible to all code.

2. Using statements, events, and delegates


C# 2005 includes support for loops and decision structures through if/else, for, do...while, and while statements. The if/else statement executes a statement based on a given condition. If the condition evaluates to true, the first statement executes. If the condition evaluates to false, the statement after the else keyword executes. if (condition) { [statement]; } else { [statement]; } In a for statement, the statement within the block repeats executing until a counter reaches a specified limit. The counter keeps track of the loop iterations, starting from an initial value you specify. for (counter, initial, limit) { [statement]; } A do...while statement tests for a specified condition if you want a statement to execute at least once. The statement will then execute again only if the tested condition is met.

do { [statement]; } while (condition); The while statement causes an enclosed statement to repeat execution for as long as a specified condition is met. This differs from the do...while loop in that the condition is evaluated before the loop iteration begins, whereas a do...while loop evaluates the condition at the end of a loop iteration. while (condition) { [statement]; }

Question
Suppose you want to use a loop to set a statement to execute at least once, and then to continue executing until a condition fails to be met. Which type of statement is the most appropriate for doing this? Options: 1. 2. 3. 4.
do...while for if/else while

Answer
You use the do...while statement to test a specified condition. Option 1 is correct. You use the do...while statement to test a specified condition or logical statement. A statement you include within a do...while block will execute at least once. Option 2 is incorrect. You use the for statement to set a specified statement to repeat executing a certain number of times. Option 3 is incorrect. You use the if/else statement to specify that one action must execute only if a specified condition is met, and that another action must execute if the condition isn't met.

Option 4 is incorrect. You use the while statement to execute a specified statement continuously until a condition evaluates to false. This type of loop doesn't, however, ensure that the statement will execute at least once. Events may be generated by the user or by the system. For example, an event that triggers when a command button is clicked is a user-generated event, whereas an event that triggers at a specified time is a system-generated event. When an event triggers, the CLR passes the event's arguments to an event handler. There are two event arguments:
sender, which represents an instance of the class that wants to raise an event and has the type System.Object e, which contains information about the event and is a System.EventArgs type object

C# 2005 permits advanced exception handling. For example, when one of multiple listeners for an event throws an exception, you can simply use the invocation list of the multicast delegate instance associated with the event to handle this. Although other types exist, Visual Studio 2005 provides two main types of event handlers the ASP.NET event handler for web applications and the Windows Forms event handler. ASP.NET event handlers are able to manage complex events at the application, session, or page level. Windows Forms Event Handlers manage events that occur when a form instance is created or destroyed. Examples of these sort of Form events include Shown, FormClosing, and FormClosed. Some examples of ASP.NET events include
Start Start End Init Load PreRender Unload Disposed

The Start event reacts when an application starts and is an application-level event.
End

The End event reacts when an application ends and is an application-level event.
Init

The Init event reacts when a page is initialized and is a page-level event.
Load

The Load event reacts when a page is loaded and is a page-level event.
PreRender

The PreRender event reacts when a page is delivered and is a page-level event.
Unload

The Unload event reacts when a page is unloaded and is a page-level event.
Disposed

The Disposed event reacts when a page is released from memory and is a page-level event. Delegates are objects that hand a task over to another part of a program. They can be used to call either shared or object functions of a class, without the delegate itself being a member of that class. In C# 2005, the delegate class itself must be declared before you can use it. In this example, a delegate named myFunction is the first statement of the Class1 class. The delegate must have the same signature as the method that it is used to reference. In this case, the delegate is used to reference the MyOtherFunction method, which accepts an int value and returns an int value. The delegate therefore must also accept an int value and return an int value. In the Main method, an instance of the delegate named myD is created, and a reference to the MyOtherFunction method is passed to it as a parameter. The Invoke method is called from the delegate instance using the necessary int parameter, which calls the MyOtherFunction method and passes that int value to it. The MyOtherFunction method returns an int value back to the Invoke statement, which can then be printed.
public class Class1 { public delegate int myFunction(int min); public int MyOtherFunction(int mer) { int mal = 4; return mer*mal; } public static void Main() { Class1 mb = new Class1(); myFunction myD = new myFunction(mb.MyOtherFunction); int returnValue = myD.Invoke(8); Console.WriteLine(returnValue); Console.Read(); } }

Question
Which ASP.NET event reacts when a page is released from memory? Options:

1. 2. 3. 4.

Disposed Load PreRender Unload

Answer
The Disposed event reacts when a page is released from memory. Option 1 is correct. The Disposed event is triggered when a page is released from memory. It is a page-level event. Option 2 is incorrect. The Load event is triggered when a page is loaded and is a page-level event. Option 3 is incorrect. The PreRender event is triggered when a page is submitted and is a pagelevel event. Option 4 is incorrect. The Unload event is triggered when a page is unloaded and is a page-level event.

Summary
C# 2005 provides several new features and enhancements on the previous version. In C# 2005, each variable contains a name, address, data type, value, scope, and lifetime. A variable name and a data type association is known as a variable declaration. One statement can contain multiple variables, and multiple variables of the same type can be declared in the same statement. Access modifiers enable you to provide variables with specific levels of access. C# 2005 supports if/else, for, do...while, and while statements. It includes ASP.NET event handlers for web applications and web forms, and Windows Forms event handlers. It also supports the use of delegates in code.

Table of Contents

Types and Classes in C# 2005


Learning objective
After completing this topic, you should be able to create types and classes in a given scenario.

1. Creating classes

In C# 2005, a class provides a description of the data, attributes, and methods that characterize a specific category of objects. For example, you may create and use a Person class to define the code resources and properties of objects that represent people. An object you create using the class is then known as an instance of the Person class. You can create multiple instances of a single class. For example, you can create Person01, Person02, and Person03 as three instances of the Person class. You can define a class to include

fields methods properties

fields Fields are variables that contain information in a class. When an application runs, the fields are retained within the objects that become instantiated. methods Methods are routines in a class that perform various actions, return values, or provide information to the code in the class. A constructor method usually titled the same name as the class is a special method that is invoked when an object is created or instantiated. Constructor methods always run first and once only for each object that is created. To add a constructor method to a class, you declare it as a public method. You can also add parameters to the constructor to assign the object that is being created one or more values, which are known as the instance variables of the class you are instantiating. properties A property is a specialized hybrid of fields and methods that formalizes setting and retrieving data values. In code, you can use the set method to set property values and the get method to retrieve these values. An indexer is written similar to a property, and allows a member object to be indexed similar to an array. Within a class, you can define the scope for a particular method or field using the same access modifiers you use to define the scope of variables private, internal, protected, protected internal, and public. For example, a method you define as public is accessible to all code, whereas a method defined as protected is accessible only to code within its class. You can create classes in C# 2005 using the class keyword. To create a class that represents cars, for example, you may declare a single class named Car.

public class Car { [Class implementation] } You can also declare multiple classes in a single file.

public class Car { [Class implementation] } public class House { [Class implementation] } public class Garden { [Class implementation] } Once you've declared a class, you can choose to add fields to it. For example, suppose you want to declare three variable fields Make, SerialNo, and Owner for the Car class. To complete the code, you specify that the Make field must contain a private value of the string type.
public class Car { MISSING CODE; private int SerialNo; private string Owner; }

You type private string Make to complete the code. The completed code declares three instance variables for the Car class. These values can be assigned and accessed through accessors and mutators.
public class Car { private string Make; private int SerialNo; private string Owner; }

You can then write a simple constructor method and use it to initialize the Owner field by assigning it a value.
public class Car { private string Make; private int SerialNo; private string Owner; public void myMethod() { } public Car() { Owner = "Bobby"; } }

After you've also declared the method named myMethod, you can create a Car object an instance of the Car class and set it to call this method.
public class CarExample { Car Car1 = new Car(); Car1.myMethod(); }

You can define more complex methods within the Car class. In this code, a method retrieves the value of the SerialNo variable and adds 1 to retrieve the next value. Normally when writing this sort of method, we would also ensure that SerialNo has been initialized to a value before it is incremented.
public class Car { private string Make; private int SerialNo; private string Owner; public void myMethod() { } public Car() { Owner = "Bobby"; } private int SerialPlusOne() { int temp = SerialNo; temp += 1; return temp;

} }

You use the return keyword to explicitly return values from a method. For example, you can use return to return the value of the serial number of the Car method as an int type and change its local scope value by 1. The type to be returned is specified just before the method's name.
public class Car { private string Make; private int SerialNo; private string Owner; public void myMethod() { } public Car() { Owner = "Bobby"; } private int SerialPlusOne() { int temp = SerialNo; temp += 1; return temp; } }

After you write the method to return the value, you declare an int variable, intRes, and use it to hold the value returned by the function.
public class CarExample { Car Car1 = new Car(); int intRes; Car1.myMethod(); intRes = Car1.SerialPlusOne(); }

Method parameters are used to send information to a method when it is called. Suppose you have written code to pass two parameters, param1 and param2 of type int into a method. You then created two different temporary values, to enable you to manipulate the values in the code. Now you want to set one value in a field location and return the other value, while ensuring that the current SerialNo value gets overwritten with the resultant value of when it is added to param1.

public int AddEmUp(int param1, int param2) { int temp1, temp2; temp1 = SerialNo; temp1 += param1; MISSING CODE; temp2 = param1; temp2 += param2; return temp2; }

You type SerialNo = temp1 to complete the code that sets the field. You have completed the required code to set the field.
public int AddEmUp(int param1, int param2) { int temp1, temp2; temp1 = SerialNo; temp1 += param1; SerialNo = temp1; temp2 = param1; temp2 += param2; return temp2; }

Next you declare another variable, intRes2, and add a function call that uses the parameters for the AddEmUp method.
Car Car1 = new Car(); int intRes1; int intRes2; Car1.myMethod(); intRes1 = Car1.SerialPlusOne(); intRes2 = Car1.AddEmUp(2, 4); }

Now suppose you want to define and then retrieve properties of the Car class. First, you define a property by naming it and specifying its type. Then you specify get to return the value of a field in the class, named Owner, and set to use a parameter so that its value can be set to the Owner field.
public string Own { get { return Owner; } set { Owner = value; } }

Then you write code to interact with the property. You declare the name variable, set the property, and finally retrieve the property and store its value in the name variable.
public class CarExample { // string name; Car car1 = new Car(); car1.Own = "Arnold"; name = car1.Own; // }

Next you want to define an indexer for your class. Suppose you want to include a list of past owners of a given car within a string array and want to access it similar to an array outside the class. You first declare your array, called PrevOwners, within your class and decide on a size of 15. Then you write your indexer, similar to a property, which will take in an integer, or int value called index.
public class Car { private string prevOwners[] = new string[15]; //... public string this [int index] { //get and set blocks here } }

The indexer requires you to specify a modifier, then the return type, and also the this keyword to indicate the current object of the class. The indexer takes in the variable index -- if the calling code is looking up the current value, the get block returns the value at the index specified. If it is setting the current value it will place the value in the array as specified by index.
public class Car { private string[] prevOwners = new string[15]; //... public string this [int index] { get { return prevOwners[index]; } set { MISSING CODE; } } }

To complete the Set statement, you type prevOwners[index] = value. You have completed the required set statement. The variable value refers to what is set in the calling code.
public class Car { private string[] prevOwners = new string[15]; //... public string this [int index] { get { return prevOwners[index]; } set { prevOwners[index] = value; } } }

Question
Suppose you want to declare a constructor method in a class called School that initializes the Teacher field, which you've already declared in a class. Which code do you use to do this? Options: 1. public string School()
{ Teacher = "Jeremy"; } public School() { Teacher = "Jeremy"; } public void Teacher() { School = "Jeremy"; }

2.

3.

Answer
To declare a constructor method, School, that initializes the Teacher field, you use the code
public School() {

Teacher = "Jeremy"; }

Option 1 is incorrect. You only specify a return type when something needs to be returned. In this case, you simply want to declare a new method and initialize a field. Option 2 is correct. To declare a constructor method, you specify School as a public method. You then initialize the field by assigning it a value. Option 3 is incorrect. You need to specify School, rather than Teacher, as the method name, and Teacher as the field name to which you assign a value.

2. Working with classes


C# 2005 provides a large number of useful classes and reference classes types of classes created when objects are instantiated. It also provides namespaces that simplify the process of referencing classes in code. Some of the most commonly used classes in C# 2005 include

the Object class the String class the Exception class the Array class

the Object class The Object class is the parent class of all objects and types, which inherit from this class automatically. In programming, this class can be useful in a variety of ways. For example, when you want to write a function that may need to return a variety of object types, you use the Object class. This is because you don't know the type of the object being returned for any single function call. You can therefore refer to it as an instance of the Object class and cast it to the proper subclass later. the String class The String class is a primitive, non-value type made up of multiple "char" value types. It can represent any combination of alphanumeric, whitespace, or special characters such as @, $, and ^. the Exception class The Exception class or System.Exception, is the base class for all exceptions in C#. Exceptions are objects that contain information about errors. the Array class The Array class is the base class used in supporting arrays, which represent a contiguous grouping of objects and primitive types indexed from 0 to an indeterminate upper-bound number, depending on the programmer's needs.

In C# 2005, the System.Collections namespace enables you to implement array features through a series of classes. Classes available in the System.Collections namespace include
Hashtable BitArray Queue Stack SortedList ArrayList

Hashtable

The Hashtable class sorts through a collection of values that have been organized using a key.
BitArray

The BitArray class manages Boolean arrays stored as bit values.


Queue

The Queue class sorts through data using a first-in, first-out (FIFO) approach.
Stack

The Stack class sorts through data using a last-in, first-out approach. SortedList The SortedList class sorts through a collection of values that are associated with keys. This stands in contrast to the Hashtable class, whose keys are not necessarily sorted. ArrayList The ArrayList class implements an array whose allocated size grows dynamically for every element that is added to it. Suppose you want to create an object type class called myObject and then cast it to the integer type.
public void res() { object myObject; int result; result = (MISSING CODE(myObject)); }

You type (int) to complete the required code. When the code runs, it will create the myObject instance and then cast it to the integer subclass specified by int.
public void res() { object myObject; int result; result = ((int)(myObject)); }

Next you want to create a String type object called myOwnString and then set it to the literal value "This is my own string."
string MISSING CODE = "This is my own string.";

To complete the code, you type myOwnString. The code now declares and initializes an object of the string type. Note that the string class here is declared similar to a variable, yet it is also possible to perform precisely the same operation by passing the string value into an object constructor.
string myOwnString = "This is my own string.";

Let's say you want to test whether the myString object, which is of the String type, has a null value. To do this, you can use an if statement to test whether the myString object is set to null.
String myString=null; if (MISSING CODE) { Console.WriteLine("The String is null"); }

You type myString == null to complete the code. When the code runs, it will test whether the value of the myString variable is set to null and, if it is, print a message on the application console.
String myString=null; if (myString == null) { Console.WriteLine("The String is null"); }

You want to declare a string array called myOwnArray and then set it to include the three indices Word 1, Word 2, and Word 3.
public void res() { MISSING CODE = {"Word 2", "Word 1", "Word 3"}; int myLength = myOwnArray.Length; for (int i = 0; i < myLength; i++) { Console.WriteLine(myOwnArray[i]); } Array.Sort(myOwnArray); for (int i = 0; i < myLength; i++) { Console.WriteLine(myOwnArray[i]); } Console.Read(); }

You type string[] myOwnArray to complete the code. You have now declared an array with three indices. Note that this array will automatically inherit properties and methods from the array class, such as the Length property which contains an integer value for the number of indices, and the Sort method, which sorts a given array.
public void res() { string[] myOwnArray = {"Word 2", "Word 1", "Word 3"}; int myLength = myOwnArray.Length; for (int i = 0; i < myLength; i++) { Console.WriteLine(myOwnArray[i]); } Array.Sort(myOwnArray); for (int i = 0; i < myLength; i++) { Console.WriteLine(myOwnArray[i]); } Console.Read(); }

You now want to import the Collections namespace so that you can call the classes of the namespace without needing to write their full hierarchy names. Then you want to declare three new objects of this namespace ArrayList, Queue, and Stack.
MISSING CODE; public class Example { ArrayList MyArrL = new ArrayList(); Queue MyQueue = new Queue(); Stack MyStack = new Stack(); }

You type using System.Collections to complete the code. You have completed the required code to import the Collections namespace.
using System.Collections; public class Example { ArrayList MyArrL = new ArrayList(); Queue MyQueue = new Queue(); Stack MyStack = new Stack(); }

Question
Suppose you create an Object instance with the code: object newObj = "test";. You would like to cast it to the type string, and store it in the variable named result.

Which code do you use to do this? Options: 1. result = ((toString)(myObject)); 2. result = ((Node)(newObj)); 3. result = ((string)(newObj));

Answer
To create an Object instance called newObj and then cast it to the string type, you use the code
result = ((string)(newObj));

Option 1 is incorrect. This code will create an Object instance called myObject and then attempt to cast it to the toString subclass, which will fail since no such subclass exists. Option 2 is incorrect. This code will create an Object instance called newObj and then send it to the Node object subclass. Option 3 is correct. This code will create an Object instance called newObj. It will then cast the new object to the specified object subclass String.

Question
Suppose you want to create a string type called newStr and then set it to the value "This is a new string". Which code do you use to do this? Options: 1. string new newStr = "This is a new string"; 2. string newStr = "This is a new string"; 3. string newStr = ("This is a new string");

Answer
To create a string class called newStr and then assign it the value "This is a new string", you use the code
string newStr = "This is a new string";

Option 1 is incorrect. This code will attempt to create a string instance called myOwnString but will be unable to assign any value since the new keyword requires an object instantiation syntax.

Option 2 is correct. This code will create a string instance called newStr. It will then initialize the new object by assigning it the specified string value, "This is a new string". Option 3 is incorrect. This code will generate a compile time error, and requires the new keyword in order for its syntax to work.

3. Using exceptions and development tools


An exception is an object that contains information about an error. Exceptions are derived from the System.Exception class. This class contains several public and protected methods. Two very commonly used methods are
GetBaseException, which returns the first exception ToString, which returns the error information

that occurs

The System.Exception class includes the following public properties:


Message Source InnerException HelpLink TargetSite StackTrace Data

Message

The Message property displays information about the error.


Source

The Source property displays the name of the object that caused the error. InnerException The InnerException property returns the object reference to a nested exception. HelpLink The HelpLink property displays a link to help information about an error. TargetSite The TargetSite property contains the method that caused the error. StackTrace The StackTrace property contains the method sequence which was running when error occurred.
Data

the

The Data property can provide additional information about an exception using a collection of key/value pairs. In C# .NET, several exceptions all inherit from the same class System.Exception (otherwise known as simply Exception) through an intermediary class called SystemException.

Some examples of these exceptions are InvalidOperationException, OutOfMemoryException, XmlException, and DataException. Through .NET Framework version 2.0, C# 2005 provides a more advanced SecurityException class than previous versions of C#. Examples of properties in the new SecurityException class include Action, Demanded, GrantedSet, DenySetInstance, FailedAssemblyInfo, and FirstPermissionThatFailed. The System.Collections.Specialized namespace in C# 2005 provides additional classes that optimize performance. For example, the StringCollection and StringDictionary classes are used to minimize time and maximize performance during coding. If an application throws an exception, you can check for errors by declaring a catch statement.
PermissionSet permitOnly = new PermissionSet(PermissionState.None); try { permitOnly.AddPermission(new SecurityPermission(PermissionState.Unrestricted)); } MISSING CODE { Console.WriteLine(myException.ToString); }

You type catch (Exception myException)to complete the code. You have completed the required code to check for general errors. You have set unrestricted permissions for the application. If this fails, an exception will be triggered.
PermissionSet permitOnly = new PermissionSet(PermissionState.None); try { permitOnly.AddPermission(new SecurityPermission(PermissionState.Unrestricted)); } catch (Exception myException) { Console.WriteLine(myException.ToString); }

In C# 2005, an object is removed when there are no remaining references to it in its environment. For example, suppose you declare the object myCar.
Car myCar = new Car();

To terminate the object once there are no more references to it, you tell the .NET runtime environment to terminate it by setting the variable to null.
myCar = null;

Two key development tools in C# 2005 include the base keyword, and a concept known as Boxing. Boxing is a process whereby the stack value is copied to the heap. For example, suppose you're working in an Object class that is a reference type (usually object types). Any stack values (usually variables or structs) will need to be converted into reference types on the heap by the system before they can be used in the Object class. The base keyword enables you to call methods straight from any base class. For example, using the base keyword in the subclass, Owner, enables the programmer to interact with values and methods in the base class.
public override string Owner { get { return base.Owner; } set { if (value > 9) { base.Owner = value; } else { throw new ArgumentException("Not Valid"); } } }

Question
Suppose you want to call a method for the Car class straight from the base class. Complete the code to do this.
public override string Car { get { return base.Car; } set { if (value > 9) { MISSING CODE.Car = value; } else { throw new ArgumentException("Not Valid"); } } }

Answer
To complete the code that calls a method for the Car class straight from the base class, you type base.

Summary
Classes describe the data, attributes, and methods that characterize a specific category of objects. You create classes using the class keyword, and then add required fields, methods, and properties to them. The return keyword is used in methods that return values, and access modifiers define method scope. Method parameters send information to a method. Examples of commonly used classes in C# 2005 include the Object, String, DBNull, and Array classes. C# 2005 also provides the System.Collections namespace, which makes it easy to reference a set of classes for manipulating collections such as arrays. The SecurityException class in C# 2005 contains several new properties. The System.Collections.Specialized namespace provides access to classes for optimizing performance. Support for boxing and the base keyword are useful development tools.

Table of Contents
| Print | Contents | Close |

Defining Types and Classes in C# 2005


Learning objective
After completing this topic, you should be able to define types and classes in a given scenario.

Exercise overview
In this exercise, you're required to define types and classes in a given scenario. This involves the following tasks:

creating types creating classes

Suppose you're using C# 2005 to create a new Person class.

Task 1: Creating types


First you want to use types and attributes to set values for the Person class.

Step 1 of 4

You want to retrieve an ID from the Person object, cast that ID to a string type, and store it in the variable named result. You have already initialized a Person object called p1. Complete the code to do this.
public class Person { string result; MISSING CODE (p1.ID); }

Result
To complete the code that retrieves the ID from the Person object, casts it to the String type, and store it in result, you type
result = ((string)

Step 2 of 4
Next you want to create a string called strUser and then set it to the "Personal information" string value. Complete the code to do this.
public class Person { string result; result = ((string) (pl.ID)); MISSING CODE = "Personal Information"; }

Result
To create the strUser class, you type
string strUser

Step 3 of 4
Suppose you've declared an object of the Integer type in code and now want to check whether the variable is set to null. To do this, you first declare an object named ncheck to which you can then compare the variable using a reference class in the System namespace. Which code declares the correct type of object or variable you will need to check against?

Options: 1. int ncheck; 2. System.Collections ncheck; 3. System.DBNull ncheck;

Result
To create the ncheck object so that you can use it to determine whether another object is set to null, you use the code
System.DBNull ncheck;

Option 1 is incorrect. You need to use the ncheck object to test whether another object is set to null. As a result, you must create the object using the System.DBNull class, rather than setting it to be of the same type as the object to which it will be compared. Option 2 is incorrect. The System.Collections namespace provides access to several classes for manipulating arrays. It doesn't, however, create an object automatically set to null, against which you can test other objects. Option 3 is correct. The DBNull reference class in the System namespace enables you to create an object set to null. Once you've done this, you can compare the object to another object to determine whether the other object is functionally equivalent to it.

Step 4 of 4
Suppose you want to import the namespace that enables you to access classes for manipulating arrays, without needing to write their full hierarchy names. Complete the code to do this.
MISSING CODE System.Collections; public class Person { string result; private object result = ((string)(p1.ID)); string strUser = "Personal Information"; }

Result
To enable you to access classes for manipulating arrays, you import the System.Collections namespace by typing
using

Task 2: Creating classes


Next you want to use classes and events to define a new class based on a user, including details such as his name, age, and address.

Step 1 of 4
Suppose you want to declare a private int variable instance for the Person class called Age. Complete the code to do this.
public class Person { private string Name; MISSING CODE private string Address; }

Result
To declare the variable instance, you type
private int Age;

Step 2 of 4
Suppose you have declared a new method, personMethod, in the Person class. You then created an instance of the Person class named Person1. Which code do you use to call the method named personMethod from the class instance? Options: 1. Person1.Person.personMethod(); 2. personMethod(); 3. Person1.personMethod();

Result
You use the following code to call the method for the Person1 object:
Person1.personMethod();

Option 1 is incorrect. When you first defined the Person1 object, you needed to specify the class of which it's an instance. You therefore don't need to specify the class to which the object belongs again, when using the object to call a method in its class.

Option 2 is incorrect. In addition to naming the required method, you need to specify the name of the object calling the method in this case, Person1. Option 3 is correct. To call a method defined for the Person class, you simply name the instance of the class the Person1 object and then specify the name of the method. By default, the Person1 object has access to the methods defined for its class.

Step 3 of 4
Suppose you want to return the value of the age of the Person method as an int type from a restrictionless method and change its local value by 3 from calling code. Complete the code to do this.
public class Person { private string Name; private int Age; private string Address; public void personMethod() { } public Person() { Address = "Mexico"; } MISSING CODE AgePlusThree() { int temp = Age; temp += 3; return temp; } }

Result
To create a new function, you type
public int

Step 4 of 4
Suppose you have written code to accept two parameters, par1 and par2, of type int and to ensure that the values are passed into a method. Then you created a different temporary value to be manipulated within the code. Now you want to set the first parameter to the field location Age.

Complete the code to do this.


public void personMethod() { } public Person() { Address = "Mexico"; } public int AgePlusThree() { int temp = Age; temp += 3; return temp; } public int TotalAge(int par1, int par2) { int temp1; temp1 = Age; temp1 += par1; MISSING CODE temp1 += par2; return temp1; } }

Result
To set one value in a field location and return the other value, you type
Age = par1;

Types and classes have now been defined using C# 2005.

Table of Contents
| Print | Contents | Close |

Essential Interfaces in C# 2005


Learning objective
After completing this topic, you should be able to use interfaces in a given scenario.

1. The System namespace

C# 2005 provides several interfaces that enable you to access, retrieve, and manipulate code and files. When you reference an object in C#, the object exposes an interface containing only the members to which the class from which you make the reference is permitted access. This limited form of access is known as encapsulation. Encapsulation helps protect objects from unauthorized use, by exposing only required code rather than all implementation details to classes outside an object's own class. It also reduces the system resources required to access code. The System namespace in C# enables you to navigate the organizational structure of the .NET Framework 2.0 class library and to access the elements it contains in code by referencing them. This namespace is available to every project you create in Visual Studio 2005. As well as providing access to classes, structures, and other elements, the System namespace provides access to several interfaces.

Note
An interface names the properties and methods that a class implementing the interface must define. Examples of interfaces you can access via the System namespace include
IComparable ICloneable IConvertible IFormattable IDisposable

IComparable The System.IComparable

interface enables you to characterize a generalized comparison method through which instances are ordered. Before the characterization can occur, the generalized comparison method must be implemented by a class or value type. interface creates a clone or copy of a class, with equivalent values to the original class of which it's a copy. interface specifies the attributes of methods that take the implementing reference of a value and convert it to a common language runtime (CLR) type of a corresponding value. interface enables you to convert the value of an object into a string by formatting it.

ICloneable The System.ICloneable

IConvertible The System.IConvertible

IFormattable The System.IFormattable IDisposable

The System.IDisposable interface enables immediate freeing and cleaning up of resources using its Dispose method. When an object is no longer needed, an application automatically uses the object's Finalize method to close it. However, this method enables a cleanup to occur, to free resources, prior to closing an object. Using the System.IDisposable interface, you can force an object to close immediately, to free the memory it occupies. Suppose you want to use the CompareTo method, available via the System.IComparable interface, to compare the value of a current object to another value you specify. To do this, you first define a class to implement the System.IComparable interface, and define the values you want to compare.
using System.Collections; public class Room : IComparable { int number; Stack hotelDataStack = new Stack(); }

Once you've defined a class and values, you call the CompareTo method directly in a function. In the function, the value you specify for comparison must be of the same type as the value to which you want to compare it.
using System.Collections; public class Room : IComparable { int number; Stack hotelDataStack = new Stack(); public Room(int n) { number = n; } public int MISSING CODE(object obj) { Room temp = ((Room)(obj)); return number.MISSING CODE(temp.number); } }

You type CompareTo to complete the code. When the completed code runs, it will return a value to indicate whether the integer represented by Room is greater than, equal to, or less than the integer represented by number.

using System.Collections; public class Room : IComparable { int number; Stack hotelDataStack = new Stack(); public Room(int n) { number = n; } public int CompareTo(object obj) { Room temp = ((Room)(obj)); return number.CompareTo(temp.number); } }

Note
If the values are equal, the code will return a value of zero. Otherwise, the code will return the positive or negative value representing the difference between the values of Room and number.

Question
What does the CompareTo method of the System.IComparable interface enable you to do? Options: 1. Compare the value of an object to another value of the same type 2. Compare the value of a reference to the value of a type 3. Compare values of different types in code

Answer
The CompareTo method enables you to compare the value of an object to another value of the same type. Option 1 is correct. The CompareTo method enables you to compare the value of an object to another value of the same type, often determining if the first object's value is greater than, less than, or equal to the value of the second. Option 2 is incorrect. You use the CompareTo method to compare the value of an object to another value of the same type. The System.IConvertible interface enables you to convert an implementing reference into a type of corresponding value, although not to compare reference and type values.

Option 3 is incorrect. The CompareTo method enables you to compare values of the same type only. Now suppose you want to implement the Dispose method available via the System.IDisposable interface, to ensure that an application disposes of the hotelDataStack object immediately, once it's no longer required. To use this method, you need to declare a class to implement the interface.
public class Room : IDisposable { Stack hotelDataStack = new Stack(); private bool disposedValue = false; protected void Dispose(bool disposing) { if (!(this.disposedValue)) { if (disposing) { hotelDataStack.Clear(); hotelDataStack = null; } } this.disposedValue = true; }

Once you've implemented the IDisposable interface, you need to use a subroutine to call the Dispose method, and to set it to stop the call to the default Finalize method.
public class Room : IDisposable { Stack hotelDataStack = new Stack(); private bool disposedValue = false; protected void Dispose(bool disposing) { if (!(this.disposedValue)) { if (disposing) { hotelDataStack.Clear(); hotelDataStack = null; } } this.disposedValue = true; } protected void MISSING CODE() { MISSING CODE(true); GC.SuppressFinalize(this); } }

You type Dispose to complete the code.

When the completed code runs, the Dispose method will close the hotelDataStack object and free the memory it occupies, as soon as the object is no longer required.
public class Room : IDisposable { Stack hotelDataStack = new Stack(); private bool disposedValue = false; protected void Dispose(bool disposing) { if (!(this.disposedValue)) { if (disposing) { hotelDataStack.Clear(); hotelDataStack = null; } } this.disposedValue = true; } protected void Dispose() { Dispose(true); GC.SuppressFinalize(this); } }

Question
Suppose you want to ensure that resources are freed immediately once an object is no longer required. Which interface in the System namespace enables you to do this? Options: 1. 2. 3. 4.
Dispose IConvertible IDisposable IFormattable

Answer
The System.IDisposable interface enables you to dispose of an object and free its resources as soon as it's no longer required. Option 1 is incorrect. Dispose is the method, rather than the interface, you use to free the resources that an object uses as soon as the object is no longer required.

Option 2 is incorrect. The System.IConvertible interface enables you to specify the attributes of methods that convert the implementing reference of a value into a CLR type of a corresponding value. Option 3 is correct. The IDisposable interface supports the Dispose method, which you use to release an object's resources as soon as the object is no longer required. Option 4 is incorrect. The System.IFormattable interface enables you to convert the value of an object into a string.

2. The System.Collections namespace


The System.Collections namespace contains classes and interfaces that enable you to define and manipulate collections of objects, such as lists, queues, arrays, hash tables, and dictionaries. Examples of interfaces available via the System.Collections namespace are
ICollection IComparer IList IEnumerator and IEnumerable IEqualityComparer IHashCodeProvider IDictionary and IDictionaryEnumerator

ICollection The ICollection IComparer

interface takes collections that are not generic and establishes their characteristics and associated objects. The IComparer interface requires a method to compare objects. This is similar to the IComparable interface of the System namespace, but IComparer is specifically intended to be used in order to sort objects within a collection.

IList

The IList interface is a group of objects wherein each can be located and referred to in an index. IEnumerator and IEnumerable Using both IEnumerator and IEnumerable in code enables you to use an enumerator to iterate non-generic data collections. The IEnumerable interface enables a class to return an enumerator that can read but not alter data, and includes a single method GetEnumerator. The IEnumerator interface enables the exposed enumerator to iterate a non-generic data collection, and includes methods such as MoveNext, Current, and Reset for navigating through the collection.
IEqualityComparer

The IEqualityComparer interface uses methods to compare and assess the equality of objects. This interface is similar to the IComparer interface, but here the interface is only used to define the rules pertaining to equality, and not overall sorting rules.
IHashCodeProvider The IHashCodeProvider

interface gives an object a hash code by applying a hash function. IDictionary and IDictionaryEnumerator The IDictionary interface depicts pairs of keys and values in a collection that is not generic. The IDictionaryEnumerator interface takes the elements of a dictionary that is not generic and enumerates them. The IEnumerator and IEnumerable interfaces must often be implemented with care. If data in a collection changes during the enumeration process, it invalidates the enumerator. To prevent this from occurring, you can use a catch statement to make certain the index range does not change unexpectedly.
public CarLot[] myCars; public int iter; public object Current { get { try { return myCars(iter); } catch (IndexOutOfRangeException ex) { throw new InvalidOperationException(); } } } public bool MoveNext() { iter = iter + 1; return (iter < myCars.Length); }

Alternatively, you can lock a data collection until the enumeration process completes.
public void Reset() { lock (MyCars) { iter = -1; } } }

Suppose you want to use the IEnumerable interface, available via the System.Collections namespace, to enable a class to return an enumerator that can read but not alter data. To do this, you first define a class to implement the IEnumerable interface. You then use the GetEnumerator method, to retrieve an enumerator.
using System.Collections; public class Car { public Car(string name, int number) { } } public class CarLot : IEnumerable { private Car[] CarsInLot = new Car[20]; public CarLot(string name, int dimension) { } public IEnumerator MISSING CODE() { return new CarTicker(CarsInLot); } } public class CarTicker { public CarTicker(Car[] myArray) { } }

To complete the code, you need to use the IEnumerable interface to expose an enumerator.
using System.Collections; public class Car { public Car(string name, int number) { } } public class CarLot : IEnumerable { private Car[] CarsInLot = new Car[20]; public CarLot(string name, int dimension) { }

public IEnumerator MISSING CODE() { return new CarTicker(CarsInLot); } } public class CarTicker { public CarTicker(Car[] myArray) { } }

You type GetEnumerator. The IEnumerable implementation code is now complete. It enables you to use an enumerator to read non-generic data collections.
using System.Collections; public class Car { public Car(string name, int number) { } } public class CarLot : IEnumerable { private Car[] CarsInLot = new Car[20]; public CarLot(string name, int dimension) { } public IEnumerator GetEnumerator() { return new CarTicker(CarsInLot); } } public class CarTicker { public CarTicker(Car[] myArray) { } }

Question
Suppose data in a collection may update during the enumeration process. How can you prevent this from invalidating the enumerator?

Options: 1. 2. 3. 4. By ensuring that the collection is generic By locking the collection By using a catch statement By using the IEqualityComparer interface

Answer
You can prevent data changes from invalidating an enumerator by locking the data collection or by using a catch statement. Option 1 is incorrect. In C# 2005, different interfaces enable you to enumerate either generic or non-generic data collections, although the generic versions are under a different namespace. For example, you use IEnumerator and IEnumerable with collections that are not generic. The type of a collection doesn't determine whether changes will invalidate the enumeration process. Option 2 is correct. The collection can be locked during enumeration so that the data in the collection does not change and disrupt the enumeration process. Option 3 is correct. The enumerator catches the exceptions that occur before they can affect the process and make it invalid. Option 4 is incorrect. The IEqualityComparer interface uses methods to compare and assess the equality of objects. It doesn't prevent data changes from invalidating an enumeration process.

Summary
In C# 2005, the System namespace provides several interfaces that enable you to access code contained in the .NET Framework 2.0 class library. The System.Collections namespace includes interfaces for defining and manipulating object collections. For example, it provides interfaces such as ICollection, IComparer, IList, IEnumerator and IEnumerable, and IDictionaryEnumerator.

Table of Contents

System.Collections Classes in C# 2005


Learning objective
After completing this topic, you should be able to use classes in the System.Collections namespace.

1. System.Collections classes
The System.Collections namespace includes several classes that enable you to implement and manipulate object collections. Examples of classes in the System.Collections namespace enable you to store object collections in different types of structures, to compare values, and to generate hashes:
Stack Stack Queue BitArray Hashtable SortedList ArrayList Comparer and CaseInsensitiveComparer CaseInsensitiveHashCodeProvider

The Stack class supports data stacks, which store non-generic collections of objects on a last-in, first-out (LIFO) basis. You can think of a stack of objects as similar to a stack of books. By default, you add objects to the top of the stack. Only the object currently on the top can be removed or manipulated. A stack can include objects of any sort. The Stack class implements the ICollection and IEnumerable interfaces. By default, a stack can hold up to ten data elements. However, if the number of elements exceeds ten, the class automatically reallocates the additional elements. It continues to do this, irrespective of the number of elements added. The Stack class includes the following methods: The Contains method searches a stack for a specified object, and returns either True or False. The Pop method removes and returns the top object of a stack. If Stack.Pop is applied to an empty stack, an error is generated and thrown. The Push method moves an object to the top of a stack. If the stack already includes 10 objects, they are automatically reallocated. The ToArray method copies a stack and all of its objects to a new array, while maintaining the original order of the objects.

The Peek method returns the top item of a stack, without altering the stack in any way.
Queue

The Queue class enables you to arrange data in a queue sequence, using a first-in, firstout (FIFO) format. When you add an object to a queue, it is placed at the end of the queue by default. Only data at the front of the queue is intended to be removed or manipulated. The Queue class implements the ICollection and IEnumerable interfaces, and can include objects of any type. Methods in the Queue class include The Contains method searches a queue for a specified object. The CopyTo method enables you to copy specified objects specified in an index range from a queue into an array. An array should already be declared in order to be passed in as a parameter. The Dequeue method returns the first item from a queue as an object. The Enqueue method adds an object to the end of a queue. The Peek method returns the first object in a queue, without actually removing it from the queue. The ToArray method copies the ordered objects of the entire queue into a new array an array that was not necessarily declared before the method was invoked.
BitArray

The BitArray class enables you to implement byte arrays to manage a series of bit values. These values are depicted as Boolean values. This class is notable for its methods that perform boolean logic operations on the elements of specified BitArrays, including And, Not, Or, and Xor.
Hashtable

The Hashtable class enables you to initiate a hash table, in which class keys and their corresponding values are stored as pairs. The keys and values may be objects of any sort. In the table, each key is converted into a hash value that references a corresponding value. Using hash tables enables fast retrieval of value pairs, based on specified keys. Methods in the Hashtable class include The ContainsKey method searches a hash table for a specified key and returns a boolean value indicating if the key is present or not.

The CopyTo method copies value and key pairs from a hash table and places them in an array beginning at a provided index, and uses the DictionaryEntry structure to sort the values. You use the Add method to add values and its paired key to a hash table. The Hashtable.Keys property of the Hashtable class provides information about the keys in a hash table, while the Hashtable.Values property provides information about their values. Since these properties are themselves collections, the ICollection interface is used in this process to ensure that all necessary methods from that interface can be called on these properties.
SortedList The SortedList

class enables you to store keys and their associated values. The pairs are sorted by their key values this is unlike the Hashtable class, where the keys are unsorted. In a sorted list, you can retrieve a value by specifying the key to which it corresponds, as you would when using a hash table. Alternatively, you can retrieve a value by specifying its index position using SetByIndex or GetByIndex as you would when using an array. This can be an advantage in some cases. As you add new elements to a sorted list, they are accepted automatically and placed in the correct sort order. This automatic readjustment also occurs when elements are removed. Accessing values in a sorted list is slower than accessing values in a hash table. However, sorted lists are more flexible because they enable you to retrieve values based on their index positions. Provided the data in a sorted list remains unchanged, the Synchronize method enables multiple users to access the list. This method uses a wrapper to secure each operation.

ArrayList

The ArrayList class enables you to implement an array that can change in size as elements are added to a list. This resizing occurs through an automatic process of reallocation. An ArrayList is similar to Queues and Stacks, but does not conform to any LIFO or FIFO functionality. The intention is that you may add or remove elements from any point in the collection through methods such as Insert and RemoveAt, which are passed indices of the collection. Like many other classes of the Systems.Collection namespace, an ArrayList uses the

method to enable users to read it simultaneously, provided that the array remains unchanged as this occurs. To ensure security, this method returns a wrapper. Comparer and CaseInsensitiveComparer The Comparer and CaseInsensitiveComparer classes use the IComparer interface to enable you to compare the values of objects. You use the Comparer class to perform case-sensitive comparisons, and CaseInsensitiveComparer to ignore case. Both classes return values to indicate whether an object is equal to, greater than, or less than another specified value. Both the Comparer and CaseInsensitiveComparer classes use Thread.CurrentCulture the current thread to determine the sort order they must use.
CaseInsensitiveHashCodeProvider The CaseInsensitiveHashCodeProvider

Synchonize

class enables you to generate and retrieve hash codes for objects. To do this, it uses a hashing algorithm that ignores case in strings. The IHashCodeProvider interface is implemented by the CaseInsensitiveHashCodeProvider class.

Question
Suppose you want to store a set of value and key pairs in a way that enables you to retrieve values based on their index positions. Which class in the System.Collections namespace can you use to do this? Options: 1. 2. 3. 4.
BitArray Comparer Hashtable SortedList

Answer
The SortedList class enables you to store key and value pairs, and to retrieve values based on their index positions. Option 1 is incorrect. The BitArray class stores a series of bit values, which are depicted as boolean values, in an array. It doesn't store key and value pairs. Option 2 is incorrect. The Comparer class enables you to perform case-sensitive comparisons of the values of objects, rather than to store key and value pairs.

Option 3 is incorrect. The Hashtable class enables you to store key and value pairs in a table. However, it doesn't enable you to retrieve values based on their index positions, because it uses a table format rather than a list format to store key and value pairs. Option 4 is correct. A SortedList is a list in which values are sorted according to the keys to which they correspond. You can retrieve values from a sorted list using their index positions or by specifying the keys to which they correspond.

2. Using collection classes


To implement any of the classes in the System.Collections namespace, you import the namespace and declare a variable as an instance of the class. You can then use the class instance with any of the methods available to the class. For example, suppose you want to create a hash table using the Hashtable class, and populate this table with values. Once you've imported the namespace and declared a class with public scope, you declare an instance of the Hashtable class in this case, a variable named myHt.
using System.Collections; public class Example { public void Main() { MISSING CODE myHt = new MISSING CODE();

You type Hashtable() to complete the declaration. Now that you've declared the myHt variable as an instance of the Hashtable class, you can use it with methods that belong to the class.
using System.Collections; public class Example { public void Main() { Hashtable myHt = new Hashtable();

In this example, you complete the required code by adding values to the hash table, checking that the values correspond to the correct key, and then copying the table values into an array.
myHt.Add("One", "Value1"); myHt.Add("Two", "Value2"); myHt.Add("Three", "Value3"); myHt.Add("Four", "Value4");

myHt.Add("Five", "Value5"); if (myHt.ContainsKey("Six")) { Console.WriteLine("This value should not be here"); } else if (myHt.ContainsKey("Two")) { Console.WriteLine("This key should be here"); } string[] arStringArray = new string[10]; myHt.Keys.CopyTo(arStringArray, 4); } }

Now suppose you've declared an instance of the Queue class named Qmine, and used the Enqueue method to add values to the instance.
public class Ex { public void Main() { Queue Qmine = new Queue(); object obj = new object(); object[] objAr1; object[] objAr2 = new object[8]; Qmine.Enqueue(2); Qmine.Enqueue(4); Qmine.Enqueue(6); Qmine.Enqueue(8); Qmine.Enqueue(10); } }

You now want to use the appropriate method to initiate a new array to contain the ordered objects in the queue.
public class Ex { public void Main() { Queue Qmine = new Queue(); object obj = new object(); object[] objAr1; object[] objAr2 = new object[8]; Qmine.Enqueue(2); Qmine.Enqueue(4); Qmine.Enqueue(6); Qmine.Enqueue(8); Qmine.Enqueue(10); objAr1 = Qmine.MISSING CODE; Qmine.CopyTo(objAr2, 3); } }

Type ToArray() to complete the code.

When the code runs, the ToArray method will copy the ordered objects in the Qmine queue to an array that it sizes appropriately. Note that in this code, the CopyTo method is used to achieve a similar thing in a different way here the array's size is pre-declared, and the elements of the new array will be copied from the third element onward until the end of the objAr2 array is reached.
public class Ex { public void Main() { Queue Qmine = new Queue(); object obj = new object(); object[] objAr1; object[] objAr2 = new object[8]; Qmine.Enqueue(2); Qmine.Enqueue(4); Qmine.Enqueue(6); Qmine.Enqueue(8); Qmine.Enqueue(10); objAr1 = Qmine.ToArray(); Qmine.CopyTo(objAr2, 3); } }

This code declares an instance of the Stack class, uses the Push method to place objects into the stack, and then uses the Pop method to extract them from the top of the stack. Note that upon extraction, the objects must be treated as instances of the Object superclass and then cast into their proper type. This is because since most collections are intended to work with most kinds of objects, Pop and other extraction methods do not intrinsically know what type of object they will be returning.
using System.Collections; public class Room { public Room() { } } public class Ex { public void Main() { Stack sta = new Stack(); Room rm1 = new Room(); Room rm2 = new Room(); Room rm3 = new Room(); Room rm4 = new Room(); Room rm5 = new Room();

sta.Push(rm1); sta.Push(rm2); sta.Push(rm3); sta.Push(rm4); sta.Push(rm5); object obj = sta.Pop(); Room myRm = ((Room)(obj)); } }

Supplement
Selecting the link title opens the resource in a new browser window. Launch window Iterators are another new feature of using Collection classes, click to find out more.

Question
Suppose you want to return the top item of a stack instance you've named stack1, without altering the stack. Which of the Stack methods do you use to do this? Options: 1. 2. 3. 4.
stack1.Contains stack1.Peek stack1.Pop stack1.ToArray

Answer
The Peek method, which you implement using the stack1 instance, returns the top item in the stack without altering the stack itself. Option 1 is incorrect. The Contains method searches for a specified object in a stack, rather than returning the top object. Option 2 is correct. The Peek method returns the top item of a stack without removing this item, and therefore without altering the stack. To implement the method, you use the instance of the Stack class that you've declared. Option 3 is incorrect. The Pop method removes and returns the top object of a stack. It therefore alters the original stack, rather than only returning the top object.

Option 4 is incorrect. The ToArray method copies the ordered objects in a stack to a new array.

3. Abstract base classes


An abstract base class is designed to enable a hierarchy of other classes to use a common base class, via a process known as subclassing. Abstract classes are unique in that their only function is to support other classes in this manner, and so cannot be instantiated. Abstract classes provide methods and properties that all their subclasses will inherit from them. Often, in the interests of simplicity, these share the same names as similar properties in other collections that do not inherit the base class. Examples of classes in the System.Collections namespace that provide the abstract base class are
CollectionBase DictionaryBase ReadOnlyCollectionBase

CollectionBase The CollectionBase DictionaryBase The DictionaryBase

class enables an abstract base class for strongly typed collections. It provides properties such as Count and Capacity, and methods such as Clear. class enables an abstract base class for pairs of keys and values. It provides properties such as Count, and methods such as Clear and CopyTo. class enables an abstract base class for strongly typed, non-generic, read-only collections. It provides properties such as Count and InnerList .

ReadOnlyCollectionBase The ReadOnlyCollectionBase

Question
Suppose you want to provide an abstract base class for representing a set of key and value pairs. Which class do you use to provide the abstract base class? Options: 1. CollectionBase 2. DictionaryBase 3. ReadOnlyCollectionBase

Answer
You use the DictionaryBase class to provide an abstract base class for representing a set of key and value pairs.

Option 1 is incorrect. The CollectionBase class takes a strongly typed collection and provides an abstract base class for it. Option 2 is correct. The DictionaryBase class takes a strongly typed collection of pairs of keys and values and provides an abstract base for it. Option 3 is incorrect. The ReadOnlyCollectionBase takes a strongly typed, non-generic, readonly collection and provides an abstract base for it.

Summary
Several classes in the System.Collections namespace enable you to implement and manipulate structures for storing collections of objects. The namespace also includes classes for comparing objects and generating hash values for them. To implement a class in the namespace, you import the namespace and then declare a variable as an instance of the class. You can then use the instance to implement the methods available to the class. Abstract base classes support abstractions, enabling subclasses to inherit from them. Classes that provide abstract base classes in the System.Collections namespace include CollectionBase, ReadOnlyCollectionBase, and DictionaryBase.

Table of Contents
| Print | Contents | Close |

Using Interfaces and Classes in C# 2005


Learning objective
After completing this topic, you should be able to use interfaces and classes in a given scenario.

Exercise overview
In this exercise, you're required to use interfaces and classes available in the System namespace in C#. This involves the following tasks:

using the IDisposable and IComparable interfaces using the Stack and HashTable classes

Task 1: Using interfaces


Suppose you're currently using C# to develop a hotel reservation application. In code for the application, you need to use interfaces available via the System namespace to accomplish various tasks.

Step 1 of 3
You want to implement an overloaded method to ensure that once objects are no longer required, the resources they occupy will be freed immediately. Complete the code that implements the required interface and method.
using System.Collections; public class Room : IDisposable { Stack hotelDataStack = new Stack(); private bool disposedValue = false; protected virtual void MISSING CODE(bool disposing) { if (!this.disposedValue) { if (disposing) { hotelDataStack.Clear(); hotelDataStack = null; } } this.disposedValue = true; } public void MISSING CODE() { MISSING CODE(true); GC.SuppressFinalize(this); } }

Result
To ensure that resources are freed immediately once objects are no longer required, you complete the code by typing
Dispose

Step 2 of 3

You now want to set the application to compare information about room reservations. The two values you want to compare are of the same type. Complete the code that implements the required interface and method.
using System.Collections; public class Room : IComparable { int number; Stack hotelDataStack = new Stack(); public Room(int n) { number = n; } public int MISSING CODE(object obj) { int functionReturnValue = 0; Room temp = (Room)obj; functionReturnValue = number.MISSING CODE(temp.number); return functionReturnValue; } }

Result
To compare values of the same type, you complete the code using
CompareTo

Step 3 of 3
Suppose you want to convert the value of an object into a string. Which interface enables you to do this? Options: 1. System.ICloneable 2. System.IConvertible 3. System.IFormattable

Result
You can convert the value of an object into a string using the System.IFormattable interface.

Option 1 is incorrect. The System.ICloneable interface creates a clone or copy of a class, with equivalent values to the original class of which it's a copy. Option 2 is incorrect. The System.IConvertible interface specifies the attributes of methods that take the implementing reference of a value and convert it to a common language runtime (CLR) type of a corresponding value. Option 3 is correct. The System.IFormattable interface enables you to convert the value of an object into a string.

Task 2: Using classes


To store collections of data and manipulate this data, you need to use classes available in the System.Collections namespace.

Step 1 of 3
Suppose you want to use the Stack class to store hotel data. Complete the code that declares an instance of the class named "sta".
using System.Collections; public class Room { public Room() { } } public class Ex { public void Main() { MISSING CODE; Room rm1 = new Room(); Room rm2 = new Room(); Room rm3 = new Room(); Room rm4 = new Room(); Room rm5 = new Room(); sta.Push(rm1); sta.Push(rm2); sta.Push(rm3); sta.Push(rm4); sta.Push(rm5); object obj = sta.Pop(); Room myRm = (Room)obj; } }

Result
To declare an instance of the Stack class named "sta", you use the code
Stack sta = new Stack();

Step 2 of 3
You now want to create a structure in which you can store key and value pairs. You need to be able to retrieve values only by specifying corresponding keys. Complete the code to declare an instance of the appropriate class named "myHt".
using System.Collections; public class Example { public void Main() { MISSING CODE; myHt.Add("One", "Value1"); myHt.Add("Two", "Value2"); myHt.Add("Three", "Value3"); myHt.Add("Four", "Value4"); myHt.Add("Five", "Value5"); if (myHt.ContainsKey("Six")) { Console.WriteLine("This value should not be here"); } else if (myHt.ContainsKey("Two")) { Console.WriteLine("This key should be here"); } string[] arStringArray = new string[11]; myHt.Keys.CopyTo(arStringArray, 4); } }

Result
To declare myHt as an instance of the appropriate class, you use the code
Hashtable myHt = new Hashtable()

Step 3 of 3

Last, suppose you've implemented an instance of the Queue class and created an array. You now want to use a method to move the objects in the queue into the array, beginning at a specified index. Which method do you use? Options: 1. 2. 3. 4.
Contains CopyTo Enqueue ToArray

Result
To move the objects in a queue into an array you've already initialized, you use the CopyTo method. Option 1 is incorrect. The Contains method enables you to search a queue for a specified object. Option 2 is correct. The CopyTo method gets an array and sizes it to accommodate chosen objects from a queue, before copying the queued objects into the array. Option 3 is incorrect. The Enqueue method adds an object to the end of a queue. Option 4 is incorrect. The ToArray method copies the ordered objects of a queue into an array, but it copies fully into a returned array and does not begin from any specified index. Interfaces and classes in the System namespace have now been used to store and manipulate data.

Table of Contents
| Print | Contents | Close |

Generic Types and Interfaces in C# 2005


Learning objective
After completing this topic, you should be able to create generic types and interfaces in a given scenario.

1. Generic types

Generics are a new feature of C# 2005. They enable you to create strongly typed data types and methods. Generic types act as templates, which you can use to instantiate any number of different classes, structures, or interfaces. For example, you may use a generic class as a template for two objects that accept values of different types, like int or string, simply by specifying the value type upon construction. The advantages of using generic templates include the ability to

create strong types reuse existing code improve speed and performance

Using a generic template to create new types enables you to access all the methods available to the generic without having to rewrite the necessary code. Also, enforcement of the generic occurs when code compiles, enabling an application to run faster.

Question
Suppose you want to create a new class that accepts only integer values. However, you know that you will need to create a similar class later on that accepts only string values. Which strategy for creating the two classes requires the least implementation and memory overhead? Options: 1. Create a class with a parameter type that can be replaced by either the int or string type at compile time 2. Create a class that uses int values and then rewrite the code to create a similar class that accepts string values 3. Create a class that uses int values and then write a wrapper class that accepts string values

Answer
Creating a generic class with a parameter type that can be replaced by either the int or string type at compile time requires the least implementation and memory overhead. Option 1 is correct. Using a class with replaceable parameters a generic class ensures that you need to write the full code for the class only once. It also ensures that enforcement of the class will occur when the code compiles instead of at runtime, resulting in faster application performance.

Option 2 is incorrect. Writing the code for each class separately is time-consuming and through new support for generics in C# unnecessary. Option 3 is incorrect. This method ensures that you do not have to rewrite the first class entirely to create the new, similar class. However, it requires the writing and use of an additional wrapper class, which increases both implementation and memory load. Generic collection classes for creating structures such as dictionaries, lists, queues, and stacks are located in the System.Collections.Generic namespace. In addition, you can create your own generic templates for your custom types. To instantiate a class using a generic template, you specify the generic collection you want to use, and use <> brackets to deliminate a type parameter. Upon defining your generic type, what is specified in the declaration is represented by a placeholder. Therefore while this value is important in declaration, when writing the definition, its name is arbitrary. Collection<T> MyClass = new Collection< T>(); The new type that is instantiated will have all the methods available as defined in the generic template. So if you declare a class based on the generic List<T>, your class will have access to all the methods used in the generic List type. When you create an instance of the generic, you specify a data type to take the place of the type placeholder. Thereafter, your class will have access to all the methods available to the generic type you've created. So if you create a new class using the generic MyClass, and you specify a string type, your new class will have access to all the MyClass methods. The statement for this declaration will be
MyClass<string> classname = new MyClass<string>();

You can specify type parameters to be any valid type, including classes, structures, interfaces, and delegates. The <> delimiters accept more than one parameter. When you use multiple parameters in a generic type, you separate them with commas. public class MyClass< T1, T2, T3> Suppose you want to create a class using the MyGeneric template with parameters myType1 and myType2. To do this, you reference the generic template, deliminate the type parameter list with <> brackets, and separate the parameters with commas.
public class MyGenericMISSING CODE

{ }

To complete the code required to create the class, you type <myType1, myType2>. The class you've created now has access to all methods built into the MyGeneric template.
public class MyGeneric<myType1, myType2> { }

You may then set up the initial values of the parameters to be used in the class.
public class MyGeneric<myType1, myType2> { private myType1 T1; private MyType2 T2; private string str; //Constructor public MyGeneric(myType1 val1, MyType2 val2, string val3) { T1 = val1; T2 = val2; str = val3; } }

You can use generics to avoid boxing and unnecessary casts, which can decrease performance. For example, you can set a function to check whether the object named x is of the type double, before boxing or casting in the MyGeneric class. The static ReferenceEquals method of the object class enables a comparison to take place and the type of x is compared to type double. You can use this approach to find out what type x is through a process of elimination.
public string tellType<myType>(myType x) { //function implementation object myOb = (object)x; if (myOb != null) { if (object.ReferenceEquals(myOb.GetType(), typeof(double))) { return "This is a double!"; } else { return "This is not a double!"; } } else

{ return "This is a null reference!"; } }

Question
Suppose you want to begin a generic template, called Reminder, to create a new class. How would the first line appear in the template definition? Options: 1. 2. 3. 4.
public public public public class class class class Reminder( Reminder< Reminder< Reminder< Type1, Type2, Type3) String, Integer, String> Type1 Type2 Type3> Type1, Type2, Type3>

Answer
To create a new class using the Reminder generic template, you can use the following code fragment:
public class Reminder< Type1, Type2, Type3>

Option 1 is incorrect. When setting the type parameters for a generic, you need to use angular <> brackets rather than the rounded () brackets that would be used in a regular parameter list. Option 2 is incorrect. This code uses specific types with the Reminder template. You would want to use these when calling or declaring the object instantiated from the generic template, but you would not want to use it in the definition itself. Option 3 is incorrect. Although this code references the correct generic template, it will result in a compilation error because the parameters are not separated by commas. Option 4 is correct. This will begin a new generic type called Reminder for a class with type parameters Type1, Type2, and Type3. Now suppose you want to use the MyGeneric template to create a new class, myG, which has the parameters int and char. To do this, you call the generic template and you substitute actual type values for the type parameters.
using System; public class Example { public void Main() {

int myOwnInt = 4; MyGenericMISSING CODE myG = new MyGeneric<int, char>(2, 'm', "This is my newobject"); String response = myG.tellType(myOwnInt); Console.WriteLine(response); } }

You type <int, char> to set the parameters for the new class. You have now set the required parameters for the new class. When the code runs, the myG class will inherit any methods from the MyGeneric template.
using System; public class Example { public void Main() { int myOwnInt = 4; MyGeneric<int, char> myG = new MyGeneric<int, char>(2, 'm', "This is my newobject"); String response = myG.tellType(myOwnInt); Console.WriteLine(response); } }

You usually create only one definition of a class within a namespace. However, you can create multiple class definitions of the same name, simply by ensuring that each definition includes a different number of type parameters. This is known as overloading.

Note
You can also use overloading for generic methods. Consider two classes named MyOwnClass, each with a different number of type parameters. Although the two classes share a common name, the compiler selects the relevant definition based on the number of parameters the programmer specifies when instantiating the class.
public class MyOwnClass<T1> { } public class MyOwnClass<T1, T2, T3> { }

When you create a generic class, you can restrict the types that can be used to create an instance of the class by placing constraints on the class parameters. To do this, you declare the acceptable type and then use the where keyword and a colon to identify the type with a class, interface, or type to which the given type parameter must belong. A generic type cannot be constrained to a

specific C# primitive value types such as int, string, or char. However, you can constrain a generic type parameter to be any primitive type or any custom structure, by using the "struct" constraint. public class classname<T> where T : Type { } You can set constraints for a general class or interface, or you can limit the constraint to a specific base class.
public class WorkGroup<T> where T : System.Windows.Forms.Control { }

If you want to use constraints to set a class to accept only types with parameter-less constructors, you need to create a new constraint. To do this, you use the where type : new() clause. public class classname<T> where T : new() { public interface IAverage< T>{}

} By constraining the type to class, you ensure that the compiler will accept only a class type argument when it calls the function, as opposed to a value type, which you could impose with a struct constraint. Say you're creating a generic class, and you want to ensure that the type argument will be of a reference type when the function is called. To do this, you need to constrain the type to a class.
public class myOwnClass<myType> MISSING CODE { public readonly myType x; public myOwnClass(myType myobj) { this.x = myobj; } }

You type where myType : class to complete the code. You can use the principle of constraining types to implement an interface constraint.

public class myOwnClass<myType> where myType : class { public readonly myType x; public myOwnClass(myType myobj) { this.x = myobj; } }

You could, for example, use a constraint to ensure that a specified type includes a Dispose method from the IDisposable interface. This method enables memory to be freed at a point of the programmer's choosing.
public string tellType<myType>(myType x) { string functionReturnValue = null; //function implementation object myOb = (object)x; if (x != null) { if (object.ReferenceEquals(x.GetType(), typeof(double))) { return "This is a double!"; } else { return "This is not a double!"; } } else { return "This is a null reference!"; } } public void killObj<myType>(string str) where myType : IDisposable { //function implementation } }

Supplement
Selecting the link title opens the resource in a new browser window. Launch window View a full example of code that uses the MyGeneric template.

Question

Suppose you are creating a List class, and you want to constrain the parameter to a struct type. Complete the code you use to constrain the class.
public class List<myType> MISSING CODE { }

Answer
To constrain the parameter to a struct type, you complete the code by typing
where myType : struct

2. Generic interfaces
All objects in C# feature interfaces, which document the public properties, methods, and events available via the classes that implement them. All objects have a default primary interface, but you can also implement secondary interfaces, which inherit from their primary counterparts. Classes that implement an interface must include whatever functions the interface stipulates. Unlike conventional interfaces, generic interfaces include placeholders for type parameters. When developers write a class that implements a generic interface, they specify the type parameter. : GenericInterface< T> You can call pre-existing generic interfaces or you can create generic interfaces yourself. Preexisting generic interfaces are found in the System namespace and the System.Collections.Generic namespace, so you import these namespaces before using the interfaces. As with generic classes, using generic interfaces

enhances the performance of an application enables you to create strongly typed collections provides better type safety than non-generic collections

Some frequently used generic interfaces in the System namespace include the
IComparable interface IEquatable interface

IComparable interface The IComparable

interface, when implemented, requires a definition of the CompareTo method, which value types and classes use to create type-specific comparison methods for ordering instances. It is implemented by types whose values can be ordered. IEquatable interface The IEquatable interface, when implemented, requires the definition of the Equal method, which value types and classes use to create type-specific methods that check different instances for equality to one another. The interface is implemented by types whose values can be created. Examples of generic interfaces available from the System.Collections.Generic namespace include
ICollection IComparer IDictionary IEnumerable IEnumerator IEqualityComparer IList

ICollection The ICollection

generic interface defines methods you can use to manipulate generic collections. It is the base interface for classes in the System.Collections.Generic namespace. It inherits the IEnumerable interface and is inherited by the IDictionary and IList interface. The IComparer generic interface defines methods that types implement to compare two objects or to customize the sort order of a collection. The default implementation of this interface is by the Comparer class.

IComparer

IDictionary The IDictionary IEnumerable The IEnumerable

generic interface represents a generic collection of key/value pairs. It is the base interface for generic collections of key/value pairs. generic interface exposes the enumerator, which supports a simple iteration over a collection of a specified type. Implementations of this generic interface must always support For Each semantics. generic interface supports a simple iteration over a generic collection. It is the base interface for all generic enumerators. defines methods to support the comparison of objects for equality. It enables you to implement customized equality comparisons for collections. The Default property of the EqualityComparer class implements this interface. The IList generic interface represents a collection of objects that can be accessed by index. It is the base interface of all generic lists.

IEnumerator The IEnumerator

IEqualityComparer The IEqualityComparer

IList

To create a new generic interface, you use a statement in which you


declare the interface using either the public or internal scope use the interface keyword name the new interface by convention, using a name that begins with an uppercase "I" use the <> delimiters and enter a placeholder for the parameter type write code for any properties, methods, and events the interface should stipulate

The interface block can be placed in any code module, although it's usually placed in a standard module. public interface IGenericInterface<Type> { }

Note
The default scope of an interface is public, so you may omit the public keyword if you wish. To use a generic interface in a class, you use a colon, reference the generic interface, and substitute an actual type for the type parameter. You will then be required to use the functions, properties, methods, and events stipulated by the interface. : IGenericInterface < MyType> Suppose you create a new IReturn generic interface, which requires that the ReturnOnePlus function be implemented when it is used. This ensures that all classes that implement the interface also require the ReturnOnePlus function.
public interface IReturn<MyType> { object ReturnOnePlus(MyType x); }

After you've created the generic IReturn interface, suppose you want to call the interface in the Test class. To do this, you set the class to implement the interface.
public class Test MISSING CODE { object IReturn<double>.ReturnOnePlus(double x) { double temp = x + 1; return temp;

} }

You type : IReturn<double> to complete the code. The completed statement will call the generic interface, IReturn. Because this interface contains a reference to the ReturnOnePlus function, this function will be required in the Test class.
public class Test : IReturn<double> { object IReturn<double>.ReturnOnePlus(double x) { double temp = x + 1; return temp; } }

You can write the code that implements the interface in different ways in various classes, while still adhering to the methods, properties, and events that the interface sets out. Now suppose you implement the IComparable interface, which requires the CompareTo function, in the Person class. Once you've done this, you also need to include the CompareTo function in the code implementation for the Person class. Thereafter, you can use a constructor to set values for the name and age objects.
public class Person : IComparable<Person> { private string name; public int age; int System.IComparable<Person>.CompareTo(Person Oage) { return age.CompareTo(Oage.age); } public Person(string n, int a) { name = n; age = a; } }

Question
Suppose you want to define a new generic interface named IQueue. You have yet to add any memebers to it. Identify the code you use to do this.

Options: 1. internal interface IQueue< Type > 2. 3.


{ } private interface IQueue< Type > { } public : Queue interface< Type > { }

Answer
The code you use to implement the IQueue interface is
internal interface IQueue< Type> { }

Option 1 is correct. You can declare an interface as having either the public or internal scope or leave this out to accept the default scope of public. You then use the interface keyword to declare the interface and, by convention, name the interface beginning with an uppercase "I". Finally, you specify the type of the interface. Option 2 is incorrect. You cannot declare a Private scope generic interface because you need to call it in different classes in order to implement it. Option 3 is incorrect. This code uses an incorrect colon operator. To implement a new generic interface, you use the interface keyword.

Question
Say you want to use the generic IComparable interface of the System.Collections.Generic namespace in the Person class. You have already imported the namespace. Complete the code you use to call the interface.
using System.Collections.Generic; public class Person MISSING CODE<Person> { private string name; public int age; }

Answer
To call the generic interface, you use the code
: IComparable

Summary
C# 2005 enables you to write reusable code that enforces strong typing in the form of generic templates. You can then use these templates to create new generic types, including classes, interfaces, and structures. You can use generic classes available via the System.Collections.Generic namespace, or create new generic classes. Each instance of a generic class inherits the methods assigned to the generic class. Generic interfaces are available in the System and System.Collections.Generic namespaces. Alternatively, you can create new or secondary generic interfaces using the interface keyword. All classes that implement a generic interface must include the functions that the interface stipulates.

Table of Contents
| Print | Contents | Close |

Generic Classes and Enumerators in C# 2005


Learning objective
After completing this topic, you should be able to create generic classes and enumerators in a given scenario.

1. Generic collections
Generic collections enable you to create strongly typed classes. These classes perform better than conventional classes and have better type safety. Existing interfaces and classes that you can use to define generic collections are found in the System.Collections.Generic namespace. Examples of classes in the System.Collections.Generic namespace include
Comparer Dictionary List, LinkedList,

and LinkListNode

SortedDictionary SortedList Stack Queue

Comparer

The Comparer class is the primary user of the IComparer interface, used to compare objects and allow for case-sensitivity in strings.
Dictionary Dictionary is a collection of keys and values, similar to a hash table. Dictionary.KeyCollection is a collection of keys in a dictionary, and Dictionary.ValueCollection is a collection of values in a dictionary. List, LinkedList, and LinkListNode List is a collection of strongly typed objects that you can access by index.

It is similar to an array list. It holds methods you can use to search, sort, and manipulate lists. LinkedList represents a doubly linked list, and LinkedListNode represents a node in a linked list.

SortedDictionary SortedDictionary is a collection of key/value pairs sorted by key. SortedDictionary.KeyCollection is a collection of keys in a sorted dictionary, and SortedDictionary.ValueCollection is a collection of values in a sorted dictionary. SortedList SortedList is a collection of key or value pairs. These are sorted by key based on the IComparer implementation. Stack

A stack is a collection of last-in, first-out instances of the same type.


Queue

A queue is a collection of objects arranged in first-in, first-out order. In C# 2005, some generic collection classes like Stack and Queue correspond to non-generic classes of the same name. Generic collection classes like List and Dictionary are derived from traditional classes such as ArrayList and Hashtable, but offer greater functionality. There are also some new collection classes that exist only in generic form, such as LinkedList and SortedDictionary. Generic collection classes are compatible with the collection classes and methods from previous versions of Visual Studio, which are housed in the System.Collection namespace. In addition to using generic collection classes provided in the System.Generic.Collections namespace, you can create your own generic collection classes and enumerators. To declare an instance of a generic collection class from the System.Collections.Generic namespace, you

import the namespace declare a new instance of the class with the new keywords

specify a type parameter

GenericClass<T> NewClass = new GenericClass<T>();

Say you want to use the pre-existing generic LinkedList collection class to declare an instance of the linked list class with a specific type. You have already imported the namespace, and you now want to declare the class with type int.
using System; using System.Collections.Generic; public class Ex { public void Main() { MISSING CODE<int> MyLinkedL = new MISSING CODE<int>(); } }

You type LinkedList to complete the declaration. This declares the generic class MyLinkedList, which is an instance of the generic linked list collection class.
using System; using System.Collections.Generic; public class Ex { public void Main() { LinkedList<int> MyLinkedL = new LinkedList<int>(); } }

You can then add elements to the class. For example, the AddFirst method adds elements to the front of the list, and the AddLast method adds elements to the back of the list.
using System; using System.Collections.Generic; public class Ex { public void Main() { LinkedList<int> MyLinkedL = new LinkedList<int>(); MyLinkedL.AddFirst(2); MyLinkedL.AddLast(3); MyLinkedL.AddFirst(1); } }

Once you've added elements to your list, you can begin searching and reading it. In this example, you use the Contains method to look for a value in the linked list and the Find method to return

a node in the list, which will be of type LinkedListNode. With this done, the literal value within this node can then be printed.
using System; using System.Collections.Generic; public class Ex { public void Main() { LinkedList<int> MyLinkedL = new LinkedList<int>(); MyLinkedL.AddFirst(2); MyLinkedL.AddLast(3); MyLinkedL.AddFirst(1); LinkedListNode<int> myNode = null; if (MyLinkedL.Contains(1)) { Console.WriteLine("The following value is present: "); myNode = MyLinkedL.Find(1); Console.WriteLine(myNode.ToString()); } else {

Note
Note the second declaration in this code. An instance of the LinkedListNode class has been declared but no value has been assigned to it so that the developer can assign a value to the object later. The following code sets the node to null in case the value for the Contains method is never found.
if (MyLinkedL.Contains(1)) { Console.WriteLine("The following value is present: "); myNode = MyLinkedL.Find(1); Console.WriteLine(myNode.ToString()); } else { myNode = null; }

The AddBefore and AddAfter methods of the LinkedList class add elements to the list before and after the LinkedListNode passed in as a parameter in this case, myNode. The second parameter is the value contained in the added node. The Remove methods remove a given node from a linked list either by specifying an index or the node itself, and the Clear method will remove all nodes from the linked list.
MyLinkedL.AddBefore(myNode, 0); MyLinkedL.AddAfter(myNode, 8);

LinkedListNode<int> myOtherNode = MyLinkedL.Find (8); MyLinkedL.Remove(myOtherNode); MyLinkedL.Remove(3); MyLinkedL.Clear(); } }

Question
Suppose you have a LinkedList called LL and a LinkedListNode called LN. What function adds a new node to a position in the list before a specified node? Options: 1. 2. 3. 4.
LL.AddFirst(LN); LL.AddLast(LN); LL.AddBefore(LN, 5); LL.AddAfter(LN, 5);

Answer
The function you use to add a new node is
LL.AddBefore(LN, 5);

Option 1 is incorrect. The AddFirst method is designed to add nodes to the beginning of a linked list. Option 2 is incorrect. The AddLast method is designed to add nodes to the end of a linked list. Option 3 is correct. The AddBefore method allows you to add a new node at a position before that specified by LN, the LinkedListNode. Option 4 is incorrect. Although the AddAfter method allows you to add a new node dependant on the position of the node passed in as a parameter, the new node is placed after the parameter node, not before it.

Question
Suppose you want to declare, but not initialize myStack, an instance of the generic Stack collection class which is of type Double. Complete the code you use to do this.

using System; using System.Collections.Generic; public class Ex { public void Main() { MISSING CODE<double> } }

myStack

= null;

Answer
You use the following code to create an instance of the generic Stack class, which is of type Double:
Stack<double> myStack = null;

Stack<double> MyStack = new Stack<double>()


2. Generic enumerators
You can use generics to make your own enumerators in generic collection classes. An enumerator is a shared, read-only data type that represents an integer constant. Enumerators enable you to loop through a generic collection typically using a foreach loop, although MoveNext and Current can be used if required. They also enable you to read data in a generic collection.

Note
You cannot use an enumerator to make changes to the data in a generic collection. To create a generic enumerator, you use the generic interfaces found in the System.Collections.Generic namespace. These generic interfaces are new in .NET Framework 2.0. The IEnumerable generic interface supports simple iterations over a collection of a specified type. When implementing this interface, you must ensure that foreach semantics are supported. The IEnumerator generic interface supports simple iterations over generic collections. It inherits the conventional IEnumerator interface and the MoveNext and Reset properties.

Implementations of collections in the System.Collections.Generic namespace are not synchronized by default. To enable a generic collection to be accessed for reading and writing by multiple threads, you need to implement your own synchronization. Enumerating through a collection is not thread-safe, even once the collection is synchronized. If the threads are modified, the enumerator will throw an exception. To ensure thread safety, you need to lock the collection for the duration of the enumeration. Alternatively, you can try to catch the exceptions using a catch statement. You can find generic enumerator structures in the System.Collections.Generic namespace. Most of these structures enumerate the classes they reference. For example, the List.Enumerator enumerates the elements of a list. Other examples of generic enumerators in the namespace enable you to enumerate linked lists, queues, stacks, dictionaries, and sorted dictionaries, as well as only the keys or only the values in dictionaries.

Note
The KeyValuePair generic structure is an exception in the System.Collections.Generic namespace. This structure, which is not an enumerator, defines key/value pairs that can be set or retrieved.

Question
Identify the features of generic enumerators in C# 2005. Options: 1. 2. 3. 4. They are thread-safe They can read data in multiple threads in generic collections by default They enable you to loop through generic collections They require the definition of the MoveNext and Reset functions

Answer
Enumerators inherit the MoveNext and Reset properties and enable you to loop through generic collections.

Option 1 is incorrect. Enumerating through a collection is not thread-safe, so you need to lock a collection before enumerating it. If you fail to do this and data in the collection updates, the enumerator will be invalidated. Option 2 is incorrect. For an enumerator to read multiple threads in a collection, the collection must first be synchronized. However, collections in the System.Collections.Generic namespace are not synchronized by default, so you need to implement your own synchronization before enumerating them. Option 3 is correct. Enumeration enables you to keep track of your position while looping through a collection, and to read data from a generic collection. Option 4 is correct. The IEnumerator interface inherits the requirement for enumerations to have the MoveNext and Reset functions, as well as the Current property when they are implemented. MoveNext ensures a basis by which the enumerator moves forward, and Reset ensures that the enumerator can be returned to its starting position. To use an enumerator to loop through a class and to keep track of your position as looping occurs, you

implement the relevant enumerator declare an integer constant define the necessary MoveNext and Reset functions, as well as the Current property implement the IEnumerable interface on the class that will actually use the enumerator you create

implement the relevant enumerator

declare an integer constantdefine the necessary MoveNext and Reset functions, as well as the Current propertyimplement the IEnumerable interface on the class that will actually use the enumerator you create

using System.Collections.Generic; public class myMiniClass { //class fields public int ID; public string description; //Constructor public myMiniClass(int x, string y)

{ this.ID = x; this.description = y; } }

Say you're working with the myMiniClass class, and you want to use an enumerator available via the generic IEnumerator interface to loop through the class. To do this, you first implement the interface using the : keyword.
public class myEnumerator MISSING CODE<myMiniClass> { //Enumerator fields public myMiniClass[] myList; public int curr = -1; private bool disposedValue = false; // To detect redundant calls

You type : IEnumerator to call the generic enumerator. Once you've implemented the IEnumerator interface, you can begin creating the list to enumerate over and the integer constant to use.
public class myEnumerator : IEnumerator<myMiniClass> { //Enumerator fields public myMiniClass[] myList; public int curr = -1; private bool disposedValue = false; // To detect redundant calls

The integer constant represents a position in the collection. It is also the value that the methods alter to keep track of position in the collection. You initialize the iterator at -1 so that the enumerator starts with a value you know to be invalid. It usually starts indexing at 0.
public class myEnumerator : IEnumerator<myMiniClass> { //Enumerator fields public myMiniClass[] myList; public int curr = -1; private bool disposedValue = false; // To detect redundant calls public myEnumerator(myMiniClass[] myCollection) { this.myList = myCollection; }

The Current property returns the current position of the integer constant. Even if it is not used it needs to be included because it is required by the interface. Notice that there are two similar implementations of Current one is for the generic

enumerator, one for a regular enumerator. This is because while MoveNext and Reset are implemented from the original IEnumerator interface and are not present in the generic IEnumerator interface, Current is present in both interfaces and had a different return type in each. Therefore, you have to create two instances to resolve this discrepancy.
public myMiniClass System.Collections.Generic.IEnumerator<myMiniClass>.Current { get { return myList(curr); } } public object System.Collections.IEnumerator.Current { get { return myList(curr); } }

The MoveNext and Reset functions are regularly used. MoveNext returns a boolean value indicating whether you have reached the end of the list you are enumerating.
public bool MoveNext() { curr += 1; if (curr < myList.Length) { return true; } else { return false; } } public void Reset() { curr = -1; }

Note
It is often customary to use the IDisposable interface with enumerations to ensure memory can be released at a time of your own choosing. It is also necessary to implement the IEnumerable interface on the class that will actually use the enumerator. The only function required is the GetEnumerator function, but it must be implemented twice because of the generic and nongeneric interface discrepancy, similar to what was seen with the Current property of IEnumerator.

public class MyOwnClass : IEnumerable<myMiniClass> { public myMiniClass[] Minis; public System.Collections.Generic.IEnumerator<myMiniClass> GetEnumerator() { return new myEnumerator(Minis); } //This is the function that is actually used. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator1(); } public System.Collections.IEnumerator GetEnumerator1() { return new myEnumerator(Minis); } }

Supplement
Selecting the link title opens the resource in a new browser window. Launch window View a full example of code for implementing an enumerator.

Question
Suppose you want to use a generic enumerator to loop through the Room class. Identify the code you write to use the interface for the generic enumerator. Options: 1. Call IEnumerator(Room) 2. : Enumerator(Room) 3. : IEnumerator(Room)

Answer
The code you use to reference the required interface is
: IEnumerator(Room)

Option 1 is incorrect. This code fragment uses the incorrect keyword for calling the IEnumerator interface. You need to use the Implements keyword to do this.

Option 2 is incorrect. To implement the interface that supports generic enumeration, you use the : and specify the name of the interface which should be preceded by an uppercase "I". Option 3 is correct. You use the : to use the interface that supports generic enumeration, and you use pass in the class that the collection is made from in as a type parameter.

Summary
You can use generic collection classes from the System.Collections.Generic namespace to create strongly typed collections, which have better type safety and offer better performance than traditional collections. Generic enumerators enable you to loop through and read data in collections. Functions required by the interface you use to implement a generic enumerator must be included in the implementation of the enumerator.

Table of Contents
| Top of page | | Print | Contents | Close |

Creating Generics in C# 2005


Learning objective
After completing this topic, you should be able to create generics in a given scenario.

Exercise overview
In this exercise, you're required to create a generic type, interface, class, and enumerator. This involves the following tasks:

creating a generic type creating a generic interface creating a generic class creating a generic enumerator

Suppose you're using C# 2005 to create a hotel reservation application. You want to create generic templates to enable strong typing and the re-use of code in your application. You also want to ensure that the algorithms you create will work regardless of the type of data fed into them.

Task 1: Creating a generic type


First you want to create a custom class that will work for various data types.

Step 1 of 2
You want to create the generic Room class, which has two type parameters that you want to designate as Type1 and Type2. Complete the code you use to create the generic class.

using System; using System.Collections.Generic; public class Missing Code { private Type1 ID; private Type2 Description; //Constructor public Room (Type1 l, Type2 d) { this.ID = l; this.Description = d; } //Generic method. In the context of the hotel, this will //return the floor description public bool NewElement(Type1 d) { //Add parameter to the type1 List. It returns true or false //based on its success }

Result
You complete the code to create the generic class by typing
Room<Type1, Type2>

Step 2 of 2
Suppose the parameters for the Room class are references for a room number and a room description. You want to constrain the type parameters to type Class and type Structure for this instance of the class. Identify the code you use to do this.

Options: 1. public class Room<S, T> where S : Class where T : Structure 2. public class Room<Type1 , Type2 > 3. public Class Room(Type1 As Class, Type2 As Structure)

Result
The code you use to constrain the type parameters to type Class and Structure respectively is
public class Room<S, T> where S : Class where T : Structure

Option 1 is correct. You use the type name to specify constraints for the type parameters. Option 2 is incorrect. You need to use the type name to ensure that the parameters are constrained to the types you specify. Option 3 is incorrect. No actual class or structure constraints are being applied here, merely a parameter list for the respective types.

Task 2: Creating a generic interface


Next you want to create an interface so that you can avoid boxing and type casting issues in the class you have created.

Step 1 of 2
You want to create a generic interface using the default public scope, and named Desc, except that you also want this name to adhere to interface naming conventions. Complete the code you use to do this.
//import statements using System; using System.Collections.Generic; //Interface implementation MISSING CODE<myType> { object GetDesc(); }

Result

To complete the code that creates the generic interface with a default internal scope, you type
interface IDesc

Step 2 of 2
You have declared your own class called Type2. Suppose you want to use the IDesc interface in the Room class you're writing for the hotel application, using this as its type parameter. Identify the code that will implement the interface. Options: 1. : IDesc(MyType) 2. : IDesc(Type2) 3. Interface IDesc<Type2>

Result
The code that implements the IDesc interface is
: IDesc<Type2>

Option 1 is incorrect. Although this code uses the :, the declaration has not substituted an actual type for the type parameter. Option 2 is correct. You use the : to call the interface, and you specify a type in place of the type parameter. Option 3 is incorrect. You use the Interface keyword when writing code to create a new interface, rather than to implement an existing interface.

Task 3: Creating a generic class


You want to use existing collection classes so that one form of structure will efficiently handle multiple types.

Step 1 of 2
Suppose you want to represent a set of whole numbers associated with guests, using a collection object named myQ that you instantiate from the Queue generic collection class. Complete the code that declares the class.

//using statements using System; using System.Collections.Generic; public class Ex { public void main() { //This represents a list of numbers associated with guests MISSING CODE myQ = new MISSING CODE(); //... } }

Result
To complete the declaration of the class, you specify the generic class from which it derives and its type using the code
Queue<int>

Step 2 of 2
You want to use the generic Room class to create a new object, rm1, which will have type parameters integer and string. Complete the code you use to do this.
//import statements using System; using System.Collections.Generic; public class Ex { public void main() { //This represents a list of numbers associated with guests Queue<int> myQ = new Queue<int>(); //This represent a list of names of guests Queue<string> myQ2 = new Queue<string>(); //This represents a list of Generic Object of type floor -//The int is the number of the room, the string is the //description of what type of room it is. Queue<Room<int, string>> myQ3 = new Queue<Room<int, string>()>(); //Generic objects are declared MISSING CODE = new Room<int, string>(503, "Single Room");

} }

Result
To complete the code that creates the rm1 class, you type
Room<int, string> rm1

Task 4: Creating a generic enumerator


You now want to give enumerator functionality to the original class that you created.

Step 1 of 2
Identify the features of the generic IEnumerator interface. Options: 1. 2. 3. 4. It enables you to loop through the classes in a collection It enables you to modify the data in collections It inherits a corresponding, non-generic interface It is thread safe

Result
The generic IEnumerator interface enables you to loop through the classes in a collection. It inherits the non-generic IEnumerator interface. Option 1 is correct. You can use the ForEach loop or the MoveNext and Current properties of the interface to loop through and read the data in a generic collection. Option 2 is incorrect. Enumerators are read-only data types that enable you to read and loop through existing data collections. You cannot use an enumerator to make changes to data in a collection. Option 3 is correct. When you implement the IEnumerator interface, you also need to implement the non-generic interface from which it inherits methods and properties. Option 4 is incorrect. If any changes are made to the elements in a collection, the enumerator will fail. The only way to ensure thread safety during enumeration is to lock the collection.

Step 2 of 2
You have already created the enumerator, and now want to use the IEnumerable interface in the class that will make use of your enumerator.

Complete the code you use to do this.


//Represents the actual collection of rooms public class Floor MISSING CODE <Room<Integer, String>> { private Room[]<int, string> FloorRooms; public Floor(Room[]<int, string> flr) { FloorRooms = new Room<int, string>[flr.Length]; int i = 0; while (i < flr.Length) { FloorRooms(i) = flr[i]; i += 1; } }

Result
The code you use to call the IEnumerable interface is
: IEnumerable

Generics have been used to improve the performance of an application.

Table of Contents
| Top of page |

Anda mungkin juga menyukai