Properties

 <  Day Day Up  >  

It is sometimes desirable to expose information as if it were a field on a type, even though the information may be calculated from multiple variables rather than stored in a single variable. For example, an Order class that contains Quantity and Cost fields may want to expose the total amount of the order. This can be done as a function, but it would be ideal if the information could be exposed as if it were a field.

 Class Order   Public Cost As Double   Public Quantity As Integer   Public Function Total() As Double       Return Cost * Quantity   End Function End Class Module Test   Sub Main()     Dim Order As Order = New Order()     Order.Cost = 34.32     Order.Quantity = 5     Console.WriteLine(Order.Total())   End Sub End Module 

Properties are type members that behave as if they were fields but that work like methods . In the preceding example, instead of exposing the order total as a function, we can use a property.

 Class Order   Public Cost As Double   Public Quantity As Integer   Public ReadOnly Property Total() As Double     Get       Return Cost * Quantity     End Get   End Property End Class Module Test   Sub Main()     Dim Order As Order = New Order()     Order.Cost = 34.32     Order.Quantity = 5     Console.WriteLine(Order.Total)   End Sub End Module 

Like a field, every property has a type that defines what kind of information it accepts or returns. The property also defines methods called accessors that are used to access the value of the property. The Get accessor of a property reads the value of the property, while the Set accessor writes the value of the property. The accessor methods can contain any code necessary to accomplish the particular operation. For example, a property can be used to validate the value being assigned to a field.

 Class Order   Private _Cost As Double   Public Property Cost() As Double     Get       Return _Cost     End Get     Set (ByVal Value As Double)       If Value <= 0 Then         Throw New ArgumentException("Cost cannot be zero or less.")       End If       _Cost = Value     End Set   End Property   Public Quantity As Integer End Class 

In this example, the _Cost field is kept private and only exposed through a public property. The property Get accessor just returns the field's value, but the property's Set accessor validates that the property is not being assigned a value of zero or less.

Style

When a programmer creates a Private field to store the information for a Public property, a common naming convention is to use the property name with a leading underscore . For example, a Public property named Total would be stored in a Private field named _Total .


A Set accessor is followed by a parameter that represents the value being assigned to the property. Only one parameter is allowed in the parameter list, and the type must match the type of the property itself. If a property omits a Set accessor, the property is read-only and cannot be assigned to. Read-only properties must additionally be declared with the ReadOnly modifier. If a property omits a Get accessor, the property is write-only and cannot be assigned to. Write-only properties must additionally be declared with the WriteOnly modifier. For example:

 Class Order   Private _Cost As Double   Public WriteOnly Property Cost() As Double     Set (ByVal Value As Double)       If Value <= 0 Then         Throw New ArgumentException("Cost cannot be zero or less.")       End If       _Cost = Value     End Set   End Property End Class Module Test   Sub Main()     Dim Order As Order = New Order()     ' OK, property has a setter     Order.Cost = 10     ' Error, property is write-only     Console.WriteLine(Order.Cost)   End Sub End Module 

Design

The ReadOnly and WriteOnly modifiers are required on the property declaration so that properties can be declared in situations where no accessors are allowed, such as MustOverride properties and properties in interfaces.


Advanced

When a property returns a structure, the fields of the value cannot be directly changed. This is because the property returns the value of the property directly, so changing the fields of that value would not affect the value stored in the property.


To illustrate the advanced point, consider this example.

 Structure Order   Public Cost As Double   Public Quantity As Integer End Structure Class Customer   Private _Order As Order   Public Property Order() As Order     Get       Return _Order     End Get     Set (Value As Order)       _Order = Value     End Set   End Property End Class Module Test   Sub ChangeOrderCost(ByVal c As Customer)     ' Error: The value of Cost cannot be changed directly     c.Order.Cost = 10.34     ' OK: The value of Cost is not changed directly     Dim o As Order = c.Order     o.Cost = 10.34     c.Order = o   End Sub End Module 

In this example, the expression c.Order returns the actual Order itself because Order is a structure. If c.Order.Cost = 10.34 were allowed to work, it would only change the Cost field of the Order value that was returned from the property, not the actual _Order field of the Customer class. The second part of the ChangeOrderCost subroutine shows how to change the Cost field of the Customer 's Order field. Copying the value back into the Order property updates the _Order field of the Customer class.

Indexed Properties

Properties can also take parameters; such properties are called indexed properties because when they are used, they are indexed in the same manner that arrays are. For example, the following code defines an OrderCollection object that functions the same as an array of Order objects.

 Class Order   Public Cost As Double   Public Quantity As Integer End Class Class OrderCollection   Private _Orders(10) As Order   Public Property Orders(ByVal Index As Integer) As Order     Get       If _Orders(Index) Is Nothing Then         _Orders(Index) = New Order()       End If       Return _Orders(Index)     End Get     Set (Value As Order)       _Orders(Index) = Value     End Set   End Property End Class Module Test   Sub Main()     Dim OrderCollection As New OrderCollection()     OrderCollection.Orders(5).Cost = 10.34     Console.WriteLine(OrderCollection.Orders(5).Cost)   End Sub End Module 

