为什么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;
}
....
}
举一个例子,我既没有接口方法的静态实现,也没有Mark Brackett介绍的“所谓的类型方法”:
当从数据库存储中读取数据时,我们有一个通用的DataTable类来处理从任何结构的表中读取数据。所有特定于表的信息都放在每个表的一个类中,每个表还保存来自DB的一行的数据,并且必须实现IDataRow接口。IDataRow中包含了要从数据库中读取的表的结构描述。DataTable在从DB中读取数据之前必须向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,实例化一个实例的开销是最小的。但是,在这种情况下它会很好。
我的(简化的)技术原因是静态方法不在虚表中,调用站点是在编译时选择的。这和你不能有覆盖或虚拟静态成员的原因是一样的。要了解更多细节,你需要一个计算机专业毕业生或编译专家——而我两者都不是。
出于政治原因,我将引用Eric Lippert(他是一名编译器专家,拥有滑铁卢大学的数学、计算机科学和应用数学学士学位)的话:
...静态方法的核心设计原则,给它们命名的原则是…在编译时,总是可以准确地确定将调用什么方法。也就是说,可以仅通过对代码的静态分析来解析该方法。
请注意,Lippert确实为所谓的类型方法留出了空间:
也就是说,与类型相关联的方法(如静态方法),它不接受不可空的“this”参数(与实例或虚拟方法不同),而是调用的方法依赖于T的构造类型(与静态方法不同,它必须在编译时确定)。
但还没有被它的实用性所说服。
假设你在问为什么你不能这样做:
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,并将其作为它可能不是一个好主意的指示。