关于c#:方法可以是静态的,但应该是吗?

Method can be made static, but should it?

Resharper喜欢为每个ASP.NET页指出可以设置为静态的多个函数。如果我真的使它们静止,这对我有帮助吗?我应该使它们静态化并将它们移到实用程序类中吗?


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

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


静态方法与实例方法< BR>10.2.5 C语言规范的静态成员和实例成员解释了这一区别。通常,静态方法可以比实例方法提供非常小的性能增强,但只能在一些极端的情况下提供(有关此问题的更多详细信息,请参见此答案)。

fxcop中的规则CA1822或代码分析状态:

"After [marking members as static], the compiler will emit non-virtual call sites to these members which will prevent a check at
runtime for each call that ensures the current object pointer is
non-null. This can result in a measurable performance gain for
performance-sensitive code. In some cases, the failure to access the
current object instance represents a correctness issue."

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


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

你不必把它移到另一个类中去,除非它被另一个类共享,而这个类同样紧密地联系在一起,从概念上讲。


我敢肯定在你的情况下不会发生这种情况,但是我在一些代码中看到过一种"臭味",那就是我必须通过维护使用大量静态方法来忍受这种气味。

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

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

只是要确保你把它们放在正确的地方。静态方法是否会干扰其他对象的内部状态?是否可以很好地说明他们的行为属于这些类中的一个类?如果你没有正确地分开关注点,你以后可能会头疼。


这是一本有趣的书:

http://thecutingledge.com/?P=57

Resharper实际上并不是建议您将方法设置为静态的。你应该问问自己,为什么这个方法在那个类中,而不是,比如,在它的签名中出现的一个类…

但雷斯哈珀的纪录片说:http://confluence.jetbrains.net/display/resharper/member+can+be+made+static


为了增加@jason true的答案,重要的是要认识到,仅仅在一个方法上放置"static"并不能保证该方法是"纯"的。对于声明它的类,它将是无状态的,但它可以很好地访问其他具有状态(应用程序配置等)的"静态"对象,这可能并不总是一件坏事,但我个人倾向于选择静态方法的原因之一是,如果它们是纯的,您可以在隔离,不用担心周围的状况。


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

另一方面,它会导致一个被实用方法扩散污染的类别。和往常一样,逻辑命名、文档和一致的团队编码约定应用可以减轻这一点。


在给定的场景中,您应该执行最可读和最直观的操作。

除了在最极端的情况下,性能参数不是一个好参数,因为实际发生的唯一事情是将一个额外的参数(this推送到堆栈上,例如方法。


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


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


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


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


只是我的建议:将所有共享的静态方法添加到实用程序类中可以添加

1
using static className;

到您的using语句,这使得代码更容易键入和读取。例如,在我继承的一些代码中,我有大量所谓的"全局变量"。我将它们全部设置为全局类的静态属性,而不是在实例类中生成全局变量。它执行任务,如果很混乱,我可以通过名称引用属性,因为我已经引用了静态名称空间。

我不知道这是不是好的做法。我有太多关于C 4/5的知识,还有太多要重构的遗留代码,所以我只是想让RoselynTips来指导我。

乔伊