943,513 Members | Top Members by Rank

Ad:
  • C# Discussion Thread
  • Marked Solved
  • Views: 2514
  • C# RSS
Sep 9th, 2009
0

complications with XML serialization

Expand Post »
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.
Last edited by Diamonddrake; Sep 9th, 2009 at 1:50 am.
Similar Threads
Reputation Points: 442
Solved Threads: 89
Master Poster
Diamonddrake is offline Offline
721 posts
since Mar 2008
Sep 9th, 2009
0

Re: complications with XML serialization

Do you want an alternative of XML serialization? Take a look at BinarySerialization
Moderator
Reputation Points: 2136
Solved Threads: 1228
Posting Genius
adatapost is offline Offline
6,527 posts
since Oct 2008
Sep 9th, 2009
1

Re: complications with XML serialization

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)
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Reflection;
  5. using System.Windows.Forms;
  6. using System.Xml.Serialization;
  7.  
  8. namespace daniweb
  9. {
  10. public partial class frmSerial2 : Form
  11. {
  12. private byte[] serializedData;
  13.  
  14. public frmSerial2()
  15. {
  16. InitializeComponent();
  17. }
  18.  
  19. private void button1_Click(object sender, EventArgs e)
  20. {
  21. ConcreteClass cc = new ConcreteClass();
  22. cc.BaseProperty1 = "abc";
  23. cc.BaseProperty2 = 5;
  24. cc.BaseProperty3 = DateTime.Now;
  25.  
  26. cc.Property1 = "ssss";
  27. cc.Property2 = 15;
  28. cc.Property3 = DateTime.Now.AddDays(5);
  29. cc.Property4 = 1324;
  30.  
  31. using (MemoryStream ms = new MemoryStream())
  32. {
  33. CustomSerializer.SerializeObject(ms, cc);
  34. serializedData = ms.ToArray();
  35. }
  36.  
  37. #region lets inspect our work
  38. {
  39. string xmlData = System.Text.ASCIIEncoding.UTF8.GetString(serializedData);
  40. Console.WriteLine(xmlData);
  41. System.Diagnostics.Debugger.Break();
  42. }
  43. #endregion
  44. }
  45.  
  46. private void button2_Click(object sender, EventArgs e)
  47. {
  48. ConcreteClass cc = new ConcreteClass();
  49. using (MemoryStream ms = new MemoryStream(serializedData))
  50. {
  51. ms.Position = 0;
  52. ms.Seek(0, SeekOrigin.Begin);
  53. CustomSerializer.DeserializeObject(ms, cc);
  54. }
  55. System.Diagnostics.Debugger.Break();
  56. }
  57. }
  58.  
  59. public class BaseClass
  60. {
  61. public string BaseProperty1 { get; set; }
  62. public int BaseProperty2 { get; set; }
  63. public DateTime BaseProperty3 { get; set; }
  64.  
  65. public BaseClass()
  66. {
  67. }
  68. }
  69.  
  70. public class ConcreteClass : BaseClass
  71. {
  72. [CustomSerialized]
  73. public string Property1 { get; set; }
  74. [CustomSerialized]
  75. public int Property2 { get; set; }
  76. [CustomSerialized]
  77. public DateTime Property3 { get; set; }
  78. public long Property4 { get; set; }
  79.  
  80. public ConcreteClass()
  81. : base()
  82. {
  83. }
  84. }
  85.  
  86. [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
  87. internal sealed class CustomSerialized : Attribute
  88. {
  89. public CustomSerialized()
  90. {
  91.  
  92. }
  93. }
  94.  
  95. public class NameValuePair
  96. {
  97. public string PropertyName { get; set; }
  98. public object PropertyValue { get; set; }
  99. public NameValuePair() { }
  100. public NameValuePair(string PropertyName, object PropertyValue)
  101. : this()
  102. {
  103. this.PropertyName = PropertyName;
  104. this.PropertyValue = PropertyValue;
  105. }
  106. }
  107.  
  108. public static class CustomSerializer
  109. {
  110.  
  111. //.DeclaredOnly - ignored inherited members
  112. private const BindingFlags SqlObjectBindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
  113.  
  114. private static bool IsMarkedCustomSerialzed(PropertyInfo Prop)
  115. {
  116. Attribute[] attrs = System.Attribute.GetCustomAttributes(Prop);
  117. foreach (Attribute at in attrs)
  118. {
  119. if ((at as CustomSerialized) != null)
  120. return true;
  121. }
  122. return false;
  123. }
  124.  
  125. private static PropertyInfo[] GetProperties(object o)
  126. {
  127. List<PropertyInfo> result = new List<PropertyInfo>();
  128. PropertyInfo[] properties = o.GetType().GetProperties(SqlObjectBindingFlags);
  129. foreach (PropertyInfo pi in properties)
  130. {
  131. if (IsMarkedCustomSerialzed(pi) && pi.CanRead && pi.CanWrite)
  132. result.Add(pi);
  133. }
  134. return result.ToArray();
  135. }
  136.  
  137. public static void SerializeObject(Stream stream, object o)
  138. {
  139. PropertyInfo[] properties = GetProperties(o);
  140. List<NameValuePair> lst = new List<NameValuePair>();
  141. foreach (PropertyInfo pi in properties)
  142. {
  143. lst.Add(new NameValuePair(pi.Name, pi.GetValue(o, null)));
  144. }
  145. XmlSerializer ser = new XmlSerializer(typeof(List<NameValuePair>));
  146. ser.Serialize(stream, lst);
  147. }
  148.  
  149. //This doesn't create the object for you since we're not serializing all properties.
  150. //It basically does "apply property changes"
  151. public static void DeserializeObject(Stream s, object o)
  152. {
  153. XmlSerializer ser = new XmlSerializer(typeof(List<NameValuePair>));
  154. List<NameValuePair> lst = (List<NameValuePair>)ser.Deserialize(s);
  155. PropertyInfo[] properties = GetProperties(o);
  156. foreach (PropertyInfo pi in properties)
  157. {
  158. NameValuePair nvp = FindInList(lst, pi.Name);
  159. if (nvp != null)
  160. {
  161. pi.SetValue(o, nvp.PropertyValue, null);
  162. }
  163. }
  164. }
  165. private static NameValuePair FindInList(List<NameValuePair> searchList, string PropertyName)
  166. {
  167. foreach (NameValuePair nvp in searchList)
  168. {
  169. if (string.Compare(nvp.PropertyName, PropertyName, true) == 0)
  170. return nvp;
  171. }
  172. return null;
  173. }
  174. }
  175. }
Featured Poster
Reputation Points: 1749
Solved Threads: 735
Senior Poster
sknake is offline Offline
3,948 posts
since Feb 2009
Sep 9th, 2009
0

Re: complications with XML serialization

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!
Reputation Points: 442
Solved Threads: 89
Master Poster
Diamonddrake is offline Offline
721 posts
since Mar 2008
Sep 10th, 2009
0

Re: complications with XML serialization

>> 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 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.
Featured Poster
Reputation Points: 1749
Solved Threads: 735
Senior Poster
sknake is offline Offline
3,948 posts
since Feb 2009
Sep 10th, 2009
0

Re: complications with XML serialization

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.

C# Syntax (Toggle Plain Text)
  1. public static void SerializeObject(Stream stream, List<object> objlist)
  2. {
  3.  
  4. List<List<NameValuePair>> newObjList = new List<List<NameValuePair>>();
  5.  
  6. foreach (object o in objlist)
  7. {
  8. PropertyInfo[] properties = GetProperties(o);
  9. List<NameValuePair> lst = new List<NameValuePair>();
  10. foreach (PropertyInfo pi in properties)
  11. {
  12. lst.Add(new NameValuePair(pi.Name, pi.GetValue(o, null)));
  13. }
  14. newObjList.Add(lst);
  15. }
  16. //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.
  17.  
  18. //or would I just serialize the list of lists and this actually work? like?
  19.  
  20. XmlSerializer ser = new XmlSerializer(typeof(List<List<NameValuePair>>));
  21. ser.Serialize(stream, newObjList);
  22. }

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.
Reputation Points: 442
Solved Threads: 89
Master Poster
Diamonddrake is offline Offline
721 posts
since Mar 2008
Sep 10th, 2009
0

Re: complications with XML serialization

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.
Featured Poster
Reputation Points: 1749
Solved Threads: 735
Senior Poster
sknake is offline Offline
3,948 posts
since Feb 2009
Sep 10th, 2009
0

Re: complications with XML serialization

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?
Reputation Points: 442
Solved Threads: 89
Master Poster
Diamonddrake is offline Offline
721 posts
since Mar 2008
Sep 11th, 2009
0

Re: complications with XML serialization

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.

C# Syntax (Toggle Plain Text)
  1. public static List<extrabutondata> DeserializeObject(Stream s)
  2. {
  3. XmlSerializer ser = new XmlSerializer(typeof(List<List<NameValuePair>>));
  4. List<List<NameValuePair>> lst = (List<List<NameValuePair>>)ser.Deserialize(s);
  5.  
  6. List<extrabutondata> extralist = new List<extrabutondata>();
  7.  
  8. for (int i = 0; i < lst.Count; i++)
  9. {
  10. extrabutondata o = new extrabutondata();
  11.  
  12.  
  13. PropertyInfo[] properties = GetProperties(o);
  14. foreach (PropertyInfo pi in properties)
  15. {
  16. NameValuePair nvp = FindInList(lst[i], pi.Name);
  17. if (nvp != null)
  18. {
  19. pi.SetValue(o, nvp.PropertyValue, null);
  20. }
  21. }
  22.  
  23. extralist.Add(o);
  24. }
  25.  
  26. return extralist;
  27. }
  28. // and example type class it uses
  29. public class extrabutondata
  30. {
  31. public extrabutondata()
  32. {
  33.  
  34. }
  35. public string name {get; set;}
  36. public int number { get; set;}
  37. }

Thanks again! that's another Daniweb form post solved by Sknake!
Reputation Points: 442
Solved Threads: 89
Master Poster
Diamonddrake is offline Offline
721 posts
since Mar 2008

This thread is solved

Either the thread starter or a moderator has marked this thread as solved. You can most likely trust the responses and answers given. There is most likely no reason for any further responses to be posted here. If you have a related question, please start a new thread in this forum instead.

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in C# Forum Timeline: C# Test Score Data
Next Thread in C# Forum Timeline: file read/write question





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC