402

ReSharper 喜欢指出每个 ASP.NET 页面的多个功能,这些功能可以设为静态。如果我将它们设为静态,它对我有帮助吗?我应该将它们设为静态并将它们移动到实用程序类吗?

4

14 回答 14

278

在我看来,性能、命名空间污染等都是次要的。问问自己什么是合乎逻辑的。该方法是在逻辑上对类型的实例进行操作,还是与类型本身相关?如果是后者,请将其设为静态方法。仅当它与不受您控制的类型相关时才将其移动到实用程序类中。

有时有些方法在逻辑上作用于实例,但还没有碰巧使用实例的任何状态。例如,如果你正在构建一个文件系统并且你已经有了目录的概念,但你还没有实现它,你可以编写一个返回文件系统对象类型的属性,它总是只是“文件” - 但它在逻辑上与实例相关,因此应该是实例方法。如果您想使方法成为虚拟方法,这也很重要——您的特定实现可能不需要状态,但派生类可能需要。(例如,询问一个集合是否是只读的——你可能还没有实现该集合的只读形式,但它显然是集合本身的属性,而不是类型。)

于 2008-10-04T06:34:03.180 回答
267

静态方法与实例方法C# 语言规范的
静态和实例成员解释了差异。通常,静态方法可以比实例方法提供非常小的性能增强,但仅在有些极端的情况下(有关更多详细信息,请参见此答案)。

FxCop 或代码分析中的规则 CA1822 指出:

“在 [将成员标记为静态] 之后,编译器将向这些成员发出非虚拟调用站点,这将阻止在运行时检查每个调用以确保当前对象指针非空。这可以带来可衡量的性能提升对于性能敏感的代码。在某些情况下,无法访问当前对象实例表示正确性问题。

实用程序类
您不应该将它们移动到实用程序类,除非它在您的设计中有意义。如果静态方法与特定类型相关,例如ToRadians(double degrees)方法与表示角度的类相关,则该方法作为该类型的静态成员存在是有意义的(注意,这是一个用于演示目的的复杂示例)。

于 2008-10-04T00:12:50.767 回答
61

将方法标记为static类中的方法很明显它不使用任何实例成员,这有助于在浏览代码时了解。

您不必将它移动到另一个类,除非它打算由另一个密切相关的类共享,概念方面。

于 2008-10-04T01:04:09.587 回答
22

我确定这不会发生在您的情况下,但是我在一些代码中看到了一种“难闻的气味”,我不得不通过维护使用大量的静态方法而遭受痛苦。

不幸的是,它们是假定特定应用程序状态的静态方法。(当然,每个应用程序只有一个用户!为什么不让 User 类在静态变量中跟踪它?)它们是访问全局变量的美化方式。他们还有静态构造函数(!),这几乎总是一个坏主意。(我知道有几个合理的例外)。

但是,当静态方法分解出实际上并不依赖于对象实例状态的域逻辑时,它们非常有用。它们可以使您的代码更具可读性。

只要确保你把它们放在正确的地方。静态方法是否侵入性地操纵其他对象的内部状态?可以证明他们的行为属于其中一个类吗?如果你没有正确地分离关注点,你以后可能会头疼。

于 2008-10-04T00:29:01.047 回答
13

这很有趣:
http ://thecuttingledge.com/?p=57

ReSharper 实际上并不建议您将方法设为静态。您应该问自己为什么该方法在该类中,而不是在其签名中显示的类之一...

但这是 ReSharper 文档所说的: http ://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static

于 2012-06-19T11:33:47.500 回答
10

只是添加到@Jason True 的答案中,重要的是要意识到仅将“静态”放在方法上并不能保证该方法将是“纯”的。对于声明它的类而言,它将是无状态的,但它可以很好地访问具有状态(应用程序配置等)的其他“静态”对象,这可能并不总是一件坏事,但原因之一是我个人倾向于在可能的情况下更喜欢静态方法,因为如果它们是纯的,您可以单独测试和推理它们,而不必担心周围的状态。

于 2009-09-03T05:52:35.903 回答
7

对于类中的复杂逻辑,我发现私有静态方法可用于创建隔离逻辑,其中实例输入在方法签名中明确定义,不会发生实例副作用。所有输出必须通过返回值或 out/ref 参数。将复杂的逻辑分解成无副作用的代码块可以提高代码的可读性和开发团队对它的信心。

另一方面,它可能导致一个类被实用方法的扩散所污染。像往常一样,逻辑命名、文档和团队编码约定的一致应用可以缓解这种情况。

于 2009-10-15T20:44:25.910 回答
6

您应该在给定的场景中做最易读和最直观的事情。

性能参数不是一个好的参数,除非在最极端的情况下,因为唯一实际发生的事情是一个额外的参数 ( this) 被压入堆栈以用于实例方法。

于 2008-10-04T00:05:49.063 回答
5

ReSharper 不检查逻辑。它只检查该方法是否使用实例成员。如果该方法是私有的并且仅由(可能只有一个)实例方法调用,则这是让它成为实例方法的标志。

于 2012-02-06T09:27:59.207 回答
3

如果这些功能在许多页面之间共享,您也可以将它们放在一个基页面类中,然后让所有使用该功能的 asp.net 页面都继承自它(并且这些功能也可以是静态的)。

于 2008-10-04T00:07:50.870 回答
3

将方法设为静态意味着您可以从类外部调用该方法,而无需先创建该类的实例。这在使用第三方供应商对象或附加组件时很有帮助。想象一下,如果您必须在调用 con.Writeline() 之前首先创建一个控制台对象“con”;

于 2008-10-04T01:08:36.083 回答
2

它有助于控制命名空间污染。

于 2008-10-04T00:04:08.180 回答
2

我希望您已经了解静态方法和实例方法之间的区别。此外,可以有一个很长的答案和一个简短的答案。其他人已经提供了长答案。

我的简短回答:是的,您可以按照 ReSharper 的建议将它们转换为静态方法。这样做没有坏处。相反,通过使方法静态,您实际上是在保护该方法,以便您不会不必要地将任何实例成员滑入该方法。这样,您可以实现 OOP 原则“最小化类和成员的可访问性”。

当 ReSharper 建议可以将实例方法转换为静态方法时,它实际上是在告诉您,“为什么 .. 这个方法位于此类中,但实际上并没有使用它的任何状态?” 所以,它让你深思。然后,您可以意识到是否需要将该方法移动到静态实用程序类。根据 SOLID 原则,一个类应该只有一个核心职责。因此,您可以通过这种方式更好地清理您的类。有时,即使在您的实例类中,您也确实需要一些辅助方法。如果是这种情况,您可以将它们保存在#region 助手中。

于 2020-05-20T03:28:59.127 回答
0

Just my tuppence:将所有共享静态方法添加到实用程序类允许您添加

using static className; 

到您的 using 语句,这使代码更快地键入和更易于阅读。例如,在我继承的一些代码中,我有大量被称为“全局变量”的东西。我没有在作为实例类的类中创建全局变量,而是将它们全部设置为全局类的静态属性。它完成了这项工作,如果杂乱无章,我可以按名称引用属性,因为我已经引用了静态命名空间。

我不知道这是否是好的做法。我有很多关于 C# 4/5 的知识要学习,还有很多遗留代码要重构,我只是想让 Roselyn 技巧指导我。

乔伊

于 2016-11-14T16:09:41.413 回答