Home.NET Classes and Properties in an Application`s...
Classes and Properties in an Application's Business Logic Layer
In this third part of a six-part series on building the business logic layer of a .NET application, we wrap up our initial discussion of classes and move on to properties. This article is excerpted from chapter five of the book Doing Objects in Visual Basic 2005, written by Deborah Kurata (Addison-Wesley, 2008; ISBN: 0321320492).
By convention, each business object class resides in a single class file. The Product class is in the Product.vb file, the Customer class is in the Customer.vb file, and so on. But that is not a requirement. A class can be divided between any number of class files.
You can break a class into two or more files by defining partial classes. Partial classes are used primarily in situations where you have a code generator that generates part of the class and custom code for the remainder of the class. By placing the generated code in a file separate from the custom code, you can more easily regenerate the generated code without affecting the custom code. Every time you add a form to a project, Visual Studio creates a partial class and generates the code defining the controls on your user interface in that class, as described in Chapter 4.
To define a partial class for your class:
Right-click the project in Solution Explorer and select Add | New Item from the context menu, or select Project | Add New Item from the main menu bar.
Alternatively, you could select Add | Class from the context menu, or select Project | Add Class from the main menu bar.
Select the Class template, name the class, and click the Add button.
You cannot have two code files with the same filename, so name the partial class with a unique name.
Visual Studio creates the class file with a .vb extension, adds it to Solution Explorer, and then displays the class in the Code Editor.
In the Code Editor, add the Partial keyword to the class definition, and modify the class name to match the original class name.
For example, the class definition of a partial class for the Product class is as follows:
Partial Public Class Product
End Class
When the application is built, the code in the file for the class and the files for any partial classes are combined into one logical class. So the runtime behaves as if there is only one class.
One other benefit of partial classes is the ability to separately define Option Strict. Your primary class can have Option Strict set to On, and your partial class can have Option Strict set to Off. This is useful if you have code that needs to work with objects without concern for conversion of their types, such as when calling components written in VB6 or other Component Object Model (COM)-based technologies.
Don’t use partial classes unnecessarily. Dividing a class into multiple class files for no particular purpose makes it more difficult to maintain the class. It is more difficult to find where code resides and see how it interacts with other code in the class.
Use partial classes for the defined purpose—separating generated code from custom code. If you are not writing your own code generators, you may never need to create a partial class. If you use third-party code generators, you may notice the partial classes that they create.
A single class file can contain any number of classes. Although you normally define a class within its own class file, you can add support classes for that class directly in the same class file.
For example, say you define a ProductOutOfStockException class that is used only by the Product class. You can define this exception class in the same code file as the Product class:
End Class ' End of the Product Class
<Serializable()> _ Public Class ProductOutOfStockException Inherits ApplicationException
Public Sub New(ByVal message As String) MyBase.New(message) End Sub
Public Sub New(ByVal message As String, _ ByVal inner As Exception) MyBase.New(message, inner) End Sub
Public Sub New( _ ByVal info As _ System.Runtime.Serialization.SerializationInfo, _ ByVal context As _ System.Runtime.Serialization.StreamingContext) MyBase.New(info, context) End Sub End Class
NOTE: This class was created with the Exception snippet. See the next chapter for details on using snippets.
NOTE: The Serializable attribute on this class defines that the exception class can be serialized. Serialization is the process of converting an object into a sequence of bytes for either storage or transmission to another location. For example, you could serialize an object to a file to save the value of all the object’s properties.
This attribute is added to the exception class to support remoting. Remoting is the process of passing an object to another computer by serializing the object. If an exception occurs on the remote computer, the exception is serialized and remoted back to the original application.
For more information on remoting, see the Lhotka book in the “Additional Reading” section. See the System.Runtime.Serialization .NET Framework class documentation for more information on serialization. See the later section “Obsolescing Methods” for more information on attributes.
This class inherits from ApplicationException to ensure that it behaves as an exception. It contains three methods, each of which calls the associated base class method. Using the same named methods with different parameters is described later, in the section “Overloading Methods.” You can create your own exceptions any time using this style of exception class.
NOTE: Although the exception snippet inherits from ApplicationException, best practices define that you should inherit from Exception instead. ApplicationException was originally set up for your use, as defined in the preceding example. However, it was misused within the .NET Framework, so the Framework developers recommend that you do not use ApplicationException in your code. (See the “Additional Reading” section for the reference to the Framework Design Guidelines book containing this recommendation.)
Don’t put multiple business object classes in a single class file. Reserve this feature for adding support classes or exception classes only. For example, business object-unique exceptions are an excellent type of class to add to a business object class file.
The properties of a class define the data associated with the class. For example, a Product class has ProductName, ProductID, and InventoryDate properties. Each object created from the class can have a different set of values for these properties.
This section details the process of creating a property. It then covers some additional techniques for working with properties.
Creating the Property
Create a property in a class for each data attribute identified for the class during the design phase. Following best practices, defining properties requires two steps.
First you create a private variable to retain the property value. This private variable is called a backing variable or backing field and retains the property’s value. You make the variable private so that it cannot be directly accessed by any code outside of the class.
Next you create a Property statement. The Property statement defines the property and the accessors used to get and set the property. The Set accessor, sometimes called the setter, sets the property’s value, and the Get accessor, sometimes called the getter, returns the property’s value.
This technique encapsulates the property by providing access to it only through the accessors. You can write code in the accessors to validate data, perform formatting, or any other business logic.
To define a property:
Open the class in the Code Editor.
Declare a private variable for the property.
For example:
Private _ProductName As String
By making the variable private, you ensure that code outside of this class can not access the property directly. All code must access the variable value through the Property statement.
Use good naming conventions for your private variable. There are several common conventions, such as prefixing the property name with m or m_ to define the variable as member-level. The convention that is currently gaining popularity is to prefix the property name with an underscore to indicate that the variable should not be used anywhere in the code except in the Property statement.
Create the Property statement for the property.
For example:
Public Property ProductName() As String
Use good naming conventions for your property name. The recommended convention is to use the property’s human-readable name, concatenating the words and using Pascal case, whereby each word in the name is capitalized.
Press the Enter key to automatically generate the remaining structure of the Property statement:
Public Property ProductName() As String Get
End Get Set(ByVal value As String)
End Set End Property
Add code within the Get and Set blocks.
The minimum code in the getter returns the value of the private variable:
Get Return _ProductName End Get
NOTE FOR VB6 DEVELOPERS: Use the Return statement instead of using the property’s name to return a value.
Add any other code to the getter, such as formatting or data conversions. For example, for a product number, the getter could add hyphens or other characters used by the human reader that are not necessarily stored with the actual data.
The minimum code in the setter sets the value of the private variable:
Set(ByVal value As String) _ProductName = value End Set
Add any other code to the setter, such as validation or data conversion. For example, code could validate that the product name is not empty before it is assigned to its private variable.
NOTE FOR VB6 DEVELOPERS: The Property statement is similar to the VB6 property procedures. However, there is no separate Let and Set. The Set statement is no longer needed to assign object variables. Object variables can now be assigned with a simple equals sign, as with any other variable (remember from Chapter 1 that everything in .NET is basically an object).
Repeat these steps to define each property of your class. Alternatively, you can use code snippets or the Class Designer, as described in the next chapter, to assist you in defining the properties of your class.
Use properties to define the data managed by your business object. Use Property statements to provide access to the properties from other parts of the application.
Building Along
For the Purchase Tracker sample application:
Open the Product class in the Code Editor.
Add the ProductName property, as defined in this section.
Open the ProductWin form in the Code Editor.
In the Load event for the ProductWin form, add code to set and then display the ProductName property:
Dim prod as Product prod = New Product prod.ProductName = "shoes" Debug.WriteLine(prod.ProductName) ' Displays shoes
Run the application. It displays your splash screen and then shows the MDI parent form. Select Products | Manage Products to display the ProductWin form. The debug message appears in the Immediate window (Debug | Windows | Immediate) or in the Output window (Debug | Windows | Output), depending on your settings.
The example in the preceding section seemed like much more code than simply adding a public variable. Why bother with Property statements?
Using a private variable and public Property statements has several advantages over just using public variables:
You can add code that is executed before a property is assigned. This code can perform validation, such as to ensure that no invalid values are assigned to the property.
You can add code that is executed before a property is retrieved. This code can format or convert the value. For example, it could add dashes to the product number for the human reader even though the dashes are not stored with the data.
Without a Property statement, any code that references the class can manipulate or destroy the property value at will.
Some of the Visual Studio tools, such as object binding, recognize only properties defined with Property statements. (See Chapter 7, “Binding the User Interface to the Business Objects,” for more information on object binding.)
For these reasons, always use private variables and public Property statements to define the properties for your classes.
Please check back tomorrow for the continuation of this article.