Модульная система в .NET, которую можно изменять во время выполнения

В настоящее время я работаю над хобби-проектом .NET, который включает в себя сложную систему объектов, которые работают в сочетании друг с другом. Однако я столкнулся с небольшой проблемой: я не могу найти механизм в .NET для поддержки замены кода во время выполнения и возможности избавиться от старого кода, загруженного ранее. Это означает динамическую замену модуля/объекта и почти мгновенное отображение изменений пользователю, например, когда он перезапускает процедуру, а не всю программу.

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

Есть ли структура или способ замены/выгрузки определенных частей кода? Как это делается в реальных приложениях? Может ли быть обходной путь? Или я выбрал не тот набор инструментов?


person ax1mx2    schedule 10.09.2014    source источник


Ответы (5)


Вам нужна какая-то система плагинов с четко определенными интерфейсами. Затем вы загружаете двоичные файлы во время выполнения (ваш плагин *.dll) и создаете из них объекты, а затем выполняете на них методы. Когда вы создаете систему, в которой объекты из ваших плагинов должны создаваться через ваш IPluginManager, у вас не возникает проблем с заменой кода во время выполнения. :)

Or

У вас есть что-то вроде папки с файлами *.cs, которые будут компилироваться (в памяти) по запросу и создавать из них объекты, которые вы хотите использовать, и вызывать для них методы. Что в основном то же самое, что и выше, без компиляции во время выполнения.

Оттуда вы можете сделать дальнейшие улучшения.

РЕДАКТИРОВАТЬ: Как вы написали, единственная проблема без использования AppDomain заключается в том, что однажды загруженные сборки не могут быть выгружены. Но это не проблема.

person user743414    schedule 10.09.2014

Я не думаю, что вам нужны отдельные домены приложений: вы можете динамически загружать сборки в пределах текущего домена приложений. И каждая сборка, вероятно, должна реализовывать некоторые определенные интерфейсы (в зависимости от вашего использования). Вы можете использовать класс FileSystemWatcher, например, для загрузки/выгрузки сборок по мере необходимости.

См. http://msdn.microsoft.com/en-us/library/25y1ya39(v=vs.110).aspx

person DvS    schedule 10.09.2014
comment
Однако вы не можете выгрузить сборку из AppDomain; вот почему необходимы отдельные AppDomains, если вы хотите что-либо выгрузить (в этот момент вы выгружаете весь AppDomain). - person Aasmund Eldhuset; 10.09.2014
comment
Ты прав. Чтобы «выгрузить» одну сборку, необходимо выгрузить весь AppDomain. - person DvS; 10.09.2014

Вы можете посмотреть MEF. Это означает: Managed Extensibility Framework.
Вот еще одна статья об этом MEF в codeproject.

Он используется для загрузки dll во время выполнения путем их компоновки. Это то, что обычно используется для plugins или чего-то еще, что вы можете поместить в папку и ожидать, что она запустится.

Вот ссылка на еще несколько руководств: Где я могу узнать о MEF?

person Noctis    schedule 10.09.2014
comment
Я рассматривал MEF как вариант, но AppDomain мне снова придется самому заниматься управлением. - person ax1mx2; 10.09.2014

Да, вы правы, невозможно просто выгрузить сборку (только AppDomains). Но я думаю, что одной из особенностей ASP.Net vNext является возможность иметь только сборки в памяти и когда вы просто изменяете исходный код на диске, он автоматически компилируется и загружается. Поэтому должен существовать механизм для выгрузки предыдущей версии.

Я думаю, что они делают это, просто создавая AppDomain, в который снова загружаются все сборки, чтобы избежать междоменной связи. Но я действительно не знаю, и, может быть, если бы вы углубились в механизм того, как они делают это в ASP.NET, вы, возможно, найдете хорошее решение. Дополнительную информацию об актуальных темах vNext вы также можете найти в блог Скотта.

person Oliver    schedule 10.09.2014

Что ж, я нашел 2 решения, которые работают для меня, которыми я хотел бы поделиться. Первый — использовать CollectibleAssembly и определить типы. Это, безусловно, немного сложно, и на этот тип динамических сборок накладывается ряд ограничений. Другой вариант — использовать язык сценариев, например IronPython или IronRuby. Также замечательной особенностью нового компилятора Roslyn является то, что он также предоставляет API-интерфейсы для сценариев, которые ранее не были доступны в среде .NET. Более того, языки сценариев Roslyn очень похожи на свои полноценные аналоги (C# или VB). И я также нашел крошечный пример его возможностей.

person ax1mx2    schedule 11.09.2014