Reputation: 21
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
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