C# 为什么可以';t接口指定静态方法?

C# 为什么可以';t接口指定静态方法?,c#,interface,static,C#,Interface,Static,我知道这个问题已经被问了一遍又一遍,但我似乎找不到足够好的答案。为了弄清楚我想知道什么,我将把它分成两个问题: 为什么接口不能有静态方法签名?我将尝试抢先回答以下问题:我希望能够在SqliteCodeGenerator和MssqlCodeGenerator上静态调用GetDbConnectionType(): interface ICodeGenerator { // this is the method I would like to be static: string Get

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

  • 为什么接口不能有静态方法签名?我将尝试抢先回答以下问题:我希望能够在
    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";
        }
    }
    
  • 另一方面,这是第二个问题,如果你知道实现上述目标的好方法,那么无论如何

  • 假设您可以在接口中指定类型必须具有特定的静态方法。。。你怎么称呼它?多态性通过实例工作,而静态成员显式地不使用实例

    说到这里,我可以看到静态接口成员在一种情况下工作:泛型类型。例如:

    // This isn't valid code...
    public void Foo<T>() where T : ICodeGenerator
    {
        string type = T.GetDbConnectionType();
    }
    
    //这不是有效的代码。。。
    public void Foo(),其中T:ICodeGenerator
    {
    字符串类型=T.GetDbConnectionType();
    }
    
    这将调用具体类型
    T
    上的静态成员

    我已经说过了,但我怀疑它的好处并不能证明它的复杂性


    就备选方案而言——通常您会有另一个接口,并且有单独的类型来实现该接口。这在某些情况下很有效,但在其他情况下则不行。

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

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

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

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


    在任何情况下,由于接口不包括静态类,因此最好能提供静态类,即使编译器将这些类和接口视为完全独立的实体,接口的用户也会觉得这些静态类很有用。

    @JonSkeet:,所以我担心你的第一句话是误导性的。我认为它是微软团队为了鼓励正确使用接口而在C#中省略的设计选择


    获得此功能的最佳方法可能是使用,这将允许您向接口的所有继承者或该接口的特定实现添加一个方法,但是您需要编写一个单独的类来保存扩展方法的实现,该扩展方法(如果没有计划)可能很容易忘记。

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

    但是如果按照你的方式,你只需要在抽象类中使函数保持静态

    要从接口执行此操作,请执行以下操作

    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) {
       }
    }
    
    定义一个类(如果使用它的类之间的逻辑必须不同,则将其设置为泛型):

    并为静态类提供该类的静态实例:

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

    错误的dup,这是一个:泛型类型成员的可能重复的可能重复
    T:BaseType
    总是绑定到
    BaseType
    ,而不是
    T
    。如果
    BaseType
    中的那些成员是虚拟的,则绑定到
    BaseType
    中定义的vtable插槽。对
    T
    类型的引用调用的虚拟成员通过
    BaseType
    类型定义的插槽号进行调度;类型
    T
    在调度中不起作用。允许类型声明和重写虚拟静态方法可能会很有用,这样,更神奇的是,
    T.VirtualStaticMethod()
    将通过
    T
    的vtable调度,使用
    BaseType
    中定义的插槽,但这将是一个很大的变化,强制类型实现静态成员,查询实现接口的类型,并且能够期望静态方法存在,这样做的好处是。@JonSkeet,你的博客文章被破坏了。你有最新消息吗?这正是我需要的。如果前一篇博文不再相关,那么在过去三年中这种情况发生了怎样的变化。非常感谢。我发现自己需要一个静态接口,只是为了避免创建这种类型的无意义实例。但是我必须同意静态接口可能会导致不必要的复杂性。@stuzor:不,这不是多态性——至少不是我使用这个术语的方式。我认为多态性是实现在执行时确定的一种方法的能力,这是基于它所调用的实例。那是整数
    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))
       ...