XML serialisation won't write out lazy-evaluated property - c#

Following on from a previous question, I am having trouble combining the Lazy<T> generic that was suggested with my XML Serialization.
Here is the functionality I am using for Lazy<T>:
public struct Lazy<T> where T : class, new()
{
private T _Value;
public bool HasValue
{
get
{
return (_Value != null);
}
}
public T Value
{
get
{
if (!HasValue)
_Value = new T();
return _Value;
}
}
}
Now the MSDN Docs say that it's fine to have an [XmlElement("ElementName")] on a property and it does indeed seem to be able to deserialize just fine. The problem comes when I am serializing an object. I am running the following piece of code:
class SomeClass
{
[XmlElement("ExternalElementName")]
public ComplexElementType InternalElementName
{
get { return _InternalElementName.Value; }
}
protected Lazy<ComplexElementType> _InternalElementName;
}
Elsewhere:
SomeClass someClass = new SomeClass();
someClass.InternalElementName.ComplexElementTypeChild = "some string";
// serialize...
The strange thing is, this works fine in the debugger but no element is output in the XML. Non Lazy<T> elements work fine. Any ideas?

The problem is that the property has no setter. Even if it would be possible to get the value to serialise it, it can't be deserialised as there is no way to put the value back in the new object.

By design, XML Serialization will only serialize public read/write properties, and public fields.

Not sure what the problem is (I have always found the XML serializer behaviour to be shifty), but why not use the Nullable<T> class? Don't re-invent the wheel :)

Related

How to XMLSerialize member Object inside a container object

I've been searching on google about this for an hour but I think I don't use the right word because I can't find a very simple example of what I'm trying to do. People always use complexe structure like List or derived object in the samples.
All I want to do is to XMLSerialize my main object called SuperFile to a file. This SuperFile class contains 2 members and these 2 members are not serialized so the resulting XML file is empty (containing only the header).
Here is my code, what am I doing wrong?
SuperFile
public class SuperFile
{
private NetworkInfo _networkInfo;
private Planification _planification;
public NetworkInfo NI
{
get
{
return _networkInfo;
}
}
public Planification Planif
{
get
{
return _planification;
}
}
}
NetworkInfo and Planification are very normal class with mostly double member and they serialize perfectly on their own if I want. But now, I want them to serialize inside the SuperFile object.
Finally, here is my code to do the serialization
public void Save(string strFilename)
{
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(ExoFile));
TextWriter WriteFileStream = new StreamWriter(strFilename);
x.Serialize(WriteFileStream, this);
WriteFileStream.Close();
}
If I put this inside SuperFile, it get serialized but the 2 other member gets skipped. I think it get serialize since it's not a complex type...
public int _nDummy;
Hope it's clear!
Thanks!
XMLSerializer has some limitations, one of which is to require a setter. (It also doesn't serialise private fields, indexers..). It's not an obvious gotcha, and has had me scratching my head in the past :)
here's an answer with some details - Why isn't my public property serialized by the XmlSerializer?

C# Xml Deserialize plus design suggestions

In my project I need to build a generic deserializer that should be backward compatible.
Example: The XML looks like
<PolicyDef name = "sample" type="type1">
<Options ......>
</PolicyDef>
The "type" is enum - PolicyTypes
e.g
public Enum PolicyTypes
{
type1 = 0,
type2 = 1
}
The PolicyDef class is defined as
[XmlRoot("PolicyDef")]
public class PolicyDef
{
private string policyName;
private PolicyTypes policyType;
public PolicyDefinition()
{
}
[XmlAttribute]
public string Name
{
get
{
return this.policyName;
}
set
{
this.policyName = value;
}
}
[XmlAttribute]
public PolicyTypes Type
{
get
{
return this.policyType;
}
set
{
this.policyType = value;
}
}
}
The Problem with this approach is that if later on I put any type other than type 1 or type 2, the XMLDeserializer will throw exception.
so if i have the xml like
<PolicyDef name = "sample" type="type_new">
<Options ......>
</PolicyDef>
The deserializer will throw error as type_new not valid.
I was wondering if there is a way to hook into the deserializer process to catch that and set a default value rather than throw error. Say if there is any invalid value, then I would set that to "type1"
Or am open to suggestions regarding how to handle this problem
Thanks and Regards
This is possibly a duplicate of C# XML Deserialization W/ Default Values
Unfortunately it seems there is no way to fall back on default enum values during deserialisation. It will require slightly more work, but if you follow the linked example and implement IXmlSerializable in your PolicyDef class, you'll be able to implement the ReadXml method in a similar way (reflecting each of the properties using a try/catch block in order to check for a default value).
Hope that helps!
Thanks Chris for the suggestion, but I don't want end up writing the complete parsing code which could be messy if the XML and corresponding class is huge and complex. I anyway used a different approach.
I changed all the enum fields to string. In this case there would be no parsing error and then expose another property that would return the parsed value as enum and if the parsing fails, then return default enum value. E.g
private string policyName;
[XmlAttribute("Type")]
public string Type
{
private get
{
return this.policyType;
}
set
{
this.policyType = value;
try
{
this.PolicyType = (PolicyTypes)Enum.Parse(typeof(PolicyTypes), this.policyType);
}
catch(Exception)
{
this.PolicyType = PolicyTypes.DefaultPolicy;
}
}
}
public PolicyTypes PolicyType
{
get;
private set;
}
And use the class property to access the value rather than the xml attribute field.

