可以是静态的C#方法应该是静态的吗?
我们今天在讨论这个问题,我有点担心。想象一下,您有一个很长的方法需要重构几行。新方法可能会从父方法中获取一些局部变量并返回一个值。这意味着它可能是静态的。
问题是:它应该是静态的吗?它在设计或选择上不是静态的,仅就其本质而言,因为它不引用任何实例值。
可以是静态的C#方法应该是静态的吗?
我们今天在讨论这个问题,我有点担心。想象一下,您有一个很长的方法需要重构几行。新方法可能会从父方法中获取一些局部变量并返回一个值。这意味着它可能是静态的。
问题是:它应该是静态的吗?它在设计或选择上不是静态的,仅就其本质而言,因为它不引用任何实例值。
Answers:
这取决于。静态方法实际上有两种:
在中小型代码库中,您实际上可以将两种方法互换使用。
如果您有一个属于第一类的方法(可以是静态的),并且需要将其更改为访问类状态,那么找出是否有可能将静态方法转换为实例方法是相对简单的。
但是,在庞大的代码库中,大量的调用站点可能会进行搜索,以查看是否有可能将静态方法转换为非静态方法而代价太高。很多时候人们会看到呼叫数量,然后说:“好吧。我最好不要更改此方法,而要创建一个满足我需要的新方法”。
这可能会导致:
这两件事都是不好的。
因此,我的建议是,如果您的代码库超过200K LOC,则仅当方法必须是静态方法时,我才将它们设为静态。
从非静态到静态的重构相对容易(只需添加一个关键字),因此如果您想稍后将可静态化为实际的静态(当您需要实例外部的功能时),则可以。但是,将可能静态的实例化方法进行逆向重构要昂贵得多。
对于大型代码库,最好是从易于扩展的角度出发,而不是从思想的纯正角度出发。
因此,对于大型项目,除非需要它们,否则不要将其静态化。对于小型项目,请尽其所能。
我不会将其设为该类的公共静态成员。原因是使它成为公共静态是在谈论类的类型:不仅“该类型知道如何执行此行为”,而且“执行此行为是该类型的责任”。而且很有可能的是,行为不再与较大的类型有任何实际关系。
但这并不意味着我根本不会使其静态。问问自己:新方法在逻辑上可以属于其他地方吗?如果您可以对此回答“是”,则可能确实希望使其保持静态(并同时移动它)。即使那不是真的,您仍然可以将其设为静态。只是不要标记它public
。
为了方便起见,您至少可以对其进行标记internal
。如果您无法轻松访问更合适的类型,通常可以避免移动方法,但是仍然可以在需要的地方使用该方法,而该方法不会显示为类用户的公共接口。 。
是的,应该。有多种耦合度量标准可以衡量您的类如何依赖其他事物,例如其他类,方法等。将方法设置为静态是一种降低耦合程度的方法,因为您可以确定静态方法不会引用任何方法。成员。
就个人而言,我非常喜欢无国籍状态。您的方法是否需要访问类的状态?如果答案为“否”(可能为“否”,否则您不会考虑将其设为静态方法),那么,继续吧。
没有进入国家的麻烦就更少了。就像隐藏一个其他类不需要的私有成员是一个好主意一样,将状态隐藏在不需要它的成员中也是一个好主意。减少访问权限意味着可以减少错误。另外,由于使静态成员保持线程安全要容易得多,因此它使线程化更容易。还需要考虑性能,因为运行时不需要将对此的引用作为静态方法的参数进行传递。
当然,缺点是,如果您发现以前的静态方法由于某种原因必须访问状态,则必须进行更改。现在,我知道这对于公共API可能是个问题,因此,如果这是公共类中的公共方法,那么也许您应该考虑一下它的含义。尽管如此,在现实世界中我从未遇到过这样的情况,在这种情况下实际上会引起问题,但是也许我很幸运。
是的,一定要这样做。
静态方法比非静态方法要快,所以是的,如果可以的话,它们应该是静态的,并且没有特殊的原因让它们保持非静态。
令我惊讶的是,实际上很少有人在此提及封装。实例方法将自动访问所有私有(实例)字段,属性和方法。除了所有从基类继承的受保护对象。
编写代码时,应编写代码,以便尽可能少地公开代码,并尽可能少地访问。
因此,是的,使代码快速运行可能很重要,如果使方法静态化,这会发生,但是通常更重要的是使代码也尽可能不产生错误。一种实现方法是让您的代码尽可能少地访问“私有内容”。
乍看之下,这似乎无关紧要,因为OP显然是在谈论这种情况下重构不会出错并创建任何新错误的重构,但是这种重构代码必须在将来进行维护和修改,这会使您的代码遭受更大的“攻击”如果有访问私有实例成员的权限,则针对新的错误”。因此,总的来说,我认为这里的结论是“是的,大多数情况下,您的方法应该是静态的”,除非有其他原因使它们不是静态的。这仅仅是因为它是“更好地使用封装和数据隐藏并创建'更安全的'代码”。
就个人而言,我别无选择,只能将其设置为静态。在这种情况下,Resharper会发出警告,并且我们的PM拥有“ Resharper不会发出警告”的规则。
这取决于但通常我不会使这些方法静态化。代码总是在变化,也许有一天我会希望将该函数虚拟化并在子类中重写它。也许有一天它将需要引用实例变量。如果必须更改每个呼叫站点,将很难进行这些更改。
我建议最好的考虑方法是:如果您需要一个在没有实例化该类的实例或保持某种全局状态时需要调用的类方法,那么使用static是一个好主意。但总的来说,我建议您最好让成员成为非静态成员。
您应该考虑一下您的方法和类:
如果最后两个为“是”,则您的方法/类可能应该是静态的。
最常用的示例可能是Math
类。每种主要的OO语言都有它,并且所有方法都是静态的。因为您需要能够在任何地方,任何时间而不使用实例的情况下使用它们。
另一个很好的例子是Reverse()
C#中的方法。
这是Array
该类中的静态方法。它会反转数组的顺序。
码:
public static void Reverse(Array array)
它甚至不返回任何内容,您的数组是反向的,因为所有数组都是Array类的实例。
只要将新方法设为私有静态,这并不是一个重大更改。实际上,FxCop将此指南作为其规则之一(http://msdn.microsoft.com/en-us/library/ms245046(VS.80).aspx)进行了包含以下信息:
将方法标记为静态后,编译器将向这些成员发出非虚拟调用站点。发出非虚拟调用站点将阻止在运行时检查每个调用,以确保当前对象指针为非空。对于性能敏感的代码,这可以导致可衡量的性能提升。在某些情况下,无法访问当前对象实例表示正确性问题。
话虽如此,戴维·基恩(David Kean)的第一条评论更简洁地总结了这些担忧,他说这实际上更多是关于正确而不是关于性能提升:
尽管此规则被归类为性能问题,但是使方法静态化的性能提高仅为1%左右。而是,它是一个正确性问题,可能表明该成员不使用其他实例成员而导致成员不完整或存在错误。将方法标记为静态(在Visual Basic中为Shared)可以清楚地表明其不接触实例状态的意图。
我通常从纯功能的功能角度来看它。是否需要是实例方法?如果没有,您可能会从强制用户传递变量而不破坏当前实例的状态中受益。(嗯,您仍然可以弄乱状态,但是重点是设计使然,而不是这样做。)我通常将实例方法设计为公共成员,并尽力使私有成员成为静态成员。如有必要(随后您可以更轻松地将它们提取到其他类中。
在那些情况下,我倾向于将方法移到静态或utils库中,因此我不会将“对象”的概念与“类”的概念混合在一起