Generics + XML Serialization + Custom Objects
I'm trying out Generics and I had this (not so) great idea of creating an XMLSerializer class. The code I pieced together is below:
public class Persist<T>
{
private strin开发者_StackOverflow中文版g _path;
public Persist(string path) {
this._path = path;
}
public void save(T objectToSave)
{
XmlSerializer s = new XmlSerializer(typeof(T));
TextWriter w = new StreamWriter(this._path);
try { s.Serialize(w, objectToSave); }
catch (InvalidDataException e) { throw e; }
w.Close(); w.Dispose();
}
public T load()
{
XmlSerializer s = new XmlSerializer(typeof(T));
TextReader r = new StreamReader(this._path);
T obj;
try { obj = (T)s.Deserialize(r); }
catch (InvalidDataException e) { throw e; }
r.Close(); r.Dispose();
return obj;
}
}
Here's the problem: It works fine on Persist<List<string>>
or Persist<List<int>>
but not on Persist<List<userObject>>
or any other custom (but serializable) objects. userObject
itself is just a class with two {get;set;} properties, which I have serialized before.
I'm not sure if the problems on my Persist class (generics), XML Serialization code, or somewhere else :( Help is very much appreciated~
Edit:
code for userObject
public class userObject
{
public userObject(string id, string name)
{
this.id = id;
this.name = name;
}
public string id { get;private set; }
public string name { get;set; }
}
Looks to me like your code should just work - even though it does have a few flaws.
EDIT: Your userObject
class isn't serializable. Xml serialization only works on types with a public, parameterless constructor - the current class won't work. Also, you should really rewrite your code to avoid explicit calls to .Close()
or .Dispose()
and instead prefer using
where possible - as is, you might get random file locking if at any point during serialization an error occurs and your method terminates by exception - and thus doesn't call .Dispose()
.
Personally, I tend to use a just-for-serialization object hierarchy that's just a container for data stored in xml and avoids any behavior - particularly side effects. Then you can use a handly little base class that makes this simple.
What I use in my projects is the following:
public class XmlSerializableBase<T> where T : XmlSerializableBase<T>
{
static XmlSerializer serializer = new XmlSerializer(typeof(T));
public static T Deserialize(XmlReader from) { return (T)serializer.Deserialize(from); }
public void SerializeTo(Stream s) { serializer.Serialize(s, this); }
public void SerializeTo(TextWriter w) { serializer.Serialize(w, this); }
public void SerializeTo(XmlWriter xw) { serializer.Serialize(xw, this); }
}
...which caches the serializer in a static object, and simplifies usage (no generic type-paramenters needed at call-locations.
Real-life classes using it:
public class ArtistTopTracks {
public string name;
public string mbid;//always empty
public long reach;
public string url;
}
[XmlRoot("mostknowntracks")]
public class ApiArtistTopTracks : XmlSerializableBase<ApiArtistTopTracks> {
[XmlAttribute]
public string artist;
[XmlElement("track")]
public ArtistTopTracks[] track;
}
Sample serialization calls:
using (var xmlReader = XmlReader.Create([...]))
return ApiArtistTopTracks.Deserialize(xmlReader);
//[...]
ApiArtistTopTracks toptracks = [...];
toptracks.SerializeTo(Console.Out);
There can be a number of reasons why your code fails: This text is particularly helpful when having issues: Troubleshooting Common Problems with the XmlSerializer . Maybe you have some type hierarchy in your user objects and the serializer does not know about it?
精彩评论