Не могу привести объект к родительскому интерфейсу

Имеется Visual Studio 2022, C#, .Net Framework 4.6.1

Есть решение, которое до недавнего времени работало: В решении три проекта:

  1. MainProject - запускаемый. Пространство имён Proj.Main
  2. Common - библиотека классов. Пространство имён Proj.Common
  3. Plugin - библиотека классов. Пространство имён Proj.Plugin

В проекте Common описан интерфейс

public interface IPlugin 
{
    string Name; // Имя плагина
    string Description; // Описание плагина
    int Execute(IWin32Window Win, object[] Params);
}

Проект Plugin содержит ссылку на проект Common и содержит следующий код

using Proj.Common;

namespace Proj.Plugin
{
    public class MyPlugin : IPlugin
    {
        public string Name => "My Plugin";
        public string Description => "This is my plugin";
        public int Execute(IWin32Window Win, object[] Params)
        {
            int ret = 0;
            ...
            return ret;
        }
        public MyPlugin() { }
    }
}

В проекте MainProject есть ссылка на проект Common и имеется следующий код:

using System.IO;
using System.Reflection;
using Proj.Common;

namespace Proj.Main
{
  public class MyApp
  {
    private Dictionary<string, IPlugin> plugins = new Dictionary<string, IPlugin>();
    private void LoadPlugins(string pt)
    {
        string[] dlls = new string[0];
        if (Directory.Exists(pt))
        {
            try
            {
                dlls = Directory.GetFiles(pt, "*.dll");
            }
            catch { return; }

            int loaded = 0;
            foreach (string dll in dlls)
            {
                if (!File.Exists(dll))
                    continue;
                Assembly PluginAssembly = null;
                try
                {
                    PluginAssembly = Assembly.LoadFrom(dll);
                }
                catch (Exception ex)
                {
                    err += $"Load {dll}:\r\n{ex.Message}\r\n\r\n";
                    iserr = true;
                    //сборка может быть не загружена по разным причинам, 
                    continue;
                }

                //В одной сборке может быть объявлено несколько типов.
                Type[] allTypes = PluginAssembly.GetExportedTypes();
                foreach (Type t in allTypes)
                {
                    //Если t - класс и, в нашем случае, наследует IPlugin
                    if (t.IsClass && t.GetInterface(nameof(IPlugin)) != null)
                    {
                        try
                        {
                            //создаем класс
                            Object oc = Activator.CreateInstance(t);
                            var plugin = (IPlugin)oc; // <== ТУТ ПРОИСХОДИТ BIG BADDABOOM!!!
                            //и добавляем его в коллекцию плагинов
                            plagins.Add(Name, plugin);
                        }
                        catch (Exception ex)
                        {
                            err += $"Create instance {t}:\r\n{ex.Message}\r\n\r\n";
                            iserr = true;
                         }
                    }
                }
            }
        }
    }
  }
}

До недавнего времени всё работало отлично. Но после очередной сборки во время преобразования объекта oc к интерфейсу IPlugin выкидывается System.InvalidCastException: "Не удалось привести тип объекта "Proj.Plugin.MyPlugin" к типу "Proj.Common.IPlugin"."

Подскажите, почему, вдруг, эта конструкция перестала работать и как это победить?

Пробовал вместо

if (t.IsClass && t.GetInterface(nameof(IPlugin)) != null)

использовать

if (t.IsClass && typeof(IPlugin).IsAssignableFrom(t)) 

В этом варианте попадания в then не происходит, typeof(IPlugin).IsAssignableFrom(t) всегда возвращает false


Ответы (1 шт):

Автор решения: Pavel Mayorov

У вас сборка Common по какой-то причине загрузилась несколько раз, и в итоге интерфейс IPlugin в MainProject и в Common стал двумя разными интерфейсами.

Для начала убедитесь, что сборка Common присутствует на диске только в одном месте, иметь два разных Common.dll - это самый простой способ получить проблему.

Если удаление лишних файлов не помогло - возможно, проблема с методом LoadFrom, и надо вместо него использовать что-то ещё.

→ Ссылка