为什么接口不能指定静态方法?
我知道这个问题已经被反复询问,但我似乎无法find足够的答案。 所以要说清楚我想知道的是什么,我将分成两个问题:
-
为什么不能有静态方法签名? 我会尝试抢占非答案,问为什么在世界上我想要做到这一点如下:我想能够静态调用
SqliteCodeGenerator
和MssqlCodeGenerator
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"; } }
-
另一方面,这是第二个问题的问题,如果你知道达成上述目标的一个好的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)) ...