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

例子:

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()方法声明为静态有什么好处吗?请不要发表意见,我有自己的看法。


当前回答

As has already been stated, there are many advantages to static methods. However; keep in mind that they will live on the heap for the life of the application. I recently spent a day tracking down a memory leak in a Windows Service... the leak was caused by private static methods inside a class that implemented IDisposable and was consistently called from a using statement. Each time this class was created, memory was reserved on the heap for the static methods within the class, unfortunately, when the class was disposed of, the memory for the static methods was not released. This caused the memory footprint of this service to consume the available memory of the server within a couple of days with predictable results.

其他回答

从FxCop规则页面:

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

As has already been stated, there are many advantages to static methods. However; keep in mind that they will live on the heap for the life of the application. I recently spent a day tracking down a memory leak in a Windows Service... the leak was caused by private static methods inside a class that implemented IDisposable and was consistently called from a using statement. Each time this class was created, memory was reserved on the heap for the static methods within the class, unfortunately, when the class was disposed of, the memory for the static methods was not released. This caused the memory footprint of this service to consume the available memory of the server within a couple of days with predictable results.

我非常喜欢所有私有方法都是静态的,除非它们真的不能静态。我更喜欢以下几点:

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个私有helper方法,那么我真的希望能够将它们拉出到一个新类中,以一种语义上有意义的方式封装步骤的子集。

当MyClass获得更多依赖时,因为我们需要日志记录,也需要通知web服务(请原谅这些陈词滥调的例子),那么很容易看到哪些方法有哪些依赖关系是很有帮助的。

像r#这样的工具可以让你从一组私有静态方法中提取一个类,只需几个按键。当所有私有helper方法都与实例字段紧密耦合时尝试这样做,您会发现这非常令人头疼。

由于没有传递this参数,它会稍微快一些(尽管调用该方法的性能成本可能比节省的成本要高得多)。

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

对静态方法的调用以Microsoft中间语言(MSIL)生成调用指令,而对实例方法的调用则生成callvirt指令,该指令还检查空对象引用。然而,在大多数情况下,两者之间的性能差异并不显著。

来源:MSDN - https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/79b3xss3(v=vs.110)