How to pass ctor args in Activator.CreateInstance or use IL?

后端 未结 8 1740
野的像风
野的像风 2020-12-07 16:06

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. (

相关标签:
8条回答
  • 2020-12-07 16:51

    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 '.

    0 讨论(0)
  • 2020-12-07 16:54

    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).

    0 讨论(0)
提交回复
热议问题