Проблема здесь в том, что загружаются оба имени Framework
со старым Framework
. На самом деле .NET не волнует, что оба определения IPlugin
совпадают. Они из разных сборок, поэтому они разные (я немного озадачен, почему он поднимет InvalidCastException
, так как такой бросок просто вернет null
в случае неудачи).
вариант A
Один из методов, который все еще будет использовать класс, будет использовать рефлексию, но это может иметь большое значение, когда в игру вступит больше типов, размещенных в Framework
. все они должны быть доступны с помощью отражения.
Вы можете создать оболочки, чтобы скрыть отражение, используя что-то вроде этого:
public class PluginWrapper : IPlugin
{
object fObj;
PropertyInfo fNameProperty;
MethodInfo fGetOtherMethod;
public PluginWrapper(object o)
{
fObj = o;
fNameProperty = o.GetType().GetInterface("IPlugin").GetProperty("Name");
fGetOtherMethod = o.GetType().GetInterface("IPlugin").GetMethod("GetOther", new Type[] { typeof(string) });
}
public string Name
{
get { return (string)fNameProperty.GetValue(fObj, null); }
}
public IOther GetOther(string name)
{
object result = fGetOtherMethod.Invoke(fObj, new object[] { name });
if (result == null)
return null;
return new OtherWrapper(result);
}
}
Тогда вы можете использовать свой объект следующим образом:
IPlugin iPlugIn = new PluginWrapper(o);
вариант B
Я могу придумать другой путь. Я не уверен, стоит ли вам идти по этой дороге, поскольку в моих глазах это выглядит как «хакерство», но я все равно поделюсь им и позволю вам решить.
Вы можете разрешить загрузку сборки, используя байтовый поток вместо AssemblyName. Таким образом, он не сможет разрешить другую Framework
сборку и даст вам возможность внести изменения в событие AssemblyResolve
:
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
Assembly dll = Assembly.Load(File.ReadAllBytes(@"C:\Program Files\WinApp\Assembly.dll"));
object o = Activator.CreateInstance(dll.GetType("WinApp.ClassThatImplementsIPlugIn"));
IPlugin iPlugIn = o as IPlugin;
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name.ToLower().StartsWith("framework,"))
return typeof(IPlugin ).Assembly;
return null;
}
Это может быть немного сложнее, поскольку тем самым вы дадите .NET обещание, что сборка совместима и что вы готовы пойти на риск. Если что-то не совместимо, могут быстро возникнуть проблемы.
Другие опции
Возможно, могут быть и способы решения проблемы с использованием элемента bindingredirect
в app.config
. Я не совсем знаю подробности о том, как это работает, но, возможно, стоит немного разобраться.