应该*静态的C#方法应该是静态的吗?

应该静态的C#方法应该是静态的吗?

我们今天正在讨论这个问题,而且我很尴尬。 想象一下,你有一个很长的方法,你重构了几行。 新方法可能会从父方法中获取一些局部variables并返回一个值。 这意味着它可能是静态的。

问题是:它应该是静态的吗? 这不是devise或select的静态,简单来说就是它没有引用任何实例值。

这取决于。 实际上有两种types的静态方法:

  1. 因为可以是静态的方法
  2. 因为他们必须是静态的方法

在一个小到中等大小的代码库中,你可以真正地对待这两种方法。

如果你有一个方法在第一类(can-be-static),并且你需要改变它来访问类的状态,那么直接找出是否有可能把静态方法变成一个实例方法。

然而,在一个庞大的代码库中,纯粹的呼叫站点数量可能会使得search能够将静态方法转换为非静态方法成本过高。 很多时候,人们会看到电话的数量,并说:“好的…我最好不要改变这种方法,而是创造一个新的,做我所需要的”。

这可能导致:

  1. 很多代码重复
  2. 方法参数数量的爆炸式增长

这两件事都很糟糕。

所以,我的build议是,如果你有一个超过200K LOC的代码库,那么我只会使方法成为静态的,如果它们是必须是静态方法的话。

从非静态到静态的重构相对比较简单(只需要添加一个关键字),所以如果你想稍后将一个静态的静态变成一个实际的静态(当你需要它在一个实例之外的function),那么你可以。 但是,逆向重构,将一个可以静态化的实例方法变得更加昂贵。

对于大代码库,最好是在易于扩展的方面出错,而不是在idealogical纯度方面。

所以,对于大项目来说,除非你需要它们,否则不要把它们变成静态的。 对于小项目,只要做你最喜欢的事。

不会让它成为这个类公共静态成员。 原因是把它变成静态的就是说类的types:不仅是“这种types知道如何做这个行为”,而且“这种行为是这种types的责任”。 而这种行为的可能性已经不再与更大的types有任何真正的关系。

这并不意味着我不会让它变成静态的。 问问你自己:这个新方法在逻辑上可以属于别处吗? 如果您可以回答“是”,那么您可能希望将其设置为静态(并将其移动)。 即使这不是真的,你仍然可以把它变成静态的。 只是不要把它public

为了方便起见,您至less可以将其标记为internal 。 如果您不便于访问更适合的types,则通常会避免需要移动该方法,但仍然可以在需要时使其可访问,从而使其不会显示为类的用户的公共接口的一部分。

不必要。

将公共方法从静态移动到非静态是一个重大改变,并且需要对所有调用者或使用者进行更改。 如果一个方法看起来像一个实例方法,但碰巧不使用任何实例成员,我会build议将它作为一个实例方法作为未来validation的一个尺度。

是。 “它可以是静态的”的原因是它不会在被调用的对象的状态下操作。 因此它不是一个实例方法,而是一个类方法。 如果它可以在不访问实例的数据的情况下做它需要做的事情,那么它应该是静态的。

是的,应该的。 有各种各样的耦合指标可以衡量你的类如何依赖于其他的东西,比如其他的类,方法等等。静态的方法是一种保持耦合度的方法,因为你可以确定静态方法不会引用成员。

我认为如果将其标记为静态,它会使它更具可读性。然后有人会知道它不会引用任何实例variables,而不必读取整个函数。

就我个人而言,我是无国界的忠实粉丝。 你的方法是否需要访问类的状态? 如果答案是否定的(可能不是,否则你不会考虑把它作为一个静态的方法),那么是的,去做吧。

没有进入状态是不那么头痛。 正如隐藏其他类别不需要的私人成员是一个好主意,隐藏不需要成员的状态是一个好主意。 访问量减less意味着更less的错误。 此外,它使线程更容易,因为保持静态成员线程安全更容易。 还有一个性能方面的考虑,因为运行时不需要将这个引用作为parameter passing给静态方法。

当然,缺点是,如果你发现以前的静态方法由于某种原因将不得不访问状态,那么你必须改变它。 现在我明白,这可能是公共API的一个问题,所以如果这是公共类中的公共方法,那么也许你应该考虑一下这个问题的含义。 尽pipe如此,我从来没有在现实世界中遇到过这样的问题,但也许我真的很幸运。

所以是的,一定要去。

静态方法比非静态方法快,所以是的,如果可以的话静态方法应该是静态的, 并且没有特殊的理由让它们变为非静态的

仅仅因为你可以做一些静态的东西不是一个好主意。 由于其devise,静态方法应该是静态的,而不是偶然的。

就像迈克尔说的那样,稍后改变它会破坏正在使用它的代码。

