为什么接口不能指定静态方法?

时间:2012-05-31 16:52:51

标签: c# interface static

我知道这个问题一直被问到,但我似乎找不到足够好的答案。所以为了弄清楚我想知道的是什么,我将把它分成两个问题:

  1. 为什么接口不能有静态方法签名?我会尝试先取消非答案,询问为什么在世界上我会想要用以下内容执行此操作:我希望能够在GetDbConnectionType()和{{1}上静态调用SqliteCodeGenerator }:

    MssqlCodeGenerator
  2. 另一方面,这是第二个问题的问题,如果你知道达到上述目标的好方法,那么无论如何......

6 个答案:

答案 0 :(得分:65)

假设您可以在接口中指定某个类型必须具有特定的静态方法......您将如何调用它?多态性通过实例工作 - 而静态成员显式使用实例。

现在,已经说过,有一个的情况,我可以看到静态接口成员工作:泛型类型。例如:

// This isn't valid code...
public void Foo<T>() where T : ICodeGenerator
{
    string type = T.GetDbConnectionType();
}

这将调用具体类型T上的静态成员。

blogged more about this,但我怀疑这种好处并不能证明复杂性。

就替代方案而言 - 通常你会有另一个接口,并且有不同的类型来实现该接口。这在某些情况下很有效,但在其他情况下则不然。

答案 1 :(得分:7)

@JonSkeet:可能create a static interface member in CIL,所以我担心你的第一个陈述会产生误导。我认为它被C#省略,作为微软团队的设计选择,鼓励正确使用接口。

获得此功能的最佳方法可能是extension methods,这些将允许您向接口的所有继承者或该接口的特定实现添加方法,但是您需要编写单独的类持有扩展方法的实现(如果没有计划)可以很容易失去跟踪。

答案 2 :(得分:1)

Jon的答案几乎涵盖了所有内容,因此我的答案仅包括使用.NET配置API的可能工作。它需要一些语法开销,但它确实为您提供了对实例的静态访问。

interface IStorage
{
    void Store(string item);
}

static class Storage
{
    private static readonly IStorage _instance;

    static Storage()
    {
        var storageTypeString = ConfigurationManager.AppSettings["storageTypeString"];
        var storageType = Type.GetType(storageTypeString, true);
        _instance = (IStorage)Activator.CreateInstance(storageType);
    }

    public static void Store(string item)
    {
        _instance.Store(item);
    }
}

答案 3 :(得分:1)

如果接口可以指定静态类,那么该类的成员将被编译器视为该接口的静态成员,这可能会有所帮助。因此,不必使用静态类Enumerable<T>来获取Enumerable<T>.Default,而是可以在语法上指定IEnumerable<T>.Default

如果接口可以指定一些这样的静态方法应该以类似于扩展方法的方式使用,但没有与它们相关联的奇怪的作用域规则(因此接口可能看起来提供多个“便利性”)将更有帮助“某些成员函数的重载,而不需要所有实现提供它们。”

如果结合这样的特性,接口方法可以被声明为“可选的”,那么当一个实现提供了一个它将被使用的方法时,并且当它没有使用extension-ish方法时,这将是非常有用的。自动替换。但是,这可能需要更改CLR。

在任何情况下,因为接口不包含静态类,所以最好的方法是提供静态类,即使编译器将这些类和接口视为完全独立的实体,接口的用户也会觉得有用。 / p>

答案 4 :(得分:0)

我知道这是旧的,但实际上你可以在名称空间之外的静态类中声明静态函数。

但他们认为你只需要在抽象类中使函数静态

从您执行此操作的界面中执行此操作

public static class Interfacefunction{
  public static string GetDbConnectionType(this ICodeGenerator me)
  {
      // this is the method I would like to be static:
      // you can even get access to me
      return "SQLiteConnection";
  }
}

答案 5 :(得分:0)

一种解决方法(虽然这种方式实际上可能更好)我决定使用的是使用静态实例而不是静态接口。

而不是:

// does not compile
ISomeInterface {
   static void DoSomething();
   static bool TestSomething(string pValue);
   // etc... 
}

static class SomeStaticClass : ISomeInterface {
   public static void DoSomething() {
   }

   public static bool TestSomething(string pValue) {
   }
}

定义一个类(如果逻辑必须在您使用它的类之间变化,则使其成为通用的):

sealed class SomeClass {
   public void DoSomething() {
      // reusable implementation
   }

   public bool TestSomething(string pValue) {
      // reusable implementation
   }
}

并将该类的静态实例提供给静态类:

static class SomeStaticClass {
   static readonly SomeClass sSomeClass = new SomeClass();
}

唯一的问题是您必须决定是否将属性公开给静态实例:

static class SomeStaticClass {
   static readonly SomeClass sSomeClass = new SomeClass();

   public static SomeClass SomeProperty { get { return sSomeClass; } }
}

...

SomeStaticClass.SomeProperty.DoSomething();
if (SomeStaticClass.SomeProperty.TestSomething(someValue))
   ...

或包装其方法:

static class SomeStaticClass {
   static readonly SomeClass sSomeClass = new SomeClass();

   public static void DoSomething() {
      sSomeClass.DoSomething();
   }

   public static bool TestSomething(string pValue) {
      sSomeClass.TestSomething(pValue);
   }
}

...

SomeStaticClass.DoSomething();
if (SomeStaticClass.TestSomething(someValue))
   ...