I have different kinds of objects in c# that I would like to save to a file (XML is preferred) but I can't use serialization since the class are not written by me but are from a DLL.
What is the best solution for this ?
I eventually used JavaScriptSerializer and it does exactly what I was looking for:
List<Person> persons = new List<Person>();
persons.Add(new Person(){Name = "aaa"});
persons.Add(new Person() { Name = "bbb" });
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
var strData = javaScriptSerializer.Serialize(persons);
var persons2 = javaScriptSerializer.Deserialize<List<Person>>(strData);
I've whipped up a quick little extension method that will "serialize" to XML, given a non-serializable object. It's pretty rough and doesn't do a heck of a lot of checking and the XML it generates you can easily tweak to meet your needs:
public static string SerializeObject<T>(this T source, bool serializeNonPublic = false)
{
if (source == null)
{
return null;
}
var bindingFlags = BindingFlags.Instance | BindingFlags.Public;
if (serializeNonPublic)
{
bindingFlags |= BindingFlags.NonPublic;
}
var properties = typeof(T).GetProperties(bindingFlags).Where(property => property.CanRead).ToList();
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb))
{
writer.WriteStartElement(typeof(T).Name);
if (properties.Any())
{
foreach (var property in properties)
{
var value = property.GetValue(source, null);
writer.WriteStartElement(property.Name);
writer.WriteAttributeString("Type", property.PropertyType.Name);
writer.WriteAttributeString("Value", value.ToString());
writer.WriteEndElement();
}
}
else if (typeof(T).IsValueType)
{
writer.WriteValue(source.ToString());
}
writer.WriteEndElement();
}
return sb.ToString();
}
I tested it on this class:
private sealed class Test
{
private readonly string name;
private readonly int age;
public Test(string name, int age)
{
this.name = name;
this.age = age;
}
public string Name
{
get
{
return this.name;
}
}
public int Age
{
get
{
return this.age;
}
}
}
as well as the number 3
and object
. The resulting XML is as such:
<?xml version="1.0" encoding="utf-16"?>
<Test>
<Name Type="String" Value="John Doe" />
<Age Type="Int32" Value="35" />
</Test>
<?xml version="1.0" encoding="utf-16"?>
<Int32>3</Int32>
<?xml version="1.0" encoding="utf-16"?>
<Object />
respectively.
write your own serializable wrappers around the non-serializable classes of the DLL.
EDIT: AutoMapper was suggested in the comments and I hadn't heard of it yet, but now that I have I'd definitely use that instead of writing the wrappers myself. Unless there's some reflection required to capture some of the internal state of the non-serializable object (if possible), I don't know if AutoMapper has anything to offer there or you'd have to see if you could capture that in your wrapper.
I would write a POCO (Plain Old Class Object) class that mimics the object from the DLL returned. Generally if you are using, I believe, .NET 3.5 or higher you have the ability to use LINQ. I favor Linq to put objects into other classes or perform sorting or other operations on them.
Here is a simple example where you would be dummying in your return object for example. Keep in mind in a DLL of course you could have many differing objects and do this multiple times. I also would wrap my methods up in their own class for re usability instead of doing it in the main. But here is a simple proof of concept
using System;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Xml.Linq;
namespace ExampleSerializer
{
class Program
{
// example class to serialize
[Serializable]
public class SQLBit
{
[XmlElement("Name")]
public string Name { get; set; }
[XmlText]
public string data { get; set; }
}
// example class to populate to get test data
public class example
{
public string Name { get; set; }
public string data { get; set; }
}
static void Main(string[] args)
{
string s = "";
// make a generic and put some data in it from the test
var ls = new List<example> { new example { Name = "thing", data = "data" }, new example { Name = "thing2", data = "data2" } };
// make a second generic and put data from the first one in using a lambda
// statement creation method. If your object returned from DLL is a of a
// type that implements IEnumerable it should be able to be used.
var otherlist = ls.Select(n => new SQLBit
{
Name = n.Name,
data = n.data
});
// start a new xml serialization with a type.
XmlSerializer xmler = new XmlSerializer(typeof(List<SQLBit>));
// I use a textwriter to start a new instance of a stream writer
TextWriter twrtr = new StreamWriter(@"C:\Test\Filename.xml");
// Serialize the stream to the location with the list
xmler.Serialize(twrtr, otherlist);
// Close
twrtr.Close();
// TODO: You may want to put this in a try catch wrapper and make up your
// own classes. This is a simple example.
}
}
}
I think the term "without-serialization" in the question header is misleading.
If i understood you correctly you want to serialize objects that have no serilisation-attributes.
There are libraries like sharpserializer and protobuf-net that can do the job for you.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.