The parameter list of a property works exactly the same as the parameter list of a function, with the exception that property parameters cannot be declared ByRef .

Compatibility

Previous versions of Visual Basic allowed indexed property parameters to be reference parameters. This is now disallowed because the .NET Framework does not allow indexed properties to modify index arguments.


Properties can be overloaded based on their parameter lists, though not on their type. This is the same as for methods, which can only be overloaded on their parameter list and not their return type. For example:

 Class Customer   Public Name As String End Class Class CustomerCollection   Private _Customers(10) As Customer   Public ReadOnly Property Customer(ByVal Index As Integer) As _Customer     Get       If _Customers(Index) Is Nothing Then         _Customers(Index) = New Customer()       End If       Return _Customers(Index)     End Get   End Property   Public ReadOnly Property Customer(ByVal Name As String) As Customer     Get       For Each CurrentCustomer As Customer In _Customers         If CurrentCustomer.Name = Name Then           Return CurrentCustomer         End If       Next CurrentCustomer       Throw New ArgumentException("No customer by that name.")     End Get   End Property End Class Module Test   Sub Main()     Dim Customers As New CustomerCollection()     Console.WriteLine(Customers.Customer(5).Name)     Console.WriteLine(Customers.Customer("Harry").Name)   End Sub End Module 

In the example, the Customers indexed property is overloaded on both Integer and String . This allows indexing the property by using either a numerical index or a customer name.

Like methods, indexed properties can be called late bound if the type of the variable being indexed is Object . For example, the following code defers checking for indexed properties until runtime.

 Module Test   Sub Main()     Dim o As Object = New OrderCollection()     o.Orders(5).Cost = 10.34     Console.WriteLine(o.Orders(5).Cost)   End Sub End Module 

Style

Late binding should only be used when absolutely necessary. Deferring type checking until runtime is more prone to errors and limits the ability of Visual Studio to provide Intellisense. Specifying Option Strict at the top of a file disallows late binding within that file.


Default Properties

An indexed property can be declared as the default property of a type. This allows the type to be indexed as if it were the default property. In the following example, when the index is applied to the Customers variable, it is equivalent to applying the index to the default property of the CustomerCollection class.

 Class Customer   Public Name As String End Class Class CustomerCollection   Private _Customers(10) As Customer   Public Default Property Customer(ByVal Index As Integer) As Customer     Get       If _Customers(Index) Is Nothing Then         _Customers(Index) = New Customer()       End If       Return _Customers(Index)     End Get     Set (Value As Customer)       _Customers(Index) = Value     End Set   End Property End Class Module Test   Sub Main()     Dim Customers As New CustomerCollection()     ' Customers(5).Name is equivalent to Customers.Customer(5).Name     Customers(5).Name = "John Doe"     Console.WriteLine(Customers(5).Name)   End Sub End Module 

In this example, the index expression 5 is applied directly to the Customers variable. The compiler knows to interpret Customers(5) as Customers.Customer(5) instead. Default properties must have index parameters.

Compatibility

Previous versions of Visual Basic allowed defining default properties without parameters because the language distinguished between value assignment ( Let ) and reference assignment ( Set ). Without this distinction, it would be impossible to assign to a variable of a type with a parameterless default property because there would be no way to tell whether the assignment was to the variable or to the default property. Default parameterless properties on COM objects can still be accessed by adding parentheses after the value (i.e., obj() will call the default parameterless property, if any, of the variable obj ).


Dictionary Lookup

A class with a default property that is indexed by a single String parameter can be accessed in a shorthand way by using the dictionary lookup operator . This operator (also called the bang operator because it uses an exclamation point) takes the identifier that follows it and uses it as the parameter to the default indexed property. For example:

 Class Customer   Public Name As String End Class Class CustomerCollection   Private _Customers(10) As Customer   Public ReadOnly Default Property Customer(ByVal Name As String) _       As Customer     Get       For Each CurrentCustomer As Customer In _Customers         If CurrentCustomer.Name = Name Then           Return CurrentCustomer         End If       Next CurrentCustomer       Throw New ArgumentException("No customer by that name.")     End Get   End Property End Class Module Test   Sub Main()     Dim Customers As New CustomerCollection()     ' Using a regular indexed property     Console.WriteLine(Customers("Harry").Name)     ' Using the dictionary lookup operator     Console.WriteLine(Customers!Harry.Name)   End Sub End Module 

In this example, the second WriteLine statement is equivalent to the first ”the string Harry after the exclamation point is passed to the default property as a string.

The dictionary lookup operation can also be used in a With statement.

 Module Test   Sub Main()     Dim Customers As New CustomerCollection()     With Customers       Console.WriteLine(!Harry.Name)       Console.WriteLine(!John.Name)       Console.WriteLine(!Tom.Name)     End With   End Sub End Module 
 <  Day Day Up  >  


The Visual Basic .NET Programming Language
The Visual Basic .NET Programming Language
ISBN: 0321169514
EAN: 2147483647
Year: 2004
Pages: 173
Authors: Paul Vick

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net