【问题标题】:Static vs. non-static method静态与非静态方法
【发布时间】:2009-07-26 14:21:23
【问题描述】:

假设您有一些方法可以在非静态类中设置为静态。
例如:

private double power(double a, double b)
    {
        return (Math.Pow(a, b));
    }

您认为将方法签名更改为静态有什么好处吗?在上面的例子中:

private static double power(double a, double b)
    {
        return (Math.Pow(a, b));
    }

即使有一些性能或内存增益,编译器不会将其作为编译时的简单优化吗?


编辑: 我正在寻找的是通过将方法声明为静态的好处。我知道这是常见的做法。我想了解它背后的逻辑。
当然,这种方法只是阐明我的意图的一个例子。

【问题讨论】:

  • @Everyone,我知道这是发展年代的一个“古老”问题,但它今天仍然相关。下面有很多优秀的答案。需要针对您的特定场景的实际性能数据?编写一个快速程序,该程序调用该方法的次数足够多(在var start = DateTime.Now() 和var end = DateTime.Now() 之间),以便能够有足够大的经过时间进行比较。使用static 运行几次,不使用static 运行几次,然后比较差异。也许也可以打开 TaskManager 并观察每个场景的内存使用情况。
  • 只是为了完整性,而不是比较两个DateTime.Now()之间的差异,使用StopWatch class。编辑 - 为什么?它比DateTime.Now() 方式更准确、更易于使用。

标签: c# performance


【解决方案1】:

按照定义,power 是无状态的,对任何封闭类都没有副作用,因此应将其声明为 static。

来自 MSDN 的 article 探讨了非静态与静态的一些性能差异。调用比实例化和调用快大约四倍,但它确实只在作为性能瓶颈的紧密循环中才重要。

【讨论】:

  • 很好的链接,但是从 2003 年开始,请谨慎对待它。例如,调用委托并不比调用实例方法慢 8 倍,但现在它慢了近 2 倍。跨度>
【解决方案2】:

如果将方法声明为静态,性能应该会略有提升,因为编译器会发出 call IL 指令而不是 callvirt。

但正如其他人所说,它应该是静态的,因为它与特定实例无关

【讨论】:

    【解决方案3】:

    请注意,编译器极不可能代表您进行更改,因为它会更改方法的签名。结果,一些精心设计的反射(如果您使用了任何反射)可能会停止工作,编译器真的无法判断是不是这种情况。

    【讨论】:

      【解决方案4】:

      您认为将方法签名更改为静态有什么好处吗?

      三大好处:

      1. 将无状态方法设为静态有助于记录和阐明其目的。否则,人们倾向于担心该方法依赖于什么神秘状态?

      2. 静态方法可以从其他静态代码中调用,因此可能更有用。

      3. 静态方法调用的运行时开销比实例调用少一点。编译器不能自动进行这种转换——原因之一是它会影响 null 的使用。即使在方法中没有使用实例状态,在空引用上调用该方法也会失败并返回 NullReferenceException。

      【讨论】:

        【解决方案5】:

        对我来说,一个容易决定的问题是“我是否必须实例化这个对象才能调用这个函数”。对于你的函数,我会说答案是否定的,所以它应该是静态的。此方法似乎与您的对象无关,所以我再次投票静态。

        【讨论】:

        • @Cody C:但是如何回答“我应该实例化这个对象才能调用这个函数吗?”这个问题?
        • IMO 只是“如果我想使用这个功能,我需要一个带状态的对象吗?”如果我只是实例化一个对象来执行一个简单的功能,那么答案通常是否定的。
        • 有问题的例子是private,所以在这种情况下这不是考虑因素(只有当它是public时才会考虑)。在这种情况下,唯一需要考虑的是与性能相关的问题。
        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

          编译器在“JIT”代码时可能会考虑内联它,因为它太短了,如果这样做,那么可能会优化对未使用的 this 参数的任何引用。但你不能依赖这些。

          您仍然必须创建一个对象来调用它,除非您将其设为静态,如果您出于其他原因不需要一个对象,那么无论如何都会有更大的开销。

          【讨论】:

          • 您已经拥有了对象 (this),例如 private 方法。
          【解决方案8】:

          此方法应该是静态的,因为它与您的类或类成员无关。它只适用于这个函数的输入。

          也许您可能需要在不创建该类的情况下调用它。所以如果它是静态的没关系,但如果不是,你不能在没有该类的任何实例的情况下调用它。


          静态方法的优点:

          无需先创建对象。该方法立即可用。

          当您拥有不依赖于特定对象状态的通用功能时,这是一个很好的选择。例如,查看 java.util 中的 Arrays 类或 Collections 类。

          静态方法可能对工厂有好处。将您的要求作为参数传递,获取一个全新的对象。看不到构造函数。

          静态方法的缺点:

          您没有对象实例,因此您只能访问静态成员和您自己的局部变量。如果你想要一个实例,你可能必须自己创建它。

          您可以创建子类,但静态方法不能是抽象的,因此很难将您的实现与调用者分离。


          (ps:我不认为编译器会优化它是否是静态的..但不确定)

          【讨论】:

            【解决方案9】:

            我相信编译器不会把它优化成静态方法。由于不必在运行时检查指针是否为空,因此可以提高性能。请查看FXCop rule 以供参考。

            【讨论】:

              【解决方案10】:

              我希望我们需要定义静态和非静态方法之间的区别。在这里,我发布了几行简单的代码来可视化概念上的差异。

              public class StaticVsNonStatic
              {
                   public string NonStaticMethod() //non-static
                   {
              
                       return "I am the Non-Static Method"; 
              
                   }
              
                   static public string StaticMethod() //static
                   {
              
                       return "I am Static Method";
                   }
              
               }
              

              现在让我们创建一个 aspx 页面尝试访问类中定义的这 2 个方法。

               public partial class StaticVsNonStatic_StaticVsNonWorkplace : System.Web.UI.Page
               {
                   protected void Page_Load(object sender, EventArgs e)
                   {
              
                      StaticVsNonStatic objStaticVsNonStatic = new StaticVsNonStatic();
                      lblDisplayNS.Text = objStaticVsNonStatic.NonStaticMethod(); //Non Static 
                      lblDisplayS.Text =  StaticVsNonStatic.StaticMethod();  //Static and called without object
                   }
               }
              

              谢谢,请给你们发邮件。

              最好的问候,Pritom Nandy [孟加拉国]

              【讨论】:

              • Elad 显然已经知道如何调用静态方法。由于您刚刚开始在此站点上回答问题,我建议您寻找尚未接受答案的问题。您可以分辨出来,因为在搜索问题时,如果有接受的答案,答案的数量是黄色的,如果没有,则为白色。如果还没有人试图回答这个问题,则有一个红色背景,这是最好看的。欢迎来到stackoverflow :)
              猜你喜欢
              • 1970-01-01
              • 2011-01-17
              • 2016-01-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多