AssemblyLoaderCache.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. namespace Atomic.Bootstrap
  6. {
  7. internal class AssemblyLoaderCache
  8. {
  9. private readonly ConcurrentDictionary<AssemblyName, object> _assemblyLoadLocks = new ConcurrentDictionary<AssemblyName, object>(AssemblyNameComparer.Ordinal);
  10. private readonly ConcurrentDictionary<AssemblyName, Assembly> _assemblyCache = new ConcurrentDictionary<AssemblyName, Assembly>(AssemblyNameComparer.Ordinal);
  11. public Assembly GetOrAdd(AssemblyName name, Func<AssemblyName, Assembly> factory)
  12. {
  13. Console.WriteLine("AssemblyLoaderCache:GetOrAdd {0}", name.Name);
  14. // If the assembly was already loaded use it
  15. Assembly assembly;
  16. if (_assemblyCache.TryGetValue(name, out assembly))
  17. {
  18. return assembly;
  19. }
  20. var loadLock = _assemblyLoadLocks.GetOrAdd(name, new object());
  21. try
  22. {
  23. // Concurrently loading the assembly might result in two distinct instances of the same assembly
  24. // being loaded. This was observed when loading via Assembly.LoadStream. Prevent this by locking on the name.
  25. lock (loadLock)
  26. {
  27. if (_assemblyCache.TryGetValue(name, out assembly))
  28. {
  29. // This would succeed in case the thread was previously waiting on the lock when assembly
  30. // load was in progress
  31. return assembly;
  32. }
  33. assembly = factory(name);
  34. if (assembly != null)
  35. {
  36. _assemblyCache[name] = assembly;
  37. }
  38. }
  39. }
  40. finally
  41. {
  42. _assemblyLoadLocks.TryRemove(name, out loadLock);
  43. }
  44. return assembly;
  45. }
  46. private class AssemblyNameComparer : IEqualityComparer<AssemblyName>
  47. {
  48. public static IEqualityComparer<AssemblyName> Ordinal = new AssemblyNameComparer();
  49. public bool Equals(AssemblyName x, AssemblyName y)
  50. {
  51. return
  52. string.Equals(x.Name, y.Name, StringComparison.Ordinal) &&
  53. string.Equals(x.CultureName ?? "", y.CultureName ?? "", StringComparison.Ordinal);
  54. }
  55. public int GetHashCode(AssemblyName obj)
  56. {
  57. var hashCode = 0;
  58. if (obj.Name != null)
  59. {
  60. hashCode ^= obj.Name.GetHashCode();
  61. }
  62. hashCode ^= (obj.CultureName ?? "").GetHashCode();
  63. return hashCode;
  64. }
  65. }
  66. }
  67. }