By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,213 Members | 2,108 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,213 IT Pros & Developers. It's quick & easy.

Serializing value types

P: n/a
When a class contains a TimeSpan property, XmlSerializer doesn't work. A
TimeSpan property is serialized like:

<MySpan />

I've read a number of posts that talk about why this happens and how to work
around it. My question is from a slightly different angle. What can I do
to my value type structures so that XmlSerializer can serialize them
properly?

For example, I have a TimeOfDay structure, what can I do to my TimeOfDay
structure so that XmlSerializer works? I've already discovered that I can
add a public property to TimeOfDay like this:

[XmlAttribute]
public string value
{
get { ...return the time of day as a string...}
set { ...set the time of day from a string...}
}

so, if another object has a TimeOfDay property named StartTime, it is
serialized like:

<StartTime value="14:30" />

which isn't too bad but, it breaks if the consumer puts [XmlAttribute] on
their property. And, I have this strange "value" property hanging around
that I have to tell people to ignore.

Any suggestions?

Thanks,

John Vottero

Nov 12 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Hi John,

First of all, I would like to confirm my understanding of your issue. From
your description, I'm still not quite sure what you get. Do you mean that
adding a [XmlAttribute] on a property that returns TimeOfDay type will make
the serialized data look bad?

Could you please paste some repro code here and show us the desired result?
Thanks!

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #2

P: n/a

"Kevin Yu [MSFT]" <v-****@online.microsoft.com> wrote in message
news:6O**************@cpmsftngxa06.phx.gbl...
Hi John,

First of all, I would like to confirm my understanding of your issue. From
your description, I'm still not quite sure what you get. Do you mean that
adding a [XmlAttribute] on a property that returns TimeOfDay type will
make
the serialized data look bad?
Not exactly. The issue is, XmlSerializer can't serialize value types. If
someone uses my TimeOfDay type like this:

public TimeOfDay StartTime
{
get { return m_StartTime;}
set { m_StartTIme = value; }
}

When the containing class is serialized by XmlSerializer they get:

<StartTime />

Note that there's no data. What I want, is something like:

<StartTime>08:00</StartTime>

If the consumer class adds [XmlAttribute] to the StartTime property, they
get this error:

There was an error reflecting property 'StartTime'.
Cannot serialize member 'StartTime'. XmlAttribute/XmlText cannot be used to
encode complex types.

when they try to serialize with XmlSerializer.

What I want is something like:

<ConsumerClass StartTime="08:00">
What can I do to my TimeOfDay type to make it work with XmlSerializer?


Could you please paste some repro code here and show us the desired
result?
Thanks!


I will work up a short but complete example.
Nov 12 '05 #3

P: n/a
"Kevin Yu [MSFT]" <v-****@online.microsoft.com> wrote in message
news:6O**************@cpmsftngxa06.phx.gbl...
Hi John,

First of all, I would like to confirm my understanding of your issue. From
your description, I'm still not quite sure what you get. Do you mean that
adding a [XmlAttribute] on a property that returns TimeOfDay type will
make
the serialized data look bad?

Could you please paste some repro code here and show us the desired
result?
Thanks!


Here's a short console program that reproduces the problem followed by the
code for the TimeOfDay type.
using System;
using System.Xml.Serialization;

namespace XmlSample
{
/// <summary>
/// The Consumer class is just a simple example of a class that consumes
/// the TimeOfDay object. This is used to illustrate a problem with
XmlSerializer,
/// the StartTime property isn't serialized correctly. The real
question is:
///
/// What can be done to the TimeOfDay type to make XmlSerializer work?
///
/// </summary>
public class Consumer
{
public Consumer()
{
}

public string Name
{
get
{
return m_Name;
}
set
{
m_Name = value;
}
}

public TimeOfDay StartTime
{
get
{
return m_StartTime;
}
set
{
m_StartTime = value;
}
}

//
// Private property backers
//
private string m_Name;
private TimeOfDay m_StartTime;
}

/// <summary>
/// Class1 contains the Main method.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// Create and populate a Consumer object
//
Consumer co = new Consumer();

co.Name = "John";
co.StartTime = new TimeOfDay("10:30");

//
// Create the XmlSerializer
//
XmlSerializer serializer = new XmlSerializer(co.GetType());

//
// Serialize!!
//
serializer.Serialize(Console.Out, co);

//
// Pause
//
Console.WriteLine();
Console.WriteLine("StartTime should be {0}", co.StartTime);
Console.WriteLine("Press Return to continue");
Console.ReadLine();
}
}
}

