int UnLoadAsmRef(SeparatedAssembly asm, Dictionary <SeparatedAssembly, bool> collection) { if (!collection[asm]) { m_assemblyDisposeCounter++; collection[asm] = true; } //получаем разницу между загруженными сборками и "выгруженными" return(collection.Count - m_assemblyDisposeCounter); }
/// <summary> /// Загрузка сборки в AppDomain /// </summary> /// <param name="fInfo">Информация о файле сборки</param> /// <param name="name">Имя сборки</param> /// <param name="hash">HASH файла</param> /// <returns>Возвращает обёртку над выгруженной сборкой</returns> internal SeparatedAssembly LoadAssembly(FileInfo fInfo, AssemblyName name, string hash) { lock (m_locker) { if (m_disposed) { throw new ObjectDisposedException($"Домен был выгружен перед загрузкой сборки '{(fInfo?.Name ?? "NULL")}'"); } //получаем экземпляр из другого AppDomain var extAsm = (ExternalAppDomainAssembly)m_domain.CreateInstanceAndUnwrap(CoreAssemblyName, ExternalAppDomainAssembly.TypeFullName); extAsm.BindAssembly(fInfo.FullName); var asm = new SeparatedAssembly(extAsm, this); asm.AssemblyName = name; asm.FileHash = hash; asm.UnLoaded += OnAssemblyDispose; m_loadedAssemblies.Add(asm, false); return(asm); } }
void OnAssemblyDispose(SeparatedAssembly asm) { if (asm == null) { return; } /* * попадаем сюда при явном вызове клиентом Dispose у сборки * * поскольку её фактически из домена выгрузить нельзя * то ведём учёт "выгруженных" */ var asmCount = -1; lock (m_locker) { if (m_loadedAssemblies.ContainsKey(asm)) { asmCount = UnLoadAsmRef(asm, m_loadedAssemblies); } else if (m_relatedAssemblies.ContainsKey(asm)) { asmCount = UnLoadAsmRef(asm, m_relatedAssemblies); } } //выгружаем текущий домен, если все его сборки помечены как "выгружена" if (asmCount == 0) { if (!m_Managed) //если домен был создан не явно { Dispose(); //самоликвидируемся } } }