Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在抽象基类中部分实现契约?_C#_.net - Fatal编程技术网

C# 如何在抽象基类中部分实现契约?

C# 如何在抽象基类中部分实现契约?,c#,.net,C#,.net,我有一个如下的界面 public interface IX { void MethodA(); void MethodB(); } public abstract class XBase:IX { public void MethodA() { // Common behaviour implementation } public abstrac

我有一个如下的界面

 public interface IX
    {
        void MethodA();
        void MethodB();
    }
public abstract class XBase:IX
    {
        public void MethodA()
        { 
            // Common behaviour implementation
        }

        public abstract void MethodB();
    }
我在接口MethodA和MethodB中有两个方法契约。我将定义一组实现上述接口的类。在这两种方法中,MethodA对于实现接口的所有类型都是通用的。我可以如下定义一个抽象类

 public interface IX
    {
        void MethodA();
        void MethodB();
    }
public abstract class XBase:IX
    {
        public void MethodA()
        { 
            // Common behaviour implementation
        }

        public abstract void MethodB();
    }
并将该类继承给需要实现上述接口的所有类型。它起作用了

但在抽象类中,我添加了“public abstract void MethodB();”。这看起来像是MethodB合同的重复

如果类是抽象的,为什么C#不允许部分接口实现?。上面的接口只有两种方法。假设一个接口有10个方法,5个是公共功能,5个不是,我们被迫添加抽象类中不常见的5个方法,因为C语言规范这么说。第13.4.7章:

与非抽象类一样,抽象类必须提供类的基类列表中列出的接口的所有成员的实现


为什么C#designers选择这样指定语言,Eric Lippert可能是最好的答案。我个人认为可以降低意外方法隐藏发生的几率,从而产生难以解释的错误消息。我个人更愿意在接口方法实现中使用overrides关键字。但是他们选择了不支持。

它不支持这一点的原因是因为您的超类没有履行合同。抽象类在其子类上强制实现的唯一方法是定义抽象方法

如果您不希望抽象类定义这些抽象方法,那么您必须告诉子类实现接口


问题是,为什么在您的超类上有5个抽象方法会是一个问题?

接口会相互传递契约要求,所以只要您有
IFoo
IBar:IFoo
,那么继承自
IBar
的类就必须实现这两个接口,显然,
IBar
无法实现
IFoo
本身的成员。我不知道为什么这种行为不能扩展到抽象基类。我相信有一个很好的理由,因为汉斯发布了规范,这显然是故意的

作为一种请不要在家尝试这种方法,您可以这样做

class Derived : Base, IFoo
{
    public void MethodB()
    {
    }
}

abstract class Base
{
    public Base()
    {
        if (!(this is IFoo))
            throw new InvalidOperationException("must implement IFoo");
    }

    public void MethodA() { }
}

interface IFoo
{
    void MethodA();
    void MethodB();
}

它让抽象基实现它想要的方法,然后通过强制派生类实现接口来强制派生类实现其余的方法。然后,派生类将负责实现基类中不存在的方法。这种方法的问题是,这是一个运行时需求,而不是编译时。

如果您有

interface IFoo {
  void MethodA();
  void MethodB();
}
abstract class Base: IFoo {
  public void MethodA() {}
  // MethodB gets implicitly generated
}
class Derived: Base {
  public void MethodB() {}
}
那么你能这样做吗:

Base myBase = ...
myBase.MethodB();

可以,因为
MethodB
是隐式的。但是,如果您稍后决定从
Base
类中删除接口
IFoo
,该怎么办?您刚刚打破了
基础的合同。。解决方案是生成的方法将是显式接口实现,但这会带来另一种痛苦。

您可以在方法声明中从“抽象”切换到“虚拟”,并提供断言:

public abstract void MethodB();
变成

public virtual void MethodB()
{
    Contract.Require( your condition );
}

我不认为抽象类或接口在您的场景中有任何不公平之处,而是根据坚实的原则(特别是:接口隔离原则):


它说,大型接口应该被划分成更小、更具体的接口,这样客户机类就不会被迫实现它们根本不使用的方法。利用这一原理可以解决您的问题。

我认为RAM的目的是,在这种情况下,编译器可以自动生成抽象接口方法签名。@Sam-可以,但对于其他实现子类的人来说,这可能会让人模糊不清。他们不一定能看到超类上的接口,那么他们怎么知道必须实现什么呢?正如SAM所说的,Pdr可以在内部生成这些抽象方法,也可以从层次结构中找到它们。假设我是从超类继承的,我会看到超类实现了接口,但它没有为所有方法契约提供实现,这意味着我必须为超类中未实现的接口方法提供实现。这有意义吗?@RAM-我明白你的意思,但这是像C#这样的语言所得到的。它对你的假设很少。那些提倡动态语言的人会花上几个小时谈论你为了取悦C#编译器而必须输入的数量,他们说得有道理。我不认为这是任何想象中最糟糕的例子。@pdr,我同意这会让人困惑,这可能是它没有完成的部分原因,但编译器可以编写来处理这种情况仍然是可行的,因为RAM问我们为什么要在抽象类上实现接口?似乎打破了is-a、acts-like-a的关系。@Cameron:事实上,我认为这是一个非常好的方法。从理论上讲,可以有许多不同的抽象基类,它们都通过一些根本不同的实现方法来实现同一个接口。Hans我知道它是强制的,但很想知道为什么语言强制这样做?。谢谢你的回答。你关于非预期方法隐藏的观点被很好地采纳了——另一种说法是,这条规则是C#设计对抗脆弱基类失败的另一种方式。然而,我要指出的是,当前规则更明显的好处是它很容易理解。你