bberger
bberger

Reputation: 142

Best way to eliminate inheritance "magic" in C# winforms?

I'm working on a legacy application wich has some flaws due to inheritance, but I'm struggling to solve it properly.

At the moment the structure of the WinForms looks like this:

There is a method inside the BaseForm which is called sth like protected virtual void InitializeMyStuff() which is overwritten in the inherited instances.

e.g.

public class BaseForm {
    public BaseForm() {
       //.. do stuff

       //.. do other stuff like initialize DB connection or read app.config values and initialize properties..
}

public virtual void InitializeMyStuff() {
        throw new NotImplementedException();
    }
}

public class ListViewForm : BaseForm {
    protected BindingSource GridBindingSource { get; set; }

    public ListViewForm {
       //do special stuff like adding the grid and some buttons
    }
}
public class ConcreteForm : ListViewForm {
public override void InitializeMyStuff() {
        GridBindingSource = my_bindingSource;
        SomeOtherUsefulProperty = myValue;
        Foo = new Bar();
        // etc.
    }
}

//Usage:
var myForm = new ConcreteForm();
myForm.InitializeMyStuff();

As you can imagine this creates some problems like: - "What things do I have to set at this point for the form to work" - "What things may not be initialized yet?" - "Which properties and method calls are at my disposal yet" and some other interesting thoughts about what may be going on in that magic blackbox.

How can I refactor this so that it gets more clear what is happening? Remember that this is a project with about 150 or more concrete forms.

My initial thought was to encapsulate those magic properties like the GridBindingSource for example into an object (e.g. FormConfiguration) and make it private in the BaseForm.

e.g. something like that

public class BaseForm {
    private FormConfigObject _formConfig = new FormConfigObject();

    protected override void OnLoad()
    {
        InitializeMyStuff(_formConfig);
    }

    protected virtual void InitializeMyStuff(FormConfigObject config)
    {}
}

The problem I have here is: the FormConfig object of the ListForm would have to have other properties for example, like GridBindingSource but I can't just change the signature in the derived classes to an ListFormConfigObject isntead of the FormConfigObject..

Can anybody suggest possible solutions to get out of this dilemma?

// Edit: straightnened out the code to what actually happens and getting rid of the virtual call in the constructor violation.

Upvotes: 3

Views: 231

Answers (1)

BartoszKP
BartoszKP

Reputation: 35891

The main question is this: are there any objects inside BaseForm that:

  • are required to be initialized in BaseForm's constructor
  • depend on the concrete implementation of the subclasses

If such objects exist then probably they should be made polymorphic, and passed into BaseForm's constructor from subclasses.

A simple example, on of many possible scenarios:

abstract class RandomPicture
{
    public RandomPicture()
    {
        shapes = new List<Shape>();
        InitializeRandomShapes();

        // do some initial drawing calculations
    }

    protected abstract void InitializeRandomShapes();

    protected List<Shape> shapes;
}

//... subclasses initialize the shapes

This can be changed to:

abstract class RandomPicture
{
    public RandomPicture(AbstractShapeCollection shapeCollection)
    {
        shapes = shapeCollection;

        // do some initial drawing calculations
    }

    private AbstractShapeCollection shapes;
}

And now subclasses provide the required information through the abstract object, so the base class can proceed with it's task.

Splitting information into various objects like this is a good refactoring start, as you create more smaller objects, that are easier to test and manage and reveal the underlying structure of a mess that you've encountered. It helps also to reduce the number of violations of Single Responsibility Principle.

Upvotes: 3

Related Questions