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

Chapter 15 Implementing Properties to Access Fields

287

Generating Automatic Properties

This chapter mentioned earlier that the principal purpose of properties is to hide the implementation of fields from the outside world. This is fine if your properties actually perform some useful work, but if the get and set accessors simply wrap operations that just read or assign a value to a field, you might be questioning the value of this approach. There are at least two good reasons why you should define properties rather than exposing data as public fields:

Compatibility with applications Fields and properties expose themselves by using different metadata in assemblies. If you develop a class and decide to use public fields, any applications that use this class will reference these items as fields. Although you use the same C# syntax for reading and writing a field that you use when reading and writing a property, the compiled code is actually quite different—the C# compiler just hides the differences from you. If you later decide that you really do need to change these fields to properties (maybe the business requirements have changed, and you need to perform additional logic when assigning values), existing applications will not be able to use the updated version of the class without being recompiled. This is awkward if you have deployed the application on a large number of users’ desktops throughout an organization. There are ways around this, but it is generally better to avoid getting into this situation in the first place.

Compatibility with interfaces If you are implementing an interface and the interface defines an item as a property, you must write a property that matches the specification in the interface, even if the property just reads and writes data in a private field. You cannot implement a property simply by exposing a public field with the same name.

The designers of the C# language recognized that programmers are busy people who should not have to waste their time writing more code than they need to. To this end, the C# compiler can generate the code for properties for you automatically, like this:

class Circle

{

public int Radius{ get; set; }

...

}

In this example, the Circle class contains a property named Radius. Apart from the type of this property, you have not specified how this property works—the get and set accessors are

288

Part III Creating Components

empty. The C# compiler converts this definition to a private field and a default implementation that looks similar to this:

class Circle

{

private int _radius; public int Radius{

get

{

return this._radius;

}

set

{

this._radius = value;

}

}

...

}

So for very little effort, you can implement a simple property by using automatically generated code, and if you need to include additional logic later, you can do so without breaking any existing applications. You should note, however, that you must specify both a get and a set accessor with an automatically generated property—an automatic property cannot be read-only or write-only.

Note The syntax for defining an automatic property is almost identical to the syntax for

defining a property in an interface. The exception is that an automatic property can specify an access modifier, such as private, public, or protected.

Initializing Objects by Using Properties

In Chapter 7, “Creating and Managing Classes and Objects,” you learned how to define constructors to initialize an object. An object can have multiple constructors, and you can define constructors with varying parameters to initialize different elements in an object. For example, you could define a class that models a triangle like this:

public class Triangle

{

private int side1Length; private int side2Length; private int side3Length;

//default constructor - default values for all sides public Triangle()

{

this.side1Length = this.side2Length = this.side3Length = 10;

}

//specify length for side1Length, default values for the others public Triangle(int length1)

Chapter 15 Implementing Properties to Access Fields

289

{

this.side1Length = length1; this.side2Length = this.side3Length = 10;

}

//specify length for side1Length and side2Length,

//default value for side3Length

public Triangle(int length1, int length2)

{

this.side1Length = length1; this.side2Length = length2; this.side3Length = 10;

}

// specify length for all sides

public Triangle(int length1, int length2, int length3)

{

this.side1Length = length1; this.side2Length = length2; this.side3Length = length3;

}

}

Depending on how many fields a class contains and the various combinations you want to enable for initializing the fields, you could end up writing a lot of constructors. There are also

potential problems if many of the fields have the same type: you might not be able to write a unique constructor for all combinations of fields. For example, in the preceding Triangle class, you could not easily add a constructor that initializes only the side1Length and side3Length

fields because it would not have a unique signature; it would take two int parameters, and the constructor that initializes side1Length and side2Length already has this signature. The so-

lution is to initialize the private fields to their default values and to define properties, like this:

public class Triangle

