tags:

views:

70

answers:

5

I find that I need to write the same code in many classes. The code has to do with conversion between types. As I am not familiar with generics, would someone suggest how to convert the following to use generics:

public class WidgetList : List<Widget> { }

public class Widget
{
    public int Id { get; set; }
    public string Name { get; set; }

    public Widget() { }

    public Widget(int Id, string Name)
    {
        this.Id = Id;
        this.Name = Name;
    }
}

public class WidgetManager
{
    public static List<Widget> ToListType(WidgetList list)
    {
        return list.ToList<Widget>();
    }

    public static WidgetList ToTypeList(List<Widget> list)
    {
        WidgetList typeList = new WidgetList();
        foreach (Widget item in list)
        {
            typeList.Add(w);
        }

        return typeList;
    }
}
A: 

It looks like you're already using generics, so maybe I'm not understanding the question. The generic List<T> gives you the strong-typing of the list contents as Widgets at the point where you declare the generic type T to be a Widget, so unless there's some explicit reason why you need the WidgetList object, that class (and the WidgetManager) are superfluous.

List<T> is not abstract, so you can accomplish everything that's shown here with just the Widget class...then when you need a list of Widgets, you can just create a List<Widget>.

Steven
A: 

I will assume you absolutely need a custom collection object (WidgetList), but see note at bottom of the answer if you are not sure. In that case what I would recommend is the following:

  • Have WidgetList implement IList<Widget> rather than deriving from List<Widget>. Else, it's rather pointless. You can still use List<Widget> as the implementation.
  • Since IList<Widget> is also an IEnumerable<Widget>, you will have ToList<Widtget>(), for free with Linq extensions.
  • Also make sure you have a WidgetList constructor taking an IEnumerable<Widget> rather than a fonction in a different class.
  • An AddRange(IEnumerable<Widget>) is also very useful.

On a side note, you don't need a WidgetList if all it does is exactly the same a List<Widget>. Just use a List<Widget> directly instead, they offer all the typing that is provided by collection objects. I know you will find a lot of those collection objects in the framework library, but they are there either because they existed before generics, or because they have additional behaviours on Add and Remove.

Coincoin
+2  A: 

Well, your code snippet is using generics.

Perhaps your impression is that generics are abstract in some sense and must be implemented to be of any use, but if that's the case you are (happily!) mistaken.

Just delete your WidgetManager and WidgetList classes. You can use List<Widget> without any additional complexity. For example:

var widgets = new List<Widget>();

widgets.Add(new Widget(42, "foo"));
widgets.Add(new Widget(43, "bar"));

foreach (var widget in widgets)
   Console.WriteLine("{0}: {1}", widget.Id, widget.Name);
ladenedge
A: 

Just a clarification to the question - since I'm also on sme's team. The reason for the strongly typed WidgetList is because we use the XML deserializer to convert a list of widgets from XML passed from our database:

<Widgets>
 <Widget>
    <Id>1</Id>
    <Name>Kitten Kung-Foo</Id>
 </Widget>
 <Widget>
    <Id>2</Id>
    <Name>Puppy Punches</Name>
 </Widget>
<Widgets>

So here's the same code again with the XML attributes:

[XmlType("Widgets"), Serializable]
public class WidgetList : List<Widget> { }

[XmlType("Widget"), Serializable]
public class Widget
{
    public int Id { get; set; }
    public string Name { get; set; }

    public Widget() { }

    public Widget(int Id, string Name)
    {
        this.Id = Id;
        this.Name = Name;
    }
}

I'm pretty sure we need the WidgetList in order for the Deserializer to pick up on the fact that there is a collection of Widgets.

Maybe not?

Sean
+1  A: 

Here's the magic:

Add an extension to IEnumerable:

public static class IEnumerableExtensions
{
    public static T2 ToListContainer<T1, T2>(this IEnumerable<T1> list) where T2: List<T1>, new()
    {
        T2 listContainer = new T2();
        listContainer.AddRange(list);
        return listContainer;
    }

}

The above will copy the contents of the IEnumerable list T1 to the new List Container object T2 and return it.

Just to test:

WidgetList widgets = new WidgetList();

widgets.Add(new Widget(1, "Dog 1"));
widgets.Add(new Widget(2, "Dog 2"));
widgets.Add(new Widget(3, "Dog 3"));
widgets.Add(new Widget(4, "Cat 1"));
widgets.Add(new Widget(5, "Dog 2"));
widgets.Add(new Widget(6, "Dog 3"));


widgets  =  (from w in widgets
             where w.Name.Contains("1")
             select w).ToListContainer<Widget, WidgetList>();

int c = widgets.Count();
Sean