为什么C#不允许静态方法来实现接口?
为什么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;
}
....
}
假设你问为什么你不能这样做:
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中,并且在编译时选择调用站点。 这是你不能拥有重写或虚拟静态成员的原因。 有关更多详细信息,您需要CS毕业生或编译器wonk - 我既不是。
出于政治原因,我会引用Eric Lippert(他是一名编译者,并拥有滑铁卢大学数学,计算机科学和应用数学学士学位(来源:LinkedIn):
...静态方法的核心设计原则,这个原则给了它们他们的名字......它总是可以在编译时被精确确定,调用什么方法。 也就是说,该方法可以通过对代码的静态分析完全解决。
请注意,Lippert为所谓的类型方法留出了空间:
也就是说,与类型(如静态)相关联的方法,它不采用不可空的“this”参数(与实例或虚拟不同),而是所调用的方法取决于构造类型T(不像静态,它必须在编译时确定)。
但尚未确定其用处。
这里的大多数答案似乎都忽略了整个观点。 多态性不仅可以在实例之间使用,也可以在类型之间使用。 当我们使用泛型时,这通常是需要的。
假设我们在泛型方法中有类型参数,我们需要对它进行一些操作。 我们不想要瞬间,因为我们不知道构造函数。
例如:
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>()
不幸的是,我只能拿出“丑陋”的选择:
使用反射丑陋,打破接口和多态的想法。
创建完全独立的工厂类
这可能会大大增加代码的复杂性。 例如,如果我们试图为域对象建模,则每个对象都需要另一个存储库类。
实例化,然后调用所需的接口方法
即使我们控制类的来源,用作通用参数,这也很难实现。 原因在于,例如,我们可能需要实例仅处于众所周知的“连接到数据库”状态。
例:
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...
}
}
}
这显然很难看,也没有必要使所有其他方法的代码复杂化。 显然,这不是一个优雅的解决方案!
链接地址: http://www.djcxy.com/p/38147.html上一篇: Why Doesn't C# Allow Static Methods to Implement an Interface?