title: Why does AppDomain still have a reference to a dynamically loaded assembly after the unload event fires?
body: <p>This is a netcore question, not a NETFX question.</p>
  <p>This workup demonstrates the behaviour. You will need to supply an assembly for it to load and make the name in the code match the name in the file system.</p>
  <pre><code>using System;
  using System.IO;
  using System.Linq;
  using System.Reflection;
  using System.Runtime.Loader;
  using System.Threading;
  
  namespace unload
  {
    public class ALC : AssemblyLoadContext
    {
      public ALC() : base(isCollectible: true) { }
      protected override Assembly Load(AssemblyName name) =&gt; null;
    }
    class Program
    {
      static void Main(string[] args)
      {
        var alc1 = new ALC();
        var alc2 = new ALC();
        Assembly assy1, assy2;
        using (var stream = new FileStream(&quot;./assy.dll&quot;, FileMode.Open))
          assy1 = alc1.LoadFromStream(stream);
        using (var stream = new FileStream(&quot;./assy.dll&quot;, FileMode.Open))
          assy2 = alc2.LoadFromStream(stream);
        var currentDomain = AppDomain.CurrentDomain;
        alc1.Unloading += alc =&gt;
        {
          Console.WriteLine(&quot;alc1 HAS UNLOADED&quot;);
        };
        alc2.Unloading += alc =&gt;
        {
          Console.WriteLine(&quot;alc2 HAS UNLOADED&quot;);
        };
        alc1.Unload();
        assy1 = null;
        alc1 = null;
        alc2.Unload();
        assy2 = null;
        alc2 = null;
        GC.Collect(); //no refs and force GC
        Thread.Sleep(100); // let other things complete
        var duplicates = from a in currentDomain.GetAssemblies() group a by a.FullName into g where g.Count() &gt; 1 select g;
        while (duplicates.Any())
        {
          GC.Collect();
          Thread.Sleep(500);
          duplicates = from a in currentDomain.GetAssemblies() group a by a.FullName into g where g.Count() &gt; 1 select g;
          Console.WriteLine(string.Join(&quot;, &quot;, duplicates.Select(g =&gt; $&quot;{g.Count()} {g.Key}&quot;)));
        }
      }
    }
  }
  </code></pre>
  <p>If you run this you will see that unload events fire but both instances of the assembly continue to be found by <code>currentDomain.GetAssemblies()</code>.</p>
  <p>Documentation for <code>AssemblyLoadContext.Unload()</code> says</p>
  <blockquote>
  <ul>
  <li>An AssemblyLoadContext can only be unloaded if it is collectible.</li>
  <li>Unloading will occur asynchronously.</li>
  <li>Unloading will not occur while there are references to the AssemblyLoadContext</li>
  </ul>
  </blockquote>
  <p>I believe this example meets all these requirements. What else might be interfering? Are there any known bugs with this?</p>
  <p>Is it possible the assemblies actually unloaded but currentDomain has failed to update its bookkeeping? How would you tell?</p>