我使用Assembly.LoadFrom()
加载程序集,因为程序集位于与Application Base目录不同的路径中。
Dim oAssembly As Assembly = _
Assembly.LoadFrom("C:\\MyFolder\\" + ddlXlate.SelectedItem.ToString() + ".dll")
我从该程序集中消耗Type
没有任何问题:
oXML = CType(oAssembly.CreateInstance(sBaseType + ".XlateContainer"), _
XlateBase.XlateContainer)
但是,当我尝试从另一个方法中使用此程序集中的Type
时会出现问题,如下所示:
oComboBox.DataSource = _
[Enum].GetValues(Type.GetType(sType + "+ItemEnum," + sAssemblyName))
sAssemblyName
实际上是我使用LoadFrom()
加载的那个。在它说找不到程序集之后,我使用AssemblyResolve
事件解决了我的问题:
订阅AssemblyResolve
活动:
AddHandler AppDomain.CurrentDomain.AssemblyResolve, _
AddressOf MyResolveEventHandler
事件处理程序方法:
Private Shared Function MyResolveEventHandler(ByVal sender As Object, _
ByVal args As ResolveEventArgs) As Assembly
Return Assembly.LoadFrom("C:\\PSIOBJ\\" + args.Name + ".dll")
End Function
我想也许会发生错误,因为它找不到我使用LoadFrom()
加载的程序集清单文件中定义的依赖程序集但是当我检查args.Name
时,我看到它正在尝试加载组装后,它没有任何问题。因此,在添加更改的事件之前,基本上无法找到已加载程序集中的类型。
我的旧代码使用了AppDomain.CurrentDomain.Load()
和Assembly.Load()
方法,并且在没有AssemblyResolve
事件的情况下工作正常。我能够从同一Assembly
内的每个位置到达动态加载AppDomain
的类型。
LoadFrom()
可以在同一个请求的程序集路径中自动找到依赖项,这可能不是问题,因为dll
需要的所有内容都存在。所以起初它看起来像AppDomain
问题,因为看起来它似乎可以从Load
上下文而不是LoadFrom
上下文到达程序集,我现在正在使用LoadFrom
上下文。
oAssembly
实例evertwhere来使用加载程序集中的任何类型?Type.GetType(...)
方法加载我可以到达任何地方(相同的AppDomain)的程序集?有人可以填写错过的分数并回答我的问题吗?
你可以使用C#,实际上我不喜欢VB.NET,但我必须在Office中使用它。
答案 0 :(得分:9)
如果我正确地理解了你的问题,那么你正试图按照以下方式做点什么:
var asm = Assembly.LoadFrom(@"D:\Projects\_Libraries\FluentNH 1.1\Castle.Core.dll");
var obj = asm.CreateInstance("Castle.Core.GraphNode");
var type = Type.GetType(obj.GetType().AssemblyQualifiedName, true); // fails
您遇到的问题是,无论您使用何种形式的程序集加载,当库与可执行文件不在同一路径中时,变量type
将始终为null
。
您遇到的问题是different loading contexts for assemblies in .NET。通常有三种,实际上有四种类型的加载上下文,简而言之:
BaseDirectory
)和PrivatePath中的程序集(请参阅RelativeSearchPath
)。 Assembly.Load(string,..)
使用此上下文。Assembly.LoadFrom
。Assembly.Load(byte\[\],..)
和Assembly.LoadFile
方法加载程序集时,或者加载未保存到磁盘的动态程序集时,将使用此上下文。在一个上下文中加载的类型与另一个上下文不兼容(您甚至无法将相同的类型从一个上下文转换为另一个上下文!)。专门针对一个上下文操作的方法无法访问另一个上下文。 Type.GetType(string)
只能在默认上下文中加载类型,除非您稍微帮助该方法。
这正是您遇到的。当程序集dll在你的应用程序的路径中时,一切正常。一旦你移动它,事情开始崩溃。
更具体地说:
当您致电Type.GetType(string)
时,它会查询路径中所有静态引用的程序集,并在当前路径(AppDomain.BaseDirectory
),GAC和{{1}中查询动态加载的程序集和。不幸的是,相对搜索路径必须相对于基本目录。
<强>结果:强>
此行为的结果是GetType 不只检查所有已加载的程序集。相反,它反过来工作,它确实:
AppDomain.RelativeSearchPath
Assembly.Load
,这可能相当混乱)。您可以自己测试一下:当您只提供程序集名称时,FileNotFoundException
将无效。
有几种解决方案。一个你已经为自己命名并保持装配对象的一个。还有一些,每个都有自己的缺点:
对实例化对象本身使用Assembly.Load
,而不是静态方法GetType()
。这样做的好处是,您不需要类型的程序集限定名称,这可能很难获得(在您的示例中,您没有说明如何设置Type.GetType(string)
,但这也不是你需要漂浮吗?)。
使用通用解析程序检查已加载的程序集并返回已加载的程序集。您无需再次致电sAssemblyName
。我对以下内容进行了测试,结果非常出色:
LoadFrom
同时使用AppDomain.CurrentDomain.AssemblyLoad和.AssemblyResolve事件。第一个用于记忆字典缓存中的每个已加载的程序集(按全名),第二个用于通过按名称从中获取值来探测该字典。这实现起来相对简单,并且可能比以前的解决方案稍微好一些。
使用:这不起作用。 GetType first 尝试加载程序集,当失败时,它不会尝试解析类型,并且此事件永远不会触发。// works for any loaded assembly, regardless of the path
private static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
{
// you may not want to use First() here, consider FirstOrDefault() as well
var asm = (from a in AppDomain.CurrentDomain.GetAssemblies()
where a.GetName().FullName == args.Name
select a).First();
return asm;
}
// set it as follows somewhere in the beginning of your program:
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
事件处理程序。我没试过这个,所以我不确定它会在你的场景中起作用。
将要解析的库添加到GAC或应用程序的任何(相对)路径。这是迄今为止最简单的解决方案。
将路径添加到app.config。这仅适用于强类型程序集,在这种情况下,您可以轻松地将它们加载到GAC中。非强类型程序集仍必须位于当前应用程序的相对路径中。
静态方法组AppDomain.CurrentDomain.TypeResolve
在第一次看到加载的程序集时表现得相当不直观。一旦理解了几个上下文背后的想法,尝试将程序集放在默认上下文中。如果无法做到这一点,您可以创建一个Type.GetType(..)
事件处理程序,这对于一般情况下并不困难。
答案 1 :(得分:0)
尝试仅在args.name正确的地方返回程序集...
Private Shared Function MyResolveEventHandler(ByVal sender As Object, _
ByVal args As ResolveEventArgs) As Assembly
//Ex: if (args.name.contains("XLATEBASE")) {Return Assembly.LoadFrom("C:\\PSIOBJ\\" + args.Name + ".dll")}
End Function