Страницы

Поиск по вопросам

суббота, 14 декабря 2019 г.

Что происходит со сборкой?

#c_sharp #рефлексия


Получилась следующая ситуация...

1) Создаем в приложении домен.
2) Загружаем в него через DoCallBack сборку Assembly.Load(...)
3) Из главного домена достаем сборки ранее созданного и например, показываем их имена.
4) Смотрим какие сборки есть в главном домене, а конкретней - там появилась эта сборка
которую мы загрузили в другой домен.

То есть, загружая сборку в другой домен, если обратиться с методу GetAssemblies,
загруженные сборки появляются и в основном домене, при этом они не просто туда переносятся,
они копируются - их можно использоваться в обоих доменах.

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

Самый главный вопрос, почему? Как избавиться от переноса сборки в основной домен?
Тут даже не в памяти дело, а в том что основной домен держит референс на сборку и не
дает её удалить, например. А инфу как-то вытаскивать надо.

class Program
    {
        static void Main ( string [ ] args )
        {
            var appDomain = AppDomain.CreateDomain("TestDomain");
            appDomain.DoCallBack(LoadModule);

            var assembly = appDomain.GetAssemblies().Single( t => t.GetName().Name
== "TestModule" );

            foreach ( var assembly1 in AppDomain.CurrentDomain.GetAssemblies() )
            {
                Console.WriteLine( assembly1.FullName );
            }
        }

        private static void LoadModule()
        {
            Assembly.Load( "TestModule" );
        }
    }

    


Ответы

Ответ 1



Существует две возможности передать объект через границу домена приложения: Через прокси. Для объектов наследующих от System.MarshalByRefObject. При этом все вызовы методов на прокси объекте автоматически перенаправляются в домен приложения, которому принадлежит исходный объект. Через бинарную сериализацию. Для объектов, которые её поддерживают. При этом создаётся копия объекта, которая более не связана с исходным объектом. При этом класс System.AppDomain наследует от System.MarshalByRefObject, в то время как класс System.Reflection.Assembly нет. То есть вызов appDomain.GetAssemblies() в Вашем коде будет перенаправлен в дополнительный домен приложения, после чего результат его работы (Assembly[]) необходимо будет передать в основной домен приложения: сериализовать в дополнительном домене и десериализовать в основном домене. Данная передача Assembly объектов в основной домен приложения и приводит к загрузке в него сборок. Чтобы избежать загрузки сборок в основной домен, не передавайте в него объекты, для десериализации которых необходимо загрузить сборку. Как то System.Reflection.Assembly объект, представляющий сборку, System.Type объект, представляющий любой тип из сборки, экземпляр любого типа из сборки. Например имена сборок можно извлекать в дополнительном домене приложения, а в основной передавать только строки: using System; using System.Linq; using System.Reflection; class Program { static void Main ( string [ ] args ) { var appDomain = AppDomain.CreateDomain("TestDomain"); appDomain.DoCallBack(LoadModule); var worker = (Worker)appDomain.CreateInstanceAndUnwrap(typeof(Worker).Assembly.FullName, typeof(Worker).FullName); foreach ( var assemblyFullName1 in worker.GetAssembliesFullName() ) { Console.WriteLine( assemblyFullName1 ); } Console.WriteLine(); foreach ( var assembly1 in AppDomain.CurrentDomain.GetAssemblies() ) { Console.WriteLine( assembly1.FullName ); } } private static void LoadModule() { Assembly.Load( "TestModule" ); } } class Worker : MarshalByRefObject { public string[] GetAssembliesFullName() { return AppDomain.CurrentDomain.GetAssemblies().Select(a => a.FullName).ToArray(); } }

Комментариев нет:

Отправить комментарий