{

private int side1Length = 10; private int side2Length = 10; private int side3Length = 10;

public int Side1Length

{

set { this.side1Length = value; }

}

public int Side2Length

{

set { this.side2Length = value; }

}

public int Side3Length

{

set { this.side3Length = value; }

}

}

290 Part III Creating Components

When you create an instance of a class, you can initialize it by specifying values for any public properties that have set accessors. This means that you can create Triangle objects and initial-

ize any combination of the three sides, like this:

Triangle tri1 = new Triangle { Side3Length = 15 };

Triangle tri2 = new Triangle { Side1Length = 15, Side3Length = 20 };

Triangle tri3 = new Triangle { Side2Length = 12, Side3Length = 17 };

Triangle tri4 = new Triangle { Side1Length = 9, Side2Length = 12,

Side3Length = 15 };

This syntax is known as an object initializer. When you invoke an object initializer in this way, the C# compiler generates code that calls the default constructor and then calls the set accessor of each named property to initialize it with the value specified. You can specify object initializers in combination with nondefault constructors as well. For example, if the Triangle class also provided a constructor that took a single string parameter describing the type of triangle, you could invoke this constructor and initialize the other properties like this:

Triangle tri5 = new Triangle(“Equilateral triangle”) { Side1Length = 3,

Side2Length = 3,

Side3Length = 3 };

The important point to remember is that the constructor runs first and the properties are set afterward. Understanding this sequencing is important if the constructor sets fields in an object to specific values and the properties that you specify change these values.

You can also use object initializers with automatic properties, as you will see in the next exercise. In this exercise, you will define a class for modeling regular polygons, containing automatic properties for providing access to the number of sides the polygon contains and the length of these sides.

Define automatic properties and use object initializers

1.In Visual Studio 2008, open the AutomaticProperties project, located in the \Microsoft Press\Visual CSharp Step by Step\Chapter 15\AutomaticProperties folder in your Documents folder.

The AutomaticProperties project contains the Program.cs file, defining the Program class with the Main and Entrance methods that you have seen in previous exercises.

2.In Solution Explorer, right-click the AutomaticProperties project, point to Add, and then click Class. In the Add New Item—AutomaticProperties dialog box, in the Name text box, type Polygon.cs, and then click Add.

The Polygon.cs file, holding the Polygon class, is created and added to the project and appears in the Code and Text Editor window.

Chapter 15 Implementing Properties to Access Fields

291

3.Add the automatic properties NumSides and SideLength, shown here in bold, to the

Polygon class:

class Polygon

{

public int NumSides { get; set; } public double SideLength { get; set; }

}

4. Add the following default constructor to the Polygon class:

class Polygon

{

public Polygon()

{

this.NumSides = 4; this.SideLength = 10.0;

}

...

}

In this exercise, the default polygon is a square with sides 10 units long.

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

6.Add the statements shown here in bold to the Entrance method:

static void Entrance()

{

Polygon square = new Polygon();

Polygon triangle = new Polygon { NumSides = 3 };

Polygon pentagon = new Polygon { SideLength = 15.5, NumSides = 5 };

}

These statements create Polygon objects. The square variable is initialized by using the default constructor. The triangle and pentagon variables are also initialized by using

the default constructor, and then this code changes the value of the properties exposed by the Polygon class. In the case of the triangle variable, the NumSides property is set to 3, but the SideLength property is left at its default value of 10.0. For the pentagon variable, the code changes the values of the SideLength and NumSides properties.

7. Add the following code to the end of the Entrance method:

static void Entrance()

{

...

Console.WriteLine(“Square: number of sides is {0}, length of each side is {1}”, square.NumSides, square.SideLength);

Console.WriteLine(“Triangle: number of sides is {0}, length of each side is {1}”, triangle.NumSides, triangle.SideLength);

Console.WriteLine(“Pentagon: number of sides is {0}, length of each side is {1}”, pentagon.NumSides, pentagon.SideLength);

}

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