Не могу привести объект к родительскому интерфейсу
Имеется Visual Studio 2022, C#, .Net Framework 4.6.1
Есть решение, которое до недавнего времени работало: В решении три проекта:
- MainProject - запускаемый. Пространство имён Proj.Main
- Common - библиотека классов. Пространство имён Proj.Common
- 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 шт):
У вас сборка Common по какой-то причине загрузилась несколько раз, и в итоге интерфейс IPlugin в MainProject и в Common стал двумя разными интерфейсами.
Для начала убедитесь, что сборка Common присутствует на диске только в одном месте, иметь два разных Common.dll - это самый простой способ получить проблему.
Если удаление лишних файлов не помогло - возможно, проблема с методом LoadFrom, и надо вместо него использовать что-то ещё.