using dnlib.DotNet; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using UnityEngine; namespace HybridCLR.Editor.Meta { public class AssemblyReferenceDeepCollector : IDisposable { private readonly IAssemblyResolver _assemblyPathResolver; private readonly List _rootAssemblies; private readonly ModuleContext _modCtx; private readonly AssemblyResolver _asmResolver; private bool disposedValue; private bool _loadedNetstandard; public Dictionary LoadedModules { get; } = new Dictionary(); public IReadOnlyList GetRootAssemblyNames() { return _rootAssemblies; } public List GetLoadedModulesExcludeRootAssemblies() { return LoadedModules.Where(e => !_rootAssemblies.Contains(e.Key)).Select(e => e.Value).ToList(); } public List GetLoadedModules() { return LoadedModules.Select(e => e.Value).ToList(); } public List GetLoadedModulesOfRootAssemblies() { return _rootAssemblies.Select(ass => LoadedModules[ass]).ToList(); } public AssemblyReferenceDeepCollector(IAssemblyResolver assemblyResolver, List rootAssemblies) { _assemblyPathResolver = assemblyResolver; _rootAssemblies = rootAssemblies; _modCtx = ModuleDef.CreateModuleContext(); _asmResolver = (AssemblyResolver)_modCtx.AssemblyResolver; _asmResolver.EnableTypeDefCache = true; _asmResolver.UseGAC = false; LoadAllAssembiles(); } private void LoadAllAssembiles() { foreach (var asm in _rootAssemblies) { LoadModule(asm); } } private ModuleDefMD LoadModule(string moduleName) { // Debug.Log($"load module:{moduleName}"); if (LoadedModules.TryGetValue(moduleName, out var mod)) { return mod; } if (moduleName == "netstandard") { if (!_loadedNetstandard) { LoadNetStandard(); _loadedNetstandard = true; } return null; } mod = DoLoadModule(_assemblyPathResolver.ResolveAssembly(moduleName, true)); LoadedModules.Add(moduleName, mod); foreach (var refAsm in mod.GetAssemblyRefs()) { LoadModule(refAsm.Name); } return mod; } private ModuleDefMD DoLoadModule(string dllPath) { //Debug.Log($"do load module:{dllPath}"); ModuleDefMD mod = ModuleDefMD.Load(dllPath, _modCtx); _asmResolver.AddToCache(mod); return mod; } private void LoadNetStandard() { DoLoadModule(_assemblyPathResolver.ResolveAssembly("netstandard2.0", true)); DoLoadModule(_assemblyPathResolver.ResolveAssembly("netstandard2.1", true)); } protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { foreach(var mod in LoadedModules.Values) { mod.Dispose(); } } LoadedModules.Clear(); disposedValue = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } }