42

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

  1. 为什么接口不能有静态方法签名?我将尝试抢占非答案,询问为什么在世界上我想用以下方法做到这一点:我希望能够静态GetDbConnectionType()调用SqliteCodeGeneratorand MssqlCodeGenerator

    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. 另一方面,这是第二个问题的问题,如果您知道实现上述目标的好选择,那么无论如何......

4

6 回答 6

65

假设你可以在一个接口中指定一个类型必须有一个特定的静态方法......你会怎么称呼它?多态性通过实例起作用——而静态成员明确地使用实例。

现在,话虽如此,在一种情况下我可以看到静态接口成员工作:泛型类型。例如:

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

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

我已经写了更多关于这个的博客,但我怀疑好处并不能证明复杂性是合理的。

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

于 2012-05-31T16:59:18.913 回答
7

@JonSkeet:可以在 CIL 中创建一个静态接口成员,所以恐怕你的第一句话会产生误导。我认为微软团队在 C# 中省略了它作为设计选择,以鼓励正确使用接口。

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

于 2014-07-17T10:37:46.287 回答
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);
    }
}
于 2012-05-31T17:11:23.433 回答
1

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

如果一个接口可以指定一些这样的静态方法应该以类似于扩展方法的方式使用,但没有与之相关的奇怪的范围规则(因此接口可能看起来为一些成员函数,而不需要所有的实现来提供它们)。

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

在任何情况下,由于接口不包含静态类,最好的办法是提供接口用户会发现有用的静态类,即使编译器会将这些类和接口视为完全独立的实体。

于 2012-05-31T17:23:29.673 回答
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";
  }
}
于 2015-02-03T19:26:56.910 回答
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))
   ...
于 2015-04-01T21:49:02.963 回答