Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning ASP.NET 2.0 With CSharp (2006) [eng]

.pdf
Скачиваний:
86
Добавлен:
16.08.2013
Размер:
20.33 Mб
Скачать

Chapter 9

Inheritance

Inheritance is another of the key features of objected-oriented software, and works just like real life, where you inherit properties and behavior from your parents. Inheritance can get quite complex, so this section covers only the basics to give you an understanding of what inheritance is and how it works, especially as it’s used in all code-behind files. The essentials of inheritance are that one class (the base class) can be inherited by another (the subclass), in which case the subclass automatically has the

same methods and properties as the base class. But the subclass can change the behavior if it needs to, or add to it.

ASP.NET uses inheritance as part of its standard programming model, and you probably already have seen this in action. For example, consider a Default.aspx Web Form, which would have the following in it:

<%@ Page Language=”C#” CodeFile=”Default.aspx.cs” Inherits=”_Default” %>

Here you can see the Inherits keyword being used, telling you that when the Web Form is compiled, it should inherit its features from the class _Default. This class is in the code-behind file:

partial class _Default : System.Web.UI.Page

{

. . .

}

Within the code file, inheritance uses the colon (:) to separate the class from the class it is inheriting from. So in the preceding example, _Default is the new class and System.Web.UI.Page is the class being inherited from (which is the base class). This means that the _Default class will contain all of the properties and methods that the System.Web.UI.Page contains. One thing to notice is the partial keyword, which tells the compiler that this class is split across multiple files: the Web Form and the code-behind file.

The following exercise has you use some simple (and rather contrived) examples to show how inheritance works.

Try It Out

Classes and Inheritance

1.Create a new class in the App_Code directory called Vehicles.cs. If the App_Code directory doesn’t exist, you can create this directory by selecting the top item in the Solution Explorer and using the right mouse button to select Add Folder and then App_Code Folder, as shown in Figure 9-9.

338

Code

Figure 9-9

2.Delete the existing template class, and create a new one called Vehicle, which has properties called Wheels and TopSpeed, and a method called Warning:

public class Vehicle

{

protected int _wheels; protected int _topSpeed; protected string _warningSound;

public int Wheels

{

get {return _wheels;} set {_wheels = value;}

}

public int TopSpeed

{

get {return _topSpeed;} set {_topSpeed = value;}

}

public virtual string Warning()

{

return _warningSound;

}

}

339

Chapter 9

3.Create another class, in the same file, called Car:

public class Car : Vehicle

{

public Car()

{

_wheels = 4; _topSpeed = 150;

_warningSound = “Honk”;

}

}

4.Create another class, called Bike:

public class Bike : Vehicle

{

public Bike()

{

_wheels = 2; base.TopSpeed = 30;

_warningSound = “Ring Ring”;

}

}

5.Create another class, called Skateboard:

public class Skateboard : Vehicle

{

public Skateboard()

{

_wheels = 4; _topSpeed = 15;

}

}

6.Between the closing bracket of the constructor and the closing bracket of the class, type the following:

Public override

7.Press the space bar to see that a little helper tip pops up (see Figure 9-10).

Figure 9-10

340

Code

8.Select the string Warning() entry and press Enter See how the function is created for you. Delete the existing return line and add a new one:

public override string Warning()

{

return “No warning - you’ll have to shout yourself”;

}

9.Save and close the class file.

10.Create a new Web Form called Inheritance.aspx. Add three buttons and three labels, so it looks like Figure 9-11. Make sure the Label next to Wheels is Label1, the Label next to Speed is Label2, and the Label next to Warning is Label3. You can use the Text property of the buttons to change the text shown on them.

Figure 9-11

11.Create an event handler for the Click event for the Car button:

protected void Button1_Click(object sender, System.EventArgs e)

{

Car myTransport = new Car();

Label1.Text = myTransport.Wheels.ToString();

Label2.Text = myTransport.TopSpeed.ToString(); Label3.Text = myTransport.Warning();

}

12.Create an event handler for the Bike button:

protected void Button2_Click(object sender, System.EventArgs e)

{

Bike myTransport = new Bike();

Label1.Text = myTransport.Wheels.ToString();

Label2.Text = myTransport.TopSpeed.ToString(); Label3.Text = myTransport.Warning();

}

13.Create an event handler for the Skateboard button:

protected void Button3_Click(object sender, System.EventArgs e)

{

Skateboard myTransport = new Skateboard(); Label1.Text = myTransport.Wheels.ToString();

Label2.Text = myTransport.TopSpeed.ToString(); Label3.Text = myTransport.Warning();

}

341

Chapter 9

14.In the Solution Explorer, right-click Inheritance.aspx, and from the menu, select Set As Start Page.

15.Press F5 to run the page. Click the three buttons and notice what is displayed in the labels.

