Createinstance() - Правильно ли я это делаю?

Я пытаюсь собрать систему плагинов с .NET, и я не уверен, правильно ли я делаю это. Основой системы является то, что определенный каталог ({apppath}/Plugins/) будет иметь кучу предварительно скомпилированных библиотек DLL, и я хочу просмотреть каждый из них с отражением и для каждого доступного класса, если он наследует определенный базовый класс (это определено в еще одной DLL, но я расскажу об этом позже), затем создайте экземпляр и вызовите определенную функцию в указанном экземпляре.

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

У меня есть конкретная проблема: я не уверен, что это правильный способ сделать это. Будет ли метод, который я пытаюсь выполнить, если можно предположить, что A.Plugin() действительно существует, а любые структуры и классы, на которые делается ссылка здесь, являются без ошибок? Если кому-то понадобится больше кода, чтобы помочь, я могу опубликовать его.

Ответ 1

В целом стратегия должна работать. Вызов Assembly.LoadFrom загрузит целевую сборку в процесс. Оттуда можно провести проверку типов и создать экземпляры этих типов.

Я думаю, что самый простой и надежный способ создания экземпляра - использовать метод Activator.CreateInstance.

For Each def As Type in ClassDefs
  Dim inst = Activator.CreateInstance(def)
  PluginsData.Add(new LoadedPluginsInfo(inst.Plugin(), False))
Next

В зависимости от ваших целей другим предложением было бы переместить блок Try/Catch в цикл, а не из него. Наличие блока Try/Catch на внешней стороне цикла означает, что если какой-либо заданный тип сборки имеет ошибку, вы отбросите все типы из этой сборки. Перемещение внутри него позволит вам отбросить только те типы, которые не работают как expect.d Однако текущее поведение может быть вашим намерением.

Ответ 2

Это должно сработать, я раньше использовал такие вещи в некоторых проектах. Я специально искал конструктор и вызывал его, но кроме того, это была та же идея.

Но вы можете посмотреть MEF, который позаботится о много вещей для вас для архитектуры плагина (если вы готовы немного подождать для версии релиза, пока она еще CTP).