【问题标题】:Why is it useful to access static members "through" inherited types?为什么“通过”继承类型访问静态成员很有用?
【发布时间】:2011-06-24 03:29:07
【问题描述】:

我很高兴 C# 不允许您访问静态成员,就像它们是实例成员一样。这避免了 Java 中的一个常见错误:

Thread t = new Thread(..);
t.sleep(..); //Probably doesn't do what the programmer intended.

另一方面,它确实允许您“通过”派生类型访问静态成员。除了运算符(它使您免于编写强制转换)之外,我想不出任何实际有用的情况。事实上,它积极鼓励错误,例如:

// Nasty surprises ahead - won't throw; does something unintended:
// Creates a HttpWebRequest instead.
var ftpRequest = FtpWebRequest.Create(@"http://www.stackoverflow.com");

// Something seriously wrong here.
var areRefEqual = Dictionary<string, int>.ReferenceEquals(dict1, dict2);

当我在不熟悉的 API 中寻找方法时,我个人会一遍又一遍地犯下类似的错误(我记得从表达式树开始;我在编辑器中点击了BinaryExpression.,我想知道为什么 IntelliSense 到底为我提供了@987654325 @ 作为一个选项)。

在我(短视)看来,此功能:

  1. 不会减少冗长;程序员必须以一种或另一种方式指定类型名称(不包括运算符和访问当前类型的继承静态成员的情况)。
  2. 鼓励出现上述错误/误导性代码。
  3. 可能会向程序员建议 C# 中的静态方法表现出某种“多态性”,而实际上它们没有。
  4. (次要)在重新编译时引入“静默”,可能是意外的重新绑定可能性。

(IMO,运营商是一个特殊情况,值得他们自己讨论。)

鉴于 C# 通常是“成功之坑”语言,为什么会有这个特性?我看不到它的好处(除了“可发现性”,它总是可以在 IDE 中解决),但我看到了很多问题。

【问题讨论】:

  • 或者,更糟糕的是,UTF8Encoding.ASCII
  • 我同意这可能会有点误导,但它符合继承的成员被视为派生类型的成员的原则。请注意,我们明确not 允许在受约束的类型参数上使用此模式,因为那样它确实具有潜在的误导性。详情请见blogs.msdn.com/b/ericlippert/archive/2007/06/14/…

标签: c# inheritance static language-design


【解决方案1】:

我同意这是一个错误功能。我不知道 Stack Overflow 上有人发布以下代码的频率:

ASCIIEncoding.ASCII

等...虽然在执行方面无害,但在阅读代码方面却具有误导性。

现在删除这个“特性”显然为时已晚,尽管我猜 C# 团队可能会针对这个和其他样式问题引入一个超级详细的警告模式。

也许 C# 的继任者会改进……

【讨论】:

  • 其实我只在 SO 上看到过once
  • StyleCop 可以尝试捕捉这些。
  • 就像@SLaks 说的,UTF8Encoding.ASCII 更糟
  • ReSharper 对此肯定发出警告......“通过派生类型访问类型的静态成员”。耶!
  • @Jon Skeet:所以为了访问静态成员,您必须了解整个继承层次结构?如果类B 定义了一个静态方法S() 并且类D 派生自B 会怎样。 D 应该说B.S() 吗?不知何故,这感觉不对,但我(还没有?)为当前的行为辩护没有强有力的论据。
【解决方案2】:

这在 WinForms 中很有用。

在任何控件或表单中,您都可以编写MousePositionMouseButtonsModifierKeys 以使用从Control 继承的static 成员。

这是否是一个好的决定仍有争议。

【讨论】:

  • 您仍然可以通过编写类的隐式上下文访问“继承的”静态成员,但除了对的。
  • 是的。我不确定我是否能想到任何用途。
  • 我同意乔恩的观点,这两件事有些正交。不过,静默重新绑定问题仍然存在,尽管这是次要的,不太可能在 WinForms 中出现。
  • @Ani:在很多情况下,不同类型的继承行为在逻辑上可能是正交的,但受到语言或框架设计的限制。例如,没有特别的理由说明为什么未密封的类 Foo 不能让外部代码使用构造函数来构造新的 Foo 实例,而不允许使用相同的构造函数构造 DerivedFoo 实例,或者为什么Foo 不应该能够为方法Bar() 指定实现,而是要求任何派生类必须提供自己的替代实现。
  • @Ani:我不认为这里的“问题”特别是静态成员被继承的事实,而是没有任何类型的类成员可以通过的标准方法公开但不可继承。
猜你喜欢
  • 1970-01-01
  • 2018-08-25
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
  • 2016-01-28
  • 1970-01-01
相关资源
最近更新 更多