2010-11-28 73 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