Knackname
Knackname

Reputation: 21

How to prevent Godot C# from loading an additional instance of a common library

In Godot I'm trying to load in C# plugins from dll files.

However, when they share a reference with a library the main program also references, the referenced library is loaded in a second time.

With two instances of the same library, I'm unable to use classes implementing the common type in the main program because it technically comes from a different instance of the library.

I believe this is happening because Godot loaded the instance of the Library it's using into a different context from the context I'm using to load in the plugin, that way it's not seeing that the Library is already loaded and loads it for the current context.

If that is true, I need some way to check what context godot was already using, and some way to specify that I want to load into that context as well. But I have no idea how to go about doing that and for the past several days have failed to find anything.

I made a minimal example with just the problem

In Library.dll:

namespace Library
{
    public interface ICommonInterface
    {
    }
}

In Plugin.dll (references Library.dll)

using Library;

namespace Plugin
{
    public class Implementation : ICommonInterface
    {
    }
}

In the Godot Script (references Library.dll)

var commonType = typeof(ICommonInterface);

var dll = Assembly.LoadFrom("Plugin.dll");

foreach (var type in dll.ExportedTypes)
{
  if (type.IsAssignableTo(commonType))
  {
    // This is what should execute, but the commonType here is from a different instance of the library
    // than the plugin is using so it's not the same
  }
  else
  {
    // Proving that the library is being loaded a second time...
    Type otherInterfaceType = type.GetInterfaces()
                                  .Where(interfaceType => interfaceType.Name
                                                                       .Equals(commonType.Name,
                                                                               StringComparison.Ordinal))
                                  .FirstOrDefault();
    if (otherInterfaceType != null
        && otherInterfaceType  != commonType)
    {
        // This is what does execute.
        // This means that there's a different interface with the same name.
        // Checking, the assembly the otherInterfaceType is from has
        // the exact same name, version, and is loaded from the same filepath
        // and it makes me very sad.
    }
  }
}

Upvotes: 1

Views: 299

Answers (1)

Knackname
Knackname

Reputation: 21

I figured out a solution:

You can get the AssemblyLoadContect from the assembly of a type you know is in the right context (in this case the ICommonInterface) and use that to load in other assemblies. That way it's in the right context and the dependancy that was already loaded is seen and not loaded again.

var context = AssemblyLoadContext.GetLoadContext(typeof(ICommonInterface).Assembly);
var dll = context.LoadFromAssemblyPath("Plugin.dll");

Upvotes: 0

Related Questions