在应用程序域静态字段 [英] Static Fields in AppDomain
问题描述
我尝试用左右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屋!