I need a performance enhanced Activator.CreateInstance() and came across this article by Miron Abramson that uses a factory to create the instance in IL and then cache it. (
To follow is @thames answer converted to VB.NET.
//' Original source: http://stackoverflow.com/questions/2024435/how-to-pass-ctor-args-in-activator-createinstance-or-use-il/2045313#2045313
//' Converted to VB with: http://www.developerfusion.com/tools/convert/csharp-to-vb/
//' code updated 2010-06-01
//' class that creates comment objects
Public Class CreatesSomeObject
//' method that creates a comment object
Public Sub CreateComment()
//' Method 1 (without cache)
Dim comment1 As Comment = ObjectFactoryFactory(Of Comment, ObjectId).CreateObject.Invoke(New ObjectId())
//' Method 2 (with cache)
Dim comment2 As Comment = ObjectFactoryFactory(Of Comment, ObjectId).CreateObjectWithCache.Invoke(New ObjectId())
//' Method 3 (without helper factory ObjectFactoryFactory)
Dim comment3 As Comment = ObjectFactory(Of Comment, ObjectId).CreateObject.Invoke(New ObjectId())
End Sub
End Class
Public Class Comment
Public Sub New(ByVal objectId As ObjectId)
End Sub
End Class
Public Class ObjectId
End Class
//' This is optional class. Just helps in creating objects when
//' a cache is needed or not needed.
Public NotInheritable Class ObjectFactoryFactory(Of T As Class, P1)
Private Sub New()
End Sub
Shared cache As Hashtable = Hashtable.Synchronized(New Hashtable())
Public Shared ReadOnly Property CreateObject() As Func(Of P1, T)
Get
Return ObjectFactory(Of T, P1).CreateObject
End Get
End Property
Public Shared ReadOnly Property CreateObjectWithCache() As Func(Of P1, T)
Get
Return ObjectFactory(Of T, P1).UseCache(cache)
End Get
End Property
End Class
//' Main object creation factory class.
Public NotInheritable Class ObjectFactory(Of T As Class, P1)
Private Sub New()
End Sub
Shared _createObject As Func(Of P1, T)
Public Shared ReadOnly Property CreateObject() As Func(Of P1, T)
Get
If _createObject IsNot Nothing Then
Return _createObject
End If
_createObject = CreateDelegate()
Return _createObject
End Get
End Property
Private Shared Function CreateDelegate() As Func(Of P1, T)
Dim objType As Type = GetType(T)
Dim types As Type() = {GetType(P1)}
Dim dynMethod = New DynamicMethod("DM$OBJ_FACTORY_" + objType.Name, objType, types, objType)
Dim ilGen As ILGenerator = dynMethod.GetILGenerator()
//' if need more than 1 arg add another Ldarg_x
//' you'll also need to add proper generics and
//' CreateDelegate signatures
ilGen.Emit(OpCodes.Ldarg_0)
ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(types))
ilGen.Emit(OpCodes.Ret)
Return DirectCast(dynMethod.CreateDelegate(GetType(Func(Of P1, T))), Func(Of P1, T))
End Function
Public Shared Function UseCache(ByVal cache As Hashtable) As Func(Of P1, T)
Dim t As Type = GetType(T)
Dim c As Func(Of P1, T) = TryCast(cache(t), Func(Of P1, T))
If c Is Nothing Then
SyncLock cache.SyncRoot
c = TryCast(cache(t), Func(Of P1, T))
If c IsNot Nothing Then
Return c
End If
c = CreateDelegate()
cache.Add(t, c)
End SyncLock
End If
Return c
End Function
End Class
Note the use //' for comments allows SO code colorizer to work correctly. After pasting this code into your project replace //' with '.
Has your profiler shown you that a large amount of time is spent in Activator.CreateInstance() (and not any constructor called by it) if you don't use the simple approach. If that is not the case, just use Activator.CreateInstance. (There seems to not be a generic CreateInstance() method with ctor arguments, but there is a non-generic one).