How It Works

To see how this works, start with the Vehicle class. This is similar to what you’ve seen before, but with a few subtle differences. One of the private variables, _warningSound, is not set anywhere — don’t worry about that, it’s deliberate, and will be used in other classes. Also the private variables are declared as protected, meaning that other classes in the same file will be able to access them. This class will be the base class that other classes inherit from. The other difference is that the Warning method has a new keyword on it — virtual:

public virtual string Warning()

{

return _warningSound;

}

A virtual method means that inheriting classes can override the method and provide their own implementation. Take a look at the inheriting classes, starting with the Car:

public class Car : Vehicle

{

public Car()

{

_wheels = 4; _topSpeed = 150;

_warningSound = “Honk”;

}

}

This defines a new class, but in the line after the class name, it specifies the class to be inherited from. This means the Car automatically has the properties and methods of the base class. The base class hasn’t set any values so the car has a constructor to do this, which uses the private variables declared by the base class. It can access those variables because they’ve been declared as Protected.

The Bike class is slightly different:

public class Bike : Vehicle

{

public Bike()

{

_wheels = 2; base.TopSpeed = 30;

_warningSound = “Ring Ring”;

}

}

The way it inherits is the same, but setting the properties is different. For the number of wheels, instead of using the private variable of the base class, the property of the class is used. Even though the current

342

Code

class doesn’t define the Wheels property itself, it does have a Wheels property because it is inherited from the base class. For the top speed, the property of the base class is called directly; the keyword base refers to the base class. There is no property for the warning sound, so the private variable is used directly.

All of these methods are acceptable, and you’ll see all three used in various pieces of documentation, books, or online tutorials. In general, it’s best to use the properties, because that fits with the objectoriented principles discussed earlier.

The Skateboard class is different:

public class Skateboard : Vehicle

{

public Skateboard()

{

_wheels = 4; _topSpeed = 15;

}

public override string Warning()

{

return “No warning - you’ll have to shout yourself”;

}

}

The constructor sets the values for _wheels and _stopSpeed, but not the warning message. The big difference is that the Warning property is overridden, meaning that instead of using the Warning method from the base class, the Skateboard class is defining its own Warning method. This is called polymorphism, and allows different classes to have the same methods and properties but with different behavior.

Using these classes is simple:

Car myTransport = new Car();

Label1.Text = myTransport.Wheels.ToString();

Label2.Text = myTransport.TopSpeed.ToString();

Label3.Text = myTransport.Warning();

This creates the new class and accesses the properties and the methods. Whatever the class type created, you can see that the same properties and methods are available. Even though these classes don’t define the properties themselves, inheritance means they have the properties. The same applies to the methods, where the Car and Bike don’t define the methods, but the Skateboard does, overriding the existing implementation and providing its own.

Variable Scope and Lifetime

Although it is related to variables, the discussion of scope and lifetime has been left until now because it affects all of the other topics discussed in this chapter. The term scope means the degree to which a variable is accessible to other code, and the scope affects the lifetime. You’ve seen how Private and Public

343

Chapter 9

affect the visibility of methods and properties, but may not realize that visibility of variables depends on where they are declared. To make this easier, have a look at some code:

public class Class1

{

private int _variable1;

private void Method1()

{

int variable2;

_variable1 = 1; variable2 = 3;

}

private void Method2()

{

_variable1 = 2;

}

}

The variable1 variable _ is declared within the class, outside of any methods, so it can be accessed from any methods and properties. On the other hand, variable2 is declared within the Method1 method, so it can only be accessed within Method1 — no other methods or properties would be able to use it. This is called a local variable.

The same rules apply to variables declared within code blocks. For example:

int number1;

if (number1 == 15)

{

int number2; number2 += 15;

}

Here number1 is declared outside of the if block, and can therefore be used within it. But number2 is declared within the code block, so it cannot be used outside of the code block. The same rules apply to other code blocks such as loops.

The foreach loop also has this:

foreach (CartItem item in Cart.Items)

{

}

The variable item is declared within the statement itself, but follows the same rule: it can only be accessed from within the loop. Trying to access it outside of the loop would generate a compile error.

344

Code

Generics

Generics refers to classes and methods that work uniformly on values of different types. Generics are often discussed as an advanced topic, and though some of it is advanced, some of it is simple and easy to use. In fact, one feature of generics is used in the shopping cart. Remember how the cart consists of two classes: the CartItem and the ShoppingCart, which uses the CartItem as a collection.

Many of the collections discussed early in the chapter provide storage for objects — the Object being a type. Because they are designed to work with a data type of Object, collections can in fact store any data type. However, when you take items out of a collection, they often need to be converted from the Object data type to their native data type. This involves extra coding and reduces performance. Another problem results because collections can store any data type, which means you can store any data type in them. If you had a collection to store the CartItem objects, you could in fact store strings, numbers, dates, and so forth in the same collection. For example, you could do this:

