Search - Articles - Dev Forums - Favorites - Member Login  
DevASP.NET for ASP.NET, VB.NET, XML and C# (C-Sharp) Developers Friday, September 03, 2010

Dev Articles
Search Directory
ASP.NET
VB.Net
C-Sharp
SQL Server
 

Methods that Return Values


If we have a method that does generate some value that should be returned, we need to use the Function keyword:

 

Public Function Age() As Integer

Return DateDiff(DateInterval.Year, mdtBirthDate, Now())

End Function

 

Notice that we need to indicate the data type of the return value when we declare a Function. In this example, we are returning the calculated age as a result of the method. We can return any value of the appropriate data type by using the Return keyword.

 

We can also return the value without using the Return keyword, by setting the value of the function name itself:

 

Public Function Age() As Integer

Age = DateDiff(DateInterval.Year, mdtBirthDate, Now())

End Function

 

This is functionally equivalent to the previous code. Either way, we can use this method with code similar to the following:

 

Dim myPerson As New Person()

Dim intAge As Integer

 

intAge = myPerson.Age()

 

The Age method returns an Integer data value that we can use in our program as required – in this case we're just storing it into a variable.


 

Indicating Method Scope

Adding the appropriate keyword in front of the method declaration indicates the scope:

 

Public Sub Walk()

 

This indicates that Walk is a Public method and is thus available to code outside our class and even outside our current project. Any application that references our assembly can make use of this method. By being Public, this method becomes part of our object's interface.

 

On the other hand, we might choose to restrict the method somewhat:

 

Friend Sub Walk()

 

By declaring the method with the Friend keyword, we are indicating that it should be part of our object's interface only for code inside our project – any other applications or projects that make use of our assembly will not be able to call the Walk method.

 

Private Function Age() As Integer

 

The Private keyword indicates that a method is only available to the code within our particular class. Private methods are very useful to help us organize complex code within each class. Sometimes our methods will contain very lengthy and complex code. In order to make this code more understandable, we may choose to break it up into several smaller routines, having our main method call these routines in the proper order. Additionally, we may use these routines from several places within our class and so, by making them separate methods, we enable reuse of the code. These sub-routines should never be called by code outside our object – and so we make them Private.

Method Parameters

We will often want to pass information into a method as we call it. This information is provided via parameters to the method. For instance, in our Person class, perhaps we want our Walk method to track the distance the person walks over time. In such a case, the Walk method would need to know how far the person is to walk each time the method is called. Add the following code to our Person class:

 

Public Class Person

Private mstrName As String

Private mdtBirthDate As Date

Private mintTotalDistance As Integer

 

Public Sub Walk(ByVal Distance As Integer)

mintTotalDistance += Distance

End Sub

 

Public Function Age() As Integer

Return DateDiff(DateInterval.Year, mdtBirthDate, Now())

End Function

End Class

 

With this implementation, a Person object will sum up all of the distances that are walked over time. Each time the Walk method is called, the calling code must pass an Integer value indicating the distance to be walked. Our code to call this method would be similar to the following:


 

Dim myPerson As New Person()

myPerson.Walk(12)

 

The parameter is accepted using the ByVal keyword. This indicates that the parameter value is a copy of the original value. This is the default way VB.NET accepts all parameters. Typically, this is desirable because it means that we can work with the parameter inside our code – including changing its value – with no risk of accidentally changing the original value back in the calling code.

 

If we do want to be able to change the value in the calling code, we can change the declaration to pass the parameter by reference by using the ByRef qualifier:

 

Public Sub Walk(ByRef Distance As Integer)

 

In this case, we'll get a reference (or pointer) back to the original value rather than receiving a copy. This means that any change we make to the Distance parameter will be reflected back in the calling code – very similar to the way object references work, as we discussed earlier in Chapter 4.

Using this technique can be dangerous, since it is not explicitly clear to the caller of our method that the value will change. Such unintended side effects can be hard to debug and should be avoided.

Properties

The .NET environment provides for a specialized type of method called a property. A property is a method specifically designed for setting and retrieving data values. For instance, we declared a variable in our Person class to contain a name, so our Person class may include code to allow that name to be set and retrieved. This could be done using regular methods:

 

Public Sub SetName(ByVal Name As String)

mstrName = Name

End Sub

 

Public Function GetName() As String

Return mstrName

End Function

 

Using methods like these, we would write code to interact with our object such as:

 

