私人财产改变它';s值,没有它';s setter被调用(也称为交叉会话).假设.NET错误
本文关键字:会话 NET 错误 假设 setter 改变 财产 调用 | 更新日期: 2023-09-27 18:28:06
为未来的读者更新:如果您发现此文本太长:这是由于静态变量导致的竞争条件。您在下面阅读的内容显示,对于正在调试并忽略static
关键字的人来说,这可能会变得多么令人困惑如果您有类似的行为,请先检查static
我正在调试此应用程序,但在代码中找不到错误。我的母版页的类有一个名为Greeting
的私有属性。在同一服务器上的两个用户大约同时(在不到一秒内)注销之前,此属性不会引起问题。然后,一个用户收到了为另一个用户准备的问候语(例如,如果John和Jane正在测试,两人都会看到"亲爱的Jane小姐!")。因此,出于调试目的,我为这个属性实现了一个getter和一个setter。两者都通过HttpContext.Current.Trace.Write()
将读取或写入的值写入trace.axd。我看到设置了正确的值。但是在最后一个get
中,读取对应的另一个用户的值<有两个连续的getter调用返回不同的值。中间没有对二传手的调用。该属性是私有的,代码分析显示,它没有从其他任何地方引用>我还在用Environment.StackTrace
将堆栈跟踪写入跟踪。代码正在按预期运行。这怎么可能与.NET本身的错误不同呢?
private static string _Greeting = String.Empty;
private static string Greeting
{
get
{
System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__get(): " + _Greeting);
System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__get() STACKTRACE: " + Environment.StackTrace);
return _Greeting;
}
set
{
_Greeting = value;
System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__set(): " + _Greeting);
System.Web.HttpContext.Current.Trace.Write("Debug", "myMasterPage.Greeting__set() STACKTRACE: " + Environment.StackTrace);
}
}
追踪摘录(化名):
Debug myMasterPage.Greeting__get(): Dear Misses Jane
Debug myMasterPage.Greeting__get(): Dear Mister John
问题是这个变量是static
,因此当一个用户登录并设置值时,另一个用户会登录并更改它。所以,静态变量是在所有线程(请求)之间共享的变量,在极少数情况下,您希望在web应用程序上声明静态变量。
您有一个所谓的竞赛条件
private static string Greeting
{
get
{
/*1.*/ Trace.Write("Debug", "myMasterPage.Greeting__get(): " + _Greeting);
/*2.*/ return _Greeting;
}
set
{
/*3.*/ _Greeting = value;
/*4.*/ Trace.Write("Debug", "myMasterPage.Greeting__set(): " + _Greeting);
}
}
我已经对相关的行进行了编号,以显示当两个线程(A和B)运行相同的代码时,如何实现您的结果,如下所示:
StaticClass.Greeting = "Hi "+username;
//some other code
Display(ShowStaticClass.Greeting);
- 程序开始,
_Greeting == string.Empty
- 线程A开始执行,到达相关代码。执行第3行。
_Greeting == "A"
- 线程A执行第4行。写出
"_Greeting saved as A"
- 线程A执行第1行。写出
"_Greeting read as A"
- 线程B开始执行,到达相关代码。执行第3行。
_Greeting == "B"
- 线程B执行第4行。写出
"_Greeting saved as B"
- 线程A执行第2行。返回
_Greeting == "B"
- 线程B执行第4行。写出
"_Greeting saved as B"
- 线程B执行第1行。写出
"_Greeting read as B"
- 线程B执行第2行。返回
_Greeting == "B"
这将导致以下日志:
"_Greeting saved as A"
"_Greeting read as A"
"_Greeting saved as B"
"_Greeting read as B"
同时返回两个线程的值CCD_ 18。
第3行和第6行并不是一个接一个地执行,但可以(也将是)在这两行之后和之前执行代码。这样,调试日志记录基本上是对你撒谎,而只告诉你真相。
如果你想为每个用户存储一些数据,如果你想在服务器端保存数据,或者你可以把它放在ViewState(客户端)中,你应该在asp.net页面中使用Session
这里有一篇关于静态变量的好文章,它应该解释你的问题。C#中静态变量的用途是什么?何时使用?为什么可以';我在方法内部声明静态变量吗?