【问题标题】:Static member does not keep assigned value静态成员不保持赋值
【发布时间】:2009-07-17 21:10:35
【问题描述】:

好的,我有一个静态类,它有两个静态成员,一个字符串和一个布尔值。
公共静态方法根据传入参数的状态为这些成员分配值。

然后调用处理静态成员的私有静态方法。

问题在于,虽然布尔值保留了它在公共函数中设置的值,但字符串却没有;它默认回到它的初始化值。这是为什么呢?
简化代码如下。

static class MessageHandler
{
    private static String m_messageToSend = String.Empty;
    private static bool m_requiresACK = false;


    public static void Send(String message)
    {
         //formatting etc (actual method sets more fields)
         m_messageToSend = message;
         m_requiresACK = true;

         Send();
    }

    private void static Send()
    {
        SendMessageDelegate sendDelegate = DoSend;
        //At this point m_requiresACK remains true but m_messageToSend does not 
        //hold value of message; it is empty.
        IAsyncResult ar = sendDelegate.BeginInvoke(m_messageToSend, m_requiresACK);


        //rest of function
    }
}

//some other class
MessageHandler.Send("Hello");

【问题讨论】:

  • 您确定它在 Send(string) 方法中被正确分配。你在简化 tge 代码的时候忘了提什么吗?
  • 为什么这是一个静态类?
  • Devio- 也许不应该,我还在学习。这似乎是最优雅的解决方案,并且不需要创建对象。类名不是很好,需要更改 - MessageHandler 可能因为它转发它们。 MessageHandler.Send(消息)。

标签: c# static-members


【解决方案1】:

此代码的线程“不安全”可能是问题所在,因为当您的线程当前处于同一方法的中间时,其他线程可能会调用 Send(string)。我建议对 Message 类进行以下重写:

static class Message
{
    public static void Send(String message)
    {
         Send(message, true);
    }

    private void static Send(string messageToSend, bool requiresACK)
    {
        SendMessageDelegate sendDelegate = DoSend;
        IAsyncResult ar = sendDelegate.BeginInvoke(messageToSend, requiresACK);

        //rest of function
    }
}

【讨论】:

  • 彼得 - 这似乎解决了问题。碰巧我直接使用成员,因为我最近倾向于这个而不是传递大量参数(实际上不止列出)。然而,当然在这个例子中,传递参数似乎更有意义 - 课程的马。
  • 成员变量通常没问题,但静态成员变量在线程安全方面需要特别注意。很高兴它解决了问题。
【解决方案2】:

这很可能是由于另一个线程调用

Message.Send("");

或者您的 AppDomain 正在卸载。没有更多信息,很难确定。

【讨论】:

    【解决方案3】:

    那里有一些巨大的线程安全问题。如果你真的想要这个静态,有一个厚颜无耻的解决方法:

    [ThreadStatic]
    private static String m_messageToSend = String.Empty;
    [ThreadStatic]
    private static bool m_requiresACK = false;
    

    这现在是静态的,但每个线程。避免了危机;但这有点……好吧,我自己会尽量避免这种需要——但它会很好用。

    重要:初始化器是每个线程,而不是每个请求;由于您的线程很可能会被重复使用,因此您应该确保在尝试使用它之前初始化状态,否则您可能会遇到旧垃圾。

    【讨论】:

    • 这一次只能在一个线程上调用,但是感谢您的提示!我确实有一个初始化方法,但删除它以减少代码。
    【解决方案4】:

    如果一个字段保持相同的值,而另一个没有,我会感到非常惊讶。

    如果这是一个 Web 应用程序,如果应用程序被回收,就会发生这种情况。

    【讨论】:

      【解决方案5】:

      我在您的 cmets 中看到,在第一行之后,私有变量为空,而不是保存参数的值。一旦你点击 Send() 的第一行,这是真的吗?

      编写单元测试或调用 Message.Send("Hello World"); 的简单测试工具。并对输出进行断言。将其与您的调用代码库隔离开来,可以了解是您的 Message 类行为异常,还是消费者发送了错误/意外数据。

      此外,除非您的 //rest of function 包括重置您的 bool,否则在发送第一条消息后它将始终为 true。

      【讨论】:

      • 碰巧是的,布尔值被重置了——还有很多其他的格式和逻辑。我大大简化了代码,使其只关注我遇到的问题。我想在未来我会添加更多的 cmets 来突出这一点……虽然很好。
      • 明白,有点期待。我只是补充说它没有被重置的机会。每隔一段时间,低垂的果实就会奏效。
      猜你喜欢
      • 2011-11-05
      • 2012-09-25
      • 1970-01-01
      • 2010-10-12
      • 2022-12-16
      • 2014-04-21
      • 1970-01-01
      • 1970-01-01
      • 2012-09-22
      相关资源
      最近更新 更多