Выгрузка сборки, загруженной с помощью Assembly.LoadFrom () - PullRequest
50 голосов
/ 07 июня 2011

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

Ответы [ 6 ]

68 голосов
/ 07 июня 2011

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

AppDomain dom = AppDomain.CreateDomain("some");     
AssemblyName assemblyName = new AssemblyName();
assemblyName.CodeBase = pathToAssembly;
Assembly assembly = dom.Load(assemblyName);
Type [] types = assembly.GetTypes();
AppDomain.Unload(dom);
34 голосов
/ 07 июня 2011

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

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

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

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

31 голосов
/ 17 января 2017

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

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

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

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

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

4 голосов
/ 07 июня 2011

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

0 голосов
/ 12 июня 2019

Если вы хотите загрузить только начальную сборку без каких-либо зависимых сборок, вы можете использовать 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);
}
0 голосов
/ 12 февраля 2019

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

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

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

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

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

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

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

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

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

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

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

А вот демонстрационное видео:

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

...