1. Trang chủ
  2. » Công Nghệ Thông Tin

Microsoft Visual C# 2010 Step by Step (P5) potx

50 432 1
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 50
Dung lượng 690,14 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

For example, if you declare an int variable named season, there is nothing to stop you from as-signing it any legal integer value apart from 0, 1, 2, or 3.. If the name of your enumerat

Trang 1

170 Part II Understanding the C# Language

You can access and modify the value held in the variable i through the pointer variable

pi like this:

*pi = 100;

This code updates the value of the variable i to 100 because pi points to the same memory location as the variable i

One of the main problems that developers learning C and C++ have is understanding

the syntax used by pointers The * operator has at least two meanings (in addition to

being the arithmetic multiplication operator), and there is often great confusion about

when to use & rather than * The other issue with pointers is that it is easy to point

somewhere invalid, or to forget to point somewhere at all, and then try to reference the data pointed to The result will be either garbage or a program that fails with an error because the operating system detects an attempt to access an illegal address in memory There is also a whole range of security flaws in many existing systems result-ing from the mismanagement of pointers; some environments (not Microsoft Windows) fail to enforce checks that a pointer does not refer to memory that belongs to another process, opening up the possibility that confidential data could be compromised Reference variables were added to C# to avoid all these problems If you really want to,

you can continue to use pointers in C#, but you must mark the code as unsafe The safe keyword can be used to mark a block of code, or an entire method, as shown here:

un-public static void Main(string [] args)

Trang 2

In this chapter, you learned about some important differences between value types that hold their value directly on the stack and reference types that refer indirectly to their objects on

the heap You also learned how to use the ref and out keywords on method parameters to gain access to the arguments You saw how assigning a value (such as the int 42) to a variable

of the System.Object class creates a boxed copy of the value on the heap and then causes the System.Object variable to refer to this boxed copy You also saw how assigning a variable of

a value type (such as an int) to a variable of the System.Object class copies (or unboxes) the value in the System.Object class to the memory used by the int

n If you want to continue to the next chapter

Keep Visual Studio 2010 running, and turn to Chapter 9

n If you want to exit Visual Studio 2010 now

On the File menu, click Exit If you see a Save dialog box, click Yes and save the project

Chapter 8 Quick Reference

Copy a value type variable Simply make the copy Because the variable is a value type, you will have

two copies of the same value For example:

int i = 42;

int copyi = i;

Copy a reference type variable Simply make the copy Because the variable is a reference type, you will

have two references to the same object For example:

Circle c = new Circle(42);

Circle refc = c;

Declare a variable that can hold

a value type or the null value

Declare the variable using the ? modifier with the type For example:

int? i = null;

Pass an argument to a ref

parameter

Prefix the argument with the ref keyword This makes the parameter an

alias for the actual argument rather than a copy of the argument The method may change the value of the parameter, and this change is made

to the actual argument rather than a local copy For example:

static void Main() {

int arg = 42;

DoWork(ref arg);

Console.WriteLine(arg);

}

Trang 3

172 Part II Understanding the C# Language

Pass an argument to an out

parameter

Prefix the argument with the out keyword This makes the parameter an

alias for the actual argument rather than a copy of the argument The

method must assign a value to the parameter, and this value is made to

the actual argument For example:

