C# AppDomain中的静态字段
我正在尝试使用AppDomain来管理一些遗留代码,这些代码在多线程环境中包含大量静态字段 我阅读了这个问题的答案:,认为它很有前途,并决定在assembly ClassLibrary1.dll中用一个非常简单的类进行尝试:C# AppDomain中的静态字段,c#,.net,appdomain,C#,.net,Appdomain,我正在尝试使用AppDomain来管理一些遗留代码,这些代码在多线程环境中包含大量静态字段 我阅读了这个问题的答案:,认为它很有前途,并决定在assembly ClassLibrary1.dll中用一个非常简单的类进行尝试: namespace ClassLibrary1 { public static class Class1 { private static int Value = 0; public static void Incremen
namespace ClassLibrary1
{
public static class Class1
{
private static int Value = 0;
public static void IncrementAndPrint()
{
Console.WriteLine(Value++);
}
}
}
下面是我的代码,它将Assembly加载到两个不同的应用程序域中,并多次调用IncrementAndPrint()
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);
我希望输出为:
0
1
2
0
1
2
因为每个AppDomain实例都会有一个本地静态字段值的副本。然而,我得到的却是:
0
1
2
3
4
5
这说明它们仍然共享静态字段值的相同副本。
谁能告诉我我做错了什么
更新:
我尝试了Erik的建议,现在我调用AppDomain类的CreateInstanceAndUnwrap()方法,而不是调用Load()和GetType(),如下所示。此外,我还将IncrementAndPrint转换为实例方法,而不是静态方法。然而,我还是得到了同样的结果
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();
看起来您正在将类型从另一个appDomain加载到当前appDomain。因此,调用静态方法的代码是从当前appDomain调用的 我不知道有任何其他方法可以在另一个域中调用静态方法,而不用在另一个域中创建对象的实例,并让该对象调用静态方法 示例:解决方案包含2个项目(类库和Winforms/Console应用程序) [类库]
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;
}
}
}
[申请]
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());
}
}
产生的结果:
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
您正在当前应用程序域中调用静态方法。您需要创建一个实例方法来调用Class1类上的静态方法。嗨,Erik,如果您查看我更新的源代码,我已经将IncrementAndPrint()转换为实例方法,并使用CreateInstanceAndUnWrap()在各自的应用程序域中创建实例。但是,我仍然得到了相同的结果。我完全忘记了在appDomain模型上提到
MarhsalByRefObject
。此外,在.NET的原始版本中,存在一个鲜为人知的错误,即在当前域中执行静态方法,然后在定义类型上调用非静态方法(在单独的域中创建)将导致在当前域中执行非静态代码(即使定义类型是MBR)。解决方案是不在同样是MBR的类型上调用静态方法。当时我们认为这是JIT优化的一个问题,因为我们认为MBR调用可以内联,因为使用了在MBR上定义的静态方法。