4

アセンブリを別の appdomain に読み込もうとしていますが (不要なときにアンロードできるようにするため)、読み込まれたアセンブリの型を検査し、型のインスタンスを (Activator を介して) 作成できるようにしたいと考えています。また、ロード時にアセンブリがロックされないようにします。

これがどのように可能かわかりません。私が試したこと:

  • Assembly.Load(File.ReadAllBytes(path)) をロードすると、アセンブリをロックせずにロードできるため、アセンブリを削除/移動できます。これにより、アセンブリが現在のアプリ ドメインに読み込まれるため、アンロードできなくなります。

  • 別の AppDomain を作成し、AppDomain.Load() を使用すると、アセンブリが新しい AppDomain に読み込まれますが、読み込まれた AppDomain にあるすべての型を確認することはできません。タイプの完全修飾型名を知っていない限り、何も作成できません。それでも、Serializable であるか、MarshallByRef から派生する必要があります。別の AppDomain のものはプロキシ経由で機能するだけなので、コントラクト/共有インターフェイスなどを使用せずにものを作成することは困難です.

  • MEF もアセンブリを現在の AppDomain にロードするため、基本的に同じことを行っています。

  • Mono.Cecil を使用すると、読み込まれたアセンブリの型を検査できますが、TypeReference を使用して型を作成できません。TypeReference を Type に変換する方法があったとしたら?

ILSpy がどのようにこれを行うかを確認しましたが、驚くことではありませんが、Mono.Cecil を使用してアセンブリをロード/アンロードしますが、型のインスタンスを作成せず、Mono.Cecil を介して可能な型検査を行うだけです。ルート。

今問題は、これは可能ですか?何か不足していますか?

4

1 に答える 1

1

アセンブリを別の appdomain にロードする場合は、当然、そこでインスタンスを作成し、そこで使用する必要があります。それ以外は、どのような問題が発生したかわかりません。

アップデート

  1. リストからタイプを選択するコードを追加
  2. ドメイン全体で型名のみを文字列として渡すように変更

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
于 2012-12-03T21:24:12.187 に答える