/////// TimeOfDay.cs

using System;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Xml.Serialization;

namespace XmlSample
{
/// <summary>
/// TimeOfDayConverter is a TypeConverter for the TimeOfDay type.
/// </summary>
public class TimeOfDayConverter : TypeConverter
{
/// <summary>
/// Returns true if the passed source Type can be converted into a
TimeOfDay.
/// </summary>
/// <param name="context"></param>
/// <param name="sourceType">THe Type to be converted.</param>
/// <returns>True if the conversion can be done.</returns>
public override bool CanConvertFrom(
ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
else
{
return base.CanConvertFrom(context, sourceType);
}
}

/// <summary>
/// Converts the passed value into a TimeOfDay.
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value">The value to convert into a
TimeOfDay.</param>
/// <returns>The new TimeOfDay.</returns>
public override object ConvertFrom(
ITypeDescriptorContext context, CultureInfo culture, object
value)
{
if (value is string)
{
return TimeOfDay.Parse((string)value);
}
else
{
return base.ConvertFrom(context, culture, value);
}
}

/// <summary>
/// Converts the passed TimeOfDay into the passed destination Type.
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value">The TimeOfDay</param>
/// <param name="destinationType">The destination Type</param>
/// <returns>The new object created from the TimeOfDay.</returns>
public override object ConvertTo(
ITypeDescriptorContext context, CultureInfo culture, object
value, Type destinationType)
{
if ((destinationType == typeof(string))
&& (value is TimeOfDay))
{
return
((TimeOfDay)value).ToString(culture.DateTimeFormat .ShortTimePattern);
}
else
{
return base.ConvertTo(context, culture, value,
destinationType);
}
}
}

/// <summary>
/// The TimeOfDay represents a time of day.
/// </summary>
[Serializable,
TypeConverter(typeof(TimeOfDayConverter)),
XmlType("time")]
public struct TimeOfDay : IComparable, IFormattable, ISerializable
{
private int timeOfDay; // The number of seconds since midnight (-1
means NULL)

/// <summary>
/// Constructs a TimeOfDay from an integer which is the seconds
since midnight.
/// </summary>
/// <param name="initial">The seconds since midnight.</param>
public TimeOfDay(int initial)
{
timeOfDay = initial;
}

/// <summary>
/// Constructs a TimeOfDay from a DateTime.
/// </summary>
/// <param name="initial">The DateTime to create the TimeOfDay
from.</param>
public TimeOfDay(DateTime initial)
{
timeOfDay = (int)(initial.TimeOfDay.Ticks /
TimeSpan.TicksPerSecond);
}

/// <summary>
/// Constructs a TimeOfDay from a string.
/// </summary>
/// <param name="initial">The string.</param>
public TimeOfDay(string initial)
{
DateTime tmpDT;

try
{
tmpDT = DateTime.Parse(initial);
timeOfDay = (int)(tmpDT.TimeOfDay.Ticks /
TimeSpan.TicksPerSecond);
}
catch
{
timeOfDay = -1;
}
}

/// <summary>
/// A TimeOfDay that is the current time.
/// </summary>
public static TimeOfDay Now
{
get
{
return new TimeOfDay(DateTime.Now);
}
}

// [XmlAttribute]
// public string value
// {
// get
// {
// if (timeOfDay < 0)
// {
// return null;
// }
// else
// {
// return "10:30";
// }
// }
// set
// {
// timeOfDay = -1;
// }
// }

/// <summary>
/// A TimeOfDay that represents a time that is not specified.
/// </summary>
public static TimeOfDay Empty
{
get
{
return new TimeOfDay(-1);
}
}

/// <summary>
/// Parse a formatted string and return it as a TimeOfDay
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static TimeOfDay Parse(string input)
{
DateTime tmpDT;
int ticks;

try
{
tmpDT = DateTime.Parse(input);
ticks = (int)(tmpDT.TimeOfDay.Ticks /
TimeSpan.TicksPerSecond);
}
catch
{
ticks = -1;
}

return new TimeOfDay(ticks);
}

/// <summary>
/// Compare two TimeOfDay objects.
/// </summary>
/// <param name="obj">The TimeOfDay to compare to.</param>
/// <returns>-1, 0 or 1.</returns>
public int CompareTo(object obj)
{
if (obj is TimeOfDay)
{
//
// We can do this
//
TimeOfDay otherTime = (TimeOfDay) obj;
return timeOfDay - otherTime.timeOfDay;
}
else
{
throw new ArgumentException();
}
}

/// <summary>
/// Compares two TimeOfDay objects to see if they represent the same
time.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
return (this.timeOfDay == ((TimeOfDay)obj).timeOfDay);
}

