我对C#很陌生,所以请耐心等待。
我注意到关于C#的第一件事是许多类都是静态方法。例如......
为什么:
Array.ForEach(arr, proc)
而不是:
arr.ForEach(proc)
为什么会这样:
Array.Sort(arr)
而不是:
arr.Sort()
随时在网上给我一些常见问题解答。如果在某个地方的某本书中有详细的答案,我也欢迎指向它的指针。我正在寻找关于此的明确答案,但您的推测值得欢迎。
答案 0 :(得分:11)
因为那些是实用程序类。考虑到C#中没有自由函数,类构造只是将它们组合在一起的一种方式。
答案 1 :(得分:8)
假设this answer正确,实例方法需要“方法表”中的额外空间。使数组方法静态化可能是一个早期节省空间的决定。
这一点,以及避免Amitd引用的this
指针检查,可以为像数组这样无处不在的东西提供显着的性能提升。
答案 2 :(得分:5)
另请参阅FXCOP
中的此规则CA1822: Mark members as static
规则说明
不访问实例数据或调用实例方法的成员可以 被标记为静态(在Visual Basic中共享)。标记后 方法为静态,编译器将发出非虚拟调用站点 这些成员。发送非虚拟呼叫站点将阻止检查 每次调用的运行时确保当前对象指针 是非null。这可以实现可测量的性能增益 性能敏感的代码。在某些情况下,无法访问 当前对象实例表示正确性问题。
答案 3 :(得分:1)
反对静态的经典动机:
1)C#有几种工具可以使测试静态方法相对容易。 C#模拟工具的比较,其中一些支持静态模拟:https://stackoverflow.com/questions/64242/rhino-mocks-typemock-moq-or-nmock-which-one-do-you-use-and-why
2)有一些众所周知的高效方法可以在不损失C#中的线程安全的情况下进行静态对象创建/逻辑。例如,在C#中使用静态类实现Singleton模式(如果选项不合适,您可以跳转到第五种方法):http://www.yoda.arachsys.com/csharp/singleton.html
3)正如@ K-ballo所提到的,每种方法都有助于C#中内存中的代码大小,而不是实例方法得到特殊处理。
那就是说,你指出的两个具体例子只是静态数组类的遗留代码支持问题,然后在C#1.0天内引入泛型和其他一些代码糖,正如@Inerdia所说。我试图回答假设您有更多的代码,可能包括外部库。
答案 4 :(得分:1)
感知功能。
“实用程序”功能与OO旨在定位的大部分功能不同。
考虑集合,I / O,数学和几乎所有实用程序的情况。
使用OO,您通常可以为您的域建模。这些东西都不适合你的领域 - 它不像你正在编码并且去“哦,我们需要订购一个新的哈希表,我们的东西已经满了”。实用的东西往往不适合。
我们非常接近,但是传递集合仍然不是很好(你的业务逻辑在哪里?你在哪里设置操纵你的集合的方法,以及你总是传递的其他一小部分或两个数据吗?)
与数字和数学相同。拥有Integer.sqrt()和Long.sqrt()以及Float.sqrt()是很困难的 - 它只是没有意义,也不是“new Math(。。sqrt()”。有很多领域它没有很好的模型。如果您正在寻找数学建模,那么OO可能不是您最好的选择。 (我在Java中创建了一个非常完整的“Complex”和“Matrix”类并使它们相当OO,但是让它们真正教会了我OO和Java的一些限制 - 我最终“使用”Groovy中的类主要是)
我从来没有见过像OO那样的任何东西,可以用来建模业务逻辑,能够演示代码之间的联系以及管理数据和代码之间的关系。
所以当我们更有意义时,我们会回到不同的模型上。
答案 5 :(得分:0)
Array
类不是通用的,不能完全通用,因为这会破坏向后兼容性。在数组实现IList<T>
的地方有一些魔力,但这只适用于下限为0的单维数组 - “list-ish”数组。
我猜测静态方法是添加适用于任何形状数组的泛型方法的唯一方法,无论它是否符合上述编译器魔法。