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() действительно существует, а все упомянутые здесь структуры и классы не содержат ошибок? Если кому-то понадобится больше кода, чтобы помочь, я могу опубликовать его.


person Sukasa    schedule 12.04.2009    source источник


Ответы (2)


В целом стратегия должна работать. Вызов 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 вне цикла означает, что если какой-либо данный тип в сборке содержит ошибку, вы отбросите все типы из этой сборки. Перемещение его внутрь позволит вам отбросить только те типы, которые не работают должным образом. d Однако текущее поведение может быть вашим намерением.

person JaredPar    schedule 12.04.2009
comment
Ладно, я не был уверен, что есть маленькая хитрость, о которой я не знал. Спасибо! - person Sukasa; 13.04.2009
comment
У меня есть собственный атрибут проверки, который применяется к Property A и имеет метод IsValid() (очевидно). Мне нужно получить значение другого свойства, скажем, Property B. Мне нужно явное приведение для (ClassName)validationContext.ObjectInstance, чтобы получить значение. Я использую Activator.CreateInstance(validationContext.ObjectType), чтобы получить свой класс ClassName. Правильно ли его использовать, потому что это происходит за счет производительности. Есть ли другой способ сделать это без использования Activator.CreateInstance(validationContext.ObjectType)? - person phougatv; 28.06.2017

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

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

person Denis Troller    schedule 12.04.2009