views:

2186

answers:

7

I have a class with some abstract methods, but I want to be able to edit a subclass of that class in the designer. However, the designer can't edit the subclass unless it can create an instance of the parent class. So my plan is to replace the abstract methods with stubs and mark them as virtual - but then if I make another subclass, I won't get a compile-time error if I forget to implement them.

Is there a way to mark the methods so that they have to be implemented by subclasses, without marking them as abstract?

A: 

How did you manage to design the base class in the designer?

Lasse V. Karlsen
I didn't design the base class in the designer.
Simon
+6  A: 

Well you could do some really messy code involving #if - i.e. in DEBUG it is virtual (for the designer), but in RELEASE it is abstract. A real pain to maintain, though.

But other than that: basically, no. If you want designer support it can't be abstract, so you are left with "virtual" (presumably with the base method throwing a NotImplementedException).

Of course, your unit tests will check that the methods have been implemented, yes? ;-p

Actually, it would probably be quite easy to test via generics - i.e. have a generic test method of the form:

[Test]
public void TestFoo() {
  ActualTest<Foo>();
}
[Test]
public void TestBar() {
  ActualTest<Bar>();
}

static void ActualTest<T>() where T : SomeBaseClass, new() {
  T obj = new T();
  Assert.blah something involving obj
}
Marc Gravell
A: 

I know its not quite what you are after but you could make all of your stubs in the base class throw the NotImplementedException. Then if any of your subclasses have not overridden them you would get a runtime exception when the method in the base class gets called.

Si Keep
Yeah, I've done that, but I want a compile-time exception.
Simon
A: 

The Component class contains a boolean property called "DesignMode" which is very handy when you want your code to behave differently in the designer than at runtime. May be of some use in this case.

Brent Rockwood
+2  A: 

You could use the reference to implementation idiom in your class.

public class DesignerHappy
{
    private ADesignerHappyImp imp_;

    public int MyMethod()
    {
        return imp_.MyMethod()    
    }

    public int MyProperty
    {
        get { return imp_.MyProperty; }
        set { imp_.MyProperty = value; }
    }
}

public abstract class ADesignerHappyImp
{
    public abstract int MyMethod();
    public int MyProperty {get; set;}
}

DesignerHappy just exposes the interface you want but forwards all the calls to the implementation object. You extend the behavior by sub-classing ADesignerHappyImp, which forces you to implement all the abstract members.

You can provide a default implementation of ADesignerHappyImp, which is used to initialize DesignerHappy by default and expose a property that allows you to change the implementation.

Curro
A: 

As a general rule, if there's no way in a language to do something that generally means that there's a good conceptual reason not to do it.

Sometimes this will be the fault of the language designers - but not often. Usually I find they know more about language design than I do ;-)

In this case you want a un-overridden virtual method to throw a compile time exception (rather and a run time one). Basically an abstract method then.

Making virtual methods behave like abstract ones is just going to create a world of confusion for you further down the line.

On the other hand, VS plug in design is often not quite at the same level (that's a little unfair, but certainly less rigour is applied than is at the language design stage - and rightly so). Some VS tools, like the class designer and current WPF editors, are nice ideas but not really complete - yet.

In the case that you're describing I think you have an argument not to use the class designer, not an argument to hack your code.

At some point (maybe in the next VS) they'll tidy up how the class designer deals with abstract classes, and then you'll have a hack with no idea why it was coded that way.

It should always be the last resort to hack your code to fit the designer, and when you do try to keep hacks minimal. I find that it's usually better to have concise, readable code that makes sense quickly over Byzantine code that works in the current broken tools.

Keith
This has long been a flaw in Visual Studio, but you can't sacrifice readability and maintainability for something the tool has lacked for years. Have you ever tried to modify complex WinForms programatically? It takes much longer and is the source of a lot of frustration. Microsoft included the Designer for a reason, and I think it is completely legitimate to do a little "hacking" to improve the maintainability of your project. Just be certain to document what you are doing and why.
Tim
@Tim - I wasn't really saying that it wasn't legitimate, my point was that it should be a last resort to hack the code to suit the tools. In this case I think the best solution is actually that in the accepted answer - throw `NotImplementedException` in the virtual members and unit test the code.
Keith
+1  A: 

Note that "DesignMode" is not set in the constructor. It's set after VS parses the InitializeComponents() method.