ReSharper抱怨方法何时可以是静态的,但不是静态的


67

当一种方法可以变成静态方法时,为什么ReSharper会抱怨呢?

是因为仅创建了一个静态方法的实例(在类型上),从而节省了性能?


2
Java和Eclipse编译器选项stackoverflow.com/questions/11240178/…有一个非常相似的问题,不同的语言,相同的问题; =)
Samuel Rossille,2012年

此检查的名称为“可以使成员成为静态(共享)成员”,并且具有“私有可访问性”和“非私有可访问性”两个变体。(在ReSharper 7.1中。)在ReSharper>选项>代码检查>检查严重性>所有>通用实践和代码改进中列出。
罗里·奥肯

此ReSharper检查的操作菜单的屏幕截图示例。(尽管它用于VB.NET代码。)
罗里·奥肯

Answers:


104

我发现该评论非常有用,因为它指出了两个重要的事项:

  1. 这使我问自己,所讨论的方法是否实际上应该属于该类型的一部分。由于它不使用任何实例数据,因此至少应考虑是否可以将其移动到自己的类型。它是该类型的组成部分,还是真的是通用实用程序方法?

  2. 如果将方法保持在特定类型上确实有意义,则可能会提高性能,因为编译器将为静态方法发出不同的代码。


15
好的答案-这不仅仅是性能。Resharper还向您提供一些设计反馈。
serg10 2009年

25

从FxCop文档获得相同的警告(强调):

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


1
的确如此,但实际上并没有取得很大的性能提升。我关闭该警告。在开发过程中,令人讨厌的是ReSharper希望使所有内容保持静态。
乍得格兰特

3
的确如此,但是忽略了一个事实,那就是您不必创建对象即可使用该方法...如果由于其他原因而不需要实例,则不必创建对象会大大提高性能。 。
Charles Bretana 09年

2
同意,性能提升通常很小(对于大多数非平凡的方法来说微不足道)。正确性原因通常是更值得关注的-如果该方法是不特定的实例,其标记静态清楚地表明,这是经过深思熟虑的,并且如果该方法指具体到一个实例,然后将收到警告您在实施中犯了一个错误。
itowlson

1
@Chad:resharper不会“想”使事情变得静态;它只是指出它仍然可以是静态的。如果可以的话,将其视为TODO标记。如果您真的在争论“想让所有内容保持静态”……我想您的代码有严重的设计问题
2011年

1
@sehe想要/推荐...但是,您想解释这个词,就是“重塑”。我不知道您从我的评论中得到了什么,这使您认为我个人使我的代码变得疯狂。好斗吗?
乍得·格兰特


5

如果将方法声明为静态,则无需创建该类的实例(零个)来使用该方法...这样可以节省垃圾回收器从回收对象中回收对象时进行构造处理,堆空间和cpu循环所需的cpu循环。堆...

还有,你的问题,正如它写的

“ ...仅创建一个静态方法的实例(在类型上)...”

表示对于实例方法,该方法的代码将针对所创建的类的每个实例重复进行。那是不对的。无论为任何类型创建多少个实例,方法的代码都只会加载到内存一次。每个实例存储在堆中的对象仅存储类型的“状态”(非静态字段和一些其他跟踪变量)。


3

这不是投诉,而只是建议。


1

您不必为静态方法将“ this”压入函数的堆栈。这是它更便宜的另一个原因。


1

对我而言,此ReSharper建议的最大好处(您可以将其设置为警告,建议或提示)。是因为它鼓励我尽可能多地使方法静态化。这是一件好事,因为静态方法对它所属的类没有直接依赖。这意味着它可以轻松地作为静态成员移至另一个类。

ReSharper中使用静态方法的另一个巧妙技巧是通过使用“使方法静态化”重构使一组相关方法静态化。这会将一些依赖项移到方法参数中。以后查看这组方法时,可能会发现它们都访问特定类型的特定对象。然后,您可以使用“使方法成为非静态的”重构,并将该对象指定为新的this指针。这会将您的方法移至另一个类。

由此:

internal class ClassA
{
    public ClassB Property { get; set; }

    public int Method()
    {
        var classB = Property;
        return classB.Property1 + classB.Property2;
    }
}

internal class ClassB
{
    public int Property1 { get; set; }
    public int Property2 { get; set; }
}

对此:

    public static int Method(ClassB property)
    {
        var classB = property;
        return classB.Property1 + classB.Property2;
    }

对此:

internal class ClassA
{
    public ClassB Property { get; set; }
}

internal class ClassB
{
    public int Property1 { get; set; }
    public int Property2 { get; set; }

    public int Method()
    {
        return Property1 + Property2;
    }
}

“这意味着它可以轻松地作为静态成员移至另一个类。”
Evren Kuzucuoglu 2011年

2
“这意味着它可以轻松地作为静态成员移至另一个类。” 这也意味着您正在编写过程性代码而不是面向对象的代码,这是一件坏事。
Evren Kuzucuoglu 2011年

@GFK:也许不是。一旦它是静态的,就可以将其移至另一个类-并可能使其成为该类的实例成员。
约翰·桑德斯

0

静态在首次使用时被实例化,并将保留在内存中。如果不再使用,则可能是一个问题。静电很难测试(模拟等)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.