关于类:何时在C#中使用静态类

When to use static classes in C#

本问题已经有最佳答案,请猛点这里访问。

下面是msdn在何时使用静态类时要说的内容:

1
2
3
4
5
6
static class CompanyInfo
{
    public static string GetCompanyName() { return"CompanyName"; }
    public static string GetCompanyAddress() { return"CompanyAddress"; }
    //...
}

Use a static class as a unit of
organization for methods not
associated with particular objects.
Also, a static class can make your
implementation simpler and faster
because you do not have to create an
object in order to call its methods.
It is useful to organize the methods
inside the class in a meaningful way,
such as the methods of the Math class
in the System namespace.

在我看来,这个例子似乎没有涵盖很多静态类的可能使用场景。在过去,我曾为相关函数的无状态套件使用过静态类,但就是这样。那么,在什么情况下应该(也不应该)声明一个类是静态的呢?


我在先前的堆栈溢出答案中写下了静态类的想法:用单一方法进行类——最佳方法?好的。

我以前喜欢用静态方法填充的实用程序类。他们对helper方法进行了大量的整合,否则这些方法会导致冗余和维护问题。它们很容易使用,没有实例化,没有处置,只是火不忘。我想这是我第一次无意中尝试创建面向服务的体系结构——很多无状态的服务只做了他们的工作,其他什么都没有。然而,随着一个系统的发展,龙就要来了。好的。

多态性好的。

假设我们有一个方法utilityClass.somemethod,它会很高兴地蜂拥而至。突然我们需要稍微改变一下功能。大多数功能都是相同的,但是我们仍然需要更改几个部分。如果不是静态方法,我们可以创建一个派生类,并根据需要更改方法内容。因为它是一个静态方法,所以我们不能。当然,如果我们只需要在旧方法之前或之后添加功能,我们可以创建一个新的类,并在其中调用旧的类——但这很恶心。好的。

界面困境好的。

由于逻辑原因,无法通过接口定义静态方法。由于我们不能重写静态方法,当我们需要通过接口传递静态类时,静态类是无用的。这使得我们无法将静态类用作策略模式的一部分。我们可以通过传递委托而不是接口来修补一些问题。好的。

测试好的。

这与上面提到的接口问题基本上是一致的。由于我们交换实现的能力非常有限,因此我们也很难用测试代码替换生产代码。同样,我们可以将它们包装起来,但这将要求我们更改代码的大部分,以便能够接受包装器而不是实际对象。好的。

福布斯斑点好的。

由于静态方法通常用作实用方法,而实用方法通常具有不同的用途,因此我们很快就会得到一个大类,其中充满了不一致的功能——理想情况下,每个类在系统中都应该有一个单独的用途。我更愿意有一个五倍的类,只要它们的目的是明确的。好的。

参数蠕变好的。

首先,这个可爱而天真的静态方法可能只需要一个参数。随着功能的增长,会添加一些新参数。很快会添加更多可选的参数,因此我们创建方法的重载(或者只添加支持它们的语言中的默认值)。不久,我们就有了一个方法,它需要10个参数。只需要前三个参数,参数4-7是可选的。但如果指定参数6,则也需要填写7-9…如果我们创建一个类的唯一目的是做这个静态方法所做的,我们可以通过在构造函数中输入所需的参数来解决这个问题,并允许用户通过属性设置可选值,或者方法同时设置多个相互依赖的值。另外,如果一个方法已经变得如此复杂,那么它很可能无论如何都需要在自己的类中。好的。

要求消费者无缘无故创建类实例好的。

最常见的一个参数是:为什么要求类的使用者创建一个用于调用这个方法的实例,而随后对该实例没有任何用处?在大多数语言中,创建类的实例是非常便宜的操作,因此速度不是问题。向消费者添加一个额外的代码行是一个低成本,为将来提供一个更可维护的解决方案奠定了基础。最后,如果您想避免创建实例,只需创建类的单例包装器,以便于重用——尽管这确实要求您的类是无状态的。如果它不是无状态的,那么您仍然可以创建处理所有事情的静态包装方法,同时从长远来看仍然可以给您带来所有好处。最后,您还可以创建一个类来隐藏实例化,就好像它是一个单例:mywrapper.instance是一个只返回new MyClass();的属性。好的。

只有西斯才是绝对的。好的。

当然,我不喜欢静态方法也有例外。对于静态方法(system.convert)来说,真正的实用程序类不会对膨胀造成任何风险,这是很好的例子。如果您的项目是一次性的,没有未来维护的需求,那么整个体系结构实际上并不重要——静态的或非静态的,并不重要——但是开发速度确实如此。好的。

标准,标准,标准!好的。

使用实例方法不会禁止您也使用静态方法,反之亦然。只要差异背后有推理,而且标准化。没有什么比用不同的实现方法查看业务层更糟糕的了。好的。好啊。