List _items = new List();

CartItem item = new CartItem( . . .);

_items.Add(item);

_items.Add(“this isn’t a cart item”); _items.Add(“65”);

When you take items out of the collection, you have no idea what data type it is unless you track which objects you put into the list.

To get around this problem, use generics, or more specifically generic collections. These are stored in the System.Collections.Generic namespace, and the one the shopping cart uses is the List:

private List<CartItem> _items;

This simply states that _items is a List, but a list of only CartItem objects. So now you do this:

List<CartItem> _items = new List<CartItem>;

CartItem item = new CartItem( . . .);

_items.Add(item);

But because the list is of a specific data type, you can’t do this:

_items.Add(“this isn’t a cart item”);

_items.Add(“65”);

Both of these lines would generate compile-time errors. Whenever you need a collection of custom classes, it’s always a good idea to use generic collections, because they improve the readability of your code, reduce the potential for errors, and provide performance improvements over the standard collections.

345

Chapter 9

Summar y

This chapter covered a lot of ground, but it was necessary. Although the rich controls in ASP.NET 2.0 provide a way to create web applications with less code than previous versions, you can’t get away without coding completely. So you’ve learned the fundamentals of coding and what you need to control your program. Specifically, this chapter covered the following topics:

You looked at variables and data types, and how to work with the different data types, seeing that data types have different features. You also looked at arrays and collections, as a way of storing groups of variables.

The control of programs is by way of decisions and loops, which use expressions and operators as part of the decision process. You saw how there are different ways to perform both decisions and loops, depending on the requirements.

You looked at classes, and how they have constructors, properties, and methods. You didn’t look at events explicitly, but like the controls you use on Web Forms, custom classes can have them if required.

You took a brief look at generics, and saw how they help produce type-safe code and improve code readability and performance.

The next chapter examines componentization, and discusses the use of code-behind files and standalone classes from the design and structure perspective rather than what the code actually means.

Exercises

1.Create a class and shared method (called DeliveryDate) to calculate a delivery date given the date of an order. All deliveries should be made within three days of the order.

2.Continuing from Exercise 1, modify the DeliveryDate method to take into account that deliveries do not happen on the weekend.

3.Modify the DeliveryDate method to take into account that an order takes three working days to process. So orders falling on a Wednesday will be delivered on the following Monday, and orders from Thursday will be delivered on the following Tuesday.

4.For each of the following Boolean expressions, say for what integer values of A each of them will evaluate to True and when they will evaluate to False:

a.NOT A=0

b.A > 0 OR A < 5

c.NOT A > 0 OR A < 5

d.A > 1 AND A < 5 OR A > 7 AND A < 10

e.A < 10 OR A > 12 AND NOT A > 20

346

10

Componentization

Programming has been through several distinct phases in its history and has moved a long way from its humble beginnings where punch-cards dashed with holes were placed into mechanical readers. Early programs on PCs were often just sequential lines of Do A, Do B, Do C kinds of commands. If you wanted to repeat a section of the code, you were left with the option of going Do A, Do A, and Do A or encasing it in a loop and telling the PC to Do A 20 times. This quickly made code repetitive and unwieldy. Worse than that, it made it hard to follow, even for the people who had written it. To follow the flow from the beginning of a program to the end was as difficult as following the path of one thread of spaghetti on a plate in a mound of food. In fact, it became commonly known as spaghetti-coding.

Over the past 20 years, there has been a move away from this kind of coding to a more objectbased approach. This is where you break down the design of an application into a series of objects, and then any time you require an object, you just call it whenever you need it. This process is known as componentization. This is the creation of small objects, or components, that are selfcontained parcels of code that have specific functions and are only called by the main application when needed. You looked at objects in Chapter 9 and saw how they could be mapped onto reallife counterparts to make coding less abstract. However, objects didn’t totally solve the problems with spaghetti-coding.

Classic ASP suffered from this malaise as well, and despite having a whole series of objects such as Response, Request, and Server, and also allowing users to create their own objects, ASP pages are still a nightmare to debug and follow if they get too big. In fact, three main problems can be highlighted, the first being that HTML code and ASP code tended to be dumped in the same page together, despite having completely different purposes. HTML manages the structure of the page, whereas ASP is concerned with what the page does. The second problem is that with any kind of data handling in a page, there are two different purposes being dealt with, the connecting to and management of data stores, and the reading and writing of the data itself to a data source. The third problem is that of code-reuse, how users could easily create portable objects that could be called from within the code over and over, and how they could end up reducing the amount of code needed.

With ASP.NET 1.x, these problems were partially addressed; however, the solutions weren’t perfect. ASP.NET 2.0 delivers the most comprehensive set of solutions to these problems. At the