Static Fields in AppDomain

江枫思渺然 提交于 2019-11-26 08:12:53

问题


I\'m experimenting ideas around using AppDomain to manage some legacy code contains lots of static fields in a multi-threaded environment.

I read answers this question: How to use an AppDomain to limit a static class\' scope for thread-safe use?, thought it\'s quite promising and decided to try it out with a very simple class in assembly ClassLibrary1.dll:

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

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

and here\'s my code that loads the assemblyinto 2 different app domains and invokes the IncrementAndPrint() several times:

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

I was expecting the output to be:

0
1
2
0
1
2

because there will be a copy of the static field Value to local to each instance of AppDomain. However, instead what I got was:

0
1
2
3
4
5

which tells me they are still all sharing the same copy of the static field Value. Can anyone tell me what have I done wrong here?

Update:

I tried Erik\'s suggestion, now I call CreateInstanceAndUnwrap() method of the AppDomain class instead of calling Load() and GetType() as shown below. Also, I\'ve converted IncrementAndPrint to an instance method rather than a static method. However, I\'m still getting the same result.

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

回答1:


It looks like you are loading a type from another appDomain into the current appDomain. Thus the code that calls the static methods are calling from the current appDomain.

I'm unaware of any other way to call a static method in another domain without creating an instance of an object in another domain, and having that object call the static method.

Example: Solution contains 2 Projects (ClassLibrary and a Winforms/Console app)

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

[Application]

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

Generated Results:

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


来源:https://stackoverflow.com/questions/4298913/static-fields-in-appdomain

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!