何时在C#中使用静态类
以下是何时使用静态类 MSDN必须说的 :
static class CompanyInfo { public static string GetCompanyName() { return "CompanyName"; } public static string GetCompanyAddress() { return "CompanyAddress"; } //... }
对于与特定对象不相关的方法,使用静态类作为组织单位。 此外,静态类可以使您的实现更简单,更快,因为您不必创build一个对象来调用它的方法。 以有意义的方式组织类中的方法是很有用的,例如System命名空间中Math类的方法。
对我来说,这个例子似乎没有涵盖静态类的很多可能的使用场景。 在过去,我使用静态类来实现无状态的相关函数套件,但就是这样。 那么,在什么情况下(而不应该)把一个类声明为静态的呢?
我在一个较早的堆栈溢出答案中写了我的静态类的想法: 类与单一的方法 – 最好的办法?
我曾经喜欢充满静态方法的工具类。 他们对辅助方法进行了大量整合,否则这些方法会导致冗余和维护地狱。 他们很容易使用,没有实例化,没有处理,只是fire'n'forget。 我想这是我第一次不知情的尝试创build一个面向服务的架构 – 许多无状态的服务,只是他们的工作,没有别的。 随着系统的发展,龙即将到来。
多态性
假设我们有方法UtilityClass.SomeMethod愉快地嗡嗡声。 突然,我们需要稍微改变function。 大部分的function是一样的,但是我们必须改变几个部分。 如果不是一个静态方法,我们可以根据需要制作派生类并更改方法内容。 由于这是一个静态的方法,我们不能。 当然,如果我们只需要在旧方法之前或之后添加function,我们就可以创build一个新类并在其中调用旧类,但这只是粗略的。
界面的困扰
出于逻辑原因,静态方法不能通过接口定义。 而且由于我们不能重载静态方法,所以当我们需要通过接口传递它们时,静态类就没有用处了。 这使我们无法使用静态类作为策略模式的一部分。 我们可以通过传递委托代替接口来修补一些问题。
testing
这基本上与上面提到的接口问题一起。 由于我们交换实现的能力非常有限,所以在使用testing代码replace生产代码时也会遇到困难。 再次,我们可以把它们包装起来,但是它需要我们改变大部分的代码,只是为了能够接受包装器而不是实际的对象。
促进斑点
由于静态方法通常被用作效用方法,效用方法通常会有不同的用途,所以我们很快就会得到一个充满非一致性function的大类 – 理想情况下,每个类在系统中应该有一个单一的目的。 只要他们的目标明确,我宁愿有五次class。
参数蠕变
首先,那个可爱又天真的静态方法可能只有一个参数。 随着function的增长,添加了一些新的参数。 不久,进一步添加的参数是可选的,所以我们创build方法的重载(或只是添加默认值,支持它们的语言)。 不久,我们有一个方法需要10个参数。 只有前三个是必需的,参数4-7是可选的。 但是,如果指定了参数6,那么也需要填充7-9 …如果我们创build了一个具有这个静态方法所做的单一目的的类,我们可以通过在构造函数,并允许用户通过属性设置可选值,或者同时设置多个相互依赖的值的方法。 而且,如果一种方法已经发展到这种复杂程度,那么无论如何它最有可能需要在自己的类中。
要求消费者没有理由地创build一个类的实例
其中一个最常见的论点是:为什么要求我们的类的消费者创build一个调用这个单一方法的实例,而之后没有使用这个实例呢? 在大多数语言中创build一个类的实例是非常非常便宜的操作,所以速度不是问题。 向消费者添加额外的代码行是为将来更可维护的解决scheme打下基础的低成本。 最后,如果你想避免创build实例,只需创build一个允许轻松重用的类的单例包装器(singleton wrapper),尽pipe这确实要求你的类是无状态的。 如果它不是无状态的,那么仍然可以创build静态包装方法来处理所有事情,同时仍然可以长期为您提供所有的好处。 最后,你也可以创build一个隐藏实例的类,就好像它是一个单例:MyWrapper.Instance是一个只返回new MyClass();
的属性new MyClass();
只有一个西斯交易绝对
当然,我也不喜欢静态方法。 真正的实用程序类别不会造成任何膨胀风险,这是静态方法的绝佳例子 – 以System.Convert为例。 如果你的项目是一次性的,对未来的维护没有任何要求,那么整体架构确实不是非常重要的 – 静态或者非静态,并不重要,但是开发速度确实是这样。
标准,标准,标准!
使用实例方法不会阻止您使用静态方法,反之亦然。 只要分化背后有推理,标准化。 没有什么比通过不同的实现方法来查看业务层更糟了。
在决定是否使类成为静态或非静态时,您需要查看您想要表示的信息。 这就需要更多的“ 自下而上 ”的编程风格,将注意力放在首先代表的数据上。 你正在写一个类似岩石或椅子的真实世界对象吗? 这些东西是物理的,并有物理属性,如颜色,重量告诉你,你可能想实例化具有不同属性的多个对象。 我可能同时需要一把黑色的椅子和一把红色的椅子。 如果你同时需要两个configuration,那么你立即知道你将要实例化它作为一个对象,所以每个对象可以是唯一的,同时存在。
另一方面,静态函数更倾向于不属于真实世界的对象或可以轻易表示的对象的行为。 请记住,C#的前身是C ++和C,您可以在其中定义不存在于类中的全局函数。 这更多地用于“ 自上而下 ”的编程。 静态方法可以用于这样的情况,即“对象”执行任务是没有意义的。 通过强制你使用类,这只是使组合相关的function更容易,这有助于你创build更多可维护的代码。
大多数类可以用静态或非静态表示,但是当你怀疑的时候,可以回到你的OOP根目录,试着去思考你所代表的东西。 这是一个执行动作的对象(可以加速,减速,转弯的车)或更抽象的东西(如显示输出)。
联系你的内部面向对象,你永远不会出错!
对于C#3.0,扩展方法可能只存在于顶级静态类中。
如果您使用代码分析工具(例如FxCop ),则build议您在不访问实例数据的情况下使方法静态化。 理由是有一个性能增益。 参考号: CA1822:将成员标记为静态 ( MSDN )。
这是一个比一个规则的指导,真的…
我确实倾向于为工厂使用静态类。 例如,这是我的一个项目中的日志logging类:
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是使用静态访问器调用的。 大部分时间对于我来说,如果你可以在一个类上调用静态方法,那么你可以这样做,所以我将这个类标记为静态的,以便更清晰。
当我希望使用函数而不是类作为重用单元时,我开始使用静态类。 以前,我是关于静态类的邪恶。 但是,学习F#让我看到了新的一面。
这是什么意思? 那么说,当处理一些超级DRY代码时,我最终得到了一堆单方法类。 我可能只是将这些方法拉入静态类,然后使用委托将它们注入到依赖项中。 这也很好地与我的dependency injection (DI)容器selectAutofac。
当然,直接依赖静态方法通常仍然是邪恶的(有一些非邪恶用途)。
我使用静态类作为定义给定types的对象可以在特定上下文中使用的“额外function”的手段。 通常他们变成实用类。
除此之外,我认为“使用静态类作为与特定对象无关的方法的组织单位”。 很好地描述了它们的用途。
静态类是非常有用的,有一个地方,例如库。
我可以提供的最好的例子是.Netmath类,一个System命名空间静态类,它包含一个math函数库。
就像其他任何事情一样,使用正确的工具来完成这项工作,如果没有任何东西可以被滥用。
不要用静态类,不要使用静态类,或者说“只能有一个”,或者不能使用静态类。
C#.Net包含许多静态类,就像Math类一样使用。
所以给予正确的实施,他们是非常有用的。
我们有一个静态的TimeZone类,它包含许多业务相关的时区函数,不需要像Math类那样创build多个类的实例,它包含一组静态类中全局可访问的TimeZone相关函数(方法) 。
自从OOP开始,这是另一个古老而又非常热门的问题。当然,使用(或不使用)静态类的原因有很多,其中大部分答案已经涵盖了大部分。
我只是把我的2美分添加到这个,说,我做了一个类静态,当这个类是在系统中是独一无二的,这真的没有任何意义的程序中的任何实例。 不过,我保留这个用于大class的用法。 我从来没有像在MSDN例子中那样将这样的小类声明为“static”,当然也不是将要成为其他类的成员的类。
我还想指出,静态方法和静态类是两个不同的事情要考虑。 在接受的答案中提到的主要缺点是静态方法 。 静态类提供了和普通类相同的灵活性(涉及属性和参数),而且它们中使用的所有方法都应该与类的存在目的相关。
在我看来,一个很好的例子是一个“FileProcessing”类,它将包含与程序各种对象相关的所有方法和属性,以执行复杂的FileProcessing操作。 拥有这个类的多个实例几乎没有任何意义,并且静态的将会使其在程序中的所有内容都可用。
我只使用静态类辅助方法,但随着C#3.0的到来,我宁愿使用扩展方法。
为什么我很less使用单例“devise模式”,我很less使用静态类方法。
基于MSDN :
- 您不能为静态类创build实例
- 如果该类声明为静态,则该类的成员variables应该是静态的
- 密封[不能被inheritance]
- 不能包含实例构造函数
- 内存pipe理
示例:math计算(math值)不会更改[定义值的标准计算]