Проблема с динамической загрузкой сборок в .NET - PullRequest
6 голосов
/ 24 мая 2010

Мы создали небольшой компонент, который принимает Id, ищет запись в базе данных для сборки / пространства имен / класса и динамически загружает экземпляр класса, который нам нужен. До сих пор он работал нормально, но при запуске этого кода в VS 2010 происходит сбой.

Private Function AssemblyLoaded(ByVal assemblyFile As String) As Assembly
    Dim assemblies() As Assembly = AppDomain.CurrentDomain.GetAssemblies

    For Each asmb As Assembly In assemblies
        If (asmb.Location = assemblyFile)) Then Return asmb
    Next
    Return Nothing
End Function

Первая проблема заключается в том, что когда итератор попадает в динамическую сборку, отсутствует asmb.Location и генерируется исключение NotSupportedException. Есть ли способ проверить наличие поля Unsupported-ness в поле Location без необходимости перехвата исключения?

Вторая проблема, asmb.Location, возвращает весь путь, а не только имя файла, что означает, что эта функция не выполняется каждый раз. Если эта функция определяет, что класс еще не загружен, мы пытаемся загрузить его и получить исключение AccessViolationException, поскольку класс уже загружен, и мы не можем «перезагрузить» его.

Изменение функции на это работает:

Private Function AssemblyLoaded(ByVal assemblyFile As String) As Assembly
    Dim assemblies() As Assembly = AppDomain.CurrentDomain.GetAssemblies

    For Each asmb As Assembly In assemblies
        Try
            If (asmb.Location.EndsWith(assemblyFile)) Then Return asmb
        Catch ex As NotSupportedException
            Continue For
        End Try
    Next

    Return Nothing
End Function

Но он кажется грязным. Есть ли лучший способ проверить, загружена ли сборка, и передать ее вызывающей стороне? Вышеуказанные проблемы характерны для .NET 4.0 или Visual Studio 2010? Я не пробовал это вне среды IDE, так как это требует довольно значительной настройки.

Ответы [ 3 ]

5 голосов
/ 24 мая 2010

Вы можете проверить, является ли сборка динамической, пропустив экземпляры AssemblyBuilder.Вы должны использовать Path.GetFileName (), чтобы изолировать имя.Помните, что это не очень хорошая идея, поскольку сборки из разных путей могут иметь одинаковые имена.Но вы, кажется, застряли с этим.Таким образом:

Private Function AssemblyLoaded(ByVal assemblyFile As String) As Assembly
    For Each asmb As Assembly In AppDomain.CurrentDomain.GetAssemblies
        If TypeOf asmb Is System.Reflection.Emit.AssemblyBuilder Then Continue For
        If System.IO.Path.GetFileName(asmb.Location) = assemblyFile Then Return asmb
    Next
    Return Nothing
End Function

Чувствительность к регистру - это то, с чем вам также следует иметь дело, возможно.

2 голосов
/ 13 сентября 2011

Чтобы добавить к ответу Ганса Пассанта: для моего приложения (C # 4.0) пропустить экземпляры AssemblyBuilder все еще не удалось. Оказывается, есть другой класс, System.Reflection.Emit.InternalAssemblyBuilder, который также выбрасывает NotSupportedException при доступе к Location.

InternalAssemblyBuilder и RuntimeAssembly (требуемый тип) оба являются внутренними, поэтому лучшее, что я мог придумать, это (в C #):

var assemblies = AppDomain.CurrentDomain
    .GetAssemblies()
    .Where(assembly => assembly.GetType().Name == "RuntimeAssembly")
    .Select(assembly => assembly.Location)
    .ToArray();
0 голосов
/ 15 декабря 2016

Если вы используете .Net 4.0, вы должны проверить Assembly.IsDynamic , которая охватывает все базы ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...