0

I have a web page where a user can drag and drop certain widgets into a single placeholder. Each widget has its own set of properties.

For example, suppose I have the following HTML widgets:

Widget1:
 - Title field
 - Technical name field

And another widget that is more dynamic:

Widget2:
 - Range picker field 1 (0 to 100)
 - Range picker field 2 (0 to 100)
               ------------------
               | (+) Add picker |
               ------------------
 (can add as many range pickers as needed)

Now with the click of a button these settings are saved to the database. But at some point I also need to read that data from it again.

For example, suppose I have the following classes for the Widgets:

interface IWidget { }

class Widget1 : IWidget
{
    public string Title {get;set;}
    public string TechnicalName {get;set;}
}

class Widget2 : IWidget
{
    public List<int> PickerValues {get;set;}
}

Then store that in a List.

var widgets = new List<IWidget>();
widgets.Add(new Widget1());
widgets.Add(new Widget2());

That would work. But then getting an object from that list again is a problem:

var widget = widgets.First();
widget.?????   // <-- NO INTELLISENSE!

That means it doesn't know what actual implementation it has. I'd have to cast it. But how, if I don't know what widgets are stored in there? It can be a list of 1, 5 or even 10 different widgets in any order.

How can I solve this problem?

7
  • Just as a side note: stackoverflow.com/questions/7552677/… Commented May 4, 2015 at 19:49
  • 2
    The point of creating an abstraction with an interface is that you shouldn't care about the concrete implementation. Currently, your interface is meaningless. What do you want to do with those widgets? Commented May 4, 2015 at 19:50
  • What do you want to do with the IWidget once you pull it out of the list? Commented May 4, 2015 at 19:50
  • you can see about as and is keywords Commented May 4, 2015 at 19:51
  • IWidget doesn't define any members, so you won't get any intellisense. You need to place common functionality in the interface, otherwise yes, you will have to cast. Commented May 4, 2015 at 19:51

3 Answers 3

1

You currently have a list of objects that all implement the IWidget interface. Accessing them directly will only give you intellisense on the properties of IWidget (which has none).

In order to resolve this, you either need to put some properties in the IWidget interface, or check the type of each item and then cast it, like:

IWidget widget = widgets.First();

var widget1 = widget as Widget1;

if (widget1 != null)
{
    widget1.TechnicalName = "new name"; // <-- We have intellisense
}

You could also have some logic that checks each widget in a loop, like:

foreach (var widget in widgets)
{
    if (widget is Widget1)
    {
        var widget1 = (Widget1) widget;
        // Do something with Widget1 types here
    }
    else if (widget is Widget2)
    {
        var widget2 = (Widget2)widget;
        // Do something with Widget2 types here
    }
}

Alternatively, you could just get the first Widget1 (or Widget2) from the list by doing something like:

Widget1 widget = widgets.OfType<Widget1>().First();
Sign up to request clarification or add additional context in comments.

Comments

1

You will need to use Polymorphism to address your issue:

interface IWidget 
{
    public void readData();
}

class Widget1 : IWidget
{
    public string Title { get; set; }
    public string TechnicalName { get; set; }

    public void readData()
    {
        Console.WriteLine("- Title: {0}\n- Technical name: {1}", Title, TechnicalName);
    }
}

class Widget2 : IWidget
{
    public List<int> PickerValues { get; set; }

    public void readData()
    {
        StringBuilder builder = new StringBuilder();
        for (int i = 1; i <= PickerValues.Count; i++)
        {
            builder.AppendLine(String.Format("- Range picker field {0}: {1}",i,PickerValues[i-1]));
        }
        Console.WriteLine(builder.ToString());
    }
}

And Later on...

        var widgets = new List<IWidget>();
        widgets.Add(new Widget1());
        widgets.Add(new Widget2());
        var widget = widgets.First();
        widget.readData(); // will print correct output for each type of widget, as implemented on each widget.

Comments

0

Maybe your choice is to type-check the instance first:

var widget = widgets.First();
if (widget is Widget1)
{
    var widget1 = (Widget1) widget;
    widget1.DoSomethingSpecificToWidget1();
}

Alternatively, with additional LinQ functionality, you can easily split your list to genric sub-lists. This will work well if you do not need to process the widgets in the order they are stored in the widgets variable.

var w1List = widgets.OfType<Widget1>();// you may also call `.ToList()`
var w2List = widgets.OfType<Widget2>();

foreach (var w1 in w1List)
{
    w1.DoSomethingSpecificToWidget1(); // w1 is now Widget1
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.