Goop
Goop

Reputation: 21

C# - How do I refer to the same Type in two different dlls?

I'm working on an API and plugin using it. I am trying to get the class of Plugin that refers to the Mod class in the API, and in the API, when IssignbleFrom(type) comes a false. how can i do?

API.dll

Loader.cs

...
string[] files = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "Mods"), "*.dll");
            foreach (var file in files)
            {
                AddLog(" mod loader : " + file);
                try
                {
                    var asm = Assembly.LoadFile(file);
                    foreach (Type type in asm.GetTypes())
                    {
AddLog("[Debug] " + type + " > " + type.BaseType + " > " + type.IsSubclassOf(typeof(Mod)) + " > " + typeof(Mod).IsAssignableFrom(type));
                        if (type.IsSubclassOf(typeof(Mod)) && type != typeof(Mod))
                        {
                            Mod mod = (Mod) Activator.CreateInstance(type);
                            mod.Register();

                            AddLog(" Mod Loaded : " + type);
                        }
                    }
                }
                catch (Exception e)
                {
                    AddLog(" Failed to create instance of mod.\n" + e.ToString());
                }
...

Mod.cs

namespace SLModder {
    public abstract class Mod {
        public abstract void Register();
    }
}

Plugin.dll

Main.cs

namespace PracticePlugin {
    public class Main : Mod 
    {
        public override void Register() {
            ServerConsole.AddLog("Plugin Enabled");
        }
    }
}

Console

[Debug] PracticePlugin.Main > SLModder.Mod > false > false

Upvotes: 1

Views: 336

Answers (1)

Eric Lippert
Eric Lippert

Reputation: 660088

TLDR: That LoadFile is almost certainly the wrong way to load an assembly for your use case.

Longer explanation:

Assemblies are loaded into an assembly context; assemblies in different contexts are considered different assemblies, and therefore all of their types are different as well.

For example, an assembly that is loaded with Load is considered a different assembly than one that is loaded by LoadFrom, even if 100% of the bytes of those assemblies are equal.

By incorrectly using Load or LoadFrom or LoadFile you can easily end up in a situation where you have what looks like two of the same type in memory, but they compare as unequal. Your first step in debugging the problem should be ensuring that you are loading the assemblies into the correct context so as to prevent this confusing situation.

I have made this mistake myself while working on plugin infrastructures; it can be quite tricky to diagnose.

See https://blogs.msdn.microsoft.com/suzcook/2003/07/21/assembly-identity/ for more information on this topic; if I recall correctly, Suzanne was one of the implementers of the assembly loading logic.

See also the documentation on LoadFile, at https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.loadfile?view=netframework-4.8, which notes:

Use the LoadFile method to load and examine assemblies that have the same identity, but are located in different paths. LoadFile does not load files into the load-from context, and does not resolve dependencies using the load path, as the LoadFrom method does. LoadFile is useful in this limited scenario because LoadFrom cannot be used to load assemblies that have the same identities but different paths; it will load only the first such assembly.

And see also https://learn.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext?view=netcore-3.0, which states:

The Assembly.LoadFile(String) method isolates the assemblies it loads by instantiating the most basic AssemblyLoadContext. It has a simplistic isolation scheme that loads each assembly in its own AssemblyLoadContext with no dependency resolution.

In short: the problem is likely because your assemblies are being loaded into an unexpectedly different context. You need to ensure that all references to assemblies that you intend to be identical are loaded into the appropriate context.


All that said: you should strongly consider using MEF or MAF instead of trying to roll your own plugin infrastructure. See Choosing between MEF and MAF (System.AddIn) for details.

Upvotes: 2

Related Questions