我有一个部署在客户端上的现有.NET 2.0 Win Forms解决方案.为了这个场景,我们称之为'WinApp.exe'.WinApp.exe直接引用名为"Assembly.dll"的专用程序集.Assembly.dll直接引用另一个名为"Framework.dll"的程序集.Framework.dll中是一个名为"IPlugIn"的类型.Framework.dll没有强名称,但程序集的版本是1.0.Assembly.dll中有一个类从Framework.dll实现IPlugIn.
我有另一个名为'Framework.exe'的.NET 2.0 Win Forms解决方案.此Win Forms项目还直接引用Framework.dll,其中定义了"IPlugIn"类型.Framework.dll没有强名称,但此程序集的版本是2.0.一点一点,Framework.dll v2中的'IPlugIn'与Framework.dll v1中的'IPlugIn'相同.Framework.exe中的代码使用反射来加载WinApp中的IPlugIn实现:
AssemblyName an = AssemblyName.GetAssemblyName("C:\\Program Files\\WinApp\\Assembly.dll");
Assembly dll = Assembly.Load(an);
object o = Activator.CreateInstance(dll.GetType("WinApp.ClassThatImplementsIPlugIn"));
IPlugIn iPlugIn = o as IPlugIn;
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.这段代码有效!现在这是麻烦的部分.我需要为Framework.dll v2分配一个强名称,以便它可以放在GAC中.但是,WinApp及其依赖程序集将不会重新部署 - 它必须继续使用它当前使用的相同版本的程序集.当我给Framework.dll v2一个强名称并重新编译并运行Framework.exe时,当上面的代码执行时,我在线上收到一个"InvalidCastException":
IPlugIn iPlugIn = o as IPlugIn;
Run Code Online (Sandbox Code Playgroud)
我想我收到了这个例外,因为现在一个版本的Framework.dll有一个强名称,运行时正在将类型"IPlugIn"视为完全不同的类型.我需要知道是否有任何方法可以解决这个问题.同样,要求是:
提前致谢!
乍得
这里的问题是加载了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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后您可以按如下方式使用您的对象:
IPlugin iPlugIn = new PluginWrapper(o);
Run Code Online (Sandbox Code Playgroud)
选项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;
}
Run Code Online (Sandbox Code Playgroud)
这可能有点棘手,因为您将向 .NET 承诺程序集是兼容的,并且您准备承担风险。如果事物不兼容,那么问题可能很快就会开始出现。
其他选项
也许还有使用bindingredirect中的元素来解决问题的方法app.config。我不太了解其工作原理的详细信息,但可能值得研究一下。
| 归档时间: |
|
| 查看次数: |
675 次 |
| 最近记录: |