Dim myPerson As New Person()

 

myPerson.SetName("Jones")

MsgBox(myPerson.GetName())

 

While this is perfectly acceptable, it is not as nice as it could be through the use of a property. A Property style method consolidates the setting and retrieving of a value into a single structure, and also makes the code within our class smoother overall. We can rewrite these two methods into a single property. Add the following code to the Person class:


 

Public Property Name() As String

Get

Return mstrName

End Get

Set(ByVal Value As String)

mstrName = Value

End Set

End Property

 

By using a property method instead, we can make our client code much more readable:

 

Dim myPerson As New Person()

 

myPerson.Name = "Jones"

MsgBox(myPerson.Name)

 

The Property method is declared with both a scope and a data type:

 

Public Property Name() As String

 

In this example, we've declared the property as Public in scope, but it can be declared using the same scope options as any other method – Public, Friend, Private, or Protected.

 

As with other methods, a Public property is accessible to any code outside our class, while Friend is available outside our class, but only to code within our VB project. Protected properties are available through inheritance, as we'll discuss in Chapter 6, and Private properties are only available to code within our class.

 

The return data type of this property is String. A property can return virtually any data type as appropriate for the nature of the value. In this regard, a property is very similar to a method declared using the Function keyword.

 

Though a Property method is a single structure, it is divided into two parts: a getter and a setter. The getter is contained within a Get...End Get block and is responsible for returning the value of the property on demand:

 

Get

Return mstrName

End Get

 

Though the code in this example is very simple, it could be more complex – perhaps calculating the value to be returned or applying other business logic to change the value as it is returned.

 

Likewise, the code to change the value is contained within a Set...End Set block:

 

Set(ByVal Value As String)

mstrName = Value

End Set


The Set statement accepts a single parameter value that stores the new value. Our code in the block can then use this value to set the property's value as appropriate. The data type of this parameter must match the data type of the property itself. By having the parameter declared in this manner, we can change the variable name used for the parameter value if needed.

 

By default, the parameter is named Value. However, if we dislike the name Value, we can change the parameter name to something else, for example:

 

Set(ByVal NewName As String)

mstrName = NewName

End Set

 

In many cases, we may apply business rules or other logic within this routine to ensure that the new value is appropriate before we actually update the data within our object.

Parameterized Properties

The Name property we created is an example of a single-value property. We can also create property arrays or parameterized properties. These properties reflect a range, or array, of values. As an example, a person will often have several phone numbers. We might implement a PhoneNumber property as a parameterized property – storing not only phone numbers, but also a description of each number. To retrieve a specific phone number we'd write code such as:

 

Dim myPerson As New Person()

Dim strHomePhone As String

 

strHomePhone = myPerson.Phone("home")

 

Or, to add or change a specific phone number, we'd write:

 

myPerson.Phone("work") = "555-9876"

 

Not only are we retrieving and updating a phone number property, but also we're updating some specific phone number. This implies a couple of things. First off, we're no longer able to use a simple variable to hold the phone number, since we are now storing a list of numbers and their associated names. Secondly, we've effectively added a parameter to our property – we're actually passing the name of the phone number as a parameter on each property call.

 

To store the list of phone numbers we can use the Hashtable class. The Hashtable is very similar to the standard VB Collection object, but it is more powerful – allowing us to test for the existence of an existing element. Add the following declaration to the Person class:

 

Public Class Person

Private mstrName As String

Private mdtBirthDate As Date

Private mintTotalDistance As Integer

Private colPhones As New Hashtable()

 

We can implement the Phone property by adding the following code to our Person class:


 

Public Property Phone(ByVal Location As String) As String

Get

Return CStr(colPhones.Item(Location))

End Get

Set(ByVal Value As String)

If colPhones.ContainsKey(Location) Then

colPhones.Item(Location) = Value

Else

colPhones.Add(Location, Value)

End If

End Set

End Property

 

The declaration of the Property method itself is a bit different from what we've seen:

 

Public Property Phone(ByVal Location As String) As String

 

In particular, we've added a parameter, Location, to the property itself. This parameter will act as the index into our list of phone numbers and must be provided both when setting or retrieving phone number values.

 

Since the Location parameter is declared at the Property level, it is available to all code within the property – including both the Get and Set blocks.

 

Within our Get block, we use the Location parameter to select the appropriate phone number to return from the Hashtable:

 

Get

