2010-11-28 107 views
28

我正在嘗試使用AppDomain來管理一些遺留代碼,這些代碼在多線程環境中包含大量靜態字段。AppDomain中的靜態字段

我看了回答了這個問題:How to use an AppDomain to limit a static class' scope for thread-safe use?,認爲這是相當有前途,並決定在裝配ClassLibrary1.dll一個非常簡單的類來嘗試一下:

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

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

,這裏是一個加載assemblyinto 2個不同的我的代碼應用程序域和調用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的每個實例的本地靜態字段Value的副本。然而,而我得到的是:

0 
1 
2 
3 
4 
5 

它告訴我他們仍然都共享相同的副本的靜態字段值。 任何人都可以告訴我我在這裏做錯了什麼?

更新:

我想埃裏克的建議,現在我叫CreateInstanceAndUnwrap(如下圖)在AppDomain類的方法,而不是調用load()和的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

你打電話給t他是當前應用程序域中的靜態方法。您需要創建一個調用Class1類的Static方法的Instance方法。 – 2010-11-28 21:39:41

+1

嗨Erik,如果你看看我更新的源代碼,我已經將IncrementAndPrint()轉換爲實例方法,並使用CreateInstanceAndUnWrap()在各個應用程序域中創建實例。然而,我仍然得到相同的結果 – oscarkuo 2010-11-29 00:23:15

回答

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