2010-11-28 13 views
28

AppDomainを使用していくつかのレガシーコードを管理するというアイデアを試していますが、マルチスレッド環境で静的フィールドが多数含まれています。それは非常に有望だと思ったし、組み立てたClassLibrary1.dllでは非常に単純なクラスでそれを試してみることにしました、How to use an AppDomain to limit a static class' scope for thread-safe use?AppDomainの静的フィールド

私は答えにこの質問を読ん

namespace ClassLibrary1 
{ 
    public static class Class1 
    { 
     private static int Value = 0; 

     public static void IncrementAndPrint() 
     { 
      Console.WriteLine(Value++); 
     } 
    } 
} 

を、ここで2つの異なるassemblyintoをロードする私のコードですアプリドメインとIncrementAndPrintを(呼び出し)を数回:

var appDomain1 = System.AppDomain.CreateDomain("AppDomain1"); 
var appDomain2 = System.AppDomain.CreateDomain("AppDomain2"); 

var assemblyInAppDomain1 = appDomain1.Load("ClassLibrary1"); 
var assemblyInAppDomain2 = appDomain2.Load("ClassLibrary1"); 

var class1InAppDomain1 = assemblyInAppDomain1.GetType("ClassLibrary1.Class1"); 
var class1InAppDomain2 = assemblyInAppDomain2.GetType("ClassLibrary1.Class1"); 

class1InAppDomain1.InvokeMember("IncrementAndPrint", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null); 
class1InAppDomain1.InvokeMember("IncrementAndPrint", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null); 
class1InAppDomain1.InvokeMember("IncrementAndPrint", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null); 

class1InAppDomain2.InvokeMember("IncrementAndPrint", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null); 
class1InAppDomain2.InvokeMember("IncrementAndPrint", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null); 
class1InAppDomain2.InvokeMember("IncrementAndPrint", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null); 

私は出力があることを期待していた。

0 
1 
2 
0 
1 
2 

AppDomainの各インスタンスにローカルな静的フィールド値のコピーが存在するためです。しかし、代わりに私が得たことだった。

0 
1 
2 
3 
4 
5 

彼らはまだすべての静的フィールド値の同じコピーを共有している私に語っています。 誰でも私がここで間違ったことを教えてもらえますか?

更新:

