2

Is there a way to save a list to disk generically? I tried data contract serializer, but it always generates an empty list.

    public static List<T> Load<T>() where T : class,new()
    {
        var serializer = new DataContractSerializer(typeof(List<T>));

        string path = HttpContext.Current.Server.MapPath("~/App_Data/" + typeof(T).ToString() + ".xml");
        if (!System.IO.File.Exists(path))
        {
            return new List<T>();
        }
        else
        {
            using (var s = new System.IO.FileStream(path, System.IO.FileMode.Open))
            {
                return serializer.ReadObject(s) as List<T>;
            }
        }
    }

    public static void Save<T>(List<T> data) where T : class,new()
    {
        var serializer = new DataContractSerializer(typeof(List<T>));

        Enumerate<T>(data);

        string path = HttpContext.Current.Server.MapPath("~/App_Data/" + typeof(T).ToString() + ".xml");
        using (var s = new System.IO.FileStream(path, System.IO.FileMode.Create))
        {
            serializer.WriteObject(s, data);
        }
    }
quillbreaker
  • 6,119
  • 3
  • 29
  • 47
  • 1
    The duplicate had errors in the code. – quillbreaker Jun 16 '14 at 15:40
  • @tekan that question doesn't appear to exist. – Austin Mullins Jun 16 '14 at 15:41
  • What does the `Enumerate(data)` method do? Does the compiler require `Enumerate(data)` instead of `Enumerate(data)`? – Keith Payne Jun 16 '14 at 15:42
  • 1
    @quillbreaker what is type of `T` you are trying to serialize? Does your code work with simple types, like string or int? Do you see generated file with data, or error occurs during serialization? – Sergey Berezovskiy Jun 16 '14 at 15:43
  • @AustinMullins When i posted it it existed... quillbreaker: Ok. – tekan Jun 16 '14 at 15:43
  • 1
    @quillbreaker you know you can press the edit button. Anyways. Lots of red flags are popping up for your code. `as` casting, could be hiding errors. `T` isn't included so I don't know if it is correctly attributed. `Enumerate` not included in code listing. `where new()` is completely superfluous (and possibly even the `where class`). Are you even sure that the `return new List()` code branch isn't running? You might not have permission to write to `App_Data`. – Aron Jun 16 '14 at 15:45
  • Do you care about how it is serialized? JSON, XML, binary? – Yuval Itzchakov Jun 16 '14 at 15:45
  • possible duplicate of [serialize list of generic type](http://stackoverflow.com/questions/19378084/serialize-list-of-generic-type) – Jodrell Jun 16 '14 at 15:50
  • I actually don't care about how it's serialized, as long as I can deserialize it. – quillbreaker Jun 16 '14 at 15:56

3 Answers3

2

You might want to use JavaScriptSerializer

var json = new JavaScriptSerializer().Serialize(thing);

JSON lists are generic.

UPDATE: Ass claimed by TimS Json.NET is better serializer so if adding 3rd party library is an option here is an article on how to do it.

Matas Vaitkevicius
  • 58,075
  • 31
  • 238
  • 265
  • @TimS. Even the microsoft team agrees. All the new Open Source Microsoft stuff uses Json.Net. – Aron Jun 16 '14 at 15:46
  • I looked into Json.Net, and it is making lists of empty objects for me. – quillbreaker Jun 16 '14 at 15:49
  • More detailed answer about this here, agreed JSON.net is desirable if available. http://stackoverflow.com/questions/9110724/serializing-a-list-to-json/9110986#9110986 – Jodrell Jun 16 '14 at 16:00
  • I have resolved the list of empty objects issue and I'm currently using the JSON.net serializer. I'll accept soon. – quillbreaker Jun 18 '14 at 18:33
2

What about a binary serializer

    public static void SerializeToBin(object obj, string filename)
    {
        Directory.CreateDirectory(Path.GetDirectoryName(filename));
        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        using (FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite))
        {
            bf.Serialize(fs, obj);
        }
    }
    public static T DeSerializeFromBin<T>(string filename) where T : new()
    {
        if (File.Exists(filename))
        {
            T ret = new T();
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                ret = (T)bf.Deserialize(fs);
            }
            return ret;
        }
        else
            throw new FileNotFoundException(string.Format("file {0} does not exist", filename));
    }
cechode
  • 1,002
  • 1
  • 8
  • 20
2

Based on what you're trying to do, the key might also be your class T, ensuring that it is decorated with the proper [DataContract] and [DataMember] attributes. Here is a working example based on your code in question (however if you don't care to be able to utilize the persisted file outside of your code, you might find better performance in the binary serializer):

[DataContract]
public class Mydata
{
    [DataMember]
    public int Id { get; set; }
    [DataMember]
    public string Name { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        List<Mydata> myData = new List<Mydata>();
        myData.Add(new Mydata() { Id = 1, Name = "Object 1" });
        myData.Add(new Mydata() { Id = 2, Name = "Object 2" });
        string path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + @"\" + typeof(Mydata).ToString() + ".xml";
        Save<Mydata>(myData, path);

        List<Mydata> myNewData = Load<Mydata>(path);
        Console.WriteLine(myNewData.Count);
        Console.ReadLine();
    }

    public static List<T> Load<T>(string filename) where T : class
    {
        var serializer = new DataContractSerializer(typeof(List<T>));

        if (!System.IO.File.Exists(filename))
        {
            return new List<T>();
        }
        else
        {
            using (var s = new System.IO.FileStream(filename, System.IO.FileMode.Open))
            {
                return serializer.ReadObject(s) as List<T>;
            }
        }
    }

    public static void Save<T>(List<T> list, string filename)
    {
        var serializer = new DataContractSerializer(typeof(List<T>));

        using (FileStream fs = new FileStream(filename, FileMode.Create))
        {
            using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs))
            {
                serializer.WriteObject(writer, list);
            }
        }
    }
}
Daniel Graham
  • 399
  • 3
  • 13