Return colPhones.Item(Location)

End Get

 

With this code, if there is no value stored matching the Location, we'll get a trappable runtime error.

 

Similarly, in the Set block, we use the Location to update or add the appropriate element in the Hashtable. In this case, we're using the ContainsKey method of Hashtable to determine whether the phone number already exists in the list. If it does, we'll simply update the value in the list – otherwise, we'll add a new element to the list for the value:

 

Set(ByVal Value As String)

If colPhones.ContainsKey(Location) Then

colPhones.Item(Location) = Value

Else

colPhones.Add(Location, Value)

End If

End Set

 

In this way, we're able to add or update a specific phone number entry based on the parameter passed by the calling code.


 

Read-Only Properties

There are times when we may want a property to be read-only – so that it can't be changed. In our Person class, for instance, we may have a read-write property for BirthDate, but just a read-only property for Age. In such a case, the BirthDate property is a normal property, as follows:

 

Public Property BirthDate() As Date

Get

Return mdtBirthDate

End Get

Set(ByVal Value As Date)

mdtBirthDate = Value

End Set

End Property

 

The Age value, on the other hand, is a derived value based on BirthDate. This is not a value that should ever be directly altered and, thus, is a perfect candidate for read-only status.

 

We already have an Age method – implemented as a Function. Remove that code from the Person class, as we'll be replacing it with a Property routine instead.

 

The difference between a Function routine and a ReadOnlyProperty is quite subtle. Both return a value to the calling code and, either way, our object is running a subroutine defined by our class module to return the value.

 

The difference is less a programmatic one than a design choice. We could create all our objects without any Property routines at all, just using methods for all interactions with the object. However, Property routines are obviously attributes of the object, while a Function might be an attribute or a method. By carefully implementing all attributes as ReadOnly Property routines, and any interrogative methods as Function routines, we will create more readable and understandable code.

 

To make a property read-only, we use the ReadOnly keyword and only implement the Get block:

 

Public ReadOnly Property Age() As Integer

Get

Return CInt(DateDiff(DateInterval.Year, mdtBirthDate, Now()))

End Get

End Property

 

Since the property is read-only, we'll get a syntax error if we attempt to implement a Set block.

Write-Only Properties

As with read-only properties, there are times when a property should be write-only – where the value can be changed, but not retrieved.

 

Many people have allergies, so perhaps our Person object should have some understanding of the ambient allergens in the area. This is not a property that should be read from the Person object since allergens come from the environment rather than from the person, but it is data that the Person object needs in order to function properly. Add the following variable declaration to our class:


 

Public Class Person

Private mstrName As String

Private mdtBirthDate As Date

Private mintTotalDistance As Integer

Private colPhones As New Hashtable()

Private mintAllergens As Integer

 

We can implement an AmbientAllergens property as follows:

 

Public WriteOnly Property AmbientAllergens() As Integer

Set(ByVal Value As Integer)

mintAllergens = Value

End Set

End Property

 

To create a write-only property, we use the WriteOnly keyword and only implement a Set block in our code. Since the property is write-only, we'll get a syntax error if we attempt to implement a

Get block.

The Default Property

Objects can implement a default property if desired. A default property can be used to simplify the use of our object at times, by making it appear as if our object has a native value. A good example of this behavior is the Collection object, which has a default property called Item that returns the value of a specific item, allowing us to write code similar to:

 

Dim colData As New Collection()

 

Return colData(Index)

 

Default properties must be parameterized properties. A property without a parameter cannot be marked as the default. This is a change from previous versions of VB, where any property could be marked as the default.

 

Our Person class has a parameterized property – the Phone property we built earlier. We can make this the default property by using the Default keyword:

 

Default Public Property Phone(ByVal Location As String) As String

Get

Return colPhones.Item(Location)

End Get

Set(ByVal Value As String)

If colPhones.ContainsKey(Location) Then

colPhones.Item(Location) = Value

Else

colPhones.Add(Location, Value)

End If

End Set

End Property

 

Prior to this change, we would need code such as the following to use the Phone property:


 

Dim myPerson As New Person()

 

MyPerson.Phone("home") = "555-1234"

 

But now, with the property marked as Default, we can simplify our code:

 

myPerson("home") = "555-1234"

 

By picking appropriate default properties, we can potentially make the use of our objects more intuitive.



DevASP.Net - Disclaimer - Privacy
© 2002-2010 DevASP.net