Creating an Object at Runtime
Abstract: No, it's not that usual Dim a As New Object kind of thing. This one's using unknown class (at design time), from unknown assembly (at design time).
Context: you want to instantiate a certain Class during runtime. The Class and the Class' Assembly is unknown at design time, therefore cannot be “strong”-typed.
Solution: Using classes from System.Reflection namespace, we can achieve this in only in one line of code:
Dim object As Object = Reflection.Assembly.LoadFrom(assemblyFileName).CreateInstance(classNameFull)
There are two input strings you must provide:
- assemblyFileName: replace with the EXE or DLL file name. Ex: “System.dll“
- classNameFull: replace with the full name (incl. the Namespace) of the Class to instantiate. Ex: “System.Object“
In many case, we don't have control over the name of the Class to instantiate, but we do have some workaround. One method is to use subclassing. The Class we are going to instantiate inherits a specific Class already defined at design time and is known to everyone. We are going to instantiate the Class, but will use only a part of it (only the inherited ones). The code would be:
Dim assemblyPackage As Assembly = Assembly.LoadFrom(assemblyFileName)
Dim object As parentClass
For Each assType As Type In assemblyPackage.GetTypes
If assType.IsSubclassOf(GetType(parentClass)) Then
object = CType(assemblyPackage.CreateInstance(assType.FullName), parentClass)
End If
Next
- parentClass: replace with the Class everyone inherited from. And since it is known at design time, you will get strong type support.
This method also adds strong typing to the object instantiated. OO purist would agree that subclassing is just overkill. Therefore a lighter method is using Interface to define contracts to implementors. We can use the following snippet to instantiate a Class that implements a known Interface.
Dim assemblyPackage As Assembly = Assembly.LoadFrom(assemblyFileName)
Dim object As IImplemented
For Each assType As Type In assemblyPackage.GetTypes
For Each interfaceType As Type In assType.GetInterfaces
If interfaceType.GUID = GetType(IImplemented).GUID Then
object = CType(assemblyPackage.CreateInstance(assType.FullName), IImplemented)
End If
Next
Next
- IImplemented: same thing like parentClass above, the Interface everyone is implementing.
Advanced users should try looking at Type.FindInterfaces method to filter in more than one Interface. You can also find more anti-OO tools in the System.Reflection namespace.
Conclusion: the more you know about the Class you are instantiating, the less code is needed to instantiate the Class. And since performance isn't the biggest problem here, feel free to use the easiest method for your clients/implementors. And don't forget those try-catch blocks to catch illegal Assembly/Class.
P.S.: Useful when using the Generic Strategy Pattern.