/// <summary>
/// Returns a hashcode for this time.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return base.GetHashCode ();
}
/// <summary>
/// Compare two times to see if the left is less than the right.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static bool operator <(TimeOfDay left, TimeOfDay right)
{
return (left.CompareTo(right) < 0);
}

/// <summary>
/// Compare two times to see if the left is less than or equal to
the right.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static bool operator <=(TimeOfDay left, TimeOfDay right)
{
return (left.CompareTo(right) <= 0);
}

/// <summary>
/// Compare two times to see if the left is greater than the right.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static bool operator >(TimeOfDay left, TimeOfDay right)
{
return (left.CompareTo(right) > 0);
}

/// <summary>
/// Compare two times to see if the left is greater than or equal to
the right.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static bool operator >=(TimeOfDay left, TimeOfDay right)
{
return (left.CompareTo(right) >= 0);
}

/// <summary>
/// Compare two times to see if they are equal.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static bool operator ==(TimeOfDay left, TimeOfDay right)
{
return (left.CompareTo(right) == 0);
}

/// <summary>
/// Compare two times to see if they are not equal.
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public static bool operator !=(TimeOfDay left, TimeOfDay right)
{
return (left.CompareTo(right) != 0);
}

/// <summary>
/// Converts a TimeOfDay to a string.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return ToString(
CultureInfo.CurrentCulture.DateTimeFormat.ShortTim ePattern,
null);
}

/// <summary>
/// COnverts a TimeOfDay to a string using the specified
formatProvider.
/// </summary>
/// <param name="formatProvider"></param>
/// <returns></returns>
public string ToString(IFormatProvider formatProvider)
{
return ToString(
CultureInfo.CurrentCulture.DateTimeFormat.ShortTim ePattern,
formatProvider);
}

/// <summary>
/// COnverts a TimeOfDay to a string using the specified format.
/// </summary>
/// <param name="format"></param>
/// <returns></returns>
public string ToString(string format)
{
return ToString(format, null);
}

/// <summary>
/// Converts a TimeOfDay to a string using the specified format and
format provider.
/// </summary>
/// <param name="format"></param>
/// <param name="formatProvider"></param>
/// <returns></returns>
public string ToString(string format, IFormatProvider
formatProvider)
{
if ((timeOfDay < 0) || (timeOfDay >= 86400))
{
//
// The value is out of range
// We interpret this as a null time
//
return string.Empty;
}
else
{
//
// We have a valid value (number of seconds since midnight)
//
DateTime dtTmp = DateTime.Today;
dtTmp = dtTmp.AddSeconds(timeOfDay);
if (format == null)
{
return dtTmp.ToString(
CultureInfo.CurrentCulture.DateTimeFormat.ShortTim ePattern,
formatProvider);
}
else
{
return dtTmp.ToString(format, formatProvider);
}
}
}

/// <summary>
/// Returns a TimeSpan from midnight to the TimeOfDay
/// </summary>
/// <returns></returns>
public TimeSpan ToTimeSpan()
{
if (timeOfDay >= 0)
{
return new TimeSpan((TimeSpan.TicksPerSecond * timeOfDay));
}
else
{
return new TimeSpan(0);
}
}

/// <summary>
/// Returns the seconds between midnight and the time of day.
/// </summary>
public int TotalSeconds
{
get
{
return timeOfDay;
}
}
#region Implementation of ISerializable
//
// Code generated by BuildISerializable
//

/// <summary>
/// Deserialization constructor.
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
private TimeOfDay(SerializationInfo info, StreamingContext context)
{
timeOfDay = info.GetInt32("timeOfDay");
}

/// <summary>
/// Serializes a TimeOfDay.
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
// An unknown external module throws a SEHException when this line
is uncommented
//[SecurityPermission(SecurityAction.Demand,
SerializationFormatter=true)]
public void GetObjectData(SerializationInfo info, StreamingContext
context)
{
info.AddValue("timeOfDay", timeOfDay);
}
#endregion
}
}
Nov 12 '05 #4

P: n/a
Hi John,

Since Xml Serialization only serializes public fields, I added a public
property to the Comsumer class.

public string val
{
get
{
return m_StartTime.ToString();
}
set
{
m_StartTime = TimeOfDay.Parse(value);
}
}

As far as I can see, I don't know any better way to serialize the TimeOfDay
struct. Sorry for the inconvenience. HTH.

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.