11.3. Partial Types

Partial types are a simple concept that enable a single type to be split across multiple files. The files are combined at compile time into a single type. As such, Partial types cannot be used to add or modify functionality in existing types. The most common reason to use Partial types is to separate generated code. In the past, elaborate class hierarchies had to be created to add additional functionality to a generated class due to fear of that code being overwritten when the class was regenerated. Using Partial types, the generated code can be partitioned into a separate file, and additional code added to a file where it will not be overwritten by the generator.

Partial types are defined by using the Partial keyword in the type definition. The following example defines a Person class across two files:

'File 1 - fields and constructor
Partial Public Class Person
    Private m_Name As String
    Private m_Age As Integer
    Public Sub New(ByVal name As String, ByVal age As Integer)
        Me.m_Name = name
        Me.m_Age = age
    End Sub
End Class

'File 2 - public properties
Public Class Person
    Public ReadOnly Property Age() As Integer
        Get
            Return Me.m_Age
        End Get
    End Property
    Public ReadOnly Property Name() As String
        Get
            Return Me.m_Name
        End Get
    End Property
End Class

You will notice that the Partial keyword is used only in one of the files. This is specific to VB.NET, because C# requires all partial classes to use this keyword. The disadvantage there is that the Partial keyword needs to be added to the generated file. The other difference in C# is that the Partial keyword appears after the class accessibility keyword (in this case, Public).

11.3.1. Form Designers

Both the Windows and Web Forms designer make use of Partial types to separate the designer code from event handlers and other code written by the developer. The Windows Forms designer generates code into an associated designer file. For example, for Form1.vb there would also be Form1.designer.vb. In addition to protecting your code so that it isn't overwritten by the generated code, having the designer code in a separate file also trims down the code files for each form. Typically, the code file would only contain event handlers and other custom code.

In the previous version of Visual Studio, Web Forms were split across two files where controls had to be defined in both the designer file and the code-behind files so event handlers could be wired up. The designer file inherited from the code-behind file, which introduced another level of complexity. With Partial types, this has been simplified, with controls being defined in the designer file and only event handlers being defined in the code file. The code file is now a code-beside file, because both the code and designer information belong to the same class.

A technique often used by VB.NET developers is to use the Handles syntax for wiring event handlers to form control events. The controls are defined in the generated code while the event handler is left to the developer. C# developers have to manually wire and unwire the event handler, which normally needs to be done as part of the constructor. This is difficult if the code generator doesn't provide an appropriate mechanism for accessing the constructor—the WinForms code generator in Visual Studio 2008 generates the following stub in the developer code file:

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }
}

11.3.2. Partial Methods

Partial types by themselves are only half the solution to separating generated code from the code you write. Take the following scenario: the generated code exposes a property, which can be used to set the eye color of the previously created Person class. In order to extend the functionality of the Person class you want to be able to execute additional code whenever this property is changed. Previously you would have had to create another class that inherits from Person, in which you override the EyeColor property, adding your own code. This leads to a very messy inheritance model that can adversely affect the performance of your application. Even if you don't override the generated methods or properties, because they will be defined as being virtual, the compiler will not inline them, adversely affecting performance.

Partial methods provide a much better model for generated code and your code to intertwine. Now, instead of code generators marking everything as virtual they can insert calls to partial methods:

Private mEyeColor As Color
Public Property EyeColor() As Color
    Get
        Return mEyeColor
    End Get
    Set(ByVal value As Color)
        EyeColorChanging()
        mEyeColor = value
        EyeColorChanged()
    End Set
End Property

Partial Private Sub EyeColorChanging()
End Sub

Partial Private Sub EyeColorChanged()
End Sub

In this snippet you can see the calls to the partial methods EyeColorChanging and EyeColorChanged as part of the EyeColor property. Below this property are the declarations for these partial methods. To insert additional code you just need to implement these methods in your code file:

Private Sub EyeColorChanging()
    MsgBox("About to change the eye color!")
End Sub

Private Sub EyeColorChanged()
    MsgBox("Eye color has been changed")
End Sub

So far you probably haven't seen any great savings over the previously mentioned inheritance model. The big advantage with partial methods is that if you choose not to implement any of the partial methods the compiler will remove the declaration and all calls to that partial method during compilation. This means that there are no runtime penalties associated with having thousands of these method declarations in the generated code file to make the generated code more extensible.

There are some limitations with partial methods, namely that the partial methods must be marked as private and cannot have return values. Both of these constraints are due to the implementation-dependent inclusion of the methods at compile time. If a method is not private, it would need to be accessible after compilation—otherwise changing the implementation would break any existing references. Similarly if a method has a return value, there may be code that depends on a value being returned from the method call, which makes excluding the method call at compilation time difficult.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.250.203