为什么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;
    }

    ....

 }

当前回答

假设你在问为什么你不能这样做:

public interface IFoo {
    void Bar();
}

public class Foo: IFoo {
    public static void Bar() {}
}

This doesn't make sense to me, semantically. Methods specified on an interface should be there to specify the contract for interacting with an object. Static methods do not allow you to interact with an object - if you find yourself in the position where your implementation could be made static, you may need to ask yourself if that method really belongs in the interface. To implement your example, I would give Animal a const property, which would still allow it to be accessed from a static context, and return that value in the implementation.

public class Animal: IListItem {
    /* Can be tough to come up with a different, yet meaningful name!
     * A different casing convention, like Java has, would help here.
     */
    public const string AnimalScreenName = "Animal";
    public string ScreenName(){ return AnimalScreenName; }
}

对于更复杂的情况,您总是可以声明另一个静态方法并委托给它。在尝试给出一个例子的过程中,我想不出您在静态和实例上下文中都要做一些非平凡的事情的任何理由,因此我将给您一个FooBar blob,并将其作为它可能不是一个好主意的指示。

其他回答

一个静态类是用c#实现的,微软用静态元素创建了一个特殊的类实例,这只是实现静态功能的一个奇怪之处。这不是一个理论观点。

接口应该是类接口的描述符——或者它是如何与之交互的,并且应该包括静态的交互。接口的一般定义(来自merriam - webster):不同事物相遇、交流或相互影响的地方或区域。当您完全忽略类的静态组件或静态类时,我们就忽略了这些坏家伙如何交互的大部分内容。

下面是一个非常清晰的例子,说明了在静态类中使用接口是非常有用的:

public interface ICrudModel<T, Tk>
{
    Boolean Create(T obj);
    T Retrieve(Tk key);
    Boolean Update(T obj);
    Boolean Delete(T obj);
}

目前,我在编写包含这些方法的静态类时没有进行任何检查,以确保我没有忘记任何东西。就像在面向对象编程之前的糟糕的编程时代。

举一个例子,我既没有接口方法的静态实现,也没有Mark Brackett介绍的“所谓的类型方法”:

当从数据库存储中读取数据时,我们有一个通用的DataTable类来处理从任何结构的表中读取数据。所有特定于表的信息都放在每个表的一个类中,每个表还保存来自DB的一行的数据,并且必须实现IDataRow接口。IDataRow中包含了要从数据库中读取的表的结构描述。DataTable在从DB中读取数据之前必须向IDataRow请求数据结构。目前看起来是这样的:

interface IDataRow {
  string GetDataSTructre();  // How to read data from the DB
  void Read(IDBDataRow);     // How to populate this datarow from DB data
}

public class DataTable<T> : List<T> where T : IDataRow {

  public string GetDataStructure()
    // Desired: Static or Type method:
    // return (T.GetDataStructure());
    // Required: Instantiate a new class:
    return (new T().GetDataStructure());
  }

}

每个表只需要读取一次GetDataStructure,实例化一个实例的开销是最小的。但是,在这种情况下它会很好。

您可以将类的静态方法和非静态方法看作是不同的接口。调用时,静态方法解析为单例静态类对象,而非静态方法解析为所处理的类的实例。所以,如果你在一个接口中使用静态和非静态方法,你实际上是在声明两个接口,而实际上我们想要接口被用来访问一个内聚的东西。

事实上,确实如此。

截至2022年年中,当前版本的c#完全支持所谓的静态抽象成员:

interface INumber<T>
{
    static abstract T Zero { get; }
}

struct Fraction : INumber<Fraction>
{
    public static Fraction Zero { get; } = new Fraction();

    public long Numerator;
    public ulong Denominator;

    ....
}

请注意,根据你的Visual Studio版本和你安装的。net SDK,你必须至少更新其中一个(或两个),或者你必须启用预览功能(参见在Visual Studio中使用预览功能和预览语言)。

看到更多:

https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/static-virtual-interface-members https://blog.ndepend.com/c-11-static-abstract-members/ https://khalidabuhakmeh.com/static-abstract-members-in-csharp-10-interfaces: ~:文本=静态% 20文摘% 20成员% 20允许% 20,像% 20 % 20其他% 20接口% 20的定义。

这里的大多数答案似乎都没有抓住重点。多态性不仅可以在实例之间使用,还可以在类型之间使用。当我们使用泛型时,这是经常需要的。

假设我们在泛型方法中有类型参数,我们需要对它做一些操作。我们不想实例化,因为我们不知道构造函数。

例如:

Repository GetRepository<T>()
{
  //need to call T.IsQueryable, but can't!!!
  //need to call T.RowCount
  //need to call T.DoSomeStaticMath(int param)
}

...
var r = GetRepository<Customer>()

不幸的是,我只能想出一些“丑陋”的选择:

Use reflection Ugly and beats the idea of interfaces and polymorphism. Create completely separate factory class This might greatly increase the complexity of the code. For example, if we are trying to model domain objects, each object would need another repository class. Instantiate and then call the desired interface method This can be hard to implement even if we control the source for the classes, used as generic parameters. The reason is that, for example we might need the instances to be only in well-known, "connected to DB" state.

例子:

public class Customer 
{
  //create new customer
  public Customer(Transaction t) { ... }

  //open existing customer
  public Customer(Transaction t, int id) { ... }

  void SomeOtherMethod() 
  { 
    //do work...
  }
}

为了使用实例化来解决静态接口问题,我们需要做以下事情:

public class Customer: IDoSomeStaticMath
{
  //create new customer
  public Customer(Transaction t) { ... }

  //open existing customer
  public Customer(Transaction t, int id) { ... }

  //dummy instance
  public Customer() { IsDummy = true; }

  int DoSomeStaticMath(int a) { }

  void SomeOtherMethod() 
  { 
    if(!IsDummy) 
    {
      //do work...
    }
  }
}

这显然是丑陋的,也是不必要的,会使所有其他方法的代码复杂化。显然,这也不是一个优雅的解决方案!