为什么不C#允许静态方法来实现一个接口?

为什么C#这样devise?

据我所知,一个接口只描述行为,并描述一个实现特定行为的接口类的契约义务。

如果class级希望以共享的方式实施这种行为,他们为什么不呢?

以下是我想到的一个例子:

// These items will be displayed in a list on the screen. public interface IListItem { string ScreenName(); ... } public class Animal: IListItem { // All animals will be called "Animal". public static string ScreenName() { return "Animal"; } .... } public class Person: IListItem { private string name; // All persons will be called by their individual names. public string ScreenName() { return name; } .... } 

假设你问为什么你不能这样做:

 public interface IFoo { void Bar(); } public class Foo: IFoo { public static void Bar() {} } 

这在语义上对我没有意义。 在接口上指定的方法应该在那里指定与对象交互的协定。 静态方法不允许你与一个对象交互 – 如果你发现你的实现可以变成静态的位置,你可能需要问自己,这个方法是否真的属于这个接口。


为了实现你的例子,我会给Animal一个const属性,它仍然允许它从一个静态的上下文访问,并在实现中返回这个值。

 public class Animal: IListItem { /* Can be tough to come up with a different, yet meaningful name! * A different casing convention, like Java has, would help here. */ public const string AnimalScreenName = "Animal"; public string ScreenName(){ return AnimalScreenName; } } 

对于更复杂的情况,你总是可以声明另一个静态方法并委托给它。 在试图拿出一个例子,我想不出有什么理由在静态和实例上下文中做一些不平凡的事情,所以我会给你一个FooBar blob,并把它作为一个迹象表明它可能不是一个好主意。

我的(简化的)技术原因是静态方法不在vtable中 ,调用站点是在编译时select的。 这是你不能拥有重写或虚拟静态成员的原因。 有关更多详细信息,您需要CSgradle生或编译器wonk – 我既不是。

出于政治原因,我将引用Eric Lippert (他是一名编译者,拥有滑铁卢大学math,计算机科学和应用math学士学位)(来源: LinkedIn ):

…静态方法的核心devise原则,给出它们名字的原则…在编译时总是可以精确地确定将调用什么方法。 也就是说,这个方法只能通过代码的静态分析来解决。

请注意,Lippert为所谓的types方法留下了空间:

也就是说,与一个types(如静态)相关的方法,它不采用非空的“this”参数(不像一个实例或虚拟),而是一个被调用方法取决于构造typesT不像静态,它必须在编译时确定)。

但尚未确定其用处。

这里的大多数答案似乎都忽略了整个观点。 多态性不仅可以在实例之间使用,也可以在types之间使用。 当我们使用generics时,这是经常需要的。

假设我们在generics方法中有types参数,我们需要对它进行一些操作。 我们不想瞬间,因为我们不知道的构造函数。

