我目前正在努力在运行时从多个但相同的程序集中实例化一个类。这是我的设置:
我有一个本机可执行文件,可以在运行时加载多个DLL。由于我的“目标DLL”是.Net程序集,我执行以下操作(对于每个目标DLL!):
加载C ++ / CLI DLL(又名DynamicLoader
)以获得本机和.Net世界之间的桥梁。之后,将创建目标DLL中的实际类的实例。
为了能够在运行时卸载目标.Net DLL,我实现了一个基于http://www.codeproject.com/Articles/8832/Plug-in-Manager的类似插件的系统。
它的简短摘要:DynamicLoader有两个类LocalLoader
和RemoteLoader
。在{root“AppDomain(在加载第一个C ++ / CLI DLL时创建)创建LocalLoader
的实例。然后,此LocalLoader
创建一个新的“目标AppDomain”并将RemoteLoader
实例化到其中。然后,此RemoteLoader
将加载目标程序集并实例化目标类。
所以我有2个以上的AppDomains。一个AppDomain将由本机可执行文件自动创建,加载第一个C ++ / CLI DLL和每个“目标AppDomain”一个AppDomain。
每个目标DLL都有自己的DynamicLoader
程序集副本,每个目标DLL都将驻留在自己的目录中。
我当前的问题在于RemoteLoader
被实例化的时候。首先,一些来源向您展示我正在做什么(没有捕获线):
void LocalLoader::InitializeRemoteLoader()
{
// Load the RemoteLoader assembly (which is actually the current one)
Assembly^ remoteLoaderAssembly = Assembly::GetAssembly(DynamicLoader::RemoteLoader::typeid);
String^ remoteLoaderCodeBase = remoteLoaderAssembly->CodeBase;
// Create new AppDomainSetup with appropriate name and base directory.
AppDomainSetup^ appDomainSetup = gcnew AppDomainSetup();
appDomainSetup->ApplicationName = m_targetAssemblyName + "_AppDomain";
appDomainSetup->ApplicationBase = Path::GetDirectoryName(remoteLoaderAssembly->Location);
appDomainSetup->PrivateBinPath = String::Empty;
// Create AppDomain for RemoteLoader and target DLL
try
{
m_targetAppDomain = AppDomain::CreateDomain(appDomainSetup->ApplicationName, nullptr, appDomainSetup);
}
catch (Exception^ e1)
{
// ERROR!
}
// Finally, create a new instance of the RemoteLoader and store the instance locally.
if (m_targetAppDomain != nullptr)
{
try
{
Object^ newInstance = m_targetAppDomain->CreateInstanceFromAndUnwrap(
remoteLoaderCodeBase,
"DynamicLoader.RemoteLoader");
if (newInstance != nullptr)
{
m_remoteLoader = (DynamicLoader::RemoteLoader^)(newInstance);
}
}
catch (Exception^ e1)
{
// ERROR!
Log4NetProvider::LocalLogger->Fatal("Could not type cast new instance of RemoteLoader to appropriate type!");
Log4NetProvider::LocalLogger->FatalFormat("Created instance of type \"{0}\" from \"{1}\".", newInstance->GetType(), newInstance->GetType()->Assembly->CodeBase);
Log4NetProvider::LocalLogger->FatalFormat("Tried to cast to type \"{0}\" from \"{1}\".", RemoteLoader::typeid, RemoteLoader::typeid->Assembly->CodeBase);
Log4NetProvider::LocalLogger->FatalFormat(".NET Exception message: {0}", typeConvException->ToString());
}
}
}
问题发生在“最后一行”m_remoteLoader = (DynamicLoader::RemoteLoader^)(newInstance);
。 DynamicLoader
第一次正在开展工作,一切正常。第二次,类型转换失败
System.InvalidCastException:无法转换透明代理以键入“DynamicLoader.RemoteLoader”。
我试图分析哪些装配在什么时候实际使用并发现:
remoteLoaderCodeBase
始终指向正确的程序集文件,因此每个“目标DLL”的程序集都在其自己的目录中。
newInstance->GetType()->Assembly->CodeBase
指向第一个DynamicLoader
大会。
RemoteLoader::typeid->Assembly->CodeBase
指向当前的DynamicLoader
汇编。
所以,长话短说:即使我明确告诉m_targetAppDomain->CreateInstanceFromAndUnwrap(...)
从特定程序集实例化我的类,它将从根AppDomain中加载的第一个程序集创建实例!我究竟做错了什么?我想这应该以某种方式起作用,但我没有看到解决方案......
啊,最后一点:我正在使用.Net 4.0,所以如果还有更好的方法,请告诉我。 ;)