How to put different objects in a List

时间:2015-05-04 19:46:14

标签: c# .net asp.net-core-mvc

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?

3 个答案:

答案 0 :(得分:1)

您目前有一个对象列表,这些对象都实现了IWidget接口。直接访问它们只会让你对IWidget(没有)的属性进行智能感知。

为了解决这个问题,您需要在IWidget界面中添加一些属性,或者检查每个项目的类型然后进行投射,如:

IWidget widget = widgets.First();

var widget1 = widget as Widget1;

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

您还可以使用一些逻辑来检查循环中的每个小部件,例如:

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
    }
}

或者,您可以通过执行以下操作从列表中获取第一个Widget1(或Widget2):

Widget1 widget = widgets.OfType<Widget1>().First();

答案 1 :(得分:1)

您需要使用多态来解决您的问题:

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());
    }
}

以后......

        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.

答案 2 :(得分:0)

也许您的选择是首先对实例进行类型检查:

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

或者,通过其他LinQ功能,您可以轻松地将列表拆分为genric子列表。如果您不需要按照它们存储在widgets变量中的顺序处理小部件,这将很有效。

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
}