eMi
eMi

Reputation: 5628

C# Return Generic List/IEnumerable, how does it works?

I have a method which returns me a list(IEnumerable) of cars..

(Works fine with Returntypes IEnumerable<Car> and List<Car>):

public IEnumerable<Car> GetCars(string xml)
{
    var myResultList;

     XElement doc = XElement.Parse(xml);
     myResultList = doc.Descendants().Descendants("dict").Select(
     x => new Employee
     {
         Id = x.Elements("string").ElementAt(0).Value,
         Prename = x.Elements("string").ElementAt(1).Value,
         Name = x.Elements("string").ElementAt(2).Value,
         Initials = x.Elements("string").ElementAt(3).Value
    }
    );

    IEnumerable<Car> enumerable = myResultList;
    return enumerable;

    //---

    //or as a List if it's better?
    List<Car> asList = enumerable.ToList();
    //then: return asList
}

Now I would like to make this Method generic. Every IEnumerable Type / Or List Type should be able.

Something like this - thats just pseudo code, as I don't know how it works;

public IEnumerable<T> GetData(string xml)
{
    var myResultList;

    //...myResultList.. will be filled here (unnecessary) 

    IEnumerable<T> enumerable = myResultList;
    return enumerable;

    //---

    //or as a List if it's better?
    List<T> asList = enumerable.ToList();
    //then: return asList
}

I hope my question is clear enough.. Just imagine you would have an other Type like House instead of Car but u wanted to use the same method for every type.

How can I achieve that? Help would be appreciated.

EDIT:

Added the Code which fills "myResultsList"

EDIT 2: 2 XML's which should work on same method:

 <plist version="1.0">
  <dict>
    <key>DataType</key>
    <string>Employee</string>
    <key>8000</key>
    <dict>
      <key>MitarbeiterNo</key>
      <string>8000</string>
      <key>Vorname</key>
      <string>Walter</string>
      <key>Name</key>
      <string>Walter Lohner Stans</string>
      <key>Initialien</key>
      <string>MAL</string>
    </dict>
    <key>8001</key>
    <dict>
      <key>MitarbeiterNo</key>
      <string>8001</string>
      <key>Vorname</key>
      <string>Motorrad</string>
      <key>Name</key>
      <string> Meierskappel</string>
      <key>Initialien</key>
      <string>MAM</string>
    </dict>
    <key>8004</key>
    <dict>
      <key>MitarbeiterNo</key>
      <string>8004</string>
      <key>Vorname</key>
      <string>Hanspeter</string>
      <key>Name</key>
      <string>Altenbürger AG  Horgen</string>
      <key>Initialien</key>
      <string>FH</string>
    </dict>
  </dict>
</plist>

and

 <plist version="1.0">
  <dict>
    <key>DataType</key>
    <string>Agent</string>
    <key>7000</key>
    <dict>
      <key>AgentNo</key>
      <string>7000</string>
      <key>Initialien</key>
      <string>VW</string>
      <key>Namen</key>
      <string>Walter Gnos Vertretungen  Vevey</string>
    </dict>
    <key>7001</key>
    <dict>
      <key>AgentNo</key>
      <string>7001</string>
      <key>Namen</key>
      <string>Miller GmbH Bern</string>
    </dict>
    <key>7002</key>
    <dict>
      <key>AgentNo</key>
      <string>7002</string>
      <key>Initialien</key>
      <string>MAL</string>
      <key>Namen</key>
      <string>Walter Lohner Stans</string>
    </dict>
  </dict>
</plist>

Upvotes: 1

Views: 5508

Answers (2)

Wouter de Kort
Wouter de Kort

Reputation: 39898

Here is an example of what you are trying to do. You can paste this code in a Console Application:

using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace Stackoverflow
{
    public class Foo
    {
        public int Id { get; set; }
        public Bar Bar { get; set; }
    }

    public class Bar { }

    class Program
    {
        private static void Main()
        {
            var foos = new List<Foo>
                           {
                               new Foo { Id =1, Bar = new Bar()},
                               new Foo { Id =2, Bar = null},
                               new Foo { Id =3, Bar = new Bar()},
                               new Foo { Id =4, Bar = null},
                           };

            var xml = ToXml(foos);

            var result = GetData<List<Foo>>(xml);
        }

        private static string ToXml(List<Foo> foos)
        {
            XmlSerializer ser = new XmlSerializer(foos.GetType());
            StringBuilder sb = new StringBuilder();
            StringWriter writer = new StringWriter(sb);
            ser.Serialize(writer, foos);

            string xml = sb.ToString();
            return xml;
        }

        public static T GetData<T>(string xml)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);

            XmlNodeReader reader = new XmlNodeReader(doc.DocumentElement);
            XmlSerializer ser = new XmlSerializer(typeof(T));
            object obj = ser.Deserialize(reader);

            T result = (T)obj;

            return result;
        }
    }
}

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1063519

The only thing you're missing is the <T>:

public IEnumerable<T> GetData<T>(string xml)

then you call it as:

var data = obj.GetData<House>(xml);

where the <House> tells GetData what the T is for that call. Note that inside GetData<T> you can use typeof(T) to get the Type, which might be necessary if you are using XmlSerializer or similar for the deserialization.

Note that in some cases it can be really handy to use generics, and it some others it can actually makes things problematic - so you might also want to consider whether it might not be more appropriate to use:

public IEnumerable GetData(Type type, string xml)

i.e. pass the Type in as a regular parameter. This can be useful if you are doing a lot of work with reflection, where generics become tricky. But to emphasize: both generic and non-generic solutions are reasonable and valid.

Upvotes: 4

Related Questions