0

So I am a beginner in software development and practicing C# in my time at home.

I have a project that I am working on and have reached a point where I am not sure how to code the functionality.

Imagine in my solution I have a winform UI with a dropdown. Inside that dropdown the user can make a choice and click a button to run a procedure. Depending on what the user has picked, it should initialize the class/object that is picked.

So the dropdown will have options such as; runOptionOne, runOptionTwo. If runOptionTwo is picked in the dropdown, upon clicking the button it will do: runOptionOne runoptionone = new runOptionOne(); runoptionone.Doaction();

I do not want to have string checks on the dropdown as that will be loads of if statements.

Is there a technique or method to initialize a specific class based on user choice.

  • Use reflection. You can use class name as string and create instance and invoke method. – Amit Verma Jul 05 '21 at 13:04
  • 2
    @AmitVerma: so the user will see the internal class name? No... – Thomas Weller Jul 05 '21 at 13:05
  • _"Use reflection."_ - Why?? There are perfectly suitable patterns without the need for reflection. It's not even making anything more simple, here! – Fildor Jul 05 '21 at 13:06
  • @ThomasWeller No. Depends on selection of user the class name can be decided. Mapping will be required from selected value and class name. – Amit Verma Jul 05 '21 at 13:06
  • @Fildor yes, there are multiple options. – Amit Verma Jul 05 '21 at 13:07
  • 1
    A `Dictionary` seems like a good option here. – Alejandro Jul 05 '21 at 13:08
  • @OP: So, your "Options" would probably implement an Interface, right? How would you know what to write into the DropBox as Item text? Is it hardcoded? Do you do some reflection magic to find all implementations of your interface? – Fildor Jul 05 '21 at 13:09
  • 2
    Do not use reflection here - it's like using a bomb to dig up a plant in your garden. – Charleh Jul 05 '21 at 13:22
  • Reflection is a complex approach to a simple problem. Interface/Base class should do the trick. Read about inheritance if you are new and it might help. – AliK Jul 05 '21 at 14:14

1 Answers1

1

Combobox.Items accepts objects. For displaying, their ToString() method will be used.

This makes it possible to access the object directly via SelectedItem. As long as they share a common interface, it's easy to call a method on them.

private void button1_Click(object sender, EventArgs e)
{
    var obj = (Interface) comboBox1.SelectedItem;
    obj.DoSomething();
}

The other classes:

internal interface Interface
{
    void DoSomething();
}

class Class1:Interface
{
    public void DoSomething() { }
    public override string ToString() => "Option 1"; // TODO: make translatable via resource
}

class Class2:Interface
{
    public void DoSomething() { }
    public override string ToString() => "Option 2";  // TODO: make translatable via resource
}

And initialization like

private void Form1_Load(object sender, EventArgs e)
{
    comboBox1.Items.Add(new Class1());
    comboBox1.Items.Add(new Class2());
}

I don't like this approach too much, since I consider the ToString() method to be rather developer oriented.

IMHO, a better approach is to have a dictionary with display strings as keys and objects as values. That way you also get rid of the if-statements and reduce cyclomatic complexity:

private readonly IDictionary<string, Interface> _displayItems = new Dictionary<string, Interface>
{
    {"Option 1", new Class1()},
    {"Option 2", new Class2()}
};

private void Form1_Load(object sender, EventArgs e)
{
    foreach (var item in _displayItems)
    {
        comboBox1.Items.Add(item.Key);
    }
}

private void button1_Click(object sender, EventArgs e)
{
    var key = (string) comboBox1.SelectedItem;
    _displayItems[key].DoSomething();
}
Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
  • @OP If you really need new instances created, you can also put `Func` as Dictionary Value : https://dotnetfiddle.net/8jF5Gk , so you have a simple Form of "Factory Functions". – Fildor Jul 05 '21 at 13:28
  • my only problem with this (unless im wrong), it looks to be making the 'object/instance of class' straight away on load {"Option 2", new Class2()} if this is the case, isnt the software making loads of objects that might not even be used? – tryingOutcoding Jul 05 '21 at 14:31
  • @tryingOutcoding: does it matter? How large are these objects? Remember: premature optimization ... – Thomas Weller Jul 05 '21 at 15:01
  • You could still store type information only if the classes are easy to construct. – Thomas Weller Jul 05 '21 at 15:13
  • Basically the only way to make huge objects is to make them hold large arrays, huge strings or large native objects (such as bitmap images). Everything else is typically quite small. It [is possible to figure out](https://stackoverflow.com/questions/28845244/calculate-size-of-object-such-that-it-include-size-of-all-its-children-and-gran) with a good debugger, but that may be beyond your current level of knowledge. – Thomas Weller Jul 05 '21 at 15:20