私人财产改变它';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

私人财产改变它';s值,没有它';s setter被调用(也称为交叉会话).假设.NET错误

问题是这个变量是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);
  1. 程序开始,_Greeting == string.Empty
  2. 线程A开始执行,到达相关代码。执行第3行。_Greeting == "A"
  3. 线程A执行第4行。写出"_Greeting saved as A"
  4. 线程A执行第1行。写出"_Greeting read as A"
  5. 线程B开始执行,到达相关代码。执行第3行。_Greeting == "B"
  6. 线程B执行第4行。写出"_Greeting saved as B"
  7. 线程A执行第2行。返回_Greeting == "B"
  8. 线程B执行第4行。写出"_Greeting saved as B"
  9. 线程B执行第1行。写出"_Greeting read as B"
  10. 线程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#中静态变量的用途是什么?何时使用?为什么可以';我在方法内部声明静态变量吗?