2010-11-28 12 views
28

içinde bazı eski kodu bir çok iş parçacıklı ortamda statik alanların bolca içerir yönetmek için uygulama etki alanı kullanarak etrafında fikirler deniyorum. oldukça umut verici olduğunu düşünmüş ve montaj ClassLibrary1.dll çok basit sınıfla denemeye karar verdi, How to use an AppDomain to limit a static class' scope for thread-safe use?:Statik Alanlar AppDomain

Ben cevaplara bu soruyu okumak

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

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

ve burada 2 farklı assemblyinto yükler kod bu Uygulamanın etki alanları ve IncrementAndPrint çağırır() birkaç kez: Ben bekliyordum

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); 

çıktı olmak:

0 
1 
2 
0 
1 
2 

AppDomain her örneği yerel statik alan Değerinin bir kopyası kalır çünkü. Bununla birlikte, benim aldığım şey, bunların hepsinin hala statik alan Değerinin aynı kopyasını paylaştığını söyleyen . Burada neyin yanlış yaptığımı bana söyleyebilir misiniz?

Güncelleme:

Ben şimdi aşağıda gösterildiği gibi yerine Load() ve GetType (çağırma AppDomain sınıfının() yöntemi) CreateInstanceAndUnwrap diyoruz, Erik'in öneri çalıştı. Ayrıca, IncrementAndPrint'i statik bir yöntem yerine örnek yöntemine dönüştürdüm. Ancak, hala aynı sonucu alıyorum.

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

Arama yapıyorsunuz t Geçerli uygulama alanında statik yöntem. Class1 sınıfındaki Statik yöntemi çağıran bir Örnek yöntemi oluşturmanız gerekir. Benim güncellenmiş kaynak koduna bir göz varsa –

+1

Merhaba Erik, ben bir örnek yöntemine IncrementAndPrint() dönüştürülür ve() ilgili uygulama alanlarındaki örneklerini oluşturmak için CreateInstanceAndUnWrap kullanmaya başlamışlardır. Ancak, hala aynı sonucu alıyorum – oscarkuo

+0

Ben appDomain Model üzerinde 'MarhsalByRefObject' bahsetmeyi tamamen unutmuşum. –

cevap

21

Başka bir appDomain öğesinden geçerli uygulama etki alanına bir tür yüklediğiniz anlaşılıyor. Böylece, statik yöntemleri çağıran kod geçerli appDomain'den çağırıyor.

başka etki alanındaki bir nesnenin örneğini oluşturarak ve bu nesne statik yöntemi çağırmak zorunda kalmadan başka bir etki statik yöntemi çağırmak için başka bir şekilde yapıldığının farkında değilim.

Örnek: Çözelti 2 Projects (ClassLibrary ve bir Win/konsol uygulaması) içeren

[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; 
     } 
    } 
} 

[Uygulama]

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()); 
    } 
} 

Oluşturulan Sonuçlar:

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

Şerefe arkadaşı, MarhsalByRefObject hile yapar. – oscarkuo

+1

Ayrıca, orijinal sürümü ile.NET, geçerli etki alanında statik olmayan yöntem olarak adlandırılan (ayrı bir etki alanında oluşturulmuş) statik olmayan yöntemler olarak adlandırılan statik bir yöntemin geçerli etki alanında yürütülmesine neden olan daha az bilinen bir hata oluştu. tanımlama tipi MBR idi. Çözüm ayrıca MBR'leri olan türlerde statik yöntemleri çağırmamaktı. MBR çağrıları MBR'de tanımlanan statik bir yöntemin kullanımı nedeniyle MBR çağrılarının inline edilebileceğine inanan JIT optimizasyonları ile ilgili bir sorun olduğuna inandık. –