例如:

 Repository GetRepository<T>() { //need to call T.IsQueryable, but can't!!! //need to call T.RowCount //need to call T.DoSomeStaticMath(int param) } ... var r = GetRepository<Customer>() 

不幸的是,我只能拿出“丑陋”的select:

  • 使用reflection丑陋,打破接口和多态的想法。

  • 创build完全独立的工厂类

    这可能会大大增加代码的复杂性。 例如,如果我们要模拟域对象,每个对象都需要另一个存储库类。

  • 实例化,然后调用所需的接口方法

    即使我们控制用作generics参数的类的源代码,这也很难实现。 原因是,例如,我们可能需要的实例只是众所周知的,“连接到数据库”状态。

例:

 public class Customer { //create new customer public Customer(Transaction t) { ... } //open existing customer public Customer(Transaction t, int id) { ... } void SomeOtherMethod() { //do work... } } 

为了使用instantine解决静态接口问题,我们需要做以下事情:

 public class Customer: IDoSomeStaticMath { //create new customer public Customer(Transaction t) { ... } //open existing customer public Customer(Transaction t, int id) { ... } //dummy instance public Customer() { IsDummy = true; } int DoSomeStaticMath(int a) { } void SomeOtherMethod() { if(!IsDummy) { //do work... } } } 

这显然是丑陋的,也没有必要使所有其他方法的代码复杂化。 显然,不是一个优雅的解决scheme!

我知道这是一个古老的问题,但很有趣。 这个例子并不是最好的。 如果你展示了一个用例,我认为它会更清晰:

stringDoSomething <T>()其中T:ISomeFunction
 {
   if(T.someFunction())
     ...
 }

只能够有静态方法实现一个接口不会达到你想要的; 需要将静态成员作为接口的一部分 。 我当然可以想象很多使用情况,特别是在能够创build事物的情况下。 我可以提供两种可能有用的方法:

  1. 创build一个静态generics类,其types参数将是您将传递给上面DoSomething的types。 这个类的每个变体将有一个或多个静态成员持有与该types相关的东西。 这个信息可以通过让每个感兴趣的类调用一个“注册信息”例程来提供,也可以通过使用Reflection来获得类variables的静态构造函数运行时的信息。 我相信后一种方法被比较器<T> .Default()所使用。
  2. 对于每个感兴趣的类T,定义一个实现IGetWhateverClassInfo <T>的类或结构,并满足“新”约束。 该类实际上不包含任何字段,但将有一个静态属性返回一个types信息的静态字段。 将该类或结构的types传递给有问题的generics例程,这将能够创build一个实例并使用它获取有关其他类的信息。 如果你为此目的使用一个类,你应该定义一个如上所述的静态generics类,以避免每次都构造一个新的描述符对象实例。 如果你使用一个结构,实例化成本应该是零,但是每个不同的结构types都需要DoSomething例程的不同扩展。

这些方法都没有吸引力。 另一方面,如果CLR中存在的机制可以干净地提供这种function,.net将允许指定参数化的“新”约束(因为知道一个类是否具有带有特定签名的构造函数在比较难以知道它是否有一个特定的签名静态方法)。

接口指定对象的行为。

静态方法不指定对象的行为,而是以某种方式影响对象的行为。

就接口表示“契约”而言,静态类实现接口似乎是安静合理的。

上述论点似乎都忽略了关于合同的观点。

近视,我猜。

当最初devise时,接口仅用于类的实例

 IMyInterface val = GetObjectImplementingIMyInterface(); val.SomeThingDefinedinInterface(); 

只是通过引入接口作为generics的约束,在接口中添加一个静态方法才有实际的用处。

(回应评论:)我相信现在改变它将需要改变到CLR,这将导致与现有的组件不兼容。

因为接口的目的是为了允许多态,所以能够传递任何数量已定义的类的实例来实现已定义的接口…保证在你的多态调用中,代码将能够find你正在调用的方法。 允许静态方法实现接口是没有意义的,

你怎么称呼它?


 public interface MyInterface { void MyMethod(); } public class MyClass: MyInterface { public static void MyMethod() { //Do Something; } } // inside of some other class ... // How would you call the method on the interface ??? MyClass.MyMethod(); // this calls the method normally // not through the interface... // This next fails you can't cast a classname to a different type... // Only instances can be Cast to a different type... MyInterface myItf = MyClass as MyInterface; 

关于在非generics上下文中使用的静态方法,我同意在接口中允许它们没有什么意义,因为如果你有一个接口的引用,你将无法调用它们。 然而,在通过在多态上下文中使用接口而创build的语言devise中存在一个根本的缺陷,但是在通用的一个中。 在这种情况下,接口根本不是一个接口,而是一个约束。 因为C#没有接口之外的约束概念,所以缺less实质性的function。 例如:

 T SumElements<T>(T initVal, T[] values) { foreach (var v in values) { initVal += v; } } 

在这里没有多态,generics使用对象的实际types并调用+ =操作符,但是由于不能确定该操作符是否存在,所以失败了。 简单的解决scheme是在约束中指定它; 简单的解决scheme是不可能的,因为操作符是静态的,静态方法不能在一个接口中,并且(这里是问题)约束被表示为接口。

C#需要的是一个真正的约束types,所有的接口也是约束,但不是所有的约束都是接口,那么你可以这样做:

 constraint CHasPlusEquals { static CHasPlusEquals operator + (CHasPlusEquals a, CHasPlusEquals b); } T SumElements<T>(T initVal, T[] values) where T : CHasPlusEquals { foreach (var v in values) { initVal += v; } } 

已经有很多关于为所有数字types实现一个算术的讨论,但是由于一个约束不是一个多态的结构,因此一个算术约束可以解决这个问题。

因为接口是inheritance结构,静态方法不能inheritance。

你似乎想要的将允许通过Type或任何types的实例调用静态方法。 这至less会导致模棱两可,这不是一个理想的特质。

关于它是否重要,将会有无尽的争论,这是最佳实践,以及是否存在性能问题。 通过简单地不支持它,C#节省了我们不必担心它。

它也可能是一个符合这个愿望的编译器会失去一些可能带来实例和静态方法之间更严格分离的优化。

你可以把类的静态方法和非静态方法看作是不同的接口。 在调用时,静态方法parsing为单例静态类对象,非静态方法parsing为所处理类的实例。 所以,如果你在一个接口中使用静态和非静态的方法,那么当我们想要使用接口来访问一个有凝聚力的东西的时候,你会有效地声明两个接口。

举一个例子,我缺less接口方法的静态实现或Mark Brackett引入的所谓的“types方法”:

从数据库存储读取数据时,我们有一个通用的DataTable类,用于处理从任何结构的表中读取数据。 所有表格的具体信息放在每个表格中的一个类中,该表格也保存了数据库中一行的数据,并且必须实现一个IDataRow接口。 包含在IDataRow中的是从数据库中读取表的结构的描述。 在从数据库读取数据之前,DataTable必须从IDataRow请求数据结构。 目前这看起来像:

 interface IDataRow { string GetDataSTructre(); // How to read data from the DB void Read(IDBDataRow); // How to populate this datarow from DB data } public class DataTable<T> : List<T> where T : IDataRow { public string GetDataStructure() // Desired: Static or Type method: // return (T.GetDataStructure()); // Required: Instantiate a new class: return (new T().GetDataStructure()); } } 

GetDataStructure只需要每个表读取一次,实例化一个实例的开销是最小的。 但是,在这种情况下,这将是很好的。

仅供参考:通过为接口创build扩展方法,您可以获得与所需相似的行为。 扩展方法将是一个共享的,不可重写的静态行为。 然而,不幸的是,这种静态的方法不会成为合同的一部分。

我想这个简短的答案是“因为它没有用处”。 要调用一个接口方法,你需要一个types的实例。 从实例方法你可以调用任何你想要的静态方法。

接口是定义的可用function的抽象集合。

无论该接口中的方法是否为静态,都是应该隐藏在接口后面的实现细节 。 将接口方法定义为静态会是错误的,因为您将不必要地强制以某种方式实现该方法。

如果方法被定义为静态的,那么实现这个接口的类将不会被封装。 在面向对象的devise中,封装是一件好事(我不会深究为什么,你可以在这里阅读: http : //en.wikipedia.org/wiki/Object-oriented )。 出于这个原因,接口中不允许使用静态方法。

静态类应该能够做到这一点,所以他们可以一般使用。 我不得不实现一个单例来达到预期的效果。

我有一堆静态业务层类,实现了像“用户”,“团队”等每个实体types的“创build”,“阅读”,“更新”,“删除”等CRUD方法。然后,我创build了一个基地控制具有实现CRUD方法的业务层类的抽象属性。 这使我可以自动从基类“创build”,“读取”,“更新”,“删除”操作。 由于静态限制,我必须使用Singleton。

大多数人似乎忘记,在OOP类也是对象,所以他们有消息,由于某种原因c#调用“静态方法”。 实例对象和类对象之间存在差异的事实仅表明语言中存在缺陷或缺陷。 关于C#的乐观主义者虽然…

The fact that a static class is implemented in C# by Microsoft creating a special instance of a class with the static elements is just an oddity of how static functionality is achieved. It is isn't a theoretical point.

An interface SHOULD be a descriptor of the class interface – or how it is interacted with, and that should include interactions that are static. The general definition of interface (from Meriam-Webster): the place or area at which different things meet and communicate with or affect each other. When you omit static components of a class or static classes entirely, we are ignoring large sections of how these bad boys interact.

Here is a very clear example of where being able to use interfaces with static classes would be quite useful:

 public interface ICrudModel<T, Tk> { Boolean Create(T obj); T Retrieve(Tk key); Boolean Update(T obj); Boolean Delete(T obj); } 

Currently, I write the static classes that contain these methods without any kind of checking to make sure that I haven't forgotten anything. Is like the bad old days of programming before OOP.

C# and the CLR should support static methods in interfaces as Java does. The static modifier is part of a contract definition and does have meaning, specifically that the behavior and return value do not vary base on instance although it may still vary from call to call.

That said, I recommend that when you want to use a static method in an interface and cannot, use an annotation instead. You will get the functionality you are looking for.

OK here is an example of needing a 'type method'. I am creating one of a set of classes based on some source XML. So I have a

  static public bool IsHandled(XElement xml) 

function which is called in turn on each class.

The function should be static as otherwise we waste time creating inappropriate objects. As @Ian Boyde points out it could be done in a factory class, but this just adds complexity.

It would be nice to add it to the interface to force class implementors to implement it. This would not cause significant overhead – it is only a compile/link time check and does not affect the vtable.

However, it would also be a fairly minor improvement. As the method is static, I as the caller, must call it explicitly and so get an immediate compile error if it is not implemented. Allowing it to be specified on the interface would mean this error comes marginally earlier in the development cycle, but this is trivial compared to other broken-interface issues.

So it is a minor potential feature which on balance is probably best left out.

I think the question is getting at the fact that C# needs another keyword, for precisely this sort of situation. You want a method whose return value depends only on the type on which it is called. You can't call it "static" if said type is unknown. But once the type becomes known, it will become static. "Unresolved static" is the idea — it's not static yet, but once we know the receiving type, it will be. This is a perfectly good concept, which is why programmers keep asking for it. But it didn't quite fit into the way the designers thought about the language.

Since it's not available, I have taken to using non-static methods in the way shown below. Not exactly ideal, but I can't see any approach that makes more sense, at least not for me.

 public interface IZeroWrapper<TNumber> { TNumber Zero {get;} } public class DoubleWrapper: IZeroWrapper<double> { public double Zero { get { return 0; } } } 

As per Object oriented concept Interface implemented by classes and have contract to access these implemented function(or methods) using object.

So if you want to access Interface Contract methods you have to create object. It is always must that is not allowed in case of Static methods. Static classes ,method and variables never require objects and load in memory without creating object of that area(or class) or you can say do not require Object Creation.