简体   繁体   中英

How to partially implement a contract in an abstract base class?

I have a interface as follows

 public interface IX
    {
        void MethodA();
        void MethodB();
    }

I have two method contracts in the interface MethodA and MethodB. I will define set of classes that will implement the above interface. Out of these two methods MethodA is common for all the types that will implement the interface. I can define a abstract class as follows

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

        public abstract void MethodB();
    }

And inherit this class to all the types that need to implement the above interface. It works.

But here in the abstract class i add 'public abstract void MethodB();'. It looks like repetition of the MethodB contract.

Why C# does not permit partial interface implementation if the class is abstract?. The above interface has only two methods. suppose one interface has 10 methods and 5 are common functionality and 5 are not, we are forced to add the 5 methods that are not common in the abstract class?

Because the C# language specification says so. Chapter 13.4.7:

Like a non-abstract class, an abstract class must provide implementations of all members of the interfaces that are listed in the base class list of the class.

Why the C# designers chose to specify the language like this is probably best answered by Eric Lippert. I'd personally guess at reducing the odds that unintended method hiding occurs, producing error messages that are very hard to interpret. I would personally have been more comfortable requiring the use of the overrides keyword for the interface method implementation. But they chose not to.

The reason it doesn't support this is because your superclass doesn't fulfil the contract. The only way for an abstract class to force implementation on its subclasses is to define abstract methods.

If you don't want the abstract class to have those abstract methods defined then you have to tell the subclasses to implement the interface instead.

Question would have to be, why would it be a problem having 5 abstract methods on your superclass?

You can switch from 'abstract' to 'virtual' in the method declaration and provide an assertion:

public abstract void MethodB();

becomes

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

Interfaces do pass along the contract requirement to each other, so as far as you have IFoo and IBar : IFoo , then classes inheriting from IBar must implement both interfaces, as clearly IBar cannot implement the members of IFoo itself. Why this behavior could not be extended to abstract base classes, I don't know. I'm sure there is a good reason, and since Hans posted the spec, it's obviously intentional.

As a please do not try this at home approach, you could do something like

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();
}

Which has the abstract base implement the methods it wants and then force the derived classes to implement the rest by enforcing that the derived classes implement the interface. The derived classes would then be responsible for implementing the methods that are not already in the base class. The problem with this approach is that this is a runtime requirement, not compile time.

How would you handle a situation where you have

interface IFoo {
  void MethodA();
  void MethodB();
}
abstract class Base: IFoo {
  public void MethodA() {}
  // MethodB gets implicitly generated
}
class Derived: Base {
  public void MethodB() {}
}

Could you then do this:

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

Ok you could, since MethodB is implicit. But what if you would later decide to remove the interface IFoo from the Base class? You just broke the Base 's contract..Solution would be that generated methods would be explicit interface implementations, but that brings another kind of pain.

I don't think abstract class or interface is doing any injustice in your scenario rather as per SOLID principles (specifically: Interface Segregation Principle) : https://msdn.microsoft.com/en-us/library/dn178470(v=pandp.30).aspx

It says large interfaces should be split into smaller and more specific ones so that client classes are not forced to implement methods they do not use at all. Utilizing this principle would solve your problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM