C#类-为什么有这么多静态方法?

C#类-为什么有这么多静态方法?,c#,C#,我对C#很陌生,所以请容忍我 关于C#,我首先注意到的一点是,许多类都是静态方法重的。例如 为什么是: Array.ForEach(arr, proc) 而不是: arr.ForEach(proc) arr.Sort() 为什么会这样: Array.Sort(arr) 而不是: arr.ForEach(proc) arr.Sort() 请随时向我指出一些网上常见问题。如果某本书中有详细的答案,我也希望有人能指出这一点。我正在寻找关于这个问题的最终答案,但欢迎您的猜测。因为这些是实用程

我对C#很陌生,所以请容忍我

关于C#,我首先注意到的一点是,许多类都是静态方法重的。例如

为什么是:

Array.ForEach(arr, proc)
而不是:

arr.ForEach(proc)
arr.Sort()
为什么会这样:

Array.Sort(arr)
而不是:

arr.ForEach(proc)
arr.Sort()

请随时向我指出一些网上常见问题。如果某本书中有详细的答案,我也希望有人能指出这一点。我正在寻找关于这个问题的最终答案,但欢迎您的猜测。

因为这些是实用程序类。考虑到C#中没有自由函数,
数组
类不是泛型的,不能完全泛型,因为这会破坏向后兼容性。数组实现了
IList
,但这只适用于下限为0的一维数组——“列表”数组


我猜静态方法是添加通用方法的唯一方法,该方法适用于任何形状的数组,无论它是否符合上述编译器魔法。

反对静态的经典动机:

  • 难测
  • 线程不安全
  • 增加内存中的代码大小
  • 1) C#提供了几种工具,使测试静态方法相对容易。C#模拟工具的比较,其中一些工具支持静态模拟:

    2) 在C#中,有一些众所周知的高性能方法可以在不丢失线程安全性的情况下创建静态对象/逻辑。例如,使用C#中的静态类实现Singleton模式(如果选项不充分,您可以跳到第五种方法):

    3) 正如@K-ballo提到的,每个方法都会增加C#中内存中的代码大小,而不是对实例方法进行特殊处理

    也就是说,正如@Inerdia所说,在C#1.0时代引入泛型和其他一些代码糖之前,您指出的两个具体示例只是静态数组类的遗留代码支持问题。我试图回答假设您有更多引用的代码,可能包括外部库。

    假设是正确的,实例方法在“方法表”中需要额外的空间。将数组方法设置为静态可能是早期节省空间的决定


    这与避免Amitd引用的
    指针检查一起,可以为像阵列这样无处不在的东西提供显著的性能提升。

    感知功能

    “实用程序”功能与OO的目标功能不同

    考虑一下集合、I/O、数学和几乎所有实用程序的情况

    使用OO,您通常可以对域进行建模。这些东西都不适合你的领域——你不是在编码然后说“哦,我们需要订购一个新的哈希表,我们的哈希表已经满了”。实用的东西往往就是不适合

    我们已经非常接近了,但是传递集合仍然不是一个很好的OO(你的业务逻辑在哪里?你把操纵你的集合的方法放在哪里,以及你总是传递的其他一两小块数据?)

    数字和数学也是如此。要有Integer.sqrt()和Long.sqrt()以及Float.sqrt(),有点困难——这根本没有意义,“new Math().sqrt()”也没有意义。有很多方面它只是没有很好的模型。如果您正在寻找数学建模,那么OO可能不是您的最佳选择。(我用Java编写了一个相当完整的“Complex”和“Matrix”类,并使它们相当面向对象,但使它们真正教会了我一些面向对象和Java的局限性——我最终主要“使用”了Groovy中的类)

    在建模业务逻辑、演示代码之间的连接以及管理数据和代码之间的关系方面,我从来没有见过比OO更好的东西

    因此,当这样做更有意义时,我们可以使用不同的模型。

    也可以从

    规则描述

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


    为什么我要测试框架方法?你是在回答这个问题,还是只是在谈论在你的代码中定义静态方法?问题是为什么C#中有这么多静态,而不是为什么框架中有这么多。这两个例子碰巧是非常古老、经过良好测试的框架方法,但我假设问题是关于C#库和代码的。我还将指出,当您的代码无法按预期工作时,有一些测试较少的较新的框架方法值得您自己编写测试—Microsoft并不是所有的方法都没有bug。我不会将
    Array
    称为实用程序类。它是所有数组派生的抽象基类…这似乎是创建这些实例方法的好地方。我认为这是一个好问题。@Daniel也许Array本身不是一个实用类,但它提供的静态方法看起来确实像是分组在其中的实用方法。不同意他们显然引用了他们自己的对象,所以他们真的应该是方法,他们可能仍然可以更改为扩展方法,但是这可能成本/收益太低了。你总是能够将任何数组类型(
    string[]
    int[]
    ,等等)视为
    array
    的实例,所以我不认为缺少泛型的论点成立。@Daniel:我的观点是,数组没有任何实例方法