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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10837906/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 15:28:38  来源:igfitidea点击:

Why can't interfaces specify static methods?

c#interfacestatic

提问by

I know this question has been asked over and over, but I can't seem to find good enough answers. So to make it clear what I'm trying to know, I'll split this in two questions:

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

  1. Why can't interfaces have static method signatures? I'll try to preempt the non-answers asking why in the world I would want to do this with the following: I would want to be able to statically invoke GetDbConnectionType()on 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. On the other hand, and this is the matter of this second question, if you know of a good alternative to reach the aforementioned goal, then by all means...

  1. 为什么接口不能有静态方法签名?我会尽力抢占非答案,询问为什么在世界上我想用下面这样做:我希望能够调用静态GetDbConnectionType()SqliteCodeGeneratorMssqlCodeGenerator

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

采纳答案by Jon Skeet

Suppose you couldspecify in an interface that a type had to have a particular static method... how would you call it? Polymorphism works through instances- whereas static members explicitly don'tuse instances.

假设你可以在一个接口中指定一个类型必须有一个特定的静态方法......你会如何调用它?多态通过实例工作——而静态成员明确使用实例。

Now, having said that, there's onesituation in which I can see static interface members working: generic types. For example:

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

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

That would call the static member on the concretetype T.

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

I've blogged more about this, but I suspect the benefit doesn't justify the complexity.

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

In terms of alternatives - usually you'd have another interface, and have separate types to implement that interface. That works well in some contexts, but not in others.

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

回答by ChaosPandion

Jon's answer covers pretty much everything so my answer only includes a possible work around using the .NET configuration API. It requires a bit of syntax overhead but it does give you static access to the instance.

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

回答by supercat

It might be somewhat helpful if an interface could specify a static class, such that members of that class would be seen by the compiler as static members of that interface. Thus, instead of having to use static class Enumerable<T>to get Enumerable<T>.Default, one could instead syntactically specify IEnumerable<T>.Default.

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

It would be even more helpful if an interface could specify that some such static methods should be usable in a fashion similar to extension methods, but without the weird scoping rules associated with them (so an interface could appear to offer multiple "convenience" overloads for some member functions without requiring all of the implementations to provide them).

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

It would be extremely helpful if, combined with such a feature, interface methods could be declared "optional", such that when an implementation provided a method it would be used, and when it did not the extension-ish method would be automatically substituted. This would probably require changes to the CLR, however.

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

In any case, because interfaces do not include static classes, the best one can do is provide static classes which users of the interface will find helpful, even though the compiler will regard those classes and the interfaces as entirely independent entities.

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

回答by Dead.Rabit

@JonSkeet: It's possible to create a static interface member in CIL, so I'm afraid your first statement is misleading. I assume it was omitted from C# as a design choice by the Microsoft team to encourage correct usage of interfaces.

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

The best way to get this functionality is probably with extension methods, these will allow you to add a method to all inheritors of your interface or to a specific implementation of that interface however you need to write a separate class to hold the implementation of the extension method which (if not planned for) can be easy to lose track of.

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

回答by Ron Bowes

I know this is old, but actually you can with static functions declared in a static class outside of a name space.

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

but they way your putting it you would just make the function static in the abstract class

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

to do it from an interface you do this

从你这样做的界面上做到这一点

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

回答by Dave Cousineau

A sort of workaround (though it may actually be better this way) for this I've decided to use is to use a static instance instead of a static interface.

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

Rather than:

而不是:

// 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) {
   }
}

Define a class (make it generic if the logic must vary between classes that you use it with):

定义一个类(如果您使用它的类之间的逻辑必须有所不同,则使其成为通用的):

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

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

and give a static instance of that class to your static class:

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

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

The only issue is that you have to decide whether to expose a property to the static instance:

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

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

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

...

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

or to wrap its methods:

或包装其方法:

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