Bart Friederichs
Bart Friederichs

Reputation: 33573

C#: Create an array of classes

I want to create a list of classes, from where I can build a "Toolbox" in my form. It boils down to a list of possible widgets that I can drag and drop into a Panel. The classes will implement the same interface and have some static methods to create the list.

Some code I have:

public interface IWidget {
   Image image { get; }
}

public class Gauge : IWidget, PictureBox {
   public static Image image {
       get {
           return Properties.Resources.gauge;
       }
   }
}

in the Form, I want to put an array like this:

IWidget[] supported_widgets = { Gauge };

and cycle over them to create the Toolbox the user can choose from, using the static methods in the classes, not by instantiating them (they will be instantiated when dropped on the Panel):

foreach (IWidget w in supported_widgets) {
    PictureBox p = new PictureBox();
    p.Image = w.getImage();

    toolbox.Controls.Add(p);
}

I experimented with System.Type, but it just feels a little overkill. What's the best way to do something like this? Is it even possible without instantiating the classes?

Upvotes: 2

Views: 2772

Answers (4)

Tallmaris
Tallmaris

Reputation: 7590

Using Type is fine as Marc said, and you can use the activator to create the object (when you drop it in the Panel). If you want to use the static methods only to populate the Toolbox, so no class creation here, then use GetMethod() and Invoke():

Type[] supported_widgets = { typeof(Gauge) };

foreach (var w in supported_widgets) {
    PictureBox p = new PictureBox();
    p.Image = w.GetMethod("getImage").Invoke(null, null);

    toolbox.Controls.Add(p);
}

Outside the scope of this answer are all the considerations about using Reflection and about having to use a string to pass the method name, which is brittle and not helpful when refactoring... Keep this in mind.

Upvotes: 1

Mihai
Mihai

Reputation: 2865

If you don't want to use Type objects, you can resort to the Factory pattern:

public interface IWidgetFactory
{
    IWidget makeWidget();
} 

public class WidgetFactory<TWidget> : IWidgetFactory where TWidget : IWidget, new() 
{
    IWidget makeWidget()
    {
        return new TWidget();
    }
}

IWidgetFactory[] supported_widgets = { new WidgetFactory<Gauge>(), new WidgetFactory<Indicator>() };

foreach (IWidgetFactory wf in supported_widgets) {
    PictureBox p = new PictureBox();
    p.Image = wf.makeWidget().getImage();

    toolbox.Controls.Add(p);
}

Upvotes: 1

Henk Holterman
Henk Holterman

Reputation: 273844

I want to create a list of classes

Taken literally that is simply not possible.

What you can do is create a list of objects (instances). That can be of the Type class that you already tried or you can create a helper class for each of your types.

 class WidgetHelper<T> where  T : IWidget, new() { }

and then you may want to add a little more functionality to IWidget.

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1064204

An IWidget represents an instance of a widget, so you can't pass it as a IWidget[] if you haven't instantiated them yet. Type, or Type[] should be fine - it isn't "overkill" - it is the appropriate and expected way of describing a type. Additionally, you can instantiate easily by just:

IWidget newInstance = (IWidget)Activator.CreateInstance(someConcreteWidgetType);

Upvotes: 2

Related Questions