我正在尝试将程序集加载到另一个appdomain(为了能够在不需要时卸载它们),而且我希望能够检查已加载程序集中的类型并创建我的类型的实例(通过Activator)。此外,我不希望程序集在加载时被锁定。
我看不出这是怎么回事。我尝试过的事情:
加载Assembly.Load(File.ReadAllBytes(path))可以帮助我加载程序集而不锁定它,因此可以删除/移动它。这会将程序集加载到当前的appdomain中,因此无法将其卸载。
创建另一个AppDomain并使用AppDomain.Load()将程序集加载到新的AppDomain中,但无法检查加载的AppDomain中的所有类型。除非我知道类型完全限定的类型名称,否则我无法创建任何内容,即使这样,它们也必须是Serializable或派生自MarshallByRef。另一个AppDomain东西只能通过Proxies工作,所以没有合同/共享接口等就很难创建东西。
MEF还会将程序集加载到当前的AppDomain中,因此它基本上都在做同样的事情。
Mono.Cecil允许对已加载的程序集进行类型检查,但之后我无法使用TypeReference创建类型。也许如果有办法将TypeReference转换为Type?
我已经检查了ILSpy是如何做到这一点的,并且毫无疑问它使用Mono.Cecil来加载/卸载程序集,但是再一次,它不会创建任何类型的实例,只是可以进行类型检查Mono.Cecil路线。
现在的问题是,这甚至可能吗?我错过了什么吗?
答案 0 :(得分:1)
如果您将程序集加载到另一个appdomain中,那么您当然应该在那里创建实例并在那里使用它们。除此之外,不确定你遇到了什么问题。
<强>更新强>
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Remoting;
public class MainClass : MarshalByRefObject
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("usage: {0} assembly", Path.GetFileName(Assembly.GetExecutingAssembly().Location));
return;
}
AppDomain other = AppDomain.CreateDomain("other");
Type myType = typeof(MainClass);
// create a loader instance in the new domain
MainClass loader = (MainClass)other.CreateInstanceAndUnwrap(myType.Assembly.FullName, myType.FullName);
string assemblyName;
string[] types = loader.LoadAssembly(args[0], out assemblyName);
Console.WriteLine("Loaded assembly {0}.", assemblyName);
Console.WriteLine("Types:");
for(int i = 0; i < types.Length; i += 1)
{
Console.WriteLine("[{0}] {1}", i, types[i]);
}
Console.Write("Enter index of type to create, -1 to exit: ");
int create = Int32.Parse(Console.ReadLine());
if (create < 0)
{
return;
}
Console.WriteLine("Creating instance of type {0}", types[create]);
Console.WriteLine("Type of the created instance was: {0}", loader.CreateInstance(assemblyName, types[create]));
}
string[] LoadAssembly(string path, out string assemblyName)
{
Console.WriteLine("LoadAssembly executing in appdomain {0}", AppDomain.CurrentDomain.FriendlyName);
Assembly assembly = Assembly.Load(File.ReadAllBytes(path));
assemblyName = assembly.FullName;
return Array.ConvertAll<Type, string>(assembly.GetExportedTypes(), x => x.FullName);
}
string CreateInstance(string assemblyName, string typeName)
{
Console.WriteLine("CreateInstance executing in appdomain {0}", AppDomain.CurrentDomain.FriendlyName);
object instance = Activator.CreateInstance(assemblyName, typeName).Unwrap();
// do something useful with the instance here
return instance.GetType().FullName;
}
public override object InitializeLifetimeService()
{
return null;
}
}
log4net.dll
的示例输出:
$ mono main.exe log4net.dll
LoadAssembly executing in appdomain other
Loaded assembly log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=a5715cc6d5c3540b.
Types:
[0] log4net.Core.SecurityContext
[1] log4net.Core.LoggerWrapperImpl
[2] log4net.Core.LogImpl
[3] log4net.Core.DefaultRepositorySelector
...
[160] log4net.Appender.AspNetTraceAppender
[161] log4net.Appender.FileAppender
...
[197] log4net.Repository.LoggerRepositoryConfigurationResetEventHandler
[198] log4net.Repository.LoggerRepositoryConfigurationChangedEventHandler
Enter index of type to create, -1 to exit: 161
Creating instance of type log4net.Appender.FileAppender
CreateInstance executing in appdomain other
Type of the created instance was: log4net.Appender.FileAppender