为什么dotnet的char.IsLower()是一个静态方法?

6
这似乎违反了每个设计指南。一个接受类型为T的单一参数的静态方法通常应该只是成员方法。
这太奇怪了,我实际上不得不发布一个StackOverflow问题来理解IsUpper的存在(因为它没有出现在自动完成中)。 编辑 我明白我早期的陈述需要一点解释。一个好的设计例子是String.ToLower()。它被定义为成员方法而不是静态void ToLower(String foo)。对我来说,同样的情况应适用于char.IsLower()。
3个回答

7

结构体的实例方法不是线程安全。 另一方面,静态方法是线程安全的。

静态方法接收结构体的副本,而实例方法使用托管指针访问数据。通过指针访问数据不是线程安全的操作,并且很容易导致竞争条件。

这就是为什么大多数结构体/基元类型的方法都是静态的而不是实例的原因。

在这里看到一个类似的问题。

为什么IsNan是Double类的静态方法而不是实例属性?


1
不是的,但它使用该值来确定某些东西(在这种情况下是大小写)。如果 IsLower 不是线程安全的,则多线程代码可能会导致 IsLower 返回错误的答案。 - Cameron MacFarland
1
我在那个答案上留了评论 - 我认为这并不能证明不可变值类型的实例方法不是线程安全的。它只能证明如果一个包含不可变值类型的变量在多个线程之间共享,它们都可以对其进行赋值。这对于静态方法和实例方法来说都是不好的。 - Daniel Earwicker
@Jay Bazuzi:如果你跟随链接,你会看到一个例子,即使是不可变的结构也可能没有线程安全的实例方法。 如果一个结构可以被复制(即使是不可变的),并且通过指针访问(就像实例方法一样),那么它就不是线程安全的。 - Pop Catalin
这不对 - 在进入方法时出现错误的值会使该方法查看随机损坏的值。这并没有改善情况。真正的问题是在没有正确锁定周围存储位置的情况下意外共享线程之间的存储位置。 - Daniel Earwicker
@Earwicker:当实例方法复制值时,您能保证它复制的是另一个线程中更改前或更改后的值吗? - Cameron MacFarland
显示剩余11条评论

3

另请参见此问题

简短版 - 初始IDE在从字符串文字(我假设也包括字符文字)调用时难以产生智能感知。因此,设计师们使方法静态化以解决此问题。

重新编辑:我在这里有一点抱怨,认为.NET设计师屈服于IDE设计师的压力。但是,在看到Pop在这个问题上的回答后,我现在不那么确定了。

编辑2:评论中的Tim问我们是否知道这是真的还是只是猜测。我找不到关于这个问题的确切参考资料,但我发现了一篇2002年的文章,讨论字符串文本中的智能感知错误。它大约在这个页面的中间部分。


这是一个很大的假设。我们真的知道吗?我们能够确认吗,还是只是猜测? - Tim
这个解释比Tim的更加合理。 - Constantin
String类上的方法和结构/原始类型上的方法没有任何共同点。这不是原因。原因是线程安全。将方法设置为静态是使其线程安全的简单方法,因为它接收结构的副本。 - Pop Catalin
@Pop 它们唯一的共同点是语言为它们定义了字面量,而 IDE 在处理这些字面量时遇到了问题。从这个意义上讲,字符串、字符 (以及整数、浮点数、十进制数等) 都是相同的。 - Cameron MacFarland
字符串的实例方法接收一个 this 引用,该引用不可更改。原始类型和结构的实例方法接收一个指向结构体的指针,该指针指向易变内存。 - Pop Catalin
显示剩余2条评论

2

在我看来,这是有意义的。

有许多静态方法只接受一个参数。使用以下方式计算平方根可能不太好:

double d = 100.0;
Console.WriteLine("Square root of d is " + d.Sqrt());

这会降低面向对象设计中的“内聚性”,这并不是一个好的实践。将这个责任分离到Math类中会更好。
double d = 100.0;
Console.WriteLine("Square root of d is " + Math.Sqrt(d));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接