这就是说,这听起来像是你正在为这个类创build一个私有效用函数,事实上,它是静态的devise。

事实上,我很惊讶这里提到了封装。 实例方法将自动访问所有私有(实例)字段,属性和方法。 除了从基类inheritance的所有保护的。

当您编写代码时,您应该尽可能less地写入代码,以便尽可能less地访问代码。

所以是的,如果你要使你的方法变成静态的,那么让你的代码更快就可能是很重要的,但是通常更重要的是让代码尽可能地不能创build错误。 一种方法是让你的代码尽可能less的访问“私人东西”。

这看起来似乎无关紧要,因为OP显然是在讨论在这种情况下不会出错的重构,并且创build了任何新的错误,但是这个重构后的代码必须在将来得到维护,并且被修改,使得代码有更大的“攻击表面“,如果它有访问私有实例成员的新bug。 所以总的来说,我认为这里的结论是“是的,大多数情况下你的方法应该是静态的”,除非有其他原因使得它们不是静态的。 这只是因为它“更好地使用封装和数据隐藏并创build'更安全的'代码”…

如果你能够重构几行代码,结果的方法可能是静态的,那么可能表明你从这个方法中取出的行根本不属于包含的类,你应该考虑将它们移到他们自己的class级

就我个人而言,我别无select,只能把它变成静态的。 Resharper在这种情况下发出警告,我们的PM有一个规则“没有来自Resharper的警告”。

这取决于,但通常我不会使这些方法静态。 代码总是在变化,也许有一天我会想让这个函数变成虚拟的,并在一个子类中覆盖它。 也许有一天它需要引用实例variables。 如果每个呼叫站点都要更改,那么做出这些更改将更加困难。

我build议最好的方法是这样的:如果你需要一个类方法,当没有实例化类的时候需要被调用,或者维护某种全局状态,那么静态是一个好主意。 但总的来说,我build议你应该更喜欢让会员变成非静态的。

你应该考虑你的方法和类:

  • 你打算如何使用它们?
  • 你需要从不同级别的代码中获得很多访问权限吗?
  • 这是几乎每一个可以想象的项目中都可以使用的方法/类。

如果最后两个是“是”,那么你的方法/类应该是静态的。

最常用的例子可能是Math类。 每个主要的OO语言都有,所有的方法都是静态的。 因为你需要能够随时随地使用它们,而不需要创build实例。

另一个很好的例子是C#中的Reverse()方法。
这是Array类中的一个静态方法。 它颠倒了你的数组的顺序。

码:

 public static void Reverse(Array array) 

它甚至不返回任何东西,你的数组是相反的,因为所有的数组都是Array类的实例。

我肯定会把我能变成静态的东西变成另外一个原因:

静态函数,当JIT'd被调用时没有“this”参数。 这意味着,例如,一个3参数的非静态函数(成员方法)被压入堆栈中的4个参数。

编译为静态函数的函数将被调用3个参数。 这可以释放JIT的寄存器并节省堆栈空间。

固有的静态方法,由于某种原因使非静态只是烦人的。 以机智:

我打电话给我的银行,要求我的余额。
他们要求我的帐号。
很公平。 实例方法。

我打电话给我的银行,并要求他们的邮寄地址。
他们要求我的帐号。
WTF? 失败 – 应该是静态方法。

只要你使新的方法私有静态它不是一个突破性的变化。 实际上,FxCop包含此指导作为其规则之一( http://msdn.microsoft.com/en-us/library/ms245046(VS.80).aspx ),其中包含以下信息:

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

也就是说,David Kean的第一个评论更简洁地总结了这个问题,他说这实际上更多的是关于正确性而不是性能上的提升:

尽pipe这个规则被归类为一个性能问题,但是静态方法的性能改进只有1%左右。 相反,这是一个正确性问题,可能由于未能使用其他实例成员而指示成员中的不完整或错误。 标记静态(Visual Basic中的共享 )方法使其清除意图不触及实例状态。

我在“只做私人方法静态”阵营。 公开的方法可以引入你不想要的耦合,并可能降低可testing性:你不能存根公共静态方法。

如果你想unit testing一个使用公共静态方法的方法,你最终也会testing静态方法,这可能不是你想要的。

我通常从纯函数的functionangular度来看待它。 它是否需要成为实例方法? 如果没有,您可能会受益于强制用户传入variables,而不是修改当前实例的状态。 (好吧,你仍然可能会破坏状态,但重点是devise,不这样做。)我一般devise实例方法作为公共成员,并尽我所能使私人成员静态。 如果有必要的话(以后可以更容易地将它们提取到其他类中)。

在这种情况下,我倾向于将方法转移到静态库或实用库,所以我不会将“对象”的概念与“类”的概念混合在一起,