How to XMLSerialize member Object inside a container object - c#

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?

Related

Serialize a type with XmlSerializer by omitting it when it has a null field

Here's a self-contained sample program that demonstrates my question: https://gist.github.com/jennings/46c20733df559d02b9ad
I'm writing a type Maybe<T> which looks like this:
public struct Maybe<T> : IXmlSerializable where T : class
{
readonly T _value;
//...
}
Can I accomplish one of these two goals of the serialization?
If a property of type Maybe<T> is being serialized, do not emit the property at all if its _value is null (string properties seem to have this behavior).
Serialize the _value in place of the Maybe<T>.
So if a class using my type looks like this:
public class AnyRandomObjectUsingMyType
{
public Maybe<string> MaybeAString{ get; set; }
}
Then if MaybeaString._value is null, I want this when serialized:
<AnyRandomObjectUsingMyType>
</AnyRandomObjectUsingMyType>
I do not want either of these:
<AnyRandomObjectUsingMyType>
<MaybeAString xsi:nil="true" />
</AnyRandomObjectUsingMyType>
<AnyRandomObjectUsingMyType>
<MaybeAString></MaybeAString>
</AnyRandomObjectUsingMyType>
I don't want to configure the serialization on AnyRandomObjectUsingMyType because there will be many, many of those. I'd much rather have Maybe<T> control this so everywhere gets the same behavior.
Some context
The type Maybe<T> is meant as a drop-in replacement for a T. But we use XML serialization in several places. If there's an object like this:
// Version 1 class
public class SomethingBeingSerialized
{
public string SomeValue { get; set; }
}
When SomeValue is null, this class serializes to this:
<SomethingBeingSerialized>
</SomethingBeingSerialized>
I want to be able to change the class to this:
// Version 2 class
public class SomethingBeingSerialized
{
public Maybe<string> SomeValue { get; set; }
}
And I want the serialized representation to be identical. If a V1 app deserializes, it gets a null string. If a V2 app deserializes, it gets a Maybe<string> which represents None.
I've tried doing this in my IXmlSerializable.WriteXml method, but when it gets called, the XmlWriter seems to already have written this much to it's underlying stream:
<SomeValue
So it seems like by the time my WriteXml method gets called, it's too late. Maybe there's another way to control this?
If I could specify to the serializer: "As soon as you encounter an object of type Maybe<T>, serialize its _value property in place of the Maybe<T>", it would also accomplish my goal.
Do not make Maybe serializable, make it's container serializable. You can have an extension method for Maybe that builds an XML Node for it's value as you desire, and in the class that's being serialized would incorporate the return value of the extension method.
public static class MaybeMethods
{
public static string SerializeValue<T>(this Maybe<T> source)
{
// Do the work to serialize the value in Maybe
}
}
In your hosting classes's serialization method
public void WriteXml(XmlWriter writer)
{
var maybeXml = myMaybe.SerializeValue();
// if maybeXml is not null, include it in your writer
}

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.

C# need to pass an object so another class can call it's methods to update it

I have a class that has 3 public List's in it. It's basically just a data holding class.
I have a file with xml like delimiters(begging and ending tags of some sort, and data value that goes in between)
I have a parse class, that detects and adds certain things to certain lists from the data holding class. Basically I'm trying to detect an opening tag, store it in the opening tag List in my data holding class.
The way I'm trying to go (based on the teachers poor excuse for an example) is Main() instantiates the data holding class into an object, likewise for the parse class. Then it calls ParseMain to parse through the file and separate tags, data values, and closing tags to their respective List inside the data holding class. Then after the Parse class is finished, back in main, I'm calling up methods inside the data class to display the data.
I'm basically being yelled at by the compiler because, even though the xml data holder class has been instantiated in main, it doesn't or can't add to the public List's I get specifically this error
"An object reference is required for the non-static field, method, or property"
How can I set the data reading classes List's from my parse class?
My teacher gave a horrible example (he had everything but the classes marked static, and basically just slapped java/c++ style code into a couple classes)
This is all extra credit for a basic programming class I'm in.(the normal version is all structural inside one class)
***Edit- adding code snippets
XMLDoc XMLData = new XMLDoc();
XMLParse parseXML1 = new XMLParse();
//Calls the parseXML1 method passing it
//the name of the currently opened file.
parseXML1.MainParse(fileIn);
then to my main parse
public void MainParse(FileStream fileIn)
{
int byteIn;
while ((byteIn = fileIn.ReadByte()) != -1)
{
if (byteIn == '<')
{
ParseElement(ref byteIn,fileIn);
}
ParseElement looks like
public void ParseElement(ref int byteIn,FileStream fileIn)
{
token += byteIn;
//First I need to get the entire tag stored in token
do
{
byteIn = fileIn.ReadByte();
token += byteIn;
} while (byteIn != '>');
token += '>';
//now I insert a / into my compare token
compareToken = token;
compareToken.Insert(1,"/");
//It's an ending tag
if (token == compareToken)
{
//figure this out later
}
//It's an opening tag,store it into element list
else
{
XMLDoc.elements.Add(token);
//also tried XMLData/elements/Add(token)
}
}
and finally my XMLDoc class looks like....
class XMLDoc
{
public List<string> elements;
public List<string> dataValues;
public List<string> endingElements;
public XMLDoc()
{
elements = new List<string>();
dataValues = new List<string>();
endingElements = new List<string>();
}
//This method simply displays the contents of the arrays
public void DisplayCollected()
{
Console.WriteLine("Begin unformatted dump");
for (int ii = 0; ii <= elements.Count;ii++)
{
Console.WriteLine("\n"+elements[ii]+dataValues[ii]+
"\n"+endingElements[ii]);
}
Console.WriteLine("End unformatted dump\n");
}
//This method will generate an xml style display
//To add later
}
I'm playing around,learning by doing and such. I've at this point had to abandon the teachers example, as mentioned above he just made every method in every class static, probably because he slapped his example together from the main lab work(which is structural and all inside the first class)
EDIT: Okay, it looks like you just need to pass the reference to the object around, e.g.
XmlDoc xmlData = new XmlDoc();
XmlParser parser = new XmlParser();
parser.MainParse(xmlData, fileIn)
...
public void MainParse(XmlDoc xmlData, FileStream fileIn)
{
...
ParseElement(xmlData, ref byteIn, fileIn);
...
}
public void ParseElement(XmlDoc xmlData, ref int byteIn,FileStream fileIn)
{
...
}
I've adjusted the names slightly to be more sensible IMO.
I would recommend that you don't use public fields in XmlDoc, by the way. Public fields violate encapsulation - use properties if you really need to just expose values, but ideally put more behaviour in the object itself.
The error message is pretty good here: "An object reference is required for the non-static field, method, or property"
You are trying to call an instance method in a static fashion, you have two options:
Make the method static.
Instantiate the class and call the method from the instance.
For example:
public class Foo()
{
public void Frob() {}
}
You cannot do this:
Foo.Frob();
But you can do this:
var foo = new Foo();
foo.Frob();
or this:
public class Foo()
{
public static void Frob() {} // Note static
}
[...]
Foo.Frob();

XML serialisation won't write out lazy-evaluated property

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 :)

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