应用程序域内的静态变量

时间:2018-06-04 05:07:25

标签: c# static clr appdomain

我在C#Library程序集中有以下类。

public static class TestClass
{
    static int counter = 0;
    static TestClass()
        {
            System.Diagnostics.Debug.Print("TestLibrary.TestClass is constructed...");
        }

        public static void Say()
        {
            System.Diagnostics.Debug.Print($"TestClass.Say called {counter++} times");
        }
}

[Serializable]
public class TestLibraryProxy
{
    static int _executionCount = 0;
        public void Execute()
        {
            System.Diagnostics.Debug.Print($"TestLibraryProxy Execute [{_executionCount++}]");
            TestClass.Say();
            TestClass.Say();
        }
}

从另一个C#应用程序我试图将上面的程序集加载到应用程序域并调用TestLibraryProxy.Execute()方法。

class Program
{
    static void Main(string[] args)
    {
        CreateAppDomainAndCallStaticMethod("MyDomain1");
        CreateAppDomainAndCallStaticMethod("MyDomain2");
        CreateAppDomainAndCallStaticMethod("MyDomain3");
        CreateAppDomainAndCallStaticMethod("MyDomain4");
    }

    private static void CreateAppDomainAndCallStaticMethod(string domainName)
    {
        AppDomain domain = AppDomain.CreateDomain(domainName);
        var k = domain.CreateInstanceAndUnwrap("TestLibrary", typeof(TestLibraryProxy).FullName) as TestLibraryProxy;
        k.Execute();
        AppDomain.Unload(domain);
    }
}
Output
TestLibraryProxy Execute [0]
TestLibrary.TestClass is constructed...
TestClass.Say called 0 times
TestClass.Say called 1 times
TestLibraryProxy Execute [1]
TestClass.Say called 2 times
TestClass.Say called 3 times
TestLibraryProxy Execute [2]
TestClass.Say called 4 times
TestClass.Say called 5 times
TestLibraryProxy Execute [3]
TestClass.Say called 6 times
TestClass.Say called 7 times

我注意到TestClass中的静态计数器值会在应用程序域中保留。即使我多次加载和卸载应用程序域,此值也会保留。

我已经读过静态变量存储在Application Domain级别。但看起来不是真的吗?不知道CLR如何跨应用程序域管理静态数据。

1 个答案:

答案 0 :(得分:3)

这是因为TestLibraryProxy已标记为[Serializable]

相反,它应该继承自MarshalByRefObject

基本上你所做的是在另一个AppDomain中创建一个对象,然后将其复制(序列化)到原始的AppDomain中。 使用MarshalByRefObject可以避免这种情况。它确保不复制对象 - 相反,您将处理对原始对象的引用(在不同的AppDomain中运行)。

如果你做了那个改变

public class TestLibraryProxy : MarshalByRefObject

输出变为:

TestLibraryProxy Execute [0]
TestLibrary.TestClass is constructed...
TestClass.Say called 0 times
TestClass.Say called 1 times

重复多次