私は以下に示すように、今私は)CreateInstanceAndUnwrap代わりにロード(呼び出しのアプリケーションドメインクラスの()メソッド)とはgettypeを(呼び出して、エリックの提案を試してみました。また、私はIncrementAndPrintを静的メソッドではなくインスタンスメソッドに変換しました。しかし、私はまだ同じ結果を得ています。

var appDomain1 = System.AppDomain.CreateDomain("AppDomain1"); 
var appDomain2 = System.AppDomain.CreateDomain("AppDomain2"); 

var class1InAppDomain1 = (Class1)appDomain1.CreateInstanceAndUnwrap("ClassLibrary1", "ClassLibrary1.Class1"); 
var class1InAppDomain2 = (Class1)appDomain2.CreateInstanceAndUnwrap("ClassLibrary1", "ClassLibrary1.Class1"); 

class1InAppDomain1.IncrementAndPrint(); 
class1InAppDomain1.IncrementAndPrint(); 
class1InAppDomain1.IncrementAndPrint(); 

class1InAppDomain2.IncrementAndPrint(); 
class1InAppDomain2.IncrementAndPrint(); 
class1InAppDomain2.IncrementAndPrint(); 
+0

あなたは彼は現在のアプリドメインの静的メソッドです。クラス1クラスの静的メソッドを呼び出すインスタンスメソッドを作成する必要があります。 –

+1

こんにちはErik、更新されたソースコードを見れば、IncrementAndPrint()をインスタンスメソッドに変換し、CreateInstanceAndUnWrap()を使用してそれぞれのアプリケーションドメインにインスタンスを作成しています。しかし、私はまだ同じ結果を得ています – oscarkuo

+0

あなたのappDomainモデル上の 'MarhsalByRefObject'については完全に忘れてしまいました。 –

答えて

21

他のappDomainのタイプを現在のappDomainに読み込んでいるようです。したがって、静的メソッドを呼び出すコードは現在のappDomainから呼び出しています。

私は別のドメインのオブジェクトのインスタンスを作成せずに、そのオブジェクトが静的メソッドを呼び出すことなく、別のドメインの静的メソッドを呼び出すことはできません。

例:溶液を2プロジェクト(ClassLibraryとWinformsの/コンソールアプリケーション)が含ま

[ClassLibrary]

using System; 

namespace MyLibrary 
{ 
    public class DomainObject : MarshalByRefObject 
    { 
     private static int _Value; 

     private static void IncrementValue() 
     { 
      DomainObject._Value++; 
     } 

     public static int Value 
     { 
      get 
      { 
       return DomainObject._Value; 
      } 
     } 

     public int GetIncrementedValue() 
     { 
      DomainObject.IncrementValue(); 
      return DomainObject.Value; 
     } 
    } 
} 

[アプリケーション]

private void button1_Click(object sender, EventArgs e) 
{ 
    AppDomain domain1 = AppDomain.CreateDomain("domain1"); 
    AppDomain domain2 = AppDomain.CreateDomain("domain2"); 

    DomainObject object1 = 
     domain1.CreateInstanceAndUnwrap("MyLibrary", "MyLibrary.DomainObject") 
     as DomainObject; 

    DomainObject object2 = 
     domain2.CreateInstanceAndUnwrap("MyLibrary", "MyLibrary.DomainObject") 
     as DomainObject; 

    if (object1 != null) 
    { 
     Console.WriteLine("object 1 Value = " 
          + object1.GetIncrementedValue().ToString()); 
     Console.WriteLine("object 1 Value = " 
          + object1.GetIncrementedValue().ToString()); 
     Console.WriteLine("object 1 Value = " 
          + object1.GetIncrementedValue().ToString()); 
    } 
    if (object2 != null) 
    { 
     Console.WriteLine("object 2 Value = " 
          + object2.GetIncrementedValue().ToString()); 
     Console.WriteLine("object 2 Value = " 
          + object2.GetIncrementedValue().ToString()); 
     Console.WriteLine("object 2 Value = " 
          + object2.GetIncrementedValue().ToString()); 
    } 

    /* Unload the Domain and re-create 
    * This should reset the Static Value in the AppDomain 
    */ 
    AppDomain.Unload(domain1); 
    domain1 = AppDomain.CreateDomain("domain1"); 
    object1 = domain1.CreateInstanceAndUnwrap("MyLibrary", 
               "MyLibrary.DomainObject") 
               as DomainObject; 

    if (object1 != null) 
    { 
     Console.WriteLine("object 1 Value = " 
          + object1.GetIncrementedValue().ToString()); 
     Console.WriteLine("object 1 Value = " 
          + object1.GetIncrementedValue().ToString()); 
     Console.WriteLine("object 1 Value = " 
          + object1.GetIncrementedValue().ToString()); 
    } 
    if (object2 != null) 
    { 
     Console.WriteLine("object 2 Value = " 
          + object2.GetIncrementedValue().ToString()); 
     Console.WriteLine("object 2 Value = " 
          + object2.GetIncrementedValue().ToString()); 
     Console.WriteLine("object 2 Value = " 
          + object2.GetIncrementedValue().ToString()); 
    } 
} 

生成された結果:

object 1 Value = 1 
object 1 Value = 2 
object 1 Value = 3 
object 2 Value = 1 
object 2 Value = 2 
object 2 Value = 3 
object 1 Value = 1 
object 1 Value = 2 
object 1 Value = 3 
object 2 Value = 4 
object 2 Value = 5 
object 2 Value = 6 
+4

歓声の仲間、MarhsalByRefObjectがトリックを行います。 – oscarkuo

+1

さらに、元のリリースの。NETでは、あまり知られていないバグがありました。現在のドメインで静的メソッドを実行すると、定義された型(別のドメインで作成された)で非静的メソッドが呼び出され、非静的コードが現行ドメインで実行されます定義型はMBRでした)。この解決策は、MBRであったタイプの静的メソッドを呼び出さないことでした。 MBRで定義された静的メソッドを使用しているため、MBR呼び出しがインライン化される可能性があるとJIT最適化で問題があると考えていました。 –

関連する問題