使用私有静态方法的优点

当创build一个具有内部私有方法的类时,通常为了减less代码重复,不需要使用任何实例字段,是否有性能或内存优势来声明该方法是静态的?

例:

foreach (XmlElement element in xmlDoc.DocumentElement.SelectNodes("sample")) { string first = GetInnerXml(element, ".//first"); string second = GetInnerXml(element, ".//second"); string third = GetInnerXml(element, ".//third"); } 

 private static string GetInnerXml(XmlElement element, string nodeName) { return GetInnerXml(element, nodeName, null); } private static string GetInnerXml(XmlElement element, string nodeName, string defaultValue) { XmlNode node = element.SelectSingleNode(nodeName); return node == null ? defaultValue : node.InnerXml; } 

将GetInnerXml()方法声明为静态是否有优势? 没有意见回应,我有意见。

从这个FxCop规则页面 :

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

当我正在写课程时,大多数方法分为两类:

  • 使用/更改当前实例状态的方法。
  • 不使用/改变当前对象状态的帮助器方法,但帮助我计算我在别处需要的值。

静态方法很有用,因为只要查看其签名,就知道调用它不会使用或修改当前实例的状态。

以这个例子:

 公共类库
 {
    私人静态图书findBook(List <Book>书籍,string标题)
     {
         //代码在这里
     }
 } 

如果一个图书馆状态的实例被搞砸了,而我试图弄清楚为什么,我可以排除findBook作为罪魁祸首,只是从它的签名。

我尝试尽可能地用方法或函数的签名进行通信,这是一个很好的方法。

对静态方法的调用会在Microsoft中间语言(MSIL)中生成调用指令,而对实例方法的调用将生成callvirt指令,该指令还将检查空对象引用。 但是,大部分时间两者之间的performance差异并不显着。

src:MSDN – http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.110).aspx

是的,编译器不需要将隐式指针传递给static方法。 即使你没有在实例方法中使用它,它仍然被传递。

因为没有传递这个参数,所以会稍微快一点(虽然调用方法的性能成本可能远远超过这个保存)。

我想说我能想到的私有静态方法的最好的理由是它意味着你不能意外地改变对象(因为没有这个指针)。

这迫使你记住也要声明该函数使用的任何类作用域成员也是静态的,这应该为每个实例保存创build这些项目的内存。

我非常希望所有私有方法都是静态的,除非他们真的不能。 我更喜欢以下内容:

 public class MyClass { private readonly MyDependency _dependency; public MyClass(MyDependency dependency) { _dependency = dependency; } public int CalculateHardStuff() { var intermediate = StepOne(_dependency); return StepTwo(intermediate); } private static int StepOne(MyDependency dependency) { return dependency.GetFirst3Primes().Sum(); } private static int StepTwo(int intermediate) { return (intermediate + 5)/4; } } public class MyDependency { public IEnumerable<int> GetFirst3Primes() { yield return 2; yield return 3; yield return 5; } } 

通过访问实例字段的每个方法。 为什么是这样? 因为随着这个计算过程变得更加复杂,并且类最终有15个私有帮助器方法,我真的希望能够将它们拉出到一个新的类中,以一种语义上有意义的方式来封装这些步骤的子集。

MyClass获得更多的依赖性,因为我们需要日志logging,也需要通知一个Web服务(请原谅陈词滥调的例子),那么真正有助于轻松看到哪些方法有哪些依赖关系。

像R#这样的工具可以让你在一些按键中从一组私有静态方法中提取一个类。 当所有私有帮助器方法紧密耦合到实例字段时,尝试这样做,你会发现它可能是一个非常头痛的问题。

如前所述,静态方法有很多优点。 然而; 请记住,他们将活在应用程序的整个生命周期。 我最近花了一天的时间跟踪Windows服务中的内存泄漏……泄漏是由实现IDisposable的类中的私有静态方法引起的,并且始终使用using语句调用。 每次创build这个类时,内存都被保留在类中的静态方法的堆上,不幸的是,当类被抛弃时,静态方法的内存没有被释放。 这导致此服务的内存占用量在几天内消耗服务器的可用内存,并产生可预测的结果。