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