Tar*_*rik 4 .net c# vb.net assemblies
我正在加载Assembly.LoadFrom()程序集使用,因为程序集位于与Application Base目录不同的路径中.
Dim oAssembly As Assembly = _
Assembly.LoadFrom("C:\\MyFolder\\" + ddlXlate.SelectedItem.ToString() + ".dll")
Run Code Online (Sandbox Code Playgroud)
我Type从该程序集中消耗了一个没有任何问题:
oXML = CType(oAssembly.CreateInstance(sBaseType + ".XlateContainer"), _
XlateBase.XlateContainer)
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试Type从下面的另一个方法中使用此程序集中的a时,会出现问题:
oComboBox.DataSource = _
[Enum].GetValues(Type.GetType(sType + "+ItemEnum," + sAssemblyName))
Run Code Online (Sandbox Code Playgroud)
sAssemblyName是我LoadFrom()实际加载的那个.在它说无法找到装配后,我使用了AssemblyResolve解决了我的问题的事件:
订阅AssemblyResolve活动:
AddHandler AppDomain.CurrentDomain.AssemblyResolve, _
AddressOf MyResolveEventHandler
Run Code Online (Sandbox Code Playgroud)
事件处理程序方法:
Private Shared Function MyResolveEventHandler(ByVal sender As Object, _
ByVal args As ResolveEventArgs) As Assembly
Return Assembly.LoadFrom("C:\\PSIOBJ\\" + args.Name + ".dll")
End Function
Run Code Online (Sandbox Code Playgroud)
我想也许错误发生,因为它找不到我LoadFrom()已经加载的程序集清单文件中定义的依赖程序集但是当我检查时args.Name,我看到它试图加载相同的程序集,之后它工作没有任何问题.因此,在添加更改的事件之前,基本上无法找到已加载程序集中的类型.
我的旧代码正在使用AppDomain.CurrentDomain.Load()和Assembly.Load()方法,他们在没有AssemblyResolve事件的情况下工作正常.我能够Assembly从同一个地方的每个地方到达动态加载的类型AppDomain.
LoadFrom()可以在同一个请求的程序集路径中自动找到依赖项,这可能不是问题,因为它dll需要的一切都在那里.所以起初它看起来像是一个AppDomain问题,因为看起来它似乎可以从Load上下文而不是LoadFrom上下文到达程序集,我现在正在使用LoadFrom上下文.
oAssemblyevertwhere实例来使用加载程序集中的任何类型?Type.GetType(...)方法加载我可以到达任何地方(相同的AppDomain)的程序集?有人可以填写错过的分数并回答我的问题吗?
你可以使用C#,实际上我不喜欢VB.NET,但我必须在Office中使用它.
如果我正确地理解了你的问题,那么你正试图按照以下方式做一些事情:
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
Run Code Online (Sandbox Code Playgroud)
您遇到的问题是,无论您使用何种形式的程序集加载,当库与可执行文件不在同一路径中时,变量type将始终存在null.
您遇到的是.NET中程序集的不同加载上下文的问题.简而言之,通常有三种,实际上有四种类型的加载上下文:
BaseDirectory参考资料)和PrivatePath中的程序集(请参阅参考资料RelativeSearchPath).Assembly.Load(string,..)使用这个上下文.Assembly.LoadFrom.Assembly.Load(byte\[\],..)和Assembly.LoadFile方法,或在加载动态组件不保存到磁盘中,使用这个上下文.在一个上下文中加载的类型与另一个上下文不兼容(您甚至无法将相同类型从一个上下文转换为另一个上下文!).专门针对一个上下文操作的方法无法访问另一个上下文.除非您稍微帮助该方法,否则Type.GetType(string) 只能在默认上下文中加载类型.
这正是你遇到的.当程序集dll在你的应用程序的路径中时,一切正常.一旦你移动它,事情开始崩溃.
更具体地说:
当您调用时Type.GetType(string),它将查询路径中的所有静态引用的程序集,并在当前路径(AppDomain.BaseDirectory),GAC和in中查询动态加载的程序集AppDomain.RelativeSearchPath.不幸的是,相对搜索路径必须相对于基目录.
结果:
这种行为的结果是的GetType并不能简单地检查所有加载的程序集.相反,它以相反的方式工作,它确实:
Assembly.LoadFileNotFoundException,这可能相当混乱).您可以自己测试:Assembly.Load当您只提供程序集名称时,它将无法工作.
有几种解决方案.一个你已经为自己命名并保持装配对象的一个.还有一些,每个都有自己的缺点:
使用GetType()实例化对象本身,而不是静态方法Type.GetType(string).这样做的好处是你不需要类型的汇编限定名称,这可能很难得到(在你的例子中,你没有说你如何设置sAssemblyName,但这不是你需要浮动的东西吗? ).
使用通用解析程序检查已加载的程序集并返回已加载的程序集.你不需要再打电话LoadFrom.我对以下内容进行了测试,结果非常出色:
// 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;
Run Code Online (Sandbox Code Playgroud)同时使用AppDomain.CurrentDomain.AssemblyLoad和.AssemblyResolve事件.第一个用于记忆字典缓存中的每个已加载的程序集(通过全名),第二个用于通过按名称获取其中的值来探测该字典.这实现起来相对简单,并且可能比先前的解决方案稍微好一些.
使用:这不起作用.GetType 首先尝试加载程序集,当失败时,它不会尝试解析类型,并且此事件永远不会触发.AppDomain.CurrentDomain.TypeResolve事件处理程序.我没试过这个,所以我不确定它会在你的场景中起作用.
将要解析的库添加到GAC或应用程序的任何(相对)路径.这是迄今为止最简单的解决方案.
添加到app.config的路径.这仅适用于强类型程序集,在这种情况下,您可以轻松地将它们加载到GAC中.非强类型程序集仍必须位于当前应用程序的相对路径中.
静态方法组Type.GetType(..)在第一次看到加载的程序集时表现得相当不直观.一旦理解了几个上下文背后的想法,尝试将程序集放在默认上下文中.如果无法做到这一点,您可以创建一个AssemblyResolve事件处理程序,这一点并不难以实现.