views:

215

answers:

6

Consider the following problem:

You have a class 'A' that serves as a base class for a lot of other similar classes, eg. a class called B.

The class A is useful in it self (and already used all over the place) and is hence not abstract.

The crux is that you now wish to enforce a new protocol requiring all classes inheriting from A (including A itself) to implement a method 'func()'. If a sub class forgets to implement func() there should be a compiler error.

class A {
  A func() { ret new A(...) }
}

class B : A {
  A func() { ret new B(...) }
}

class C : A {
  // Should give error : no func()
}

Is the problem clear? I can't make A::func() abstract since I want to be able to keep using A as a concrete class. I can't make it virtual since that would cause sub classes to fall back on the super class (and not give compiler errors).

The only thing that comes close to a solution is creating a new abstract class A* and have all custom types inherit from that and replace all current usages of A as a concrete class with a new class 'DefaultA' that inherits from A*. This seems messy. Please tell me there is some other way to do this?

+10  A: 

There is simply no way to both keep A a concrete type and force a compiler error if sub types do not override a particular method.

JaredPar
+1 True. If you want compile-time enforcement of method implementation you'll have to apply an interface to ALL classes that require the method(s)
Dave Swersky
One could always refactor the implementation to create an `ABase` that is equivalent to `A` but has `func` as abstract protected, and then make `sealed A : ABase` with a default implementation.
LBushkin
+1  A: 

If that is what you need to do, then yes.

In my opinion though, you may wish to reconsider this requirement. I have often implemented similar frameworks, where forcing implementations in sub-classes was a clever trick. What I then found was that as a consumer of these frameworks I would duplicate code or default to some inane implementation (like the empty method). Neither of which is ideal, as they add clutter and noise, and reduce maintainability.

Additionally, if the application of this pattern is as a self-factory (ie your example has sub-classes returning instances of themselves), then you may wish to try something different, like a proper factory pattern. Er, and by "try" I mean leverage an Inversion of Control Container, like Castle Windsor, Ninject, Unity.

johnny g
Thanks for your answers! I guess I'm just being a bit paranoid :) Since I'm an old C++ programmer starting out with C# I hoped for something along the lines of a template function that would break if instantiated with the wrong type .... but I realize that isn't very c#-ish
4ZM
I would prefer to see a subclass which overrides the abstract ValidateStuff() function with an empty implementation, and a code comment explaining why it doesn't require any validation. IMO, it makes the code easier to maintain, and more useful as an example to other developers creating similar subclasses. Compare that to a subclass which doesn't override the virtual ValidateStuff() function, and leaves me wondering why. Was it not needed, or did the developer just forget to implement it? For that reason, I don't think those empty functions are always just "clutter".
mikemanne
A: 

This is perhaps even messier, but you might be able to force B, C, D etc. to implement an interface requiring func(). Then make sure they're always constructed via a factory method. So something vaguely like:

public class B: A, IFunc{
   private B(){}
   public static B Create(){ return new B(); }

}
Nik
But the goal is to find every class that has not been modify to implement func(). This method will miss every class that has not been modified you require IFunc. This doesn't solve the problem; it merely moves it.
James Curran
A: 

You cannot instantiate the A class if it is abstract. Thus,

new A();

and

abstract A func(); // within the A class definition

are contradictory.

If you steer away from abstract, and go virtual instead, you can get runtime (not compile-time) checking:

// In the A class definition.
protected virtual A func()
{
    if (GetType() != typeof(A))
        throw // ...
}
kbrimington
+1  A: 

Basically, you are asking us to "Make this break, but don't make this break." Perhaps you see the inherent conflict.

This is one of the reasons why base classes should only be used as base classes, and not used as themselves.

James Curran
+2  A: 

Well, as you say, you could create an intermediate abstract class X that inherits from A and require that derived classes inherit from X. X then declares a protected abstract method with the signature matching func and override the func from A to call that method. Here's an example:

class A {
    public virtual A func() { ... }
}

abstract class X : A {
    protected abstract A funcImpl();

    public override A func() { return funcImpl(); }
}

class B : X  { /* must now implement funcImpl() to avoid compiler error */ }

class C : X  { /* must now implement funcImpl() to avoid compiler error */ }

The main problem with this approach is requiring that all derived class now inherit from X rather than A. So you've just changed the enforcement problem from one kind to another.

A cleaner approach, in my opinion, is to refactor A into a base class ABase and have func be abstract there. Then seal A and require B and C to inherit from ABase rather than A:

class ABase {
    public abstract ABase func();    }

sealed class A : ABase {
    public override ABase func() { ... }
} 

class B : ABase { 
    // forced to override func()
    public override ABase func() { ... }
}

You would have to replace all uses of A with ABase - but there are some excellent refactoring tools in Visual Studio (and third party tools like ReSharper) that make this substantially less painful than it once was.

LBushkin