为什么c#是这样设计的?
根据我的理解,一个接口只描述行为,并且服务于描述实现接口的类的契约义务。
如果类希望在共享方法中实现这种行为,为什么不应该呢?
以下是我想到的一个例子:
// 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;
}
....
}
这里有一个需要类型方法的例子。我正在创建一组基于源XML的类之一。所以我有一个
static public bool IsHandled(XElement xml)
函数,在每个类上依次调用。
函数应该是静态的,否则我们会浪费时间创建不合适的对象。
正如@Ian Boyde指出的那样,它可以在工厂类中完成,但这只会增加复杂性。
最好将它添加到接口中,以强制类实现者实现它。这不会造成很大的开销——它只是一个编译/链接时间检查,不会影响虚表。
然而,这也将是一个相当小的改进。由于方法是静态的,我作为调用者,必须显式地调用它,因此如果它没有实现,就会立即得到编译错误。允许在接口上指定它将意味着这个错误在开发周期中稍微提前出现,但与其他损坏的接口问题相比,这是微不足道的。
所以这是一个次要的潜在特性,总的来说最好还是忽略不计。
假设你在问为什么你不能这样做:
public interface IFoo {
void Bar();
}
public class Foo: IFoo {
public static void Bar() {}
}
This doesn't make sense to me, semantically. Methods specified on an interface should be there to specify the contract for interacting with an object. Static methods do not allow you to interact with an object - if you find yourself in the position where your implementation could be made static, you may need to ask yourself if that method really belongs in the interface.
To implement your example, I would give Animal a const property, which would still allow it to be accessed from a static context, and return that value in the implementation.
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,并将其作为它可能不是一个好主意的指示。
我知道这是个老问题,但很有趣。这个例子并不是最好的。我认为如果你展示一个用例会更清楚:
string DoSomething<T>() where T:ISomeFunction
{
if (T.someFunction())
...
}
仅仅使用静态方法实现接口并不能达到你想要的效果;所需要的是将静态成员作为接口的一部分。我当然可以想象出许多用例,特别是当它能够创建东西的时候。我可以提供两种可能有用的方法:
Create a static generic class whose type parameter will be the type you'd be passing to DoSomething above. Each variation of this class will have one or more static members holding stuff related to that type. This information could supplied either by having each class of interest call a "register information" routine, or by using Reflection to get the information when the class variation's static constructor is run. I believe the latter approach is used by things like Comparer<T>.Default().
For each class T of interest, define a class or struct which implements IGetWhateverClassInfo<T> and satisfies a "new" constraint. The class won't actually contain any fields, but will have a static property which returns a static field with the type information. Pass the type of that class or struct to the generic routine in question, which will be able to create an instance and use it to get information about the other class. If you use a class for this purpose, you should probably define a static generic class as indicated above, to avoid having to construct a new descriptor-object instance each time. If you use a struct, instantiation cost should be nil, but every different struct type would require a different expansion of the DoSomething routine.
这些方法都不太吸引人。另一方面,我希望如果CLR中存在能够干净地提供这类功能的机制,.net将允许指定参数化的“new”约束(因为知道一个类是否具有具有特定签名的构造函数似乎与知道它是否具有具有特定签名的静态方法在难度上相当)。