Click here to Skip to main content
15,883,883 members
Articles / Programming Languages / MSIL

Dynamic Objects, Factories, and Runtime Machines to Boost Performance

Rate me:
Please Sign up or sign in to vote.
4.79/5 (10 votes)
27 Nov 2007CPOL7 min read 48.1K   303   46  
An examination of dynamic object instantiation and runtime machines to boost performance.
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) @Everywhere
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions