2016-07-28 14 views
2

を横断するとき、私は私の問題の根本的な原因は、これと同様の問題であると確信しているタイプをターゲットに変換することができません。オブジェクトタイプはのAppDomain

How do I pass references as method parameters across AppDomains?

this answer特に、私はかなりよく分かりませんそれを修正する方法。

これは私が書いているVisual Studio拡張機能があり、それができるようにするために必要なことの1つはアセンブリを別のドメインにロードすることです私はそれでやった)とそれでいくつかのものをする。だから私は自分のドメインは、次のように設定している:

// The actual ApplicationBase of the current domain will be the one of VS and not of my plugin 
// We need our new AppDomain to be able to find our assemblies 
var p = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 
var setup = new AppDomainSetup() 
{ 
    ApplicationBase = p 
}; 
domain = AppDomain.CreateDomain("MyTest_AppDomain", AppDomain.CurrentDomain.Evidence, setup); 
var t = typeof(Proxy); 
proxy = domain.CreateInstanceAndUnwrap(t.Assembly.FullName, 
    t.FullName, 
    false, 
    BindingFlags.Default, 
    null, 
    new object[] { assemblyPath }, 
    null, 
    null) as Proxy; 

私はそれは上のコードと同じアセンブリで定義されていていても私のクラスProxyをロードできるようにするためApplicationBaseを設定する必要がありました。戻る私のようなものを持っている新しいAppDomainの新しいAppDomainProxyのインスタンスを作成した同じクラスの

public class Proxy : MarshalByRefObject 
{ 
    private Assembly _assembly; 

    private IEnumerable<Type> _types; 

    public IEnumerable<Type> Types 
    { 
     get 
     { 
      if (_types == null && _assembly != null) 
      { 
       _spiders = _assembly.GetTypes().Where(t => typeof(IFoo).IsAssignableFrom(t)).ToList(); 
      } 
      return _types; 
     } 
    } 

    public Proxy(string assemblyPath) 
    { 
     _assembly = Assembly.LoadFile(assemblyPath); 
    } 

    public IFoo GetInstanceOf(string fooType) 
    { 
     var type = Types.FirstOrDefault(t => t.FullName == fooType); 
     if (type == null) 
     { 
      throw new InvalidOperationException($"Unknown type {fooType} in assembly {_assembly.FullName}"); 
     } 
     return GetInstanceOf(type); 
    } 
    private IFoo GetInstanceOf(Type fooType) 
    { 
     var obj = Activator.CreateInstance(fooType); 
     return obj as IFoo; 
    } 

    public override object InitializeLifetimeService() 
    { 
     return null; 
    } 
} 

:それがなければ、私はFileNotFoundExceptions

を得ていた今私のProxyクラスには、次のようになりますこの:

public IFoo GetInstanceOf(Type type) 
{ 
    var name = type.FullName; 
    var foo = proxy.GetInstanceOf(name); 
    return foo; 
} 

は当初、私は直接のタイプを渡しproxy.GetInstanceOfを呼び出そうとしましたが、それはfoはおそらく働いていませんでしたr私が持っているコードと同じ理由は動作しません。私はラインvar foo = proxy.GetInstanceOf...ラインに着くとき、私はメッセージでArgumentExceptionを取得:

オブジェクト型は、型をターゲットに変換することはできません。

私はMyTest_AppDomainIFooDefaultDomainのようにIFoo同じであると見なされていないため、問題があると考えているが、私はこの問題を解決する正しい方法は何であるかわかりません。

IFoo自体が別の3番目のアセンブリで定義されていて、VSIXプロジェクトと別のドメインに読み込もうとしているアセンブリの両方が参照されていることが関係する場合があります。私はMyTest_AppDomainと同じ場所にあるIFooアセンブリをDefaultDomainと同じ位置にロードすることを確信する必要があります。そうでない場合は、同じものであることを納得させる必要があります。

注:IFooを実装するすべてのクラスは、抽象基盤FooBaseから継承し、それ自体はMarshalByRefObjectから継承されます。

編集私の問題はここから来るかもしれない。この詳細を考える:

_assembly = Assembly.LoadFile(assemblyPath); 

assemblyPathApplicationBaseに異なるパスがあるとIFooが定義されている場所、そのパスが(foo.dllのそれ自身のバージョンを持っています)。それで、ロードする前にそこから読み込んでいますか?ApplicationBaseProxy.GetInstanceOf私はtypeof(IFoo).Assembly.Locationを見ることができ、それはApplicationBaseに設定されている予想されるパスを与えますが、私のアセンブリがロードされると、そこからfoo.dllが得られるとは思いません。

+0

IFooをリファレンスでベースにしたいのですか、またはアプリケーションドメインで新しいコピーを期待しますか?あなたはすでにMarshalByRefで前者をやっているので、新しいコピーが必要だと思っています。 IFooによって実装されているものはすべてシリアル化可能であることを確認してください。インスタンスはシリアル化され、アプリケーションドメインをまたいで逆シリアル化されるべきです。 – Igor

+0

@Igor:新しいアプリケーションドメインにインスタンスを作成し、そのドメインへの参照をデフォルトのドメインに渡して、メソッドを呼び出していくつかのイベントに登録できるようにしたいと思います。 –

+0

動作しません(デフォルト)。アプリケーションドメインは、.Netリモーティングを使用して相互に通信します。アプリケーションドメイン間で受け渡されるインスタンスは基本的にコピーです。 'IFoo'を返すと、他のアプリケーションドメインで作成されたインスタンスへの参照ではなく' IFoo'のコピーが得られます(デフォルトでは)ので、IFooのイベントやメソッドを呼び出すことができず、それらのメソッドを処理するアプリケーションドメインを作成しました。 (もっと来る...) – Igor

答えて

1

私は簡単なサンプルをまとめました。これはあなたが期待することを行い、IFooは呼び出し元への参照によってマーシャリングされます。

using System; 
using System.Reflection; 

namespace AppdomainTesting 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var p = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 
      var setup = new AppDomainSetup() 
      { 
       ApplicationBase = p 
      }; 
      IProxy proxy; 
      var domain = AppDomain.CreateDomain("MyTest_AppDomain", AppDomain.CurrentDomain.Evidence, setup); 
       var t = typeof(Proxy); 
      proxy = domain.CreateInstanceAndUnwrap(t.Assembly.FullName, 
       t.FullName, 
       false, 
       BindingFlags.Default, 
       null, 
       null, 
       null, 
       null) as IProxy; 

      // works 
      var typeofFoo = typeof(Foo); 
      var foo = proxy.GetFoo(new TypeDef() { Asembly = typeofFoo.Assembly.FullName, FullTypeName = typeofFoo.FullName }); 
      Console.WriteLine(foo.Domain); 

      // Type also implements Serializable attribute (my mistake, I thought it did not) 
      foo = proxy.GetFoo(typeofFoo); 
      Console.WriteLine(foo.Domain); 

      Console.WriteLine(); 
      Console.WriteLine("ENTER to exit"); 
      Console.ReadLine(); 
     } 
    } 

    public interface IFoo 
    { 
     string Domain { get; } 
    } 

    public class Foo : MarshalByRefObject, IFoo 
    { 
     public string Domain 
     { 
      get { return System.AppDomain.CurrentDomain.FriendlyName; } 
     } 
    } 
    public interface IProxy 
    { 
     IFoo GetFoo(TypeDef typeToGet); 
     IFoo GetFoo(Type type); 
    } 
    [Serializable] 
    public class TypeDef 
    { 
     public string Asembly { get; set; } 
     public string FullTypeName { get; set; } 
    } 

    public class Proxy : MarshalByRefObject, IProxy 
    { 
     public IFoo GetFoo(TypeDef typeToGet) 
     { 
      var type = Type.GetType(typeToGet.FullTypeName + ", " + typeToGet.Asembly, true); 
      var instance = Activator.CreateInstance(type) as IFoo; 
      return instance; 
     } 
     public IFoo GetFoo(Type type) 
     { 
      var instance = Activator.CreateInstance(type) as IFoo; 
      return instance; 
     } 
    } 
} 
関連する問題