I'm trying to put together a plugins system with .NET, and I'm not sure if I'm doing it correctly. The basis of the system is that a specific directory ({apppath}/Plugins/) will have a bunch of precompiled DLLs, and I want to look through each one with reflection, and for every class available, if it inherits a specific base class (this is defined in yet another DLL, but I'll go into that later), then create an instance of it and call a specific function in said instance.
Public Sub ScanPluginsInDirectory(ByVal Directory As String)
Dim Plugins As New IO.DirectoryInfo(Directory)
Dim Files As IO.FileInfo() = Plugins.GetFiles("*.dll")
Dim CryptType As Type = GetType(CryptPluginBase)
Dim PluginsData as List(Of LoadedPluginsInfo)
For Each DllFile As IO.FileInfo In Files
Try
Dim thisAsm As Assembly = Assembly.LoadFrom(DllFile.FullName)
Dim ClassDefs = thisAsm.GetTypes().Where(Function(type) CryptType.IsAssignableFrom(type))
For Each ClassDef As Type In ClassDefs
Dim A As Object
A = ClassDef.Assembly.CreateInstance(ClassDef.Name)
PluginsData.Add(New LoadedPluginsInfo(A.Plugin(), False))
Next
Catch ex As Exception
Continue For
End Try
Next
End Sub
The specific problem I have is, I'm not sure this is the right way to do this. Would the method I'm trying to do work, if it can be assumed that A.Plugin()
actually exists and any structures and classes referenced here are bug-free? If anyone would need more code in order to help, I can post it.
Overall the strategy should work. The Assembly.LoadFrom call will load the target assembly into the process. From there it is possible to do type inspection and create instances of those types.
I think the easiest and most reliable way to create the instance is to use the Activator.CreateInstance method.
For Each def As Type in ClassDefs
Dim inst = Activator.CreateInstance(def)
PluginsData.Add(new LoadedPluginsInfo(inst.Plugin(), False))
Next
Depending on your goals, another suggestion would be to move the Try/Catch block into the loop instead of out of it. Having the Try/Catch block on the outside of the loop means that if any given type in an assembly does have an error, you will discard all types from that assembly. Moving it inside will allow you to discard only the types that do not work as expect.d The current behavior may be your intent though.
This should work, I've been using this kind of thing in some projects before. I specifically looked for a constructor and invoked it but apart from that it was the same idea.
But you might want to look at MEF, which takes care of a LOT of things for you for a plugin architecture (if you are willing to wait a bit for the release version, it's still CTP for now).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With