代码之家  ›  专栏  ›  技术社区  ›  NerdFury

使用私有静态方法的优点

  •  178
  • NerdFury  · 技术社区  · 16 年前

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

    例子:

    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()方法声明为静态方法有什么好处吗?没有意见回复,我有意见。

    8 回复  |  直到 16 年前
        1
  •  190
  •   Scott Dorman    16 年前

    FxCop rule page 对此:

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

        2
  •  80
  •   Neil    7 年前

    当我编写一个类时,大多数方法分为两类:

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

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

    举个例子:

    public class Library
    {
        private static Book findBook(List<Book> books, string title)
        {
            // code goes here
        }
    }

    如果一个图书馆状况的例子被搞砸了,我想弄明白为什么,我可以从它的签名中排除被发现是罪魁祸首的可能性。

    我尽量使用方法或函数的签名进行通信,这是一种很好的方式。

        3
  •  71
  •   Marek Takac    12 年前

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

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

        4
  •  13
  •   Kent Boogaart    16 年前

    是的,编译器不需要传递隐式 this 指针指向 static 方法。即使您不在实例方法中使用它,它仍然在被传递。

        5
  •  5
  •   Free Wildebeest    16 年前

    因为没有传递这个参数,所以速度会稍微快一点(尽管调用这个方法的性能成本可能比节省的成本要高得多)。

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

        6
  •  4
  •   Joel Coehoorn    16 年前

    这就迫使您记住,还要将函数使用的任何类范围的成员声明为静态成员,这样可以节省为每个实例创建这些项的内存。

        7
  •  1
  •   sara    8 年前

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

    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服务(请原谅这些陈词滥调的例子),然后很容易地看到哪些方法具有哪些依赖项是非常有用的。

    像R这样的工具可以让您通过几次击键从一组私有静态方法中提取类。当所有私有助手方法都与实例字段紧密耦合时,尝试这样做,您会发现这可能是一个非常头痛的问题。

        8
  •  -3
  •   James Haumann    8 年前

    如前所述,静态方法有许多优点。但是,请记住,它们将在应用程序的生命周期中一直存在于堆中。我最近花了一天时间在一个Windows服务中查找内存泄漏…泄漏是由实现IDisposable的类内的私有静态方法引起的,并且始终从using语句调用该方法。每次创建该类时,堆上都为该类中的静态方法保留了内存,不幸的是,当释放该类时,静态方法的内存没有释放。这导致此服务的内存占用在几天内消耗服务器的可用内存,并产生可预测的结果。