title: Two Dlls Loaded with Assembly.LoadFrom Define the Same Class and Work Fine?
body: <p>This is freaking me out, and I'm guessing it's because I'm severely misunderstanding something basic about how assemblies get loaded. I was not expecting this to work, can someone explain why it does?</p>
  
  <p>Projects:</p>
  
  <ul>
  <li>Plugins has the definition of a plugin class</li>
  <li>Lib1 References Plugins and defines a plugin class</li>
  <li>Lib2 References Plugins and defines a plugin class</li>
  <li>Console references Plugins and looks for dlls near itself to load</li>
  </ul>
  
  <p>Lib1 and Lib2 share a code file via symlink:</p>
  
  <pre><code>namespace Shared
  {
      public class SharedClass
      {
          public static string Key { get; set; }
      }
  }
  </code></pre>
  
  <p>Lib1 Plugin:</p>
  
  <pre><code>namespace Lib1
  {
      public class Lib1Plugin : Plugin
      {
          public override void Load()
          {
              SharedClass.Key = "Lib1 Key";
  
              Console.WriteLine(SharedClass.Key);
          }
  
          public override void Run()
          {
              Console.WriteLine(SharedClass.Key);
          }
      }
  }
  </code></pre>
  
  <p>Lib2 Plugin:</p>
  
  <pre><code>namespace Lib2
  {
      public class Lib2Plugin : Plugin
      {
          public override void Load()
          {
              SharedClass.Key = "Lib2 Key";
  
              Console.WriteLine(SharedClass.Key);
          }
  
          public override void Run()
          {
              Console.WriteLine(SharedClass.Key);
          }
      }
  }
  </code></pre>
  
  <p>Console:</p>
  
  <pre><code>    static class Functions
      {
          public static IEnumerable&lt;Type&gt; FindDerivied(Assembly asm, Type baseType)
          {
              try
              {
                  return asm.GetTypes().Where(t =&gt; baseType.IsAssignableFrom(t) &amp;&amp; t != baseType);
              }
              catch (Exception e)
              {
                  return new List&lt;Type&gt;();
              }
          }
      }
      class Program
      {
          static void Main(string[] args)
          {
              var di = new DirectoryInfo("Plugins");
  
              var bos = new List&lt;Plugin&gt;();
              if (di.Exists)
              {
                  var dlls = di.EnumerateFiles();
                  foreach (var dll in dlls)
                  {
                      var asm = Assembly.LoadFrom(dll.FullName);
  
                      var builders = Functions.FindDerivied(asm, typeof(Plugin));
                      foreach (var builder in builders)
                      {
                          var bo = (Plugin)Activator.CreateInstance(builder);
  
                          bo.Load();
                          bos.Add(bo);
                      }
                  }
  
                  foreach (var bo in bos)
                  {
                      bo.Run();
                  }
  
                  var asms = AppDomain.CurrentDomain.GetAssemblies();
                  foreach (var asm in asms)
                  {
                      var exports =
                          asm.GetExportedTypes().Where(type =&gt; type.Name == "SharedClass")
                          .ToList();
  
                      foreach (var export in exports)
                      {
                          Console.WriteLine(export.FullName);
                      }
                  }
              }
          }
      }
  </code></pre>
  
  <p>Output:</p>
  
  <pre><code>Lib1 Key
  Lib2 Key
  Lib1 Key
  Lib2 Key
  Shared.SharedClass
  Shared.SharedClass
  </code></pre>
  
  <p>How does it know the difference!?</p>