【问题标题】:Should I always make my methods static where possible?我应该尽可能让我的方法静态吗?
【发布时间】:2011-04-11 14:34:25
【问题描述】:

我经常思考这个问题......这可能是一个白痴问题,但这里是。

假设我有这门课:

public class SomeClass
{
    public int AProperty { get; set; }

    public void SomeMethod()
    {
        DoStuff(AProperty);
    }
}

这样做有什么好处:

public class SomeClass
{
    public int AProperty { get; set; }

    public static void SomeMethod(int arg)
    {
        DoStuff(arg);
    }
}

唯一明显的优势是我现在可以直接访问SomeMethod

那么,将这些方法设为静态是一种好的做法吗?稍微重构一下就可以了,还是浪费我的时间?

编辑:我忘了提(ShellShock 的评论提醒了我)我问的原因是我使用 ReSharper,它总是提出“方法 X 可以设为静态”等建议...

【问题讨论】:

标签: c# parameters methods static


【解决方案1】:

没有。 Static is evil。它将调用者与使用的类和 makes it hard to test 紧密耦合。

【讨论】:

  • Microsoft 的代码分析工具总是建议如果没有实例依赖项,我应该将方法设为静态。这是个坏建议吗?
  • @ShellShock 可能是。如果你有很多这样的方法,你可能违反了 OOP 原则。对象的方法应该(几乎)始终使用与对象关联的数据。
  • @dark_charlie:所以你的意思是,如果你可以有一个静态方法,你应该重组把它放在一个静态实用程序类中吗?如果方法在逻辑上与类绑定,但技术上不使用任何成员怎么办?
  • 正确答案当然是“视情况而定”。存在静态方法属于类的情况。但这些很少见,一般规则是尽量避免使用静态方法。
  • 呃,Math.Max 不难测试。
【解决方案2】:

我认为这将取决于您希望使用这些方法的方式。如果将静态方法用作类的几个实例的通用方法,则可以使用静态方法。

举个例子,假设您有一个字符串类和两个字符串 A 和 B。要比较 A 和 B,您可以使用 A.CompareTo(B) 方法或 String.Compare(A, B)方法。

如果我错了,请纠正我。

【讨论】:

  • 我认为XDocument.Parse 会是一个更好的例子。创建一个 XDocument 只是为了使用它的 parse 方法来创建你真正想要的 XDocument 并没有多大意义。
【解决方案3】:

静态方法是有意义的,如果你应该能够在不创建类的对象之前调用它们。例如,在 Java 中,Math-Class 仅包含静态方法,因为仅实例化 Math-Class 以对其他对象进行数学运算没有多大意义。

大多数时候最好避免使用静态方法。你应该熟悉面向对象的编程——那里有很多很好的资源,解释了所有的概念,比如静态方法等。

【讨论】:

    【解决方案4】:

    Static 不是邪恶的。 Static 使用不当是邪恶的,就像我们编程工具包的许多部分一样。

    Static 非常有优势。正如the accepted answer here 指出的那样,static 可能会提高速度。

    作为一般规则,如果方法不使用类的任何字段,那么它是评估其功能的好时机,但是最终可以在不实例化对象的情况下调用的实用方法通常很有用。例如DirectoryInformationFileInformation 类包含有用的静态方法。

    编辑

    感到有义务指出它确实使模拟变得更加困难,但它仍然绝对是可测试的。

    这只是意味着您需要更加努力地考虑 static 方法的去向,以便您始终可以测试它们而无需依赖模拟/存根。 (即:不要将它们放在需要持久连接到数据库的 DTO 上)。

    【讨论】:

      【解决方案5】:

      我将尝试回答涉及您提供的代码示例的具体问题。

      如果SomeMethod 仅在声明它的类中有用,我会避免静态转换并将其保留为实例方法。

      如果SomeMethod 在它所在的类之外有用,则将其从类中排除。这可能是某处静态实用程序类中的静态方法。要使其可测试,请确保其所有依赖项都作为参数传递给它。如果它有大量依赖项,您可能需要查看设计并确切了解它应该做什么 - 作为您传递给它的类之一中的实例方法可能会更好。

      有人说静电是邪恶的。这通常是由于可变静态状态提供的陷阱,其中变量从调用静态构造函数的点到应用程序域的拆除,在两者之间变化。依赖于该状态的代码可能会出现不可预测的行为,并且测试可能会变得非常可怕。但是,不引用可变静态状态的静态方法绝对没有问题。

      举一个(非常简单的)例子,静态是邪恶的,但可以转换为非邪恶的版本,想象一个计算某人年龄的函数:

      static TimeSpan CalcAge(DateTime dob) { return DateTime.Now - dob; }
      

      这是可测试的吗?答案是不。它依赖于DateTime.Now 的大量不稳定静态状态。您不能保证每次都为相同的输入提供相同的输出。为了使其对测试更加友好:

      static TimeSpan CalcAge(DateTime dob, DateTime now) { return now - dob; }
      

      现在函数所依赖的所有值都被传入,并且它是完全可测试的。相同的输入会得到相同的输出。

      【讨论】:

      • 你说如果方法只在类中有用,那么就不要让它成为静态的。使方法静态化不是也可以获得性能吗?否则,拥有private static 方法(这是可能的,并且实际上由 ReSharper 建议)有什么意义?
      • @awe - 你说得对,调用静态方法应该更快。但是,我认为对于这个特定示例,调用someClassInstance.SomeMethod()SomeClass.SomeMethod(someClassInstance.AProperty) 更好。我不认为问题中建议的重构是最好的事情 - 在许多其他情况下它是。 ReSharper 是否建议对上面的示例进行重构?如果它在方法访问实例属性时这样做,我会感到惊讶。如果您愿意,您可以全力以赴并为 all 您的非虚拟实例方法编写 static SomeMethod(SomeClass this)
      • 在这种情况下我同意你的看法,但你的表述方式让我不清楚。我的意思是在示例中,方法仅在类的上下文中有用,但在技术上不使用任何类成员。该方法实际上只是某种实用功能,但除了类中的其他代码之外,没有其他代码需要此功能。如果您的方法不使用类中的任何非静态成员或方法,Resharper 建议重构。我在我创建的 ReSharper 建议将其设为静态的私有方法中注意到了这一点。
      • @awe - 对于您的示例,我同意将方法设为静态并将其留在类中。事实上,这对我来说是一个相当常见的重构。
      • 性能说明。静态函数和非虚拟方法具有完全相同的每次调用性能特征。使静态函数更快的原因是您不需要在调用对象之前实例化它的实例。这意味着你少了一个 GC 对象。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-05
      • 1970-01-01
      • 1970-01-01
      • 2013-12-20
      相关资源
      最近更新 更多