Wednesday, May 21, 2008

Reflection in .NET

Building an Extensible Application

In the sections that follow, you'll see a complete example that illustrates the process of building an extensible Windows Forms application that you can augment via external assemblies. To serve as a road map, the extensible sample application includes the following assemblies:

  • CommonSnappableTypes.dll—This assembly contains type definitions that will be implemented by each snap-in as well as referenced by the extensible Windows Forms application.
  • CSharpSnapIn.dll—A snap-in written in C# that leverages the types of CommonSnappableTypes.dll.
  • Vb2005SnapIn.dll—A snap-in written in Visual Basic 2005, which leverages the types of CommonSnappableTypes.dll.
  • MyPluggableApp.exe—This Windows Forms application (which also leverages CommonSnappableTypes.dll) will be the entity that may be extended by the functionality of each snap-in. This application will make use of dynamic loading, reflection, and late binding to dynamically discover the functionality of assemblies of which it has no prior knowledge.

Building CommonSnappableTypes.dll

First you'll need to create an assembly that contains the types a given snap-in must leverage to plug into your extensible Windows Forms application. The CommonSnappableTypes class library project defines two such types: using System;

namespace CommonSnappableTypes
{
// All snap-ins must implement this interface.
public interface IAppFunctionality
{ void DoIt(); }

// Optionally, snap-in designers may supply
// company information.
[AttributeUsage(AttributeTargets.Class)]
public sealed class CompanyInfoAttribute :
System.Attribute
{
private string companyName;
private string companyUrl;
public CompanyInfoAttribute(){}

public string Name
{
get { return companyName; }
set { companyName = value; }
}

public string Url
{
get { return companyUrl; }
set { companyUrl = value; }
}
}
}


The IAppFunctionality type provides a polymorphic interface for all snap-ins that the extensible Windows Forms application can consume. Because this example is purely illustrative, it exposes a single method named DoIt(). In a more realistic example, imagine an interface (or a set of interfaces) that allows the snap-in to generate scripting code, render an image onto the application's toolbox, or integrate into the main menu of the hosting application.

The CompanyInfoAttribute type is a custom attribute that snap-in creators can optionally apply to their snap-in. As you can tell by the name of this class, [CompanyInfo] allows the snap-in developers to provide some basic details about the component's point of origin. Notice that you can create custom attributes by extending the System.Attribute base class, and you can annotate them with the [AttributeUsage] attribute to define valid targets where developers can apply your attribute (limited to class types in the preceding code example).

Building the C# Snap-In

Next, you need to create a type that supports the IAppFunctionality interface. Again, to focus on the overall design of an extensible application, a trivial implementation is in order. Create a new C# code library named CSharpSnapIn that defines a class type named "TheCSharpModule." Given that this class must make use of the types defined in CommonSnappableTypes, be sure to set a reference to that assembly (as well as System.Windows.Forms.dll so you can display a pertinent message for the example).

using System;
using CommonSnappableTypes;
using System.Windows.Forms;

namespace CSharpSnapIn
{
[CompanyInfo(Name = "Intertech Training",
Url = "www.intertechtraining.com")]
public class TheCSharpModule : IAppFunctionality
{
// Using explicit interface implementation,
// as only the extensible app
// will need to obtain IAppFunctionality.
void IAppFunctionality.DoIt()
{
MessageBox.Show(
"You have just used the C# snap in!");
}
}
}


Notice that I chose to make use of explicit interface implementation when supporting the IAppFunctionality interface. This is not required; however, the idea is that the only part of the system that needs to directly interact with this interface type is the hosting Windows Forms application. Also note that the code uses named property syntax to specify the values used to set the Name and Url properties of the [CompanyInfo] attribute.

Building a Visual Basic 2005 Snap-In

Now, to simulate the role of a third-party vendor who prefers Visual Basic 2005 over C#, create a new Visual Basic 2005 code library (Vb2005SnapIn) that references the same assemblies as the previous CSharpSnapIn project. The code behind this class type is again intentionally simple: Imports System.Windows.Forms


Imports CommonSnappableTypes

Url:="www.ChuckySoft.com")> _
Public Class TheVb2005Module
Implements IAppFunctionality

Public Sub DoIt() Implements
CommonSnappableTypes.IAppFunctionality.DoIt
MessageBox.Show(
"You have just used the VB 2005 snap in!")
End Sub
End Class

Notice that applying attributes in Visual Basic 2005 requires angle bracket syntax (< >) rather than the C#-centric square brackets ([ ]). Additionally, note that the code uses the Implements keyword at both the class and method level to add support for interface types.

No comments: