当创建具有内部私有方法的类时,通常为了减少代码重复,不需要使用任何实例字段,将方法声明为静态是否具有性能或内存优势?
示例:
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()方法声明为静态是否有任何优势?没有意见回复,我有意见。
答案 0 :(得分:197)
将方法标记为静态后,编译器将向这些成员发出非虚拟调用站点。发出非虚拟调用站点将阻止在运行时检查每个调用,以确保当前对象指针为非null。这可以为性能敏感的代码带来可测量的性能提升。在某些情况下,无法访问当前对象实例表示正确性问题。
答案 1 :(得分:83)
当我上课时,大多数方法分为两类:
静态方法很有用,因为只要查看它的签名,就会知道调用它不会使用或修改当前实例的状态。
举个例子:
public class Library { private static Book findBook(List<Book> books, string title) { // code goes here } }
如果一个库状态的实例被搞砸了,而我想弄明白为什么,我可以排除findBook作为罪魁祸首,仅仅是因为它的签名。
我尝试使用方法或函数的签名尽可能多地进行通信,这是一种很好的方法。
答案 2 :(得分:73)
对静态方法的调用会生成Microsoft中间语言(MSIL)中的调用指令,而对实例方法的调用会生成callvirt指令,该指令还会检查空对象引用。 但是,大多数情况下两者之间的性能差异并不显着。
src:MSDN - http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.110).aspx
答案 3 :(得分:13)
是的,编译器不需要将隐式this
指针传递给static
方法。即使你没有在你的实例方法中使用它,它仍然被传递。
答案 4 :(得分:5)
由于没有传递这个参数,它会稍快一些(虽然调用方法的性能成本可能远远超过这个节省)。
我想说我能想到私有静态方法的最好理由是它意味着你不会意外地改变对象(因为没有这个指针)。
答案 5 :(得分:4)
这迫使你记住也要声明函数使用的任何类范围的成员也是静态的,这应该节省为每个实例创建这些项的内存。
答案 6 :(得分:2)
我非常希望所有私有方法都是静态的,除非它们真的不可能。我更喜欢以下内容:
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
获得更多依赖关系因为我们需要日志记录并且还需要通知Web服务时(请原谅陈词滥调的例子),那么很容易看出哪些方法具有哪些依赖关系。< / p>
像R#这样的工具允许您通过几次击键从一组私有静态方法中提取类。当所有私有帮助器方法与实例字段紧密耦合时,尝试执行此操作,并且您将看到它可能非常令人头疼。
答案 7 :(得分:-3)
如前所述,静态方法有许多优点。然而;请记住,他们将在应用程序的生命周期中生活。我最近花了一天时间跟踪Windows服务中的内存泄漏......泄漏是由实现IDisposable的类中的私有静态方法引起的,并且始终从using语句调用。每次创建此类时,都会在堆上为类中的静态方法保留内存,遗憾的是,当处理类时,静态方法的内存未被释放。这导致此服务的内存占用量在几天内消耗服务器的可用内存,并产生可预测的结果。