为什么c#是这样设计的?

根据我的理解,一个接口只描述行为,并且服务于描述实现接口的类的契约义务。

如果类希望在共享方法中实现这种行为,为什么不应该呢?

以下是我想到的一个例子:

// These items will be displayed in a list on the screen.
public interface IListItem {
  string ScreenName();
  ...
}

public class Animal: IListItem {
    // All animals will be called "Animal".
    public static string ScreenName() {
        return "Animal";
    }
....
}

public class Person: IListItem {

    private string name;

    // All persons will be called by their individual names.
    public string ScreenName() {
        return name;
    }

    ....

 }

当前回答

Regarding static methods used in non-generic contexts I agree that it doesn't make much sense to allow them in interfaces, since you wouldn't be able to call them if you had a reference to the interface anyway. However there is a fundamental hole in the language design created by using interfaces NOT in a polymorphic context, but in a generic one. In this case the interface is not an interface at all but rather a constraint. Because C# has no concept of a constraint outside of an interface it is missing substantial functionality. Case in point:

T SumElements<T>(T initVal, T[] values)
{
    foreach (var v in values)
    {
        initVal += v;
    }
}

这里没有多态性,泛型使用对象的实际类型并调用+=操作符,但这失败了,因为它不能确定该操作符是否存在。简单的解决方案是在约束中指定它;简单的解决方案是不可能的,因为操作符是静态的,静态方法不能在接口中,(这就是问题所在)约束被表示为接口。

c#需要的是一个真正的约束类型,所有的接口都是约束,但不是所有的约束都是接口,然后你可以这样做:

constraint CHasPlusEquals
{
    static CHasPlusEquals operator + (CHasPlusEquals a, CHasPlusEquals b);
}

T SumElements<T>(T initVal, T[] values) where T : CHasPlusEquals
{
    foreach (var v in values)
    {
        initVal += v;
    }
}

已经有很多关于为所有数字类型创建i算术来实现的讨论,但是存在效率问题,因为约束不是多态构造,所以创建算术约束可以解决这个问题。

其他回答

您想要的是允许通过Type或该类型的任何实例调用静态方法。这至少会导致歧义,这不是一个理想的特征。

关于这是否重要,这是最佳实践,以及这样做是否存在性能问题,将会有无休止的争论。通过简单地不支持它,c#使我们不必担心它。

遵循这一愿望的编译器也可能会失去一些优化,而这些优化可能会带来实例方法和静态方法之间更严格的分离。

供您参考:您可以通过为接口创建扩展方法来获得与您想要的类似的行为。扩展方法将是一个共享的、不可覆盖的静态行为。然而,不幸的是,这个静态方法不是契约的一部分。

从概念上讲,接口没有理由不能定义包含静态方法的契约。

对于当前的c#语言实现,限制是由于允许继承基类和接口。如果“类SomeBaseClass”实现了“接口ISomeInterface”和“类SomeDerivedClass: SomeBaseClass, ISomeInterface”也实现了接口,实现接口方法的静态方法将会编译失败,因为静态方法不能与实例方法具有相同的签名(实例方法将出现在实现接口的基类中)。

静态类在功能上与单例类相同,并且具有与单例类相同的目的,只是语法更简洁。因为单例可以实现接口,所以静态的接口实现在概念上是有效的。

因此,这可以简单地归结为c#的实例名称冲突和跨继承的同名静态方法的限制。c#没有理由不能“升级”以支持静态方法契约(接口)。

我的(简化的)技术原因是静态方法不在虚表中,调用站点是在编译时选择的。这和你不能有覆盖或虚拟静态成员的原因是一样的。要了解更多细节,你需要一个计算机专业毕业生或编译专家——而我两者都不是。

出于政治原因,我将引用Eric Lippert(他是一名编译器专家,拥有滑铁卢大学的数学、计算机科学和应用数学学士学位)的话:

...静态方法的核心设计原则,给它们命名的原则是…在编译时,总是可以准确地确定将调用什么方法。也就是说,可以仅通过对代码的静态分析来解析该方法。

请注意,Lippert确实为所谓的类型方法留出了空间:

也就是说,与类型相关联的方法(如静态方法),它不接受不可空的“this”参数(与实例或虚拟方法不同),而是调用的方法依赖于T的构造类型(与静态方法不同,它必须在编译时确定)。

但还没有被它的实用性所说服。

接口是已定义可用功能的抽象集合。

该接口中的方法是否表现为静态行为是应该隐藏在接口后面的实现细节。将接口方法定义为静态是错误的,因为您将不必要地强制该方法以某种方式实现。

如果方法被定义为静态的,那么实现接口的类就不会像它应该的那样被封装。在面向对象设计中,封装是一件值得努力的事情(我不会详细说明原因,你可以在这里阅读:http://en.wikipedia.org/wiki/Object-oriented)。因此,在接口中不允许使用静态方法。