| | |
complications with XML serialization
Please support our C# advertiser: Intel Parallel Studio Home
Thread Solved |
In my project I had been using a set of arrays to hold some data, realized it was a bad design, so then I decided to create an object that holds all the relevant data, and add them to an arraylist, this work great except all the data was information that extended a complicated dynamic button. So then, since the button was a custom user control anyway. I just added the fields i needed to store to the button class its self and everything was simple and right with the world.
then I come to the problem of saving the date, XML serialization is the method of choice, but I have a problem, This would want to save ALL the public properties of the button, not just the custom ones, so I ask.
Is there a way to denote that just these X amount of properties be serialized without going through and overriding all the properties in the base class and and adding a bracket that asks for it to be omitted?
alternatively, say I created a class that just holds my data properties and had my button class additionally inherit from that. giving it those fields, would there be a way to just serialize the members gained from that 2nd inheritance? (since # only supports 1 baseclass I refer of course to a linear inheritance) even still I just don't think this is the solution, I just don't know how to go about this, Other than go back to a separate data object.
then I come to the problem of saving the date, XML serialization is the method of choice, but I have a problem, This would want to save ALL the public properties of the button, not just the custom ones, so I ask.
Is there a way to denote that just these X amount of properties be serialized without going through and overriding all the properties in the base class and and adding a bracket that asks for it to be omitted?
alternatively, say I created a class that just holds my data properties and had my button class additionally inherit from that. giving it those fields, would there be a way to just serialize the members gained from that 2nd inheritance? (since # only supports 1 baseclass I refer of course to a linear inheritance) even still I just don't think this is the solution, I just don't know how to go about this, Other than go back to a separate data object.
Last edited by Diamonddrake; Sep 9th, 2009 at 1:50 am.
No -- you either need to handle the reflection yourself, serialize all the data, or mark the members you want serialized. Here is how you can serialize the data yourself. This is on a form with two buttons:
c# Syntax (Toggle Plain Text)
using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Windows.Forms; using System.Xml.Serialization; namespace daniweb { public partial class frmSerial2 : Form { private byte[] serializedData; public frmSerial2() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { ConcreteClass cc = new ConcreteClass(); cc.BaseProperty1 = "abc"; cc.BaseProperty2 = 5; cc.BaseProperty3 = DateTime.Now; cc.Property1 = "ssss"; cc.Property2 = 15; cc.Property3 = DateTime.Now.AddDays(5); cc.Property4 = 1324; using (MemoryStream ms = new MemoryStream()) { CustomSerializer.SerializeObject(ms, cc); serializedData = ms.ToArray(); } #region lets inspect our work { string xmlData = System.Text.ASCIIEncoding.UTF8.GetString(serializedData); Console.WriteLine(xmlData); System.Diagnostics.Debugger.Break(); } #endregion } private void button2_Click(object sender, EventArgs e) { ConcreteClass cc = new ConcreteClass(); using (MemoryStream ms = new MemoryStream(serializedData)) { ms.Position = 0; ms.Seek(0, SeekOrigin.Begin); CustomSerializer.DeserializeObject(ms, cc); } System.Diagnostics.Debugger.Break(); } } public class BaseClass { public string BaseProperty1 { get; set; } public int BaseProperty2 { get; set; } public DateTime BaseProperty3 { get; set; } public BaseClass() { } } public class ConcreteClass : BaseClass { [CustomSerialized] public string Property1 { get; set; } [CustomSerialized] public int Property2 { get; set; } [CustomSerialized] public DateTime Property3 { get; set; } public long Property4 { get; set; } public ConcreteClass() : base() { } } [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] internal sealed class CustomSerialized : Attribute { public CustomSerialized() { } } public class NameValuePair { public string PropertyName { get; set; } public object PropertyValue { get; set; } public NameValuePair() { } public NameValuePair(string PropertyName, object PropertyValue) : this() { this.PropertyName = PropertyName; this.PropertyValue = PropertyValue; } } public static class CustomSerializer { //.DeclaredOnly - ignored inherited members private const BindingFlags SqlObjectBindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static bool IsMarkedCustomSerialzed(PropertyInfo Prop) { Attribute[] attrs = System.Attribute.GetCustomAttributes(Prop); foreach (Attribute at in attrs) { if ((at as CustomSerialized) != null) return true; } return false; } private static PropertyInfo[] GetProperties(object o) { List<PropertyInfo> result = new List<PropertyInfo>(); PropertyInfo[] properties = o.GetType().GetProperties(SqlObjectBindingFlags); foreach (PropertyInfo pi in properties) { if (IsMarkedCustomSerialzed(pi) && pi.CanRead && pi.CanWrite) result.Add(pi); } return result.ToArray(); } public static void SerializeObject(Stream stream, object o) { PropertyInfo[] properties = GetProperties(o); List<NameValuePair> lst = new List<NameValuePair>(); foreach (PropertyInfo pi in properties) { lst.Add(new NameValuePair(pi.Name, pi.GetValue(o, null))); } XmlSerializer ser = new XmlSerializer(typeof(List<NameValuePair>)); ser.Serialize(stream, lst); } //This doesn't create the object for you since we're not serializing all properties. //It basically does "apply property changes" public static void DeserializeObject(Stream s, object o) { XmlSerializer ser = new XmlSerializer(typeof(List<NameValuePair>)); List<NameValuePair> lst = (List<NameValuePair>)ser.Deserialize(s); PropertyInfo[] properties = GetProperties(o); foreach (PropertyInfo pi in properties) { NameValuePair nvp = FindInList(lst, pi.Name); if (nvp != null) { pi.SetValue(o, nvp.PropertyValue, null); } } } private static NameValuePair FindInList(List<NameValuePair> searchList, string PropertyName) { foreach (NameValuePair nvp in searchList) { if (string.Compare(nvp.PropertyName, PropertyName, true) == 0) return nvp; } return null; } } }
Scott you never cease to amaze me! This is some great code, let me ask so questions to make sure I got it.
these Bindingflags allow you to tell the serializer to only serialize the public members declared in that object, not the inherited members?
--if so this is awesome.
and could this be modified to serialize a list of classes?
from what I can follow the data is saved just as pairs of property names and the values of each, so multiple objects that have the same property names... just not sure how I could handle that.
Thanks!
these Bindingflags allow you to tell the serializer to only serialize the public members declared in that object, not the inherited members?
--if so this is awesome.
and could this be modified to serialize a list of classes?
from what I can follow the data is saved just as pairs of property names and the values of each, so multiple objects that have the same property names... just not sure how I could handle that.
Thanks!
>> these Bindingflags allow you to tell the serializer to only serialize the public members declared in that object, not the inherited members? --if so this is awesome.
Yes. This only does properties (have get/set, not fields).
>>and could this be modified to serialize a list of classes?
Yes. I almost always serialize List<class>
from what I can follow the data is saved just as pairs of property names and the values of each, so multiple objects that have the same property names... just not sure how I could handle that.
You can't have multiple property names the same. IE a button doesn't have two properties called "Text", it can only have a single property. The only exception to this is when you inherit a class you can override the member -- but regardless it is still a single property name/value pair. You can also hide inherited members with the
The reason this doesn't apply is because you said you wanted to serialize X properties in a class and ignore inheritence so I cannot think of a single way where this would be a problem.
Yes. This only does properties (have get/set, not fields).
>>and could this be modified to serialize a list of classes?
Yes. I almost always serialize List<class>
from what I can follow the data is saved just as pairs of property names and the values of each, so multiple objects that have the same property names... just not sure how I could handle that.
You can't have multiple property names the same. IE a button doesn't have two properties called "Text", it can only have a single property. The only exception to this is when you inherit a class you can override the member -- but regardless it is still a single property name/value pair. You can also hide inherited members with the
new keyword, but again this doesn't apply.The reason this doesn't apply is because you said you wanted to serialize X properties in a class and ignore inheritence so I cannot think of a single way where this would be a problem.
Thanks for the reply!
what i meant was, your serializer/dematerializer methods accept an object. but that object is expected to be a class with members, I need those functions to accept a list of objects. not just an object.
I can't seem to figure out how to get it to work right. I got a result, but the XML file is then fairly confusing and for some reason the resulting XML file's objects are always backwards, as in the last object in the list is first in the xml file.
note, code is modified from the code you posted previously.
and as far as the deserialzing such a thing. I can't even get started.
-->a briefing of my final goal is to have a bar of dynamically created buttons with special values that need to be saved. then when the app opens back up i need it to parse the xml to return a list of objects that I can loop through and create a new special button for each one, assigning the special values to each one as it goes.
-->stuck in the mud at the first corner I'm afraid, but you did an amazing job getting me to the starting line.
what i meant was, your serializer/dematerializer methods accept an object. but that object is expected to be a class with members, I need those functions to accept a list of objects. not just an object.
I can't seem to figure out how to get it to work right. I got a result, but the XML file is then fairly confusing and for some reason the resulting XML file's objects are always backwards, as in the last object in the list is first in the xml file.
C# Syntax (Toggle Plain Text)
public static void SerializeObject(Stream stream, List<object> objlist) { List<List<NameValuePair>> newObjList = new List<List<NameValuePair>>(); foreach (object o in objlist) { PropertyInfo[] properties = GetProperties(o); List<NameValuePair> lst = new List<NameValuePair>(); foreach (PropertyInfo pi in properties) { lst.Add(new NameValuePair(pi.Name, pi.GetValue(o, null))); } newObjList.Add(lst); } //now I have a lists of lists right? now what do I do do I serialize each one separately then add the resulting stream to another serializer? I'm kind of at a loss. this serialization thing is new to me. //or would I just serialize the list of lists and this actually work? like? XmlSerializer ser = new XmlSerializer(typeof(List<List<NameValuePair>>)); ser.Serialize(stream, newObjList); }
note, code is modified from the code you posted previously.
and as far as the deserialzing such a thing. I can't even get started.
-->a briefing of my final goal is to have a bar of dynamically created buttons with special values that need to be saved. then when the app opens back up i need it to parse the xml to return a list of objects that I can loop through and create a new special button for each one, assigning the special values to each one as it goes.
-->stuck in the mud at the first corner I'm afraid, but you did an amazing job getting me to the starting line.
Last edited by Diamonddrake; Sep 10th, 2009 at 5:49 pm.
So mark the special's button class with the attribute I gave you and serialize the button. I don't understand the need for a double list.
because the buttons are not predefined. they are created dynamically by a user. I can't hardcode them. they will have to be added to a list upon creation. then multiple instances of this class will need to be serialized.
I can't seen any other way to do it besides serializing a list of lists!
am I wrong?
I can't seen any other way to do it besides serializing a list of lists!
am I wrong?
Alright! I figured it out. I modified your deserialize method to return a list of custom objects contains just the extra data members that will be marked in the extendedbutton control class that way I can loop through them and create my buttons form them. I used all concept code because I don't like practicing in my real projects but I decided I would post the result for learning purposes for future visitors to the site.
Thanks for everything sknake! without your help I'm not sure I could have done it.
modified deserialize method.
Thanks again! that's another Daniweb form post solved by Sknake!
Thanks for everything sknake! without your help I'm not sure I could have done it.
modified deserialize method.
C# Syntax (Toggle Plain Text)
public static List<extrabutondata> DeserializeObject(Stream s) { XmlSerializer ser = new XmlSerializer(typeof(List<List<NameValuePair>>)); List<List<NameValuePair>> lst = (List<List<NameValuePair>>)ser.Deserialize(s); List<extrabutondata> extralist = new List<extrabutondata>(); for (int i = 0; i < lst.Count; i++) { extrabutondata o = new extrabutondata(); PropertyInfo[] properties = GetProperties(o); foreach (PropertyInfo pi in properties) { NameValuePair nvp = FindInList(lst[i], pi.Name); if (nvp != null) { pi.SetValue(o, nvp.PropertyValue, null); } } extralist.Add(o); } return extralist; } // and example type class it uses public class extrabutondata { public extrabutondata() { } public string name {get; set;} public int number { get; set;} }
Thanks again! that's another Daniweb form post solved by Sknake!
![]() |
Similar Threads
- Writing to an XML without overwriting data (VB.NET)
- Xml serializable problem (C#)
- XMl serialization (VB.NET)
- VB6 Serialization (Visual Basic 4 / 5 / 6)
- XML Serialization (C#)
Other Threads in the C# Forum
- Previous Thread: C# Test Score Data
- Next Thread: file read/write question
| Thread Tools | Search this Thread |
Tag cloud for serialization, xml
actionscript3 ajax api asp.net blogger blogging c# code delete development error flash flipbook gdata google html javascript kernel linspire linus linux microsoft news node nodes openoffice optimisation perl php programming rss serialization soap standards swappingxmlfromflash swappingxmlnodes swf synchronous tanenbaum tannenbaum text torvalds transform txttoxmlconverter vb2008 w3c web xml xmlnotloading xmlonserver xsl xslt