WCF private member reference in DataContract class becomes NULL

I have a pecular problem in my WCF in the web services layer.
When I instantiate a private member (_Wagon) of my class (This instantiation is not null) in WCF, after few seconds, it's become null.
I've been trying to diagnose the problem, but no result so far.
So I'm turning to you people to help me solve this problem.
Thank you.
Hence there is my code :
[DataContract]
public class RemoteWagon
{
private readonly IWagon _Wagon;
public RemoteWagon(IWagon Wagon)
{
_Wagon = Wagon; //_Wagon isn't null here
}
~RemoteWagon()
{
Trace.WriteLine("Do nothing");
}
[DataMember]
public RemoteBreakpoint Breakpoint
{
set
{
if (value == null)
{
_Wagon.Breakpoint = null; //_Wagon member is NULL...
}
else
{
//... useless code in this context.
}
}
}
}
This would happen if your class had been serialized and deserialized by DataContractSerializer (for example when sending data between client and server)
Some reference: DataContractSerializer doesn't call my constructor?
If this is the case, then one possible solution, that worked for me: https://stackoverflow.com/a/9419943/724944
So a quick check&fix for this problem (I assume that you want to initialize the field yourself and not serialize it) would be to create method:
[OnDeserializing]
private void OnDeserializing(StreamingContext c)
{
_Wagon = initializeWagon();
}
however, as you probably noticed, you won't be able to pass Wagon during deserialization - you'll have to initialize it differently.
On the other hand, If you want _Wagon serialized, then expose it as public [DataMember] property
It seems that if you want _Wagon serialized you should mark it as a DataMember and ditch the "readonly" on it. If you don't want it serialized, show us your code to construct and fill this object.

Find out whether property setter is called in DeSerialization process

Is there a way to find out whether an object property is called as part of the DeSerialization process (e.g. by the XmlSerializationReaderXXX).
Background: A typical scenario is to disable events and complex operations in that case, until the initialization is complete.
One approach I have found, is to "interpret" the stack and look up whether the call is triggered by XmlSerializationReaderXXX, which is not so elegant IMHO. Is there anything better?
public SomeClass SomeProperty
{
get { ..... }
set
{
this._somePropertyValue = value;
this.DoSomeMoreStuff(); // Do not do this during DeSerialization
}
}
-- Update --
As Salvatore has mentioned, somehow similar to How do you find out when you've been loaded via XML Serialization?
I have a possible solution.
public class xxx
{
private int myValue;
[XmlElement("MyProperty")]
public int MyPropertyForSerialization
{
get { return this.myValue; }
set
{
Console.WriteLine("DESERIALIZED");
this.myValue = value;
}
}
[XmlIgnore]
public int MyProperty
{
get { return this.myValue; }
set
{
Console.WriteLine("NORMAL");
this.myValue = value;
}
}
}
class Program
{
static void Main(string[] args)
{
xxx instance = new xxx();
instance.MyProperty = 100; // This should print "NORMAL"
// We serialize
var serializer = new XmlSerializer(typeof(xxx));
var memoryStream = new MemoryStream();
serializer.Serialize(memoryStream, instance);
// Let's print our XML so we understand what's going on.
memoryStream.Position = 0;
var reader = new StreamReader(memoryStream);
Console.WriteLine(reader.ReadToEnd());
// Now we deserialize
memoryStream.Position = 0;
var deserialized = serializer.Deserialize(memoryStream) as xxx; // This should print DESERIALIZED
Console.ReadLine();
}
}
The trick is using the XmlIgnore, it will force the xml serializer to ignore our property, then we use XmlElement to rename the property for serialization with the name of the property we want.
The problem with this technique is that you have to expose a public property for serialization, and is in some way bad because it can virtually be called by everyone.
It will not work if the member is private, unfortunally.
It works, is not totally clean, but is thread safe and don't rely on any flag.
Another possibility is to use something like the Memento pattern.
Using the same trick you can add a property called for example Memento that returns another object that contains properties suitable only for serialization, it can makes things a little cleaner.
Did you think instead of changing approach and using DataContractSerializer? It is much more powerful and produces pure XML. It supports the OnDeserializationCallback mechanism.
Since you got a pretty complex scenario you might want to consider creating a "data core" class which will be actually serialized/deserialized using simple direct way. Then your complex object is constructed from that object and you fire all events/operations as normal. It will make sequence of deserialize -> fire events/operations more explicit and easier to understand.
There's an OnDeserializingAttribute/OnDeserializedAttribute attributes pair. You can set isDeserializing flag while object is being deserialized. I don't know if they play well with XML serialization, though.
For XML Serialization solution could be implementing IXmlSerializable and embedding such logic into the ReadXml()/WriteXml() method
To have finer control of the deserialization process you could implement IXmlSerializable interface for SomeClass - in ReadXML you can then for example have some field set a flag that you are in deserialization... this flag can then be checked in the respective methods... and on completion it needs to be reset.
Another option (though not for XML IIRC) is to implement the above via OnDeserializingAttribute and OnDeserializedAttribute .
I misunderstood the question at first, but you want to ask from within setter if you are called during deserialization. To do that, use a static flag:
[serializable]
class SomeClass
{
public static IsSerializing = false;
SomeProperty
{
set
{
if(IsSerializing) DoYouStuff();
}
}
}
and then set the flag just before the serialization:
try
{
SomeClass.IsSerializing = true;
deserializedClass = (SomeClass)serializer.Deserialize(reader);
}
finaly
{
SomeClass.IsSerializing = false; //make absolutely sure you set it back to false
}
Note that same approach can work even if you deserialize a class that contains a member of your class...
Set a breakpoint on the property, and run in debug mode. It will break at the point of access for the getter/setter that you set the breakpoint on.

Serializing an arraylist in C#

I have a class that contains a number of standard fields and an arraylist.
Is there any way to serialize the class using an XmlSerializer?
Attempts so far result in an error message saying:
Unhandled Exception: System.InvalidOperationException: There was an error
generating the XML document. ---> System.InvalidOperationException: The type
XMLSerialization.DataPoints was not expected. Use the XmlInclude or
SoapInclude attribute to specify types that are not known statically.
Some cut-down representations of the classes are shown below:
public class StationData
{
private DateTime _CollectionDate;
private string _StationID;
private ArrayList _PolledData;
public StationData()
{
}
public DateTime CollectionDate
{
get { return _CollectionDate; }
set { _CollectionDate = value; }
}
public string StationID
{
get { return _StationID; }
set { _StationID = value; }
}
[XmlInclude(typeof(DataPoints))]
public ArrayList PolledData
{
get { return _PolledData; }
set { _PolledData = value; }
}
}
public class DataPoints
{
private string _SubStationID;
private int _PointValue;
public DataPoints
{
}
public string SubStationID
{
get { return _SubStationID; }
set { _SubStationID = value; }
}
public int PointValue
{
get { return _PointValue; }
set { _PointValue = value; }
}
}
I have had success with the following:
[XmlArray("HasTypeSpecialisations")]
[XmlArrayItem("TypeObject", typeof(TypeObject), IsNullable = false)]
public List<TypeObject> TypeSpecialisations
This results in:
<HasTypeSpecialisations>
<TypeObject />
<TypeObject />
</HasTypeSpecialisations>
In your situation I would try something like:
[XmlArrayItem(typeof(DataPoints))]
public ArrayList PolledData
Based on this link http://msdn.microsoft.com/en-us/library/2baksw0z(VS.85).aspx you should also be able to use this
[XmlElement(Type = typeof(DataPoints))]
public ArrayList PolledData
The XmlSerializer generates some code at runtime to serialize your class. It is necessary for this class to know all types that can occur.
The ArrayList does not give this information, but you can give it by using a XmlInclude attribute on the property that returns the ArrayList.
[XmlInclude(typeof(DataPoints))]
public ArrayList Points {
...
}
You could also use the generic List<> class.
I think you could get around this by using a generic list (List<>) instead of an ArrayList, however, I'm going to assume you can't use generics for one reason or another.
You need to tell the compiler what type is contained in the ArrayList so it can serialize it since all it knows it that it contains objects.
Add this above your property and it should clear it up.
[System.Xml.Serialization.XmlInclude(typeof(XMLSerialization.DataPoints))]
Of course, replace XMLSerialization.DataPoints with whatever class is contained in the ArrayList.
Take a look at this article which describes the basic problem you are having and a solution around it (Like using the XmlInclude attribute). Basically what that says is that the serializer encountered a type it doesn't know how to serialize. If you post some code it would also help greatly.
The method I always used to serialize lists was to convert them to Arrays (which has the necessary type information). I admit this is a bit dirty, but if you can't get a proper list to serialize, this will work.

Categories

Resources