Client LuaCsForBarotrauma
AssemblyManager.cs
1 using System;
2 using System.Collections.Concurrent;
3 using System.Collections.Generic;
4 using System.Collections.Immutable;
5 using System.Diagnostics.CodeAnalysis;
6 using System.Linq;
7 using System.Reflection;
8 using System.Runtime.CompilerServices;
9 using System.Runtime.Loader;
10 using System.Threading;
11 using Microsoft.CodeAnalysis;
12 using Microsoft.CodeAnalysis.CSharp;
13 
14 // ReSharper disable EventNeverSubscribedTo.Global
15 // ReSharper disable InconsistentNaming
16 
17 namespace Barotrauma;
18 
19 /***
20  * Note: This class was written to be thread-safe in order to allow parallelization in loading in the future if the need
21  * becomes necessary as there is almost no serial performance overhead for adding threading protection.
22  */
23 
28 public class AssemblyManager
29 {
30  #region ExternalAPI
31 
35  public event Action<Assembly> OnAssemblyLoaded;
36 
41  public event Action<Assembly> OnAssemblyUnloading;
42 
46  public event Action<string, Exception> OnException;
47 
51  public event Action<Guid> OnACLUnload;
52 
53 
58  public ImmutableList<WeakReference<MemoryFileAssemblyContextLoader>> StillUnloadingACLs
59  {
60  get
61  {
62  OpsLockUnloaded.EnterReadLock();
63  try
64  {
65  return UnloadingACLs.ToImmutableList();
66  }
67  finally
68  {
69  OpsLockUnloaded.ExitReadLock();
70  }
71  }
72  }
73 
74 
75  // ReSharper disable once MemberCanBePrivate.Global
80  {
81  get
82  {
83  OpsLockUnloaded.EnterReadLock();
84  try
85  {
86  return UnloadingACLs.Any();
87  }
88  catch (Exception)
89  {
90  return false;
91  }
92  finally
93  {
94  OpsLockUnloaded.ExitReadLock();
95  }
96  }
97  }
98 
99  // Old API compatibility
100  public IEnumerable<Type> GetSubTypesInLoadedAssemblies<T>()
101  {
102  return GetSubTypesInLoadedAssemblies<T>(false);
103  }
104 
105 
113  public IEnumerable<Type> GetSubTypesInLoadedAssemblies<T>(bool rebuildList)
114  {
115  Type targetType = typeof(T);
116  string typeName = targetType.FullName ?? targetType.Name;
117 
118  // rebuild
119  if (rebuildList)
120  RebuildTypesList();
121 
122  // check cache
123  if (_subTypesLookupCache.TryGetValue(typeName, out var subTypeList))
124  {
125  return subTypeList;
126  }
127 
128  // build from scratch
129  OpsLockLoaded.EnterReadLock();
130  try
131  {
132  // build list
133  var list1 = _defaultContextTypes
134  .Where(kvp1 => targetType.IsAssignableFrom(kvp1.Value) && !kvp1.Value.IsInterface)
135  .Concat(LoadedACLs
136  .SelectMany(kvp => kvp.Value.AssembliesTypes)
137  .Where(kvp2 => targetType.IsAssignableFrom(kvp2.Value) && !kvp2.Value.IsInterface))
138  .Select(kvp3 => kvp3.Value)
139  .ToImmutableList();
140 
141  // only add if we find something
142  if (list1.Count > 0)
143  {
144  if (!_subTypesLookupCache.TryAdd(typeName, list1))
145  {
146  ModUtils.Logging.PrintError(
147  $"{nameof(AssemblyManager)}: Unable to add subtypes to cache of type {typeName}!");
148  }
149  }
150  else
151  {
152  ModUtils.Logging.PrintMessage(
153  $"{nameof(AssemblyManager)}: Warning: No types found during search for subtypes of {typeName}");
154  }
155 
156  return list1;
157  }
158  catch (Exception e)
159  {
160  this.OnException?.Invoke($"{nameof(AssemblyManager)}::{nameof(GetSubTypesInLoadedAssemblies)}() | Error: {e.Message}", e);
161  return ImmutableList<Type>.Empty;
162  }
163  finally
164  {
165  OpsLockLoaded.ExitReadLock();
166  }
167  }
168 
176  public bool TryGetSubTypesFromACL<T>(Guid id, out IEnumerable<Type> types)
177  {
178  Type targetType = typeof(T);
179 
180  if (TryGetACL(id, out var acl))
181  {
182  types = acl.AssembliesTypes
183  .Where(kvp => targetType.IsAssignableFrom(kvp.Value) && !kvp.Value.IsInterface)
184  .Select(kvp => kvp.Value);
185  return true;
186  }
187 
188  types = null;
189  return false;
190  }
191 
198  public bool TryGetSubTypesFromACL(Guid id, out IEnumerable<Type> types)
199  {
200  if (TryGetACL(id, out var acl))
201  {
202  types = acl.AssembliesTypes.Select(kvp => kvp.Value);
203  return true;
204  }
205 
206  types = null;
207  return false;
208  }
209 
210 
217  public IEnumerable<Type> GetTypesByName(string typeName)
218  {
219  List<Type> types = new();
220  if (typeName.IsNullOrWhiteSpace())
221  return types;
222 
223  bool byRef = false;
224  if (typeName.StartsWith("out ") || typeName.StartsWith("ref "))
225  {
226  typeName = typeName.Remove(0, 4);
227  byRef = true;
228  }
229 
230 
231  TypesListHelper();
232  if (types.Count > 0)
233  return types;
234 
235  // we couldn't find it, rebuild and try one more time
236  RebuildTypesList();
237  TypesListHelper();
238 
239  if (types.Count > 0)
240  return types;
241 
242  OpsLockLoaded.EnterReadLock();
243  try
244  {
245  // fallback to Type.GetType
246  Type t = Type.GetType(typeName, false, false);
247  if (t is not null)
248  {
249  types.Add(byRef ? t.MakeByRefType() : t);
250  return types;
251  }
252 
253  foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
254  {
255  try
256  {
257  t = assembly.GetType(typeName, false, false);
258  if (t is not null)
259  types.Add(byRef ? t.MakeByRefType() : t);
260  }
261  catch (Exception e)
262  {
263  this.OnException?.Invoke(
264  $"{nameof(AssemblyManager)}::{nameof(GetTypesByName)}() | Error: {e.Message}", e);
265  }
266  }
267  }
268  finally
269  {
270  OpsLockLoaded.ExitReadLock();
271  }
272 
273  return types;
274 
275  void TypesListHelper()
276  {
277  if (_defaultContextTypes.TryGetValue(typeName, out var type1))
278  {
279  if (type1 is not null)
280  types.Add(byRef ? type1.MakeByRefType() : type1);
281  }
282 
283  OpsLockLoaded.EnterReadLock();
284  try
285  {
286  foreach (KeyValuePair<Guid,LoadedACL> loadedAcl in LoadedACLs)
287  {
288  var at = loadedAcl.Value.AssembliesTypes;
289  if (at.TryGetValue(typeName, out var type2))
290  {
291  if (type2 is not null)
292  types.Add(byRef ? type2.MakeByRefType() : type2);
293  }
294  }
295  }
296  finally
297  {
298  OpsLockLoaded.ExitReadLock();
299  }
300  }
301  }
302 
308  public IEnumerable<Type> GetAllTypesInLoadedAssemblies()
309  {
310  OpsLockLoaded.EnterReadLock();
311  try
312  {
313  return _defaultContextTypes
314  .Select(kvp => kvp.Value)
315  .Concat(LoadedACLs
316  .SelectMany(kvp => kvp.Value?.AssembliesTypes.Select(kv => kv.Value)))
317  .ToImmutableList();
318  }
319  catch
320  {
321  return ImmutableList<Type>.Empty;
322  }
323  finally
324  {
325  OpsLockLoaded.ExitReadLock();
326  }
327  }
328 
335  public IEnumerable<LoadedACL> GetAllLoadedACLs()
336  {
337  OpsLockLoaded.EnterReadLock();
338  try
339  {
340  if (!LoadedACLs.Any())
341  {
342  return ImmutableList<LoadedACL>.Empty;
343  }
344 
345  return LoadedACLs.Select(kvp => kvp.Value).ToImmutableList();
346  }
347  catch
348  {
349  return ImmutableList<LoadedACL>.Empty;
350  }
351  finally
352  {
353  OpsLockLoaded.ExitReadLock();
354  }
355  }
356 
357  #endregion
358 
359  #region InternalAPI
360 
366  [MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.NoInlining)]
367  internal ImmutableList<LoadedACL> UnsafeGetAllLoadedACLs()
368  {
369  if (LoadedACLs.IsEmpty)
370  return ImmutableList<LoadedACL>.Empty;
371  return LoadedACLs.Select(kvp => kvp.Value).ToImmutableList();
372  }
373 
377  public event System.Func<LoadedACL, bool> IsReadyToUnloadACL;
378 
391  public AssemblyLoadingSuccessState LoadAssemblyFromMemory([NotNull] string compiledAssemblyName,
392  [NotNull] IEnumerable<SyntaxTree> syntaxTree,
393  IEnumerable<MetadataReference> externalMetadataReferences,
394  [NotNull] CSharpCompilationOptions compilationOptions,
395  string friendlyName,
396  ref Guid id,
397  IEnumerable<Assembly> externFileAssemblyRefs = null)
398  {
399  // validation
400  if (compiledAssemblyName.IsNullOrWhiteSpace())
401  return AssemblyLoadingSuccessState.BadName;
402 
403  if (syntaxTree is null)
404  return AssemblyLoadingSuccessState.InvalidAssembly;
405 
406  if (!GetOrCreateACL(id, friendlyName, out var acl))
407  return AssemblyLoadingSuccessState.ACLLoadFailure;
408 
409  id = acl.Id; // pass on true id returned
410 
411  // this acl is already hosting an in-memory assembly
412  if (acl.Acl.CompiledAssembly is not null)
413  return AssemblyLoadingSuccessState.AlreadyLoaded;
414 
415  // compile
416  AssemblyLoadingSuccessState state;
417  string messages;
418  try
419  {
420  state = acl.Acl.CompileAndLoadScriptAssembly(compiledAssemblyName, syntaxTree, externalMetadataReferences,
421  compilationOptions, out messages, externFileAssemblyRefs);
422  }
423  catch (Exception e)
424  {
425  ModUtils.Logging.PrintError($"{nameof(AssemblyManager)}::{nameof(LoadAssemblyFromMemory)}() | Failed to compile and load assemblies for [ {compiledAssemblyName} / {friendlyName} ]! Details: {e.Message} | {e.StackTrace}");
426  return AssemblyLoadingSuccessState.InvalidAssembly;
427  }
428 
429  // get types
430  if (state is AssemblyLoadingSuccessState.Success)
431  {
432  _subTypesLookupCache.Clear();
433  acl.RebuildTypesList();
434  OnAssemblyLoaded?.Invoke(acl.Acl.CompiledAssembly);
435  }
436  else
437  {
438  ModUtils.Logging.PrintError($"Unable to compile assembly '{compiledAssemblyName}' due to errors: {messages}");
439  }
440 
441  return state;
442  }
443 
451  public bool SetACLToTemplateMode(Guid guid)
452  {
453  if (!TryGetACL(guid, out var acl))
454  return false;
455  acl.Acl.IsTemplateMode = true;
456  return true;
457  }
458 
468  public AssemblyLoadingSuccessState LoadAssembliesFromLocations([NotNull] IEnumerable<string> filePaths,
469  string friendlyName, ref Guid id)
470  {
471 
472  if (filePaths is null)
473  {
474  var exception = new ArgumentNullException(
475  $"{nameof(AssemblyManager)}::{nameof(LoadAssembliesFromLocations)}() | file paths supplied is null!");
476  this.OnException?.Invoke($"Error: {exception.Message}", exception);
477  throw exception;
478  }
479 
480  ImmutableList<string> assemblyFilePaths = filePaths.ToImmutableList(); // copy the list before loading
481 
482  if (!assemblyFilePaths.Any())
483  {
484  return AssemblyLoadingSuccessState.NoAssemblyFound;
485  }
486 
487  if (GetOrCreateACL(id, friendlyName, out var loadedAcl))
488  {
489  var state = loadedAcl.Acl.LoadFromFiles(assemblyFilePaths);
490  // if failure, we dispose of the acl
491  if (state != AssemblyLoadingSuccessState.Success)
492  {
493  DisposeACL(loadedAcl.Id);
494  ModUtils.Logging.PrintError($"ACL {friendlyName} failed, unloading...");
495  return state;
496  }
497  // build types list
498  _subTypesLookupCache.Clear();
499  loadedAcl.RebuildTypesList();
500  id = loadedAcl.Id;
501  foreach (Assembly assembly in loadedAcl.Acl.Assemblies)
502  {
503  OnAssemblyLoaded?.Invoke(assembly);
504  }
505  return state;
506  }
507 
508  return AssemblyLoadingSuccessState.ACLLoadFailure;
509  }
510 
511 
512  [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.Synchronized)]
513  public bool TryBeginDispose()
514  {
515  OpsLockLoaded.EnterWriteLock();
516  OpsLockUnloaded.EnterWriteLock();
517  try
518  {
519  _subTypesLookupCache.Clear();
520  _defaultContextTypes = _defaultContextTypes.Clear();
521 
522  foreach (KeyValuePair<Guid, LoadedACL> loadedAcl in LoadedACLs)
523  {
524  if (loadedAcl.Value.Acl is not null)
525  {
526  if (IsReadyToUnloadACL is not null)
527  {
528  foreach (Delegate del in IsReadyToUnloadACL.GetInvocationList())
529  {
530  if (del is System.Func<LoadedACL, bool> { } func)
531  {
532  if (!func.Invoke(loadedAcl.Value))
533  return false; // Not ready, exit
534  }
535  }
536  }
537 
538  foreach (Assembly assembly in loadedAcl.Value.Acl.Assemblies)
539  {
540  OnAssemblyUnloading?.Invoke(assembly);
541  }
542 
543  UnloadingACLs.Add(new WeakReference<MemoryFileAssemblyContextLoader>(loadedAcl.Value.Acl, true));
544  loadedAcl.Value.ClearTypesList();
545  loadedAcl.Value.Acl.Unload();
546  loadedAcl.Value.ClearACLRef();
547  OnACLUnload?.Invoke(loadedAcl.Value.Id);
548  }
549  }
550 
551  LoadedACLs.Clear();
552  return true;
553  }
554  catch(Exception e)
555  {
556  // should never happen
557  this.OnException?.Invoke($"{nameof(TryBeginDispose)}() | Error: {e.Message}", e);
558  return false;
559  }
560  finally
561  {
562  OpsLockUnloaded.ExitWriteLock();
563  OpsLockLoaded.ExitWriteLock();
564  }
565  }
566 
567 
568  [MethodImpl(MethodImplOptions.NoInlining)]
569  public bool FinalizeDispose()
570  {
571  bool isUnloaded;
572  OpsLockUnloaded.EnterUpgradeableReadLock();
573  try
574  {
575  GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); // force the gc to collect unloaded acls.
576  List<WeakReference<MemoryFileAssemblyContextLoader>> toRemove = new();
577  foreach (WeakReference<MemoryFileAssemblyContextLoader> weakReference in UnloadingACLs)
578  {
579  if (!weakReference.TryGetTarget(out _))
580  {
581  toRemove.Add(weakReference);
582  }
583  }
584 
585  if (toRemove.Any())
586  {
587  OpsLockUnloaded.EnterWriteLock();
588  try
589  {
590  foreach (WeakReference<MemoryFileAssemblyContextLoader> reference in toRemove)
591  {
592  UnloadingACLs.Remove(reference);
593  }
594  }
595  finally
596  {
597  OpsLockUnloaded.ExitWriteLock();
598  }
599  }
600  isUnloaded = !UnloadingACLs.Any();
601  }
602  finally
603  {
604  OpsLockUnloaded.ExitUpgradeableReadLock();
605  }
606 
607  return isUnloaded;
608  }
609 
618  [MethodImpl(MethodImplOptions.NoInlining)]
619  public bool TryGetACL(Guid id, out LoadedACL acl)
620  {
621  acl = null;
622  OpsLockLoaded.EnterReadLock();
623  try
624  {
625  if (id.Equals(Guid.Empty) || !LoadedACLs.ContainsKey(id))
626  return false;
627  acl = LoadedACLs[id];
628  return true;
629  }
630  finally
631  {
632  OpsLockLoaded.ExitReadLock();
633  }
634  }
635 
636 
645  [MethodImpl(MethodImplOptions.NoInlining)]
646  private bool GetOrCreateACL(Guid id, string friendlyName, out LoadedACL acl)
647  {
648  OpsLockLoaded.EnterUpgradeableReadLock();
649  try
650  {
651  if (id.Equals(Guid.Empty) || !LoadedACLs.ContainsKey(id) || LoadedACLs[id] is null)
652  {
653  OpsLockLoaded.EnterWriteLock();
654  try
655  {
656  id = Guid.NewGuid();
657  acl = new LoadedACL(id, this, friendlyName);
658  LoadedACLs[id] = acl;
659  return true;
660  }
661  finally
662  {
663  OpsLockLoaded.ExitWriteLock();
664  }
665  }
666  else
667  {
668  acl = LoadedACLs[id];
669  return true;
670  }
671 
672  }
673  catch(Exception e)
674  {
675  this.OnException?.Invoke($"{nameof(GetOrCreateACL)}Error: {e.Message}", e);
676  acl = null;
677  return false;
678  }
679  finally
680  {
681  OpsLockLoaded.ExitUpgradeableReadLock();
682  }
683  }
684 
685 
686  [MethodImpl(MethodImplOptions.NoInlining)]
687  private bool DisposeACL(Guid id)
688  {
689  OpsLockLoaded.EnterWriteLock();
690  OpsLockUnloaded.EnterWriteLock();
691  try
692  {
693  if (LoadedACLs.ContainsKey(id) && LoadedACLs[id] == null)
694  {
695  if (!LoadedACLs.TryRemove(id, out _))
696  {
697  ModUtils.Logging.PrintWarning($"An ACL with the GUID {id.ToString()} was found as null. Unable to remove null ACL entry.");
698  }
699  }
700 
701  if (id.Equals(Guid.Empty) || !LoadedACLs.ContainsKey(id))
702  {
703  return false; // nothing to dispose of
704  }
705 
706  var acl = LoadedACLs[id];
707 
708  foreach (Assembly assembly in acl.Acl.Assemblies)
709  {
710  OnAssemblyUnloading?.Invoke(assembly);
711  }
712 
713  _subTypesLookupCache.Clear();
714  UnloadingACLs.Add(new WeakReference<MemoryFileAssemblyContextLoader>(acl.Acl, true));
715  acl.Acl.Unload();
716  acl.ClearACLRef();
717  OnACLUnload?.Invoke(acl.Id);
718 
719  return true;
720  }
721  catch (Exception e)
722  {
723  this.OnException?.Invoke($"{nameof(DisposeACL)}() | Error: {e.Message}", e);
724  return false;
725  }
726  finally
727  {
728  OpsLockLoaded.ExitWriteLock();
729  OpsLockUnloaded.ExitWriteLock();
730  }
731  }
732 
733  internal AssemblyManager()
734  {
735  RebuildTypesList();
736  }
737 
741  private void RebuildTypesList()
742  {
743  try
744  {
745  _defaultContextTypes = AssemblyLoadContext.Default.Assemblies
746  .SelectMany(a => a.GetSafeTypes())
747  .ToImmutableDictionary(t => t.FullName ?? t.Name, t => t);
748  _subTypesLookupCache.Clear();
749  }
750  catch(ArgumentException ae)
751  {
752  this.OnException?.Invoke($"{nameof(RebuildTypesList)}() | Error: {ae.Message}", ae);
753  try
754  {
755  // some types must've had duplicate type names, build the list while filtering
756  Dictionary<string, Type> types = new();
757  foreach (var type in AssemblyLoadContext.Default.Assemblies.SelectMany(a => a.GetSafeTypes()))
758  {
759  try
760  {
761  types.TryAdd(type.FullName ?? type.Name, type);
762  }
763  catch
764  {
765  // ignore, null key exception
766  }
767  }
768 
769  _defaultContextTypes = types.ToImmutableDictionary();
770  }
771  catch (Exception e)
772  {
773  this.OnException?.Invoke($"{nameof(RebuildTypesList)}() | Error: {e.Message}", e);
774  ModUtils.Logging.PrintError($"{nameof(AssemblyManager)}: Unable to create list of default assembly types! Default AssemblyLoadContext types searching not available.");
775 #if DEBUG
776  ModUtils.Logging.PrintError($"{nameof(AssemblyManager)}: Exception Details :{e.Message} | {e.InnerException}");
777 #endif
778  _defaultContextTypes = ImmutableDictionary<string, Type>.Empty;
779  }
780  }
781  }
782 
783  #endregion
784 
785  #region Data
786 
787  private readonly ConcurrentDictionary<string, ImmutableList<Type>> _subTypesLookupCache = new();
788  private ImmutableDictionary<string, Type> _defaultContextTypes;
789  private readonly ConcurrentDictionary<Guid, LoadedACL> LoadedACLs = new();
790  private readonly List<WeakReference<MemoryFileAssemblyContextLoader>> UnloadingACLs= new();
791  private readonly ReaderWriterLockSlim OpsLockLoaded = new ();
792  private readonly ReaderWriterLockSlim OpsLockUnloaded = new ();
793 
794  #endregion
795 
796  #region TypeDefs
797 
798 
799  public sealed class LoadedACL
800  {
801  public readonly Guid Id;
802  private ImmutableDictionary<string, Type> _assembliesTypes = ImmutableDictionary<string, Type>.Empty;
803  public MemoryFileAssemblyContextLoader Acl { get; private set; }
804 
805  internal LoadedACL(Guid id, AssemblyManager manager, string friendlyName)
806  {
807  this.Id = id;
808  this.Acl = new(manager)
809  {
810  FriendlyName = friendlyName
811  };
812  }
813  public ref readonly ImmutableDictionary<string, Type> AssembliesTypes => ref _assembliesTypes;
814 
818  internal void ClearACLRef()
819  {
820  Acl = null;
821  }
822 
826  internal void RebuildTypesList()
827  {
828  if (this.Acl is null)
829  {
830  ModUtils.Logging.PrintWarning($"{nameof(RebuildTypesList)}() | ACL with GUID {Id.ToString()} is null, cannot rebuild.");
831  return;
832  }
833 
834  ClearTypesList();
835  try
836  {
837  _assembliesTypes = this.Acl.Assemblies
838  .SelectMany(a => a.GetSafeTypes())
839  .ToImmutableDictionary(t => t.FullName ?? t.Name, t => t);
840  }
841  catch(ArgumentException)
842  {
843  // some types must've had duplicate type names, build the list while filtering
844  Dictionary<string, Type> types = new();
845  foreach (var type in this.Acl.Assemblies.SelectMany(a => a.GetSafeTypes()))
846  {
847  try
848  {
849  types.TryAdd(type.FullName ?? type.Name, type);
850  }
851  catch
852  {
853  // ignore, null key exception
854  }
855  }
856 
857  _assembliesTypes = types.ToImmutableDictionary();
858  }
859  }
860 
861  internal void ClearTypesList()
862  {
863  _assembliesTypes = ImmutableDictionary<string, Type>.Empty;
864  }
865  }
866 
867  #endregion
868 }
869 
870 public static class AssemblyExtensions
871 {
877  public static IEnumerable<Type> GetSafeTypes(this Assembly assembly)
878  {
879  // Based on https://github.com/Qkrisi/ktanemodkit/blob/master/Assets/Scripts/ReflectionHelper.cs#L53-L67
880 
881  try
882  {
883  return assembly.GetTypes();
884  }
885  catch (ReflectionTypeLoadException re)
886  {
887  try
888  {
889  return re.Types.Where(x => x != null)!;
890  }
891  catch (InvalidOperationException)
892  {
893  return new List<Type>();
894  }
895  }
896  catch (Exception)
897  {
898  return new List<Type>();
899  }
900  }
901 }
MemoryFileAssemblyContextLoader Acl
ref readonly ImmutableDictionary< string, Type > AssembliesTypes
Provides functionality for the loading, unloading and management of plugins implementing IAssemblyPlu...
bool TryGetACL(Guid id, out LoadedACL acl)
Tries to retrieve the LoadedACL with the given ID or null if none is found. WARNING: External referen...
AssemblyLoadingSuccessState LoadAssembliesFromLocations([NotNull] IEnumerable< string > filePaths, string friendlyName, ref Guid id)
Tries to load all assemblies at the supplied file paths list into the ACl with the given Guid....
IEnumerable< Type > GetTypesByName(string typeName)
Allows iteration over all types, including interfaces, in all loaded assemblies in the AsmMgr who's n...
Action< string, Exception > OnException
Called whenever an exception is thrown. First arg is a formatted message, Second arg is the Exception...
Action< Assembly > OnAssemblyLoaded
Called when an assembly is loaded.
ImmutableList< WeakReference< MemoryFileAssemblyContextLoader > > StillUnloadingACLs
[DEBUG ONLY] Returns a list of the current unloading ACLs.
IEnumerable< LoadedACL > GetAllLoadedACLs()
Returns a list of all loaded ACLs. WARNING: References to these ACLs outside of the AssemblyManager s...
System.Func< LoadedACL, bool > IsReadyToUnloadACL
Used by content package and plugin management to stop unloading of a given ACL until all plugins have...
IEnumerable< Type > GetSubTypesInLoadedAssemblies< T >()
IEnumerable< Type > GetAllTypesInLoadedAssemblies()
Allows iteration over all types (including interfaces) in all loaded assemblies managed by the AsmMgr...
bool IsCurrentlyUnloading
Checks if there are any AssemblyLoadContexts still in the process of unloading.
bool TryGetSubTypesFromACL< T >(Guid id, out IEnumerable< Type > types)
Tries to get types assignable to type from the ACL given the Guid.
bool SetACLToTemplateMode(Guid guid)
Switches the ACL with the given Guid to Template Mode, which disables assembly name resolution for an...
Action< Guid > OnACLUnload
For unloading issue debugging. Called whenever MemoryFileAssemblyContextLoader [load context] is unlo...
AssemblyLoadingSuccessState LoadAssemblyFromMemory([NotNull] string compiledAssemblyName, [NotNull] IEnumerable< SyntaxTree > syntaxTree, IEnumerable< MetadataReference > externalMetadataReferences, [NotNull] CSharpCompilationOptions compilationOptions, string friendlyName, ref Guid id, IEnumerable< Assembly > externFileAssemblyRefs=null)
Compiles an assembly from supplied references and syntax trees into the specified AssemblyContextLoad...
Action< Assembly > OnAssemblyUnloading
Called when an assembly is marked for unloading, before unloading begins. You should use this to clea...
bool TryGetSubTypesFromACL(Guid id, out IEnumerable< Type > types)
Tries to get types from the ACL given the Guid.
AssemblyLoadContext to compile from syntax trees in memory and to load from disk/file....