【问题标题】:Static methods vs instance methods in C#C# 中的静态方法与实例方法
【发布时间】:2009-02-27 19:57:52
【问题描述】:

对于我正在编写的应用程序,我希望具有极高的可扩展性,扩展方法似乎可以满足我的需求,并且能够在没有实例的情况下调用它们,这也是我需要的。

我记得读过静态方法比实例方法更快,但没有获得 GC 的优势。这是正确的吗?

除非我通过设计而不是速度找到更好的替代方案,否则我不太可能改变我的设计。但仍然想了解更多信息,我想知道速度、GC 等方面的差异。

编辑:谢谢。更多信息:假设我们有一个 Person 类:

class Person

可以有一个实例距离方法,比如:

this.Distance (Person p)

这很好,但是这并没有让我能够计算 2 个点(比如 Point3)之间的距离,而无需创建 Person 类的实例。

我想做的是这样的:

class Person (no Distance methods)

但距离的扩展方法:

Distance (this Person, Person)
Distance (this Point3, Point3)

这样我都可以做到:

myPerson.Distance (yourPerson)

Extensions.Distance (pointA, pointB)

EDIT2:@Jon,是的,我认为这就是(不要获得 GC 的优势)的意思,但我不知何故认为静态方法会造成这种负担/开销。

【问题讨论】:

    标签: c# .net garbage-collection clr methods


    【解决方案1】:

    在静态方法和实例方法之间进行选择是面向对象设计的问题。如果您正在编写的方法是一个对象的行为,那么它应该是一个实例方法。如果它不依赖于对象的实例,它应该是静态的。

    基本上,静态方法属于一个类型,而实例方法属于一个类型的实例。

    【讨论】:

    • 这是否意味着对于 Customer 对象,拥有像“GetAge()”这样的实例方法和像“CustomerHelper.GetCustomersFromState(int stateId)”这样的静态方法是正确的做法?
    • GetAge 作为实例方法是有意义的。不过我不清楚后者。
    • @MehrdadAfshari 所以CustomerDAL class 有一个method GetAllCustomers(..)....与EmployeeDAL 相同,它有GetAllEmployees() .....应该是实例方法?如果是这样 - 在这些类中什么样的方法(请提供示例)应该是静态的?
    【解决方案2】:

    “没有得到 GC 的优势”是什么意思?方法不是垃圾收集 - 实例是。

    虚拟方法比非虚拟方法慢,而且我猜在任何实例方法之前都有讨厌的空检查,但这并不重要。选择最合适的设计。

    静态方法对于测试来说是一件痛苦的事情 - 例如,如果您通过调用一些静态方法在方法 Foo() 中进行身份验证,那么当您测试 Foo() 时,您不能让它只调用一个模拟身份验证器(除非静态方法本身允许您这样做)。但是,如果你给你正在测试的任何东西的原始实例提供一个包含Authenticate() 方法的接口的模拟实现,你可以让它按照你想要的方式运行。

    编辑:在这种情况下,听起来您真正需要的是 Point 类型上的一个实例方法来计算两点之间的距离(“这个”一个和另一个) - 或者可能是一个静态工厂方法Distance 类型。

    【讨论】:

    • 谢谢乔恩。现在有意义吗?
    • 谢谢乔恩。我没有距离类型,因为它只是一个浮点数。实例是我不确定是否使用的地方。就像我可以在 Point 中使用 Distance 方法,但我也想说 PointToRGBColor,但在我的设计中,似乎这种 RGB 方法也应该是扩展。
    • 现在在这里实例化 100% 有意义,就像 RGB 方法可以在 Color 类中一样。但这会阻止我在必须有实例时直接使用该功能。对于 Point 来说,没关系,因为它是需要使用它的最基本类型。
    • 嗯...我并没有真正遵循 Point/RGB 示例。如果它仅适用于某些上下文(而不是总是,对于任何点,任何用法),它作为一种扩展方法可能是有意义的。我建议不要使用扩展方法
    【解决方案3】:

    如果更快是指方法中的代码执行得更快,那么不是。静态方法中的代码与非静态方法中的代码一样快。

    如果您正在谈论执行对方法的调用的开销,它会变得有点复杂。对于像 Java 这样的语言来说,实例调用具有更多开销是很常见的。但在 C# 中,情况并非如此,因为实例方法默认不是虚拟的。

    因此,虚拟方法比非虚拟方法的开销略多。静态方法不能是虚拟的,但实例方法可以声明为虚拟的。

    对于垃圾回收,这主要与字段相关,而不是方法。静态字段可以从代码中的任何地方访问,因此垃圾收集器无法确定是否会再次使用引用,因此永远不会收集它。

    【讨论】:

      【解决方案4】:

      根据您的示例,我将编写一个静态实用函数来查找两点之间的距离:

      public static class Geometry
      {
          public static double GetDistanceBetween(Point a, Point b) { ... }
      }
      

      然后我会给 Person 一个名为 Position 的属性,它返回一个点。所以我可以写:

      double distance = Geometry.GetDistanceBetween(personA.Position, personB.Position);
      

      它实际上已经是英文了 - 为什么要让它更加晦涩难懂?如果你把距离作为一个方法,那么你可以这样写:

      personA.Distance(personB)
      

      或:

      personB.Distance(personA)
      

      这两种排序之间没有区别,但方法调用语法的使用表明可能存在区别。

      【讨论】:

      • 谢谢,是的,Position 是我的 Person 类中的一个属性。但是这些操作是由用户通过示意图来构建的。所以我希望有一个统一的方式来做这件事,但也有能力直接使用它们,而无需在 UI 中创建任何原理图项。
      • 顺便说一句,我没有得到第二部分。你的意思是 personA.Distance(personB) 和 Extensions.Distance 是一样的吗?
      • 首先我让 personA 算出到 personB 的距离,然后我让 personB 算出到 personA 的距离。两个人互换了。通过将其作为一种方法,您暗示该人正在以他们自己的独特性来解决它,这是一种误导。我建议不要添加距离方法
      • 我不知道您所说的用户构造操作是什么意思。您能否详细说明您的问题?
      • 谢谢。你的意思是我应该有一个静态的距离方法?还是您在谈论实例方法?需要注意的另一件事是我正在尝试使用 LINQ 样式语法,例如 person.A().B().C().D() ...
      猜你喜欢
      • 1970-01-01
      • 2012-11-12
      • 2015-06-22
      • 1970-01-01
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 2012-08-30
      相关资源
      最近更新 更多