如何在派生类型中使用类的静态成员?

75

我在使用Resharper 4.1时遇到了一个有趣的警告:“通过派生类型访问类型的静态成员”。以下是出现此警告的代码示例:

class A {
    public static void SomethingStatic() {
       //[do that thing you do...]
    }
}

class B : A {
}

class SampleUsage {
    public static void Usage() {
        B.SomethingStatic(); // <-- Resharper warning occurs here
    }
}

有没有人知道通过B使用A的静态成员会存在什么问题(如果有的话)?

4个回答

85

可能会误导人的一个地方是当静态属性是工厂方法时,例如WebRequest类具有一个名为Create的工厂方法,如果通过派生类访问,则允许编写此类型的代码。

var request = (FtpWebRequest)HttpWebRequest.Create("ftp://ftp.example.com");

这里的request是一个类型为FtpWebRequest的对象,但它让人困惑的是看起来像是从一个类似的兄弟类HttpWebRequest创建而来,尽管Create方法实际上是在基类WebRequest中定义的。下面的代码意思相同,但更清晰易懂:

var request = (FtpWebRequest)WebRequest.Create("ftp://ftp.example.com");

最终通过派生类型访问静态成员变量没有什么大的问题,但是不这样做通常会使代码更加清晰易懂。


这是一个我以前从未考虑过的问题。谢谢 Greg! - Swim
很棒的解释,真的很有帮助。还是谷歌上的第一个结果^^ - marcgg
1
是的,当有人认为足够了并在HttpWebRequest上实现Create方法并隐藏它时,这也很有趣。重新编译,代码崩溃。许多编程语言仍然认为世界不会改变。 - Maarten Bodewes

30

B.SomethingStatic() 的调用表明SomethingStaticB的成员。这是不正确的。毫无疑问,SomethingStaticA的成员。它可以被不限定地访问B的成员(就像它是B的成员一样)纯属于方便。而当使用B来修饰它时,可以访问它也是错误的,我个人认为。


我认为子类应该继承超类的每个属性,特别是对于我现在所在的项目来说,这对工厂模式非常有帮助。 - NullVoxPopuli
我不同意。当前的行为是有益的,我有一个有效的案例。这是我的想法:class Validator : ValidatorBase<ThrowStrategy> {}。用法:Validator.CheckNonEmpty(str)。将其与ValidatorBase<ThrowStrategy>.CheckNonEmpty(str)进行比较。 - Gebb
@Gebb:恐怕我没有理解你的观点。所以你设计了一个难以输入的类层次结构。这如何使我所说的无效?如果是我,我会期望Validator.CheckNonEmptyValidatorBase<ThrowStrategy>.CheckNonEmpty表现不同,因为它们是由不同类型提供的。但事实并非如此,这令人困惑。如果你有另一个派生类,你也会在那个类上调用CheckNonEmpty吗?这个错误的特性在某些情况下节省了一些输入,但这并不是一个好的特性。 - P Daddy
@PDaddy:重要的不是打字,而是可读性。虽然CheckNonEmpty看起来属于Validator类,但只要它的作用显而易见,那就没关系了。 - Gebb

15

这通常不是警告,而只是一个建议。你正在不必要地创建对某个东西的依赖。

假设您后来决定B不需要继承A。如果您遵循Resharper的建议,您将不需要修改那行代码。


2
你在实例方法中也会遇到同样的问题。按照这个逻辑,为什么还要继承呢?或者我有什么地方理解不对吗? - NullVoxPopuli
@NullVoxPopuli - 有些人建议完全避免实现继承。一些流行的Java和C#书籍也提出了这个观点(参见这篇论文:http://www.isase.us/wisr3/7.pdf)。但无论如何,如果在`A`中有一个实例方法`Foo`,那么对于变量`b`引用的`B`实例,您不像静态情况下那样有自由地说“在哪里”查找`Foo`。您必须从`b`开始,无论您做什么。因此,它与静态情况并不完全相同。 - Daniel Earwicker

2

是的,我也见过这个,我一直认为它只是警告我因为它是不必要的。 A.SomethingStatic(); 会做同样的事情。


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