当决定是将类设置为静态还是非静态时,您需要查看您试图表示的信息。这需要一种更"自下而上"的编程风格,在这种风格中,您将重点放在要首先表示的数据上。你所写的班级是一个真实世界的物体,比如一块石头,还是一把椅子?这些东西是物理的,并且具有物理属性,例如颜色、重量,这告诉您可能需要实例化具有不同属性的多个对象。我可能同时想要一把黑色的椅子和一把红色的椅子。如果您同时需要两个配置,那么您马上就会知道您想要将其实例化为一个对象,这样每个对象都可以是唯一的,并且可以同时存在。

另一方面,静态函数往往更适合于不属于真实世界对象或您可以轻松表示的对象的操作。请记住,C的前身是C++和C,在这里你可以定义一个类中不存在的全局函数。这为"自上而下"编程提供了更多帮助。静态方法可用于"对象"无法执行任务的情况。通过强制您使用类,这使得对相关功能进行分组变得更容易,从而帮助您创建更易于维护的代码。

大多数类都可以用静态或非静态的方式表示,但是当您有疑问时,只需回到OOP根目录并尝试思考您所表示的内容。这是一个执行动作(一辆可以加速、减速、转弯的汽车)的对象还是更抽象的对象(如显示输出)。

接触你内心的OOP,你永远不会出错!


对于C 3.0,扩展方法只能存在于顶级静态类中。


如果您使用代码分析工具(例如fxcop),建议您在方法不访问实例数据的情况下标记方法static。其基本原理是有一个性能增益。msdn:ca1822-将成员标记为静态。

它更像是一条准则,而不是一条规则,真的…


我确实倾向于为工厂使用静态类。例如,这是我的一个项目中的日志类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class Log
{
   private static readonly ILoggerFactory _loggerFactory =
      IoC.Resolve<ILoggerFactory>();

   public static ILogger For<T>(T instance)
   {
      return For(typeof(T));
   }

   public static ILogger For(Type type)
   {
      return _loggerFactory.GetLoggerFor(type);
   }
}

您可能已经注意到IOC是用静态访问器调用的。对我来说,大多数时候,如果你能在一个类上调用静态方法,那就是你所能做的,所以为了更加清晰起见,我把这个类标记为静态的。


静态类非常有用,并且有一个位置,例如库。

我能提供的最好的例子是.NET数学类,它是一个包含数学函数库的系统命名空间静态类。

就像其他任何事情一样,为工作使用正确的工具,如果不是,任何东西都可能被滥用。

毫无疑问地将静态类视为错误的,不要使用它们,或者说"可能只有一个"或者"没有",这和过度使用它们一样错误。

C.NET包含许多与数学类一样使用的静态类。

因此,考虑到正确的实现,它们非常有用。

我们有一个静态时区类,它包含许多与业务相关的时区函数,不需要创建该类的多个实例,就像数学类一样,它在静态类中包含一组全局可访问的时区相关函数(方法)。


当我希望使用函数而不是类作为重用单元时,我已经开始使用静态类。以前,我都是关于静态类的邪恶。然而,学习f让我从新的角度看待它们。

我这是什么意思?好吧,比如说,当编写一些超干代码时,我最终得到了一组方法类。我可以将这些方法拉入静态类,然后使用委托将它们注入依赖项。这也很适合我的依赖注入(DI)容器选择autopac。

当然,直接依赖静态方法仍然是邪恶的(有一些非邪恶的用途)。


我使用静态类作为定义"额外功能"的方法,给定类型的对象可以在特定的上下文中使用这些功能。通常它们是实用程序类。

除此之外,我认为"使用静态类作为与特定对象无关的方法的组织单元。"可以很好地描述它们的预期用途。


这是自OOP介入以来另一个古老但非常热门的问题。当然,使用(或不使用)静态类的原因有很多,其中大多数都包含在大量的答案中。

我只需要把我的2美分加到这个上面,说,我使一个类是静态的,当这个类在系统中是唯一的,并且在程序中有它的任何实例是没有意义的。但是,我将此用法保留在大型类中。我从不将msdn示例中的此类小类声明为"static",当然,也不会声明将成为其他类成员的类。

我还想指出静态方法和静态类是两个不同的事情要考虑。公认答案中提到的主要缺点是静态方法。静态类提供与普通类(涉及属性和参数)相同的灵活性,其中使用的所有方法都应与类的存在目的相关。

在我看来,静态类的候选对象的一个很好的例子是"fileprocessing"类,它包含与执行复杂文件处理操作的程序的各种对象相关的所有方法和属性。拥有这个类的多个实例几乎没有任何意义,而静态的实例将使程序中的所有内容都可以使用它。


我只对助手方法使用静态类,但是随着C 3.0的出现,我更愿意对这些方法使用扩展方法。

我很少使用静态类方法,原因与我很少使用单例"设计模式"的原因相同。


基于MSDN:

  • 不能为静态类创建实例
  • 如果类声明为static,则该类的成员变量应为static
  • 密封[不能继承]
  • 不能包含实例构造函数
  • 内存管理
  • 示例:数学计算(数学值)不会更改[定义值的标准计算]