在应用程序域静态字段 [英] Static Fields in AppDomain

查看:225
本文介绍了在应用程序域静态字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试用左右AppDomain中来管理一些旧式code中含有大量的在多线程环境中静态字段的想法。

我看了回答了这个问题:<一href="http://stackoverflow.com/questions/307292/how-to-use-an-appdomain-to-limit-a-static-class-scope-for-thread-safe-use">How使用AppDomain中限制一个静态类'范围线程安全使用,认为这是相当有前途,并决定尝试一下,在装配ClassLibrary1.dll一个非常简单的类:

 命名空间ClassLibrary1的
{
    公共静态类1级
    {
        私有静态int值= 0;

        公共静态无效IncrementAndPrint()
        {
            Console.WriteLine(价值++);
        }
    }
}
 

这是我的code加载的assemblyinto 2个不同的应用程序域,并调用IncrementAndPrint()多次:

  VAR appDomain1 = System.AppDomain.CreateDomain(AppDomain1);
变种appDomain2 = System.AppDomain.CreateDomain(AppDomain2);

变种assemblyInAppDomain1 = appDomain1.Load(ClassLibrary1的);
变种assemblyInAppDomain2 = appDomain2.Load(ClassLibrary1的);

变种class1InAppDomain1 = assemblyInAppDomain1.GetType(ClassLibrary1.Class1);
变种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中的每个实例。但是,而是我得到的是:

  0
1
2
3
4
五
 

这告诉我,他们仍然是所有共享的静态字段值相同的副本。 谁能告诉我什么,我做错了吗?

更新:

我想埃里克的建议,现在我叫CreateInstanceAndUnwrap在AppDomain类的()方法,而不是调用load()和的GetType(),如下图所示。另外,我已经转换IncrementAndPrint实例方法,而不是一个静态方法。不过,我仍然得到同样的结果。

  VAR appDomain1 = System.AppDomain.CreateDomain(AppDomain1);
变种appDomain2 = System.AppDomain.CreateDomain(AppDomain2);

VAR class1InAppDomain1 =(1级)appDomain1.CreateInstanceAndUnwrap(ClassLibrary1的,ClassLibrary1.Class1);
VAR class1InAppDomain2 =(1级)appDomain2.CreateInstanceAndUnwrap(ClassLibrary1的,ClassLibrary1.Class1);

class1InAppDomain1.IncrementAndPrint();
class1InAppDomain1.IncrementAndPrint();
class1InAppDomain1.IncrementAndPrint();

class1InAppDomain2.IncrementAndPrint();
class1InAppDomain2.IncrementAndPrint();
class1InAppDomain2.IncrementAndPrint();
 

解决方案

它看起来像您正在加载从其他的AppDomain类型到当前的AppDomain。因此,code调用静态方法调用从当前的AppDomain。

我不知道调用另一个域中的静态方法,无需在其他领域创建一个对象的实例,并具有对象调用静态方法的任何其他方式。

例如:解决方案包含2个项目(ClassLibrary和一个WinForms /控制台应用程序)

[ClassLibrary]

 使用系统;

命名空间在MyLibrary
{
    公共类的domainObject:MarshalByRefObject的
    {
        私有静态诠释_Value;

        私有静态无效IncrementValue()
        {
            DomainObject._Value ++;
        }

        公共静态int值
        {
            得到
            {
                返回DomainObject._Value;
            }
        }

        公众诠释GetIncrementedValue()
        {
            DomainObject.IncrementValue();
            返回DomainObject.Value;
        }
    }
}
 

[应用]

 私人无效的button1_Click(对象发件人,EventArgs的)
{
    AppDomain中域1 = AppDomain.CreateDomain(域1);
    AppDomain中域2 = AppDomain.CreateDomain(域2);

    domainObject的object1 =
        domain1.CreateInstanceAndUnwrap(MyLibrary的,MyLibrary.DomainObject)
        作为domainObject的;

    domainObject的Object2的=
        domain2.CreateInstanceAndUnwrap(MyLibrary的,MyLibrary.DomainObject)
        作为domainObject的;

    如果(object1!= NULL)
    {
        Console.WriteLine(对象1值=
                          + object1.GetIncrementedValue()的ToString());
        Console.WriteLine(对象1值=
                          + object1.GetIncrementedValue()的ToString());
        Console.WriteLine(对象1值=
                          + object1.GetIncrementedValue()的ToString());
    }
    如果(Object2的!= NULL)
    {
        Console.WriteLine(目标2值=
                          + object2.GetIncrementedValue()的ToString());
        Console.WriteLine(目标2值=
                          + object2.GetIncrementedValue()的ToString());
        Console.WriteLine(目标2值=
                          + object2.GetIncrementedValue()的ToString());
    }

    / *卸载域并重新创建
     *这应该在AppDomain中重新设置静态值
     * /
    AppDomain.Unload(DOMAIN1);
    域1 = AppDomain.CreateDomain(域1);
    object1 = domain1.CreateInstanceAndUnwrap(MyLibrary的,
                                              MyLibrary.DomainObject)
                                              作为domainObject的;

    如果(object1!= NULL)
    {
        Console.WriteLine(对象1值=
                          + object1.GetIncrementedValue()的ToString());
        Console.WriteLine(对象1值=
                          + object1.GetIncrementedValue()的ToString());
        Console.WriteLine(对象1值=
                          + object1.GetIncrementedValue()的ToString());
    }
    如果(Object2的!= NULL)
    {
        Console.WriteLine(目标2值=
                          + object2.GetIncrementedValue()的ToString());
        Console.WriteLine(目标2值=
                          + object2.GetIncrementedValue()的ToString());
        Console.WriteLine(目标2值=
                          + object2.GetIncrementedValue()的ToString());
    }
}
 

生成的结果:

 对象1值= 1
对象1值= 2
对象1值= 3
对象2值= 1
目标2值= 2
目标2值= 3
对象物1值= 1
对象1值= 2
对象1值= 3
目标2值= 4
目标2值= 5
目标2值= 6
 

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

解决方案

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

这篇关于在应用程序域静态字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