ChatGPT解决这个技术问题 Extra ChatGPT

何时在 C# 中使用静态类 [重复]

这个问题在这里已经有了答案:Class with single method -- best approach? (15 个回答) 7 年前关闭。

以下是 MSDN has to say under When to Use Static Classes

静态类 CompanyInfo { 公共静态字符串 GetCompanyName() { return "CompanyName"; } 公共静态字符串 GetCompanyAddress() { return "CompanyAddress"; } //... } 使用静态类作为与特定对象无关的方法的组织单元。此外,静态类可以使您的实现更简单、更快,因为您不必创建对象即可调用其方法。以有意义的方式组织类内部的方法很有用,例如 System 命名空间中的 Math 类的方法。

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

作为 C# 的新手,解释一下为什么这被标记为 singleton vs static class 的重复问题以及这两者如何相互关联会很有帮助。
mr5、单例和静态类基本上是一回事。单例是其他语言用来模拟静态类的设计模式,因为其他语言(如Java)没有内置静态类,所以你必须依赖单例设计模式来创建这样的类。 Static类是不能实例化的类,可以直接使用(比如Console类)。 tutorialspoint.com/design_pattern/singleton_pattern.htm 如果您选中此项,您将看到当您使用 Singleton 时,您并没有创建新实例...
...您正在使用已在 Singleton 类中创建的那个,并且您可以通过 .getInstance() 方法访问它。 C# 通过一个简单的关键字“static”解决了所有这些问题。
单例类和静态类本质上是完全相反的东西。一个可以实例化,另一个禁止实例化。
恕我直言,在为对象设计属性时,请考虑盒子内部的实例化和开箱即用的静态类。

C
Callum Watkins

我在早期的 Stack Overflow 回答中写下了我对静态类的想法:Class with single method -- best approach?

我曾经喜欢充满静态方法的实用程序类。他们对辅助方法进行了极大的整合,否则这些方法会导致冗余和维护地狱。它们非常易于使用,无需实例化,无需处置,只需一劳永逸。我想这是我第一次在不知情的情况下尝试创建面向服务的架构——许多无状态服务只是完成了它们的工作,没有别的。然而,随着系统的发展,巨龙即将到来。

多态性

假设我们有方法 UtilityClass.SomeMethod 愉快地嗡嗡作响。突然我们需要稍微改变一下功能。大多数功能是相同的,但我们仍然必须更改几个部分。如果它不是静态方法,我们可以创建一个派生类并根据需要更改方法内容。因为它是一个静态方法,我们不能。当然,如果我们只需要在旧方法之前或之后添加功能,我们可以创建一个新类并在其中调用旧类——但这很糟糕。

接口问题

由于逻辑原因,不能通过接口定义静态方法。而且由于我们不能覆盖静态方法,所以当我们需要通过接口传递静态类时,它们是无用的。这使我们无法使用静态类作为策略模式的一部分。我们可能会在 passing delegates instead of interfaces 之前修补一些问题。

测试

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

促进斑点

由于静态方法通常用作实用方法,而实用方法通常有不同的用途,我们很快就会得到一个充满不连贯功能的大型类——理想情况下,每个类在系统中应该有一个单一的用途。只要他们的目的明确,我宁愿有五倍的课程。

参数蠕变

首先,那个可爱又纯真的静态方法可能只需要一个参数。随着功能的增长,添加了几个新参数。很快就会添加更多可选参数,因此我们创建方法的重载(或仅添加默认值,使用支持它们的语言)。不久之后,我们就有了一个需要 10 个参数的方法。只有前三个是真正需要的,参数 4-7 是可选的。但是如果指定了参数 6,那么 7-9 也需要填写……如果我们创建一个类的目的只是为了做这个静态方法所做的事情,我们可以通过在构造函数,并允许用户通过属性设置可选值,或者同时设置多个相互依赖的值的方法。此外,如果一个方法已经发展到如此复杂的程度,它很可能无论如何都需要在自己的类中。

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

最常见的论点之一是:为什么要求我们类的消费者创建一个实例来调用这个单一方法,而之后却没有使用该实例?在大多数语言中,创建类的实例是一项非常便宜的操作,因此速度不是问题。向消费者添加额外的代码行成本很低,可以为未来更易于维护的解决方案奠定基础。最后,如果您想避免创建实例,只需创建一个允许轻松重用的类的单例包装器 - 尽管这确实要求您的类是无状态的。如果它不是无状态的,您仍然可以创建处理所有内容的静态包装器方法,同时从长远来看仍然为您提供所有好处。最后,您还可以创建一个隐藏实例化的类,就好像它是一个单例一样:MyWrapper.Instance 是一个只返回 new MyClass(); 的属性

只有西斯在绝对交易

当然,我不喜欢静态方法也有例外。不会造成任何膨胀风险的真正实用程序类是静态方法的极好案例 - 以 System.Convert 为例。如果您的项目是一次性的,对未来的维护没有要求,那么整体架构真的不是很重要 - 静态或非静态,并不重要 - 但是开发速度确实如此。

标准,标准,标准!

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


Steve Yegge 也写过它。但是他的帖子比在这里发布的要长。如果您仍然不相信,请尝试 steve.yegge.googlepages.com/singleton-considered-stupid
有没有人注意到“只有西斯交易绝对”这句话是绝对的?对不起。没办法。
就像我竭力想表达我的观点一样,耶格也是如此。他的一些观点归结为正常的编程考虑 - 如果单例保持有价值的资源开放,那当然可能是一个问题。仔细考虑后,单例和静力学之类的地方都有。
@John Kraft:这显然是西斯写的。
他的问题是“何时使用静态类”——但您似乎已经回答了“何时不使用静态类”的问题——很微妙。但是我仍然不知道你什么时候应该使用它们。一些适当使用的例子会很好+如果两个线程非常接近地调用静态类或方法怎么办 - 那是什么时候好/坏?
T
Tim S. Van Haren

在决定将类设为静态还是非静态时,您需要查看您尝试表示的信息。这需要一种更“自下而上”的编程风格,您首先关注您所代表的数据。你正在写的课程是像石头还是椅子这样的真实世界的对象?这些东西是物理的,并且具有诸如颜色、重量等物理属性,这些属性告诉您您可能想要实例化具有不同属性的多个对象。我可能同时想要一把黑色椅子和一把红色椅子。如果您同时需要两个配置,那么您会立即知道您希望将其实例化为一个对象,这样每个对象都可以是唯一的并且可以同时存在。

另一方面,静态函数倾向于更多地用于不属于现实世界对象或您可以轻松表示的对象的动作。请记住,C# 的前身是 C++ 和 C,您可以在其中定义类中不存在的全局函数。这有助于“自上而下”的编程。静态方法可用于“对象”执行任务没有意义的情况。通过强制您使用类,这使得对相关功能进行分组变得更加容易,从而帮助您创建更可维护的代码。

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

与你内心的 OOP 联系,你永远不会出错!


“你一定是无形的,无形的,就像水一样。当你把水倒进杯子里时,它就变成了杯子。当你把水倒进瓶子里时,它就变成了瓶子。当你把水倒进茶壶里,它就变成了茶壶。水可以滴落,也可以崩溃。变得像水一样,我的朋友。” - 李小龙
@Chef_Code 对不起,我无法理解 - 如果您不介意我问,您的报价与给定问题有什么关系?
您可以在 C++ 中的类中创建,与 C# 几乎相同,这是 C++ 和 C 之间的主要区别。
很好的解释——就简单性和简洁性而言,这是我见过的最好的解释。我会向这个主题的任何人推荐这一个加上 Mark Rasmussen 的更多细节!
J
Jason Bunting

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


C
Community

如果您使用代码分析工具(例如 FxCop),如果该方法不访问实例数据,它会建议您标记方法 static。理由是有性能提升。 MSDN: CA1822 - Mark members as static

与其说是规则,不如说是指导方针,真的……


此外,实例类中私有方法的此类静态声明向开发人员传达了有用的附加信息。它告知此类私有静态方法不会更改实例状态。即该方法是类中的实用方法。
R
Rob

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

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 是使用静态访问器调用的。对我来说,大多数时候,如果你可以在一个类上调用静态方法,那就是你所能做的,所以为了更加清晰,我将这个类标记为静态。


为什么在泛型方法中定义一个未使用的参数?
@JohnClearZ 可能是因为您可以使用现有对象调用 For 并获取它的记录器,而无需考虑对象的实际类型。只是一个猜测。
B
BenMorel

静态类非常有用并且占有一席之地,例如库。

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

就像其他任何事情一样,使用正确的工具来完成工作,否则任何事情都可能被滥用。

将静态类视为错误,不要使用它们,或者说“只能有一个”或没有,与过度使用它们一样错误。

C#.Net 包含许多与 Math 类一样使用的静态类。

因此,如果实现正确,它们将非常有用。

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


说“只能有一个”的答案不是在谈论静态类的数量,而是很可爱(虽然相当不正确)暗示只能有一个实例的事实(错误,因为实际上只能有零个实例)
啊,谢谢柯克,因此我很困惑;在任何情况下,简单地忽略静态或笼统地说单例模式更好(如我所见)在我看来是从工具箱中取出一个非常有价值的工具。
“只能有一个”是指现实世界中可以用静态类表示的概念或事物。与 System.Math 一样,您可能只需要一种方法来获取特定输入并离开并获得正确答案。只有一种方法可以进行基本数学 - 其他任何东西都太专业而无法与标准库相关联。另一个例子可能是一个只有一个房间或一个运动场的简单视频游戏。
P
Peter Mortensen

当我希望使用函数而不是类作为我的重用单元时,我已经开始使用静态类。以前,我都是关于静态类的邪恶的。但是,学习 F# 让我对它们有了新的认识。

我这是什么意思?好吧,假设在编写一些超级 DRY 代码时,我最终得到了一堆单一方法类。我可能只是将这些方法拉入一个静态类,然后使用委托将它们注入到依赖项中。这也与我选择的 dependency injection (DI) 容器 Autofac 配合得很好。

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


T
Trap

我使用静态类来定义给定类型的对象可以在特定上下文中使用的“额外功能”。通常它们是实用程序类。

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


T
ThunderGr

这是自 OOP 开始以来另一个古老但非常热门的问题。当然,使用(或不使用)静态类的原因有很多,其中大部分都已在众多答案中涵盖。

我将为此添加我的 2 美分,说,我将一个类设为静态,当这个类在系统中是唯一的并且在程序中拥有它的任何实例时真的没有意义。但是,我将这种用法保留给大班。我从不将 MSDN 示例中的小类声明为“静态”,当然,也不会声明将成为其他类成员的类。

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

在我看来,静态类候选的一个很好的例子是“FileProcessing”类,它将包含与程序的各种对象相关的所有方法和属性,以执行复杂的 FileProcessing 操作。拥有多个此类的实例几乎没有任何意义,并且静态将使程序中的所有内容都可以轻松使用它。


j
jonnii

我只对辅助方法使用静态类,但随着 C# 3.0 的出现,我宁愿使用扩展方法。

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


我宁愿不将扩展方法用于辅助方法。扩展方法很混乱,让其他开发人员感到困惑,并且在其他语言中通常不直观。扩展方法有其目的,但不是作为通用辅助方法恕我直言。
澄清一下,通过辅助方法,我的意思是:string.ToSentence() 或 string.Camelize()。基本上任何会存在于像 StringHelpers 这样的类中的东西。
扩展方法让你陷入了困境……我认为如果你发现自己为给定类型添加了超过 2 个扩展方法,那么可能是时候检查一下原因了。
这两个例子,我特别不喜欢。类型越通用,就越不适合扩展方法。最糟糕的例子是开始将 ToInt32() 方法添加到 Object、ToDateTime() 等。我宁愿将它们放在单独的类中。
A
Amir

基于 MSDN

您不能为静态类创建实例如果声明为静态的类,则该类的成员变量应该是静态的 Sealed [不能继承] 不能包含实例构造函数内存管理

示例:数学计算(数学值)不会改变 [STANDARD CALCULATION FOR DEFINED VALUES]


您只是在描述什么是静态类,而不是描述它们何时实用,或者它们的目的是什么。
问题是关于何时使用静态类而不是你可以用静态类做什么。