Reputation: 144
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?
Projects:
Lib1 and Lib2 share a code file via symlink:
namespace Shared
{
public class SharedClass
{
public static string Key { get; set; }
}
}
Lib1 Plugin:
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);
}
}
}
Lib2 Plugin:
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);
}
}
}
Console:
static class Functions
{
public static IEnumerable<Type> FindDerivied(Assembly asm, Type baseType)
{
try
{
return asm.GetTypes().Where(t => baseType.IsAssignableFrom(t) && t != baseType);
}
catch (Exception e)
{
return new List<Type>();
}
}
}
class Program
{
static void Main(string[] args)
{
var di = new DirectoryInfo("Plugins");
var bos = new List<Plugin>();
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 => type.Name == "SharedClass")
.ToList();
foreach (var export in exports)
{
Console.WriteLine(export.FullName);
}
}
}
}
}
Output:
Lib1 Key
Lib2 Key
Lib1 Key
Lib2 Key
Shared.SharedClass
Shared.SharedClass
How does it know the difference!?
Upvotes: 0
Views: 446
Reputation: 239636
There is nothing preventing two assemblies from declaring types with identical fully-qualified names. Whether those types are similar or completely different (or here, are actually defined in the same source file) is irrelevant.
Although the page discussing extern alias
uses "two versions of the same assembly" as it's motivating example, it's describing the general mechanism that would allow any consuming application to consume two (or more) libraries that declare types with identical fully-qualified type names.
You might have to reference two versions of assemblies that have the same fully-qualified type names. For example, you might have to use two or more versions of an assembly in the same application. By using an external assembly alias, the namespaces from each assembly can be wrapped inside root-level namespaces named by the alias, which enables them to be used in the same file.
And further, what this comes down to is that a fully-qualified type name, by itself, does not uniquely identify a specific type. A type's identity includes not just its name but also its assembly.
Upvotes: 2
Reputation: 2397
You did not share compiled code, but the file SharedClass.cs file. So the libraries don't know about each other's SharedClass, and hence there is nothing which should "know the difference". At compile time, each plugin gets linked to the SharedClass contained in the same assembly, and at runtime there are two SharedClasses which do not know anything about each other.
Upvotes: 0