static void Main() {

Unbox a value Cast the object reference that refers to the boxed value to the type of the

value variable For example:

int i = (int)o;

Cast an object safely Use the is operator to test whether the cast is valid For example:

WrappedInt wi = new WrappedInt();

object o = wi;

if (o is WrappedInt) {

WrappedInt temp = (WrappedInt)o;

Trang 4

173

Chapter 9

Creating Value Types with

Enumerations and Structures

After completing this chapter, you will be able to:

n Declare an enumeration type

n Create and use an enumeration type

n Declare a structure type

n Create and use a structure type

n Explain the differences in behavior between a structure and a class

In Chapter 8, “Understanding Values and References,” you learned about the two

fundamental types that exist in Microsoft Visual C#: value types and reference types A value

type variable holds its value directly on the stack, whereas a reference type variable holds

a reference to an object on the heap In Chapter 7, “Creating and Managing Classes and Objects,” you learned how to create your own reference types by defining classes In this chapter, you’ll learn how to create your own value types

C# supports two kinds of value types: enumerations and structures We’ll look at each of

them in turn

Working with Enumerations

Suppose you want to represent the seasons of the year in a program You could use the integers 0, 1, 2, and 3 to represent spring, summer, fall, and winter, respectively This system would work, but it’s not very intuitive If you used the integer value 0 in code, it wouldn’t be obvious that a particular 0 represented spring It also wouldn’t be a very robust solution For

example, if you declare an int variable named season, there is nothing to stop you from

as-signing it any legal integer value apart from 0, 1, 2, or 3 C# offers a better solution You can

create an enumeration (sometimes called an enum type), whose values are limited to a set of

symbolic names

Declaring an Enumeration

You define an enumeration by using the enum keyword, followed by a set of symbols

identifying the legal values that the type can have, enclosed between braces Here’s how to

Trang 5

174 Part II Understanding the C# Language

declare an enumeration named Season whose literal values are limited to the symbolic names Spring, Summer, Fall, and Winter:

enum Season { Spring, Summer, Fall, Winter }

Using an Enumeration

After you have declared an enumeration, you can use it in exactly the same way as any other

type If the name of your enumeration is Season, you can create variables of type Season, fields of type Season, and parameters of type Season, as shown in this example:

enum Season { Spring, Summer, Fall, Winter }

Season colorful = Season.Fall;

Console.WriteLine(colorful); // writes out 'Fall'

Note As you can with all value types, you can create a nullable version of an enumeration

variable by using the ? modifier You can then assign the null value, as well the values defined by the enumeration, to the variable:

Season? colorful = null;

Notice that you have to write Season.Fall rather than just Fall All enumeration literal names

are scoped by their enumeration type This is useful because it allows different enumerations

to coincidentally contain literals with the same name

Also, notice that when you display an enumeration variable by using Console.WriteLine, the

compiler generates code that writes out the name of the literal whose value matches the value of the variable If needed, you can explicitly convert an enumeration variable to a string

Trang 6

that represents its current value by using the built-in ToString method that all enumerations

automatically contain For example:

string name = colorful.ToString();

Console.WriteLine(name); // also writes out 'Fall'

Many of the standard operators you can use on integer variables can also be used on

enu-meration variables (except the bitwise and shift operators, which are covered in Chapter 16,

“Using Indexers”) For example, you can compare two enumeration variables of the same

type for equality by using the equality operator (==), and you can even perform arithmetic

on an enumeration variable (although the result might not always be meaningful!)

Choosing Enumeration Literal Values

Internally, an enumeration type associates an integer value with each element of the ation By default, the numbering starts at 0 for the first element and goes up in steps of 1 It’s possible to retrieve the underlying integer value of an enumeration variable To do this, you must cast it to its underlying type Remember from the discussion of unboxing in Chapter 8 that casting a type converts the data from one type to another as long as the conversion is

enumer-valid and meaningful The following code example writes out the value 2 and not the word Fall (in the Season enumeration Spring is 0, Summer 1, Fall 2, and Winter 3):

enum Season { Spring, Summer, Fall, Winter }

Season colorful = Season.Fall;

Console.WriteLine((int)colorful); // writes out '2'

If you prefer, you can associate a specific integer constant (such as 1) with an enumeration

literal (such as Spring), as in the following example:

enum Season { Spring = 1, Summer, Fall, Winter }

Important The integer value with which you initialize an enumeration literal must be a

compile-time constant value (such as 1)

If you don’t explicitly give an enumeration literal a constant integer value, the compiler gives

it a value that is 1 greater than the value of the previous enumeration literal except for the

very first enumeration literal, to which the compiler gives the default value 0 In the ing example, the underlying values of Spring, Summer, Fall, and Winter are now 1, 2, 3, and 4

preced-You are allowed to give more than one enumeration literal the same underlying value For

example, in the United Kingdom, Fall is referred to as Autumn You can cater to both cultures

as follows:

enum Season { Spring, Summer, Fall, Autumn = Fall, Winter }

Trang 7

176 Part II Understanding the C# Language

Choosing an Enumeration’s Underlying Type

When you declare an enumeration, the enumeration literals are given values of type int You

can also choose to base your enumeration on a different underlying integer type For

exam-ple, to declare that Season’s underlying type is a short rather than an int, you can write this:

enum Season : short { Spring, Summer, Fall, Winter }

The main reason for doing this is to save memory; an int occupies more memory than a short, and if you do not need the entire range of values available to an int, using a smaller

data type can make sense

You can base an enumeration on any of the eight integer types: byte, sbyte, short, ushort, int, uint, long, or ulong The values of all the enumeration literals must fit inside the range of the chosen base type For example, if you base an enumeration on the byte data type, you can

have a maximum of 256 literals (starting at 0)

Now that you know how to declare an enumeration, the next step is to use it In the ing exercise, you will work with a Console application to declare and use an enumeration that represents the months of the year

follow-Create and use an enumeration

1 Start Microsoft Visual Studio 2010 if it is not already running

2 Open the StructsAndEnums project, located in the \Microsoft Press\Visual CSharp Step

By Step\Chapter 9\StructsAndEnums folder in your Documents folder

3 In the Code and Text Editor window, display the Month cs file

The source file contains an empty namespace named StructsAndEnums

4 Add an enumeration named Month for modeling the months of the year inside the

StructsAndEnums namespace, as shown in bold here The 12 enumeration literals for Month are January through December

namespace StructsAndEnums

{

enum Month

{

January, February, March, April,

May, June, July, August,

September, October, November, December

}

}

Trang 8

5 Display the Program cs file in the Code and Text Editor window

As in the exercises in previous chapters, the Main method calls the DoWork method

and traps any exceptions that occur

6 In the Code and Text Editor window, add a statement to the DoWork method to declare

a variable named first of type Month and initialize it to Month.January Add another

statement to write the value of the first variable to the Console

The DoWork method should look like this:

static void DoWork()

7 On the Debug menu, click Start Without Debugging

Visual Studio 2010 builds and runs the program Confirm that the word January is

written to the console

8 Press Enter to close the program and return to the Visual Studio 2010 programming

environment

9 Add two more statements to the DoWork method to increment the first variable and

display its new value to the console, as shown in bold here:

static void DoWork()

10 On the Debug menu, click Start Without Debugging

Visual Studio 2010 builds and runs the program Confirm that the words January and February are written to the console

Notice that performing a mathematical operation (such as the increment operation) on

an enumeration variable changes the internal integer value of the variable When the variable is written to the console, the corresponding enumeration value is displayed

Trang 9

178 Part II Understanding the C# Language

11 Press Enter to close the program and return to the Visual Studio 2010 programming

environment

12 Modify the first statement in the DoWork method to initialize the first variable to

Month.December, as shown in bold here:

static void DoWork()

13 On the Debug menu, click Start Without Debugging

Visual Studio 2010 builds and runs the program This time the word December is written

to the console, followed by the number 12 Although you can perform arithmetic on an

enumeration, if the results of the operation are outside the range of values defined for the enumerator, all the runtime can do is interpret the value of the variable as the cor-responding integer value

14 Press Enter to close the program and return to the Visual Studio 2010 programming

environment

Working with Structures

You saw in Chapter 8 that classes define reference types that are always created on the heap

In some cases, the class can contain so little data that the overhead of managing the heap becomes disproportionate In these cases, it is better to define the type as a structure A structure is a value type Because structures are stored on the stack, as long as the structure

is reasonably small, the memory management overhead is often reduced

Like a class, a structure can have its own fields, methods, and (with one important exception discussed later in this chapter) constructors

Common Structure Types

You might not have realized it, but you have already used structures in previous

exer-cises in this book In C#, the primitive numeric types int, long, and float are aliases for the structures System.Int32, System.Int64, and System.Single, respectively These struc-

tures have fields and methods, and you can actually call methods on variables and

liter-als of these types For example, all of these structures provide a ToString method that

Trang 10

can convert a numeric value to its string representation The following statements are all legal statements in C#:

You don’t see this use of the ToString method often, because the Console.WriteLine

method calls it automatically when it is needed Use of the static methods exposed by these structures is much more common For example, in earlier chapters you used the

static int.Parse method to convert a string to its corresponding integer value What you are actually doing is invoking the Parse method of the Int32 structure:

string s = "42";

int i = int.Parse(s); // exactly the same as Int32.Parse

These structures also include some useful static fields For example, Int32.MaxValue is the maximum value that an int can hold, and Int32.MinValue is the smallest value you can store in an int

The following table shows the primitive types in C# and their equivalent types in the Microsoft NET Framework Notice that the string and object types are classes (refer-ence types) rather than structures

bool System.Boolean Structure

byte System.Byte Structure

decimal System.Decimal Structure

double System.Double Structure

float System.Single Structure

int System.Int32 Structure

long System.Int64 Structure

object System.Object Class

sbyte System.SByte Structure

short System.Int16 Structure

string System.String Class

uint System.UInt32 Structure

ulong System.UInt64 Structure

ushort System.UInt16 Structure

Trang 11

180 Part II Understanding the C# Language

Declaring a Structure

To declare your own structure type, you use the struct keyword followed by the name of the

type, followed by the body of the structure between opening and closing braces For

exam-ple, here is a structure named Time that contains three public int fields named hours, minutes, and seconds:

struct Time

{

public int hours, minutes, seconds;

}

As with classes, making the fields of a structure public is not advisable in most cases; there

is no way to control the values held in public fields For example, anyone could set the value

of minutes or seconds to a value greater than 60 A better idea is to make the fields private

and provide your structure with constructors and methods to initialize and manipulate these fields, as shown in this example:

“Operator Overloading ”

Use structures to implement simple concepts whose main feature is their value When you copy a value type variable, you get two copies of the value In contrast, when you copy a ref-erence type variable, you get two references to the same object In summary, use structures for small data values where it’s just as or nearly as efficient to copy the value as it would be

to copy an address Use classes for more complex data that is too big to copy efficiently

Trang 12

Understanding Structure and Class Differences

A structure and a class are syntactically similar, but there are a few important differences Let’s look at some of these differences:

n You can’t declare a default constructor (a constructor with no parameters) for a

struc-ture The following example would compile if Time were a class, but because Time is a

structure, it does not:

The reason you can’t declare your own default constructor for a structure is that the

compiler always generates one In a class, the compiler generates the default

con-structor only if you don’t write a concon-structor yourself The compiler-generated default

constructor for a structure always sets the fields to 0, false, or null—just as for a class

Therefore, you should ensure that a structure value created by the default constructor behaves logically and makes sense with these default values If you don’t want to use these default values, you can initialize fields to different values by providing a nonde-fault constructor However, if you don’t initialize a field in your nondefault structure constructor, the compiler won’t initialize it for you This means that you must explic-itly initialize all the fields in all your nondefault structure constructors or you’ll get a compile-time error For example, although the following example would compile and

silently initialize seconds to 0 if Time were a class, because Time is a structure, it fails to

n In a class, you can initialize instance fields at their point of declaration In a structure,

you cannot The following example would compile if Time were a class, but because Time is a structure, it causes a compile-time error:

struct Time

{

private int hours = 0; // compile-time error

private int minutes;

private int seconds;

}

Trang 13

182 Part II Understanding the C# Language

The following table summarizes the main differences between a structure and a class

Is this a value type or a reference type? A structure is a value

type

A class is a reference type

Do instances live on the stack or the heap? Structure instances

are called values and

live on the stack

Class instances are called

objects and live on the

heap Can you declare a default constructor? No Yes

If you declare your own constructor, will

the compiler still generate the default

constructor?

If you don’t initialize a field in your own

constructor, will the compiler automatically

initialize it for you?

Are you allowed to initialize instance fields at

their point of declaration?

There are other differences between classes and structures concerning inheritance These differences are covered in Chapter 12

Declaring Structure Variables

After you have defined a structure type, you can use it in exactly the same way as any other

type For example, if you have defined the Time structure, you can create variables, fields, and parameters of type Time, as shown in this example:

private Time currentTime;

public void Method(Time parameter)

Note You can create a nullable version of a structure variable by using the ? modifier You can

then assign the null value to the variable:

Time? currentTime = null;

Trang 14

Understanding Structure Initialization

Earlier in this chapter, you saw how the fields in a structure can be initialized by using a structor If you call a constructor, the various rules described earlier guarantee that all the fields in the structure will be initialized:

con-Time now = new con-Time();

The following graphic depicts the state of the fields in this structure:

However, because structures are value types, you can create structure variables without calling a constructor, as shown in the following example:

Time now;

This time, the variable is created but its fields are left in their uninitialized state The following

graphic depicts the state of the fields in the now variable Any attempt to access the values in

these fields will result in a compiler error:

Note that in both cases, the Time variable is created on the stack

If you’ve written your own structure constructor, you can also use that to initialize a structure variable As explained earlier in this chapter, a structure constructor must always explicitly initialize all its fields For example:

struct Time

{

private int hours, minutes, seconds;

Trang 15

184 Part II Understanding the C# Language

public Time(int hh, int mm)

The following example initializes now by calling a user-defined constructor:

Time now = new Time(12, 30);

The following graphic shows the effect of this example:

It’s time to put this knowledge into practice In the following exercise, you will create and use

a structure to represent a date

Create and use a structure type

1 In the StructsAndEnums project, display the Date cs file in the Code and Text Editor

window

2 Add a structure named Date inside the StructsAndEnums namespace

This structure should contain three private fields: one named year of type int, one named month of type Month (using the enumeration you created in the preceding exercise), and one named day of type int The Date structure should look exactly as

follows:

struct Date

{

private int year;

private Month month;

private int day;

}

Consider the default constructor that the compiler will generate for Date This tor sets the year to 0, the month to 0 (the value of January), and the day to 0 The year value 0 is not valid (because there was no year 0), and the day value 0 is also not valid

construc-(because each month starts on day 1) One way to fix this problem is to translate the

year and day values by implementing the Date structure so that when the year field holds the value Y, this value represents the year Y + 1900 (or you can pick a different

Trang 16

century if you prefer), and when the day field holds the value D, this value represents the day D + 1 The default constructor will then set the three fields to values that

represent the date 1 January 1900

3 Add a public constructor to the Date structure This constructor should take three

parameters: an int named ccyy for the year, a Month named mm for the month, and an int named dd for the day Use these three parameters to initialize the corresponding fields A year field with the value Y represents the year Y + 1900, so you need to initial- ize the year field to the value ccyy – 1900 A day field with the value D represents the day D + 1, so you need to initialize the day field to the value dd – 1

The Date structure should now look like this (with the constructor shown in bold):

struct Date

{

private int year;

private Month month;

private int day;

public Date(int ccyy, Month mm, int dd)

4 Add a public method named ToString to the Date structure after the constructor

This method takes no arguments and returns a string representation of the date

Remember, the value of the year field represents year + 1900, and the value of the day field represents day + 1

Note The ToString method is a little different from the methods you have seen so far Every type, including structures and classes that you define, automatically has a ToString

method whether or not you want it Its default behavior is to convert the data in a variable

to a string representation of that data Sometimes, the default behavior is meaningful;

oth-er times, it is less so For example, the default behavior of the ToString method genoth-erated for the Date class simply generates the string “StructsAndEnums.Date” To quote Zaphod Beeblebrox in The Restaurant at the End of the Universe by Douglas Adams (Pan Macmillan,

1980), this is “shrewd, but dull ” You need to define a new version of this method that

overrides the default behavior by using the override keyword Overriding methods are

dis-cussed in more detail in Chapter 12

The ToString method should look like this:

public override string ToString()

Trang 17

186 Part II Understanding the C# Language

The Format method of the String class enables you to format data It operates in a similar manner to the Console.WriteLine method, except that rather than displaying

data to the console it returns the formatted result as a string In this example, the

posi-tional parameters are replaced with the text representations of the values of the month field, the expression this.day + 1, and the expression this.year + 1900 The ToString

method returns the formatted string as its result

5 Display the Program cs file in the Code and Text Editor window

6 In the DoWork method, comment out the existing four statements Add code to the

DoWork method to declare a local variable named defaultDate, and initialize it to a Date value constructed by using the default Date constructor Add another statement

to DoWork to write the defaultDate variable to the console by calling Console.WriteLine

Note The Console.WriteLine method automatically calls the ToString method of its

argument to format the argument as a string

The DoWork method should now look like this:

static void DoWork()

7 On the Debug menu, click Start Without Debugging to build and run the program

Verify that the date January 1 1900 is written to the console

8 Press the Enter key to return to the Visual Studio 2010 programming environment 9 In the Code and Text Editor window, return to the DoWork method, and add two more

statements In the first statement, declare a local variable named weddingAnniversary

and initialize it to July 4 2010 (In an example of supreme irony, I actually did get ried on Independence Day and hence lost my independence!) In the second statement,

mar-write the value of weddingAnniversary to the console

The DoWork method should now look like this:

static void DoWork()

Trang 18

10 On the Debug menu, click Start Without Debugging Confirm that the date July 4 2010 is

written to the console below the previous information

11 Press Enter to close the program

Copying Structure Variables

You’re allowed to initialize or assign one structure variable to another structure variable, but only if the structure variable on the right side is completely initialized (that is, if all its fields are populated with valid data rather than undefined values) The following example compiles

because now is fully initialized The graphic shows the results of performing the assignment

Time now = new Time(12, 30);

Time copy = now;

The following example fails to compile because now is not initialized:

Time now;

Time copy = now; // compile-time error: now has not been assigned

When you copy a structure variable, each field on the left side is set directly from the

corresponding field on the right side This copying is done as a fast, single operation that copies the contents of the entire structure and that never throws an exception Compare this

behavior with the equivalent action if Time were a class, in which case both variables (now and copy) would end up referencing the same object on the heap

Note C++ programmers should note that this copy behavior cannot be customized

Trang 19

188 Part II Understanding the C# Language

In the final exercise in this chapter, you will contrast the copy behavior of a structure with that of a class

Compare the behavior of a structure and a class

1 In the StructsAndEnums project, display the Date cs file in the Code and Text Editor

window

2 Add the following method to the Date structure This method advances the date in the

structure by one month If, after advancing the month, the value of the month field

has moved beyond December, this code resets the month to January and advances the

value of the year field by 1

public void AdvanceMonth()

3 Display the Program cs file in the Code and Text Editor window

4 In the DoWork method, comment out the first two statements that create and display

the value of the defaultDate variable

5 Add the following code shown in bold to the end of the DoWork method This code

creates a copy of the weddingAnniversary variable called weddingAnniversaryCopy and

prints out the value of this new variable

static void DoWork()

{

Date weddingAnniversaryCopy = weddingAnniversary;

Console.WriteLine(“Value of copy is {0}”, weddingAnniversaryCopy);

}

6 Add the following statements to the end of the DoWork method that call the

AdvanceMonth method of the weddingAnniversary variable, and then display the value

of the weddingAnniversary and weddingAnniversaryCopy variables:

static void DoWork()

Trang 20

7 On the Debug menu, click Start Without Debugging to build and run the application

Verify that the console window displays the following messages:

July 4 2010

Value of copy is July 4 2010

New value of weddingAnniversary is July 4 2010

Value of copy is August 4 2010

The first message displays the initial value of the weddingAnniversary variable (July 4 2010) The second message displays the value of the weddingAnniversaryCopy variable You can see that it contains a copy of the date held in the weddingAnniversary variable (July 4 2010) The third message displays the value of the weddingAnniversary variable after changing the month of the weddingAnniversaryCopy variable to August 4 2010

Notice that it has not changed from its original value of July 4 2010 The final message

displays the value of the weddingAnniversaryCopy variable You can see that this has

changed to August 4 2010

8 Press Enter and return to Visual Studio 2010

9 Display the Date cs file in the Code and Text Editor window

10 Change the Date structure into a class, as shown in bold in the following code example:

class Date

{

}

11 On the Debug menu, click Start Without Debugging to build and run the application

again Verify that the console window displays the following messages:

July 4 2010

Value of copy is July 4 2010

New value of weddingAnniversary is August 4 2010

Value of copy is August 4 2010

The first two messages and the fourth message are the same as before However, the

third message shows that the value of the weddingAnniversary variable has changed

to August 4 2010 Remember that a structure is a value type, and when you copy a value type variable you make a copy of all the data in the variable However, a class is

a reference type, and when you copy a reference type variable you copy a reference to the original variable If the data in a class variable changes, all references to this variable see the changes

12 Press Enter and return to Visual Studio 2010

In this chapter, you have seen how to create and use enumerations and structures You have learned some of the similarities and differences between a structure and a class, and you have seen how to define constructors to initialize the fields in a structure You have also

learned how to represent a structure as a string by overriding the ToString method

Trang 21

190 Part II Understanding the C# Language

n If you want to continue to the next chapter

Keep Visual Studio 2010 running, and turn to Chapter 10

n If you want to exit Visual Studio 2010 now

On the File menu, click Exit If you see a Save dialog box, click Yes and save the project

Chapter 9 Quick Reference

Declare an enumeration Write the keyword enum, followed by the name of the type, followed by a pair

of braces containing a comma-separated list of the enumeration literal names For example:

enum Season { Spring, Summer, Fall, Winter }

Declare a structure type Write the keyword struct, followed by the name of the structure type, followed

by the body of the structure (the constructors, methods, and fields) For ample:

ex-struct Time {

public Time(int hh, int mm, int ss) { }

private int hours, minutes, seconds;

}

Declare a structure variable Write the name of the structure type, followed by the name of the variable,

followed by a semicolon For example:

Trang 22

191

Chapter 10

Using Arrays and Collections

After completing this chapter, you will be able to:

n Declare, initialize, and use array variables

n Declare, initialize, and use variables of various collection types

You have already seen how to create and use variables of many different types However, all the examples of variables you have seen so far have one thing in common—they hold infor-

mation about a single item (an int, a float, a Circle, a Date, and so on) What happens if you

need to manipulate a set of items? One solution is to create a variable for each item in the set, but this leads to a number of further questions: How many variables do you need? How should you name them? If you need to perform the same operation on each item in the set (such as increment each variable in a set of integers), how would you avoid very repetitive code? This solution assumes that you know, when you write the program, how many items you will need, but how often is this the case? For example, if you are writing an application that reads and processes records from a database, how many records are in the database, and how likely is this number to change?

Arrays and collections provide mechanisms that solve the problems posed by these

questions

What Is an Array?

An array is an unordered sequence of elements All the elements in an array have the same

type (unlike the fields in a structure or class, which can have different types) The elements

of an array live in a contiguous block of memory and are accessed by using an integer index (unlike fields in a structure or class, which are accessed by name)

Declaring Array Variables

You declare an array variable by specifying the name of the element type, followed by a pair

of square brackets, followed by the variable name The square brackets signify that the

vari-able is an array For example, to declare an array of int varivari-ables named pins, you write

int[] pins; // Personal Identification Numbers

Microsoft Visual Basic programmers should note that you use square brackets and not parentheses C and C++ programmers should note that the size of the array is not part of the

Trang 23

192 Part II Understanding the C# Language

declaration Java programmers should note that you must place the square brackets before

the variable name

Note You are not restricted to primitive types as array elements You can also create arrays of

structures, enumerations, and classes For example, you can create an array of Time structures

like this:

Time[] times;

Tip It is often useful to give array variables plural names, such as places (where each element is

a Place), people (where each element is a Person), or times (where each element is a Time)

Creating an Array Instance

Arrays are reference types, regardless of the type of their elements This means that an

array variable refers to a contiguous block of memory holding the array elements on the

heap, just as a class variable refers to an object on the heap, and this contiguous block of memory does not hold its array elements directly on the stack as a structure does (To review values and references and the differences between the stack and the heap, see Chapter 8,

“Understanding Values and References ”) Remember that when you declare a class variable,

memory is not allocated for the object until you create the instance by using new Arrays

follow the same rules—when you declare an array variable, you do not declare its size You specify the size of an array only when you actually create an array instance

To create an array instance, you use the new keyword followed by the element type, followed

by the size of the array you’re creating between square brackets Creating an array also

ini-tializes its elements by using the now familiar default values (0, null, or false, depending on

whether the type is numeric, a reference, or a Boolean, respectively) For example, to create

and initialize a new array of four integers for the pins variable declared earlier, you write this:

pins = new int[4];

The following graphic illustrates the effects of this statement:

Trang 24

The size of an array instance does not have to be a constant; it can be calculated at run time,

as shown in this example:

int size = int.Parse(Console.ReadLine());

int[] pins = new int[size];

You’re allowed to create an array whose size is 0 This might sound bizarre, but it’s useful in situations where the size of the array is determined dynamically, and could even be 0 An

array of size 0 is not a null array

Initializing Array Variables

When you create an array instance, all the elements of the array instance are initialized to a default value depending on their type You can modify this behavior and initialize the ele-ments of an array to specific values if you prefer You achieve this by providing a comma-

separated list of values between a pair of braces For example, to initialize pins to an array of four int variables whose values are 9, 3, 7, and 2, you write this:

int[] pins = new int[4]{ 9, 3, 7, 2 };

The values between the braces do not have to be constants They can be values calculated at run time, as shown in this example:

Random r = new Random();

int[] pins = new int[4]{ r.Next() % 10, r.Next() % 10,

r.Next() % 10, r.Next() % 10 };

Note The System.Random class is a pseudorandom number generator The Next method

returns a nonnegative random integer in the range 0 to Int32.MaxValue by default The Next

method is overloaded, and other versions enable you to specify the minimum value and

maxi-mum value of the range The default constructor for the Random class seeds the random number

generator with a time-dependent seed value, which reduces the possibility of the class cating a sequence of random numbers An overloaded version of the constructor enables you

dupli-to provide your own seed value That way, you can generate a repeatable sequence of random numbers for testing purposes

The number of values between the braces must exactly match the size of the array instance being created:

int[] pins = new int[3]{ 9, 3, 7, 2 }; // compile-time error

int[] pins = new int[4]{ 9, 3, 7 }; // compile-time error

int[] pins = new int[4]{ 9, 3, 7, 2 }; // OK

Trang 25

194 Part II Understanding the C# Language

When you’re initializing an array variable, you can actually omit the new expression and

the size of the array The compiler calculates the size from the number of initializers

and generates code to create the array For example:

int[] pins = { 9, 3, 7, 2 };

If you create an array of structures, you can initialize each structure in the array by calling the structure constructor, as shown in this example:

Time[] schedule = { new Time(12,30), new Time(5,30) };

Creating an Implicitly Typed Array

The element type when you declare an array must match the type of elements that you

at-tempt to store in the array For example, if you declare pins to be an array of int, as shown in the preceding examples, you cannot store a double, string, struct, or anything that is not an int in this array If you specify a list of initializers when declaring an array, you can let the C#

compiler infer the actual type of the elements in the array for you, like this:

var names = new[]{"John", "Diana", "James", "Francesca"};

In this example, the C# compiler determines that the names variable is an array of strings It is

worth pointing out a couple of syntactic quirks in this declaration First, you omit the square

brackets from the type; the names variable in this example is declared simply as var, and not var[] Second, you must specify the new operator and square brackets before the initializer

list

If you use this syntax, you must ensure that all the initializers have the same type This next example causes the compile-time error “No best type found for implicitly typed array”:var bad = new[]{"John", "Diana", 99, 100};

However, in some cases, the compiler will convert elements to a different type if doing so

makes sense In the following code, the numbers array is an array of double because the stants 3.5 and 99.999 are both double, and the C# compiler can convert the integer values 1 and 2 to double values:

con-var numbers = new[]{1, 2, 3.5, 99.999};

Generally, it is best to avoid mixing types and hoping that the compiler will convert them for you

Implicitly typed arrays are most useful when you are working with anonymous types,

described in Chapter 7, “Creating and Managing Classes and Objects ” The following code

Ngày đăng: 05/07/2014, 16:20

TỪ KHÓA LIÊN QUAN