CodeDOM - выполнить скомпилированный код, второй раз выдает ошибку - PullRequest
1 голос
/ 08 декабря 2011

В настоящее время я борюсь с генератором кода CodeDOM и выполняю скомпилированные сборки. Все работает как чудо, кроме запуска скомпилированного кода во второй раз.

Настройка

Пользователь «программирует» модель, которая будет переведена в исполняемую программу. Пользователь может определить, должна ли сборка создаваться только в памяти или на диске, иметь ли исходный код или только исполняемый файл. Когда он нажимает кнопку «Выполнить», дерево CodeDOM собирается и компилируется, записывается на диск (при необходимости) и выполняется.

Исключение

Когда он нажимает кнопку «Выполнить» во второй раз, выдается исключение:

ошибка CS0016: невозможно записать в выходной файл '': - «Процесс не может получить доступ к файлу, потому что он используется другой процесс. "

Поскольку я могу компилировать код так часто, как хочу, не сталкиваясь с ошибкой, я бы предположил, что он как-то влияет на работу сборки. Я искал в Интернете информацию по этой теме, но все, что я нашел, - это создание отдельного AppDomain и его последующая выгрузка.

Вот фрагмент кода, который выполняет сборку:

if ( RunProject )
{
  _log.info( "Compiled without errors, running..." );
  Assembly compiledAssembly = res.CompiledAssembly;
  AppDomain compiledAssemblyDomain = AppDomain.CreateDomain( "compiledAssemblyDomain" );
  compiledAssemblyDomain.ExecuteAssemblyByName( compiledAssembly.GetName( ) );
  AppDomain.Unload( compiledAssemblyDomain );
}

Исполняемый файл может быть удален только в случае выхода из программы, как если бы файл был заблокирован текущим доменом приложения. Что делать? Спасибо за вашу помощь!


Обновление

Когда вышеуказанный код выполняется, основной файл загружается в исполняющую сборку (или я ошибаюсь?). Консоль отладки содержит следующую информацию:

[13:42:19.5576171]  i  Compiled without errors, running...
'XXX.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\...\bin\main.exe'

и через несколько секунд после выхода из выполненной сборки:

The thread '.NET SystemEvents' (0x20d0) has exited with code 0 (0x0). 
The thread '<No Name>' (0x1d20) has exited with code 0 (0x0).

где XXX - имя моего основного приложения, компилирующего код. Разве файл не должен загружаться где-то еще? Не XXX.vshost.exe не открывает дескриптор и не закрывает его после выгрузки домена приложения?

1 Ответ

1 голос
/ 08 декабря 2011

Я немного боролся с этим (я делал нечто подобное с Scrolling Game Development Kit 2 ). Вы должны быть очень осторожны, чтобы убедиться, что все, что вы делаете с этим скомпилированным кодом, происходит внутри этого другого AppDomain, чтобы при выгрузке этого AppDomain все ссылки на DLL выгружались вместе с ним. Если вы ссылаетесь на тип из скомпилированного кода, эта DLL также будет загружена в ваш AppDomain, и выгрузка другого домена не принесет пользы. Поэтому мне нужно было определить интерфейсы в общей DLL, которые можно загрузить в оба домена, чтобы я мог вызывать функции в другой DLL без загрузки типов из другой DLL. Просто убедитесь, что каждый объект, который вы создаете в другой DLL, использует интерфейс, определенный в общей DLL (или другой открытый интерфейс, не определенный в пользовательской DLL). Затем приведите каждый объект, который вы создаете, из этой DLL к одному из этих интерфейсов. Вы никогда не можете напрямую использовать типы, определенные в этой DLL.

РЕДАКТИРОВАТЬ: Обратите внимание на следующее примечание из Документация MSDN о свойстве CompiledAssembly

Примечание Метод доступа get для свойства CompiledAssembly вызывает метод Load для загрузки скомпилированная сборка в текущий домен приложения. После вызова метода доступа get, скомпилированная сборка не может быть удалена до тех пор, пока текущий домен приложения не будет выгружен.

...