Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C# 2008 Step by Step.pdf
Скачиваний:
27
Добавлен:
25.03.2016
Размер:
14 Мб
Скачать
☆

176

Part II Understanding the C# Language

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;

}

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

Question

Structure

Class

Is this a value type or a reference type?

A structure is a value

A class is a reference type.

type.

 

Do instances live on the stack or the heap?

Structure instances

Class instances are called

 

are called values and

objects and live on the

 

live on the stack.

heap.

 

 

 

Can you declare a default constructor?

No

Yes

 

 

 

If you declare your own constructor, will

Yes

No

the compiler still generate the default

 

 

constructor?

 

 

 

 

 

If you don’t initialize a field in your own

No

Yes

constructor, will the compiler automati-

 

 

cally initialize it for you?

 

 

Are you allowed to initialize instance fields

No

Yes

at their point of declaration?

 

 

 

 

 

There are other differences between classes and structures concerning inheritance. These differences are covered in Chapter 12, “Working with Inheritance.” Now that you know how to declare structures, the next step is to use them to create values.

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:

struct Time

{

...

private int hours, minutes, seconds;

}

Chapter 9 Creating Value Types with Enumerations and Structs

177

class Example

{

public void Method(Time parameter)

{

Time localVariable;

...

}

private Time currentTime;

}

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;

Understanding Structure Initialization

Earlier in this chapter, you saw how the fields in a structure are initialized by using a constructor. However, because structures are value types, you can create structure variables without calling a constructor, as shown in the following example:

Time now;

In this example, the variable is created but its fields are left in their uninitialized state. Any attempt to access the values in these fields will result in a compiler error. The following graphic depicts the state of the fields in the now variable:

If you call a constructor, the various rules of structure constructors described earlier guarantee that all the fields in the structure will be initialized:

Time now = new Time();

178 Part II Understanding the C# Language

This time, the default constructor initializes the fields in the structure, as shown in the following graphic:

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

{

public Time(int hh, int mm)

{

hours = hh; minutes = mm; seconds = 0;

}

...

private int hours, minutes, seconds;

}

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:

Chapter 9 Creating Value Types with Enumerations and Structs

179

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 initialized). 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.

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

180

Part II Understanding the C# Language

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 constructor will set the year to 0, the month to 0 (the value of January), and the day to 0. The year value 0 is not valid (there was no year 0), and the day value 0 is also not valid (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 (you can pick a different 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 of Y represents the year Y + 1900, so you need to initialize the year field to the value ccyy – 1900. A day field of 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 (the constructor is shown in bold):

struct Date

{

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

{

this.year = ccyy - 1900; this.month = mm; this.day = dd - 1;

}

private int year; private Month month; private int day;

}

Chapter 9 Creating Value Types with Enumerations and Structs

181

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; other times, it is less so. For example, the default behavior of the ToString method generated for the Date class simply generates the string “StructsAndEnums.Date”. To quote Zaphod Beeblebrox in The Restaurant at the End of the Universe (Douglas Adams, Del Rey, 2005),

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 discussed in

more detail in Chapter 12.

The ToString method should look like this:

public override string ToString()

{

return this.month + “ “ + (this.day + 1) + “ “ + (this.year + 1900);

}

Note The + signs inside the parentheses are the arithmetic addition operator. The others are the string concatenation operator. Without the parentheses, all occurrences of the + sign would be treated as the string concatenation operator because the expression being evaluated is a string. It can be a little confusing when the same symbol in a single expression denotes different operators!

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

6.Add a statement to the end of the Entrance 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 Entrance 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.

182

Part II Understanding the C# Language

 

The Entrance method should now look like this:

 

static void Entrance()

 

{

...

Date defaultDate = new Date(); Console.WriteLine(defaultDate);

}

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. (The original output of the Entrance method will be displayed first.)

8.Press the Enter key to return to the Visual Studio 2008 programming environment.

9.In the Code and Text Editor window, return to the Entrance method, and add two more statements. The first statement should declare a local variable named halloween

and initialize it to October 31 2008. The second statement should write the value of halloween to the console.

The Entrance method should now look like this:

static void Entrance()

{

...

Date halloween = new Date(2008, Month.October, 31); Console.WriteLine(halloween);

}

Note When you type the new keyword, IntelliSense will automatically detect that there are two constructors available for the Date type.

10.On the Debug menu, click Start Without Debugging. Confirm that the date October 31 2008 is written to the console below the previous information.

11.Press Enter to close the program.

You have successfully used the enum and struct keywords to declare your own value types and then used these types in code.

If you want to continue to the next chapter:

Keep Visual Studio 2008 running, and turn to Chapter 10.

If you want to exit Visual Studio 2008 now:

On the File menu, click Exit. If you see a Save dialog box, click Yes (if you are using Visual Studio 2008) or Save (if you are using Visual C# 2008 Express Edition) and save the project.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]