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

我知道这个问题已经被反复询问,但我似乎无法find足够的答案。 所以要说清楚我想知道的是什么,我将分成两个问题:

  1. 为什么不能有静态方法签名? 我会尝试抢占非答案,问为什么在世界上我想要做到这一点如下:我想能够静态调用SqliteCodeGeneratorMssqlCodeGenerator GetDbConnectionType()

     interface ICodeGenerator { // this is the method I would like to be static: string GetDbConnectionType(); } abstract class CodeGeneratorBase : ICodeGenerator { public abstract string GetDbConnectionType(); public void GenerateSomeCode(StringBuilder s) { s.AppendLine("var foo = new " + GetDbConnectionType() + "();"); } } class SqliteCodeGenerator : CodeGeneratorBase { public override string GetDbConnectionType() { return "SQLiteConnection"; } } class MssqlCodeGenerator : CodeGeneratorBase { public override string GetDbConnectionType() { return "SqlConnection"; } } 
  2. 另一方面,这是第二个问题的问题,如果你知道达成上述目标的一个好的select,那么通过一切手段…

假设你可以在一个接口中指定一个types必须有一个特定的静态方法…你怎么称呼它? 多态性通过实例工作 – 而静态成员显式使用实例。

现在,说了这样一个情况,我可以看到静态接口成员的工作:genericstypes。 例如:

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

这将调用具体typesT上的静态成员。

我已经在这方面进行了更多的博客 ,但是我怀疑这个好处并不能certificate这个复杂性。

在替代方面 – 通常你会有另一个接口,并有不同的types来实现这个接口。 这在某些情况下运作良好,但在其他情况下则不会。

@JonSkeet:可以在CIL中创build一个静态接口成员 ,所以恐怕你的第一个陈述是误导性的。 我认为它从C#中被忽略了,作为微软团队鼓励正确使用接口的一个deviseselect。

获得这种function的最好方法可能是使用扩展方法 ,这些方法允许你为接口的所有inheritance者或接口的特定实现添加一个方法,但是你需要编写一个单独的类来保存扩展的实现方法(如果没有计划的话)可能很容易失踪。

Jon的答案涵盖了几乎所有的东西,所以我的答案只包括使用.NETconfigurationAPI的可能工作。 它需要一些语法开销,但它确实可以让你静态访问实例。

 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); } } 

如果一个接口可以指定一个静态类,那么这个类的成员可以被编译器视为该接口的静态成员(因此,而不必使用静态类Enumerable<T>来得到Enumerable<T>.Default ,可以在语法上指定IEnumerable<T>.Default 。如果一个接口可以指定某些类似于扩展方法的静态方法可用,但是没有奇怪的作用域规则(所以一个接口似乎可以为一些成员函数提供多重的“方便”重载,而不需要所有的实现提供它们)。如果结合这样一个特性,可以声明接口方法将是非常有用的“可选的”,这样当一个实现提供了一个方法的时候就可以使用它,而当它不会自动replaceextension-ish方法的时候,这可能需要改变 但是,CLR。

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

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

但是他们的方式就是把它放在抽象类中

从一个界面做到这一点

 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"; } } 

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

而不是:

 // 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)) ...