|
Imports System.Reflection
Imports System.Reflection.Emit
Imports System.Threading
''' -----------------------------------------------------------------------------
''' Project : Widgets
''' Class : WidgetFactory
''' -----------------------------------------------------------------------------
''' <summary>
'''
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' [pliebscher] 7/20/2007 Created
''' </history>
''' -----------------------------------------------------------------------------
Public Class WidgetFactory
Private Shared _MachineCache As New Hashtable
Private Shared _DelegateCache As New Hashtable
Private Shared _ConstructorCache As New Hashtable
Private Shared _IsInitialized As Boolean = InitCache()
Private Sub New()
End Sub
Public Shared Function GetWidget(ByVal widgetType As Type) As Widget
Return DirectCast(_MachineCache(widgetType), IWidgetInstanceMachine).GetInstance()
End Function
Public Shared Function GetWidgetByConstructorInfo(ByVal widgetType As Type) As Widget
Dim Ctor As ConstructorInfo = DirectCast(_ConstructorCache(widgetType), ConstructorInfo)
Return DirectCast(Ctor.Invoke(New Object() {}), Widget)
End Function
Public Shared Function GetWidgetBySystemActivator(ByVal widgetType As Type) As Widget
Return DirectCast(Activator.CreateInstance(widgetType), Widget)
End Function
Public Shared Function GetWidgetByDelegate(ByVal widgetType As Type) As Widget
Return DirectCast(_DelegateCache(widgetType), GetInstanceDelegate).Invoke()
End Function
''' -----------------------------------------------------------------------------
''' <summary>
''' Pre-scan for Widgets. This example only scan's this assembly. Each assembly in
''' the AppDomain could aslo be scanned in a real-world implementation.
''' </summary>
''' <returns></returns>
''' <remarks>
''' </remarks>
''' <history>
''' [pliebscher] 7/20/2007 Created
''' </history>
''' -----------------------------------------------------------------------------
Private Shared Function InitCache() As Boolean
For Each [type] As Type In System.Reflection.Assembly.GetExecutingAssembly.GetTypes
If [type].IsSubclassOf(GetType(Widget)) Then
' Dynamic Factory
_MachineCache.Add([type], GetWidgetInstanceMachine([type]))
' Delegate
Dim GetInstanceMethod As MethodInfo = [type].GetMethod("GetWidgetInstance", BindingFlags.Public Or BindingFlags.Static)
Dim GetInstanceDelegate As GetInstanceDelegate = DirectCast(System.Delegate.CreateDelegate(GetType(GetInstanceDelegate), GetInstanceMethod), GetInstanceDelegate)
_DelegateCache.Add([type], GetInstanceDelegate)
' Constructor
_ConstructorCache.Add([type], [type].GetConstructor(System.Type.EmptyTypes))
End If
Next
Return True
End Function
''' -----------------------------------------------------------------------------
''' <summary>
'''
''' </summary>
''' <param name="widgetType"></param>
''' <returns></returns>
''' <remarks>
''' </remarks>
''' <history>
''' [pliebscher] 7/20/2007 Created
''' </history>
''' -----------------------------------------------------------------------------
Private Shared Function GetWidgetInstanceMachine(ByVal widgetType As Type) As IWidgetInstanceMachine
Dim Name As String = widgetType.FullName & "InstanceMachine"
Dim AssemblyName As AssemblyName = New AssemblyName
AssemblyName.Name = Name
Dim SavePath As String = "C:\Temp"
Dim TypeName As String = widgetType.Name & "Machine"
' Define the assembly...
Dim AssemblyBuilder As AssemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(AssemblyName, AssemblyBuilderAccess.RunAndSave, SavePath)
Dim ModuleBuilder As ModuleBuilder = AssemblyBuilder.DefineDynamicModule("Machine", Name & ".dll")
' Define the class "Public Class SuperWidgetFactory"
Dim TypeBuilder As TypeBuilder = ModuleBuilder.DefineType(TypeName, TypeAttributes.Public)
' Implement our interface "Implements IWidgetInstanceMachine"
TypeBuilder.AddInterfaceImplementation(GetType(IWidgetInstanceMachine))
' Define the constructor "Public Sub New()"
TypeBuilder.DefineDefaultConstructor(MethodAttributes.Public)
' Define the input parameter array. In this case there are none but,
' If you want to pass parameters (i.e. GetInstance(name As String, order As Integer) ),
' simply list the Types in the braces: {GetType(String), GetType(Integer)}
Dim InParamTypes As Type() = New Type() {}
' Define the return Type...
Dim ReturnType As Type = GetType(Widget)
' Define the "GetInstance()" method...
Dim GetInstance_MethodBuilder As MethodBuilder = TypeBuilder.DefineMethod("GetInstance", MethodAttributes.Public Or MethodAttributes.Virtual, ReturnType, InParamTypes)
' Get the Widget's contructor. In this case, we have no input parameters so
' the derived class', System.Object, contructor will be called.
Dim WidgetCtor As ConstructorInfo = widgetType.GetConstructors()(0)
' Get an IL generator to emit to body of the method...
Dim GetInstance_ILGenerator As ILGenerator = GetInstance_MethodBuilder.GetILGenerator
' Emit the body of the GetInstance method:
' "Return New xxxWidget"
' ----------------------------------------
' Creates the Widget and pop's in onto the stack...
GetInstance_ILGenerator.Emit(OpCodes.Newobj, WidgetCtor)
' Return's the Widget from the stack...
GetInstance_ILGenerator.Emit(OpCodes.Ret)
TypeBuilder.CreateType()
' Uncomment to save...
'AssemblyBuilder.Save(Name & ".dll")
Return DirectCast(AssemblyBuilder.CreateInstance(TypeName), IWidgetInstanceMachine)
End Function
End Class
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.