Подтвердить что ты не робот

Выгрузите сборку, загруженную Assembly.LoadFrom()

Мне нужно проверить количество времени для запуска GetTypes() после загрузки dll. Код выглядит следующим образом.

Assembly assem = Assembly.LoadFrom(file);
sw = Stopwatch.StartNew();
var types1 = assem.GetTypes();
sw.Stop();
double time1 = sw.Elapsed.TotalMilliseconds;

Я хотел бы выгрузить и перезагрузить dll, чтобы проверить время, потраченное на запуск GetTypes().

  • Как я могу его выгрузить? assem = null достаточно хорош?
  • Есть ли явный способ вызова сборщика мусора для восстановления ресурса, выделенного для сборки?
4b9b3361

Ответ 1

К сожалению, вы не можете выгрузить сборку после ее загрузки. Но вы можете выгрузить AppDomain. Что вы можете сделать, так это создать новый AppDomain (AppDomain.CreateDomain(...)), загрузите сборку в это приложение для работы с ней, а затем выгрузите AppDomain, когда это необходимо. При выгрузке AppDomain все собранные сборки будут выгружены. (См. ссылка)

Чтобы вызвать сборщик мусора, вы можете использовать

GC.Collect(); // collects all unused memory
GC.WaitForPendingFinalizers(); // wait until GC has finished its work
GC.Collect();

GC вызывает финализаторы в фоновом потоке, поэтому вам нужно подождать и снова вызвать Collect(), чтобы убедиться, что вы удалили все.

Ответ 2

Можно ли использовать другой AppDomain?

AppDomain dom = AppDomain.CreateDomain("some");     
AssemblyName assemblyName = new AssemblyName();
assemblyName.CodeBase = pathToAssembly;
Assembly assembly = dom.Load(assemblyName);
Type [] types = assembly.GetTypes();
AppDomain.Unload(dom);

Ответ 3

Вместо использования LoadFrom() или LoadFile() вы можете использовать Load with File.ReadAllBytes(). При этом он не использует файл сборки, но будет читать его и использовать данные чтения.

Ваш код будет выглядеть так

Assembly assem = Assembly.Load(File.ReadAllBytes(filePath));
sw = Stopwatch.StartNew();
var types1 = assem.GetTypes();
sw.Stop();
double time1 = sw.Elapsed.TotalMilliseconds;

Отсюда Мы не можем выгрузить файл, пока не будут выгружены все содержащиеся в нем домены.

Надеюсь это поможет.:)

Ответ 4

Вы не можете выгрузить сборку из текущего AppDomain. Но вы можете создать новый AppDomain, загрузить сборки в него, выполнить код внутри нового AppDomain и затем выгрузить его. Проверьте следующую ссылку: MSDN

Ответ 5

Сборка не может быть выгружена, к сожалению, и, более того, если вы используете домены приложений, тогда это не позволит вам общаться с API/сборками вашего основного приложения.

Лучшее описание проблемы можно найти здесь:

Руководство по хостингу скриптов http://www.csscript.net/help/Script_hosting_guideline_.html

Если вы хотите запускать код С# без связи с вашим основным приложением - тогда лучше всего интегрировать API сценариев С#:

https://github.com/oleg-shilo/cs-script/tree/master/Source/deployment/samples/Hosting/Legacy%20Samples/CodeDOM/Modifying%20script%20without%20restart

А для интеграции вам понадобятся следующие пакеты:

С# скрипт: http://www.csscript.net/CurrentRelease.html

Расширение Visual Studio: https://marketplace.visualstudio.com/items?itemName=oleg-shilo.cs-script

Однако, если вы хотите связаться со своим сценарием С# с вашим приложением - тогда использование одного и того же домена приложения с постоянно меняющимся именем сборки на данный момент является единственным способом - но это, к сожалению, съедает оперативную память и дисковое пространство.

Пример кода, как это сделать, можно найти здесь:

https://github.com/tapika/cppscriptcore CsScriptHotReload.sln

А вот и демо-видео:

https://drive.google.com/open?id=1jOECJj0_UPNdllwF4GWb5OMybWPc0PUV

Ответ 6

Если вы хотите загрузить только начальную сборку без каких-либо зависимых сборок, вы можете использовать Assembly.LoadFile в AppDomain, а затем выгрузить AppDomain, когда закончите.

Создайте класс загрузчика для загрузки и работы со сборкой:

class Loader : MarshalByRefObject
{
    public void Load(string file)
    {
        var assembly = Assembly.LoadFile(file);
        // Do stuff with the assembly.
    }
}

Запустите загрузчик в отдельном домене приложения следующим образом:

var domain = AppDomain.CreateDomain(nameof(Loader), AppDomain.CurrentDomain.Evidence, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(typeof(Loader).Assembly.Location) });
try {
    var loader = (Loader)domain.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
    loader.Load(myFile);
} finally {
    AppDomain.Unload(domain);
}