将程序集加载到另一个AppDomain和类型检查

时间:2012-11-30 03:17:31

标签: .net reflection mono appdomain .net-assembly

我正在尝试将程序集加载到另一个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路线。

现在的问题是,这甚至可能吗?我错过了什么吗?

1 个答案:

答案 0 :(得分:1)

如果您将程序集加载到另一个appdomain中,那么您当然应该在那里创建实例并在那里使用它们。除此之外,不确定你遇到了什么问题。

<强>更新

  1. 添加了从列表中选择类型的代码
  2. 更改为仅在域中传递类型名称作为字符串

  3. 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