【问题标题】:Is it bad practice to have state in a static class?在静态类中有状态是不好的做法吗?
【发布时间】:2011-02-14 19:04:22
【问题描述】:

我想做这样的事情:

public class Foo {
    // Probably really a Guid, but I'm using a string here for simplicity's sake.
    string Id { get; set; }

    int Data { get; set; }

    public Foo (int data) {
        ...
    }

    ...
}

public static class FooManager {
    Dictionary<string, Foo> foos = new Dictionary<string, Foo> ();

    public static Foo Get (string id) {
        return foos [id];
    }

    public static Foo Add (int data) {
        Foo foo = new Foo (data);
        foos.Add (foo.Id, foo);

        return foo;
    }

    public static bool Remove (string id) {
        return foos.Remove (id);
    }

    ...

    // Other members, perhaps events for when Foos are added or removed, etc.
}

这将允许我从任何地方管理Foos 的全局集合。然而,有人告诉我静态类应该始终是无状态的——你不应该使用它们来存储全局数据。总体而言,全球数据似乎不受欢迎。如果我不应该使用静态类,那么解决这个问题的正确方法是什么?

注意:我确实找到了similar question,但给出的答案并不真正适用于我的情况。

【问题讨论】:

    标签: c# static singleton global-variables


    【解决方案1】:

    您似乎在这里寻找的是单例类,而不是静态类。对于无状态例程,应引用静态类和方法。单例类在每个应用程序运行时被实例化一次,并且只被实例化一次,并且具有类的全部功能。以后每次引用它时,都会返回具有完全相同成员属性的完全相同的实例。

    “C# singleton”的第一个谷歌结果似乎对实现有一个相当不错的解释。 http://www.yoda.arachsys.com/csharp/singleton.html

    【讨论】:

    • 请注意,虽然单例也不是很好的做法,因为它们会创建依赖等。最后,IoC(控制反转)和依赖注入将是更好的解决方案。
    【解决方案2】:

    全局数据既强大又是常见的问题来源,这就是使用依赖注入等技术的原因。您可以将其视为正常的解耦问题。在程序中的很多地方直接引用全局数据会在全局数据和所有这些地方之间建立强耦合。

    但是,在您的示例中,您已将对数据的访问隔离到一个类中,该类控制全局数据访问的确切细节。由于一些全局数据通常是不可避免的,我认为这是一个很好的方法。

    例如,您可以比较 app.config 和 web.config 是如何通过 .NET 框架使用的。它们是通过具有静态属性AppSettings 的静态类System.Configuration.ConfigurationManager 访问的,它隐藏了如何访问全局数据的详细信息。

    【讨论】:

      【解决方案3】:

      一般来说还不错。在极少数情况下,这样做比实现其他开销大的东西更有必要。

      但建议注意线程安全。

      您应该锁定对字典的每次调用,以便一次只有一个线程可以访问它。

      
      private static readonly object LockStaticFields = new object();
      
      public static Foo Add (int data) {
              lock(LockStaticFields)
              {
                 Foo foo = new Foo (data);
                 foos.Add (foo.Id, foo);
      
                 return foo;
              }
          }
      
      

      【讨论】:

      • 如果您在多线程环境中工作,我会补充:“您应该锁定对字典的每次调用”。否则将是无用的开销
      • 嗯,也许你是对的。但我的经验告诉我,最好总是那样做。我在公司工作,现在必须重构几乎所有东西,因为最初它不是为多线程环境实现的。我认为这比第一次实现线程安全的成本要高得多,尽管您可能不需要这种安全性。
      【解决方案4】:

      在您的类中使用只读静态属性,该属性在类的所有实例中都是相同的。从构造函数等根据需要递增和递减。

      【讨论】:

        【解决方案5】:

        谁认为静态类应该是无状态的?静态意味着声明。

        只知道静态类在 CLR 中的工作原理:

        • 您无法控制调用静态构造函数的时间。
        • 静态类对每个调用程序都有一个单独的状态。

        还要注意并发问题。

        顺便说一句,我很惊讶人们经常说“不要使用 X”。这就像有人走进你的工具棚,指着六种工具说:“那些工具是不好的做法。”这没有意义。

        【讨论】:

        • 在必要时使用它,但要聪明地避免问题。以后要灵活地转向更好的东西。
        【解决方案6】:

        我一直在静态类中使用列表来处理永远不会(或极少)改变的事情——方便加载选择列表等,而无需每次都访问数据库。由于我不允许更改,我不必担心锁定/访问控制。

        【讨论】:

          【解决方案7】:

          要考虑的另一件事是应用程序本身及其预算。真的需要比静态类更复杂的东西吗?

          【讨论】:

            猜你喜欢
            • 2011-09-22
            • 2011-07-07
            • 1970-01-01
            • 1970-01-01
            • 2010-12-28
            • 2011-08-13
            • 2022-01-18
            • 1970-01-01
            相关资源
            最近更新 更多