In my project I receive an XmlElement of which I have to parse a few properties back to a class.
For mapping these I use the XmlConvert class. But the source being XML there often are empty nodes or nodes that are not readable. Rather then throwing a bunch of errors, I want to get a NULL back to store in my class.
I started making an XmlConvertExtentions class that does things in the following spirit:
public static class XmlConvertExtentions
{
public static int? ToNullableInt32 (this XmlConvert c, string s){
try{ return XmlConvert.ToInt32(s); }
catch{ return null; }
}
}
I strongly believe that I'm not the first developper in need of such a functionality and I'm wondering if I'm not inventing yet another wheel.
Furthermore I feel like I'm inventing a really ugly wheel. The try catch feels bad. Is there a better way?
--EDIT--
And now I also noticed that it doesn't even work :P
I think it's because you can't extend static classes.
If the node is null or empty, what is s?
How about just:
if(string.IsNullOrEmpty(s)) return null;
return XmlConvert.ToInt32(s);
Note also that LINQ-to-XML has more graceful handling of these conversions (via casts).
I don't know if it is possible in your case / situation, but have you already though on using the XML serialization classes, and deserialize the XML by the XmlSerializer classes directly into instances of your custom class, instead of doing it all manually ?
Related
We have some document-types:
class Document
{
public void virtual Print()
}
class PDF : Document
{
public void override Print()
{
Console.WriteLine("PDF Printed");
}
}
class Excel : Document
{
public void override Print()
{
Console.WriteLine("Excel Printed");
}
}
Suppose we have a list of documents (Document objects) and we call the virtual function Print() on all of them.
foreach(Document doc in DocumentsList)
{
doc.Print();
}
I know Polymorphism is much sophisticated way of implementing it but can we really do the same using switch statement as well? I had a long argument with a fellow on it and he says it's possible. Is it?
Yes, you can always use a switch (or an if-else chain), asking for the type. You can keep document type information in your object, for example as an enum, and use it in a switch.
Why you shouldn't do that? Because you have to extend all these switches when you add a new derived type.
To avoid that, you can implement something more automatic: Have a list of pointers to functions (or delegates in C#) which you fill for each single object with the functions suitable for this particular object (for example, the print delegate would point to print_pdf() for PDF files and to print_excel() for excel files). And hey, there you have hand-crafted a poor man's polymorphism.
The sweet thing about polymorphism is that the code using a polymorphic object can be type agnostic. It does not know what precise type the object actually has, and does not want to know. The precise type may not have existed back when the code handling the object was written. All the detail information is hidden within the type which is awesome for maintenance.
Yes you can, of course you can interrogate the member of the list on each iteration, and there are plenty of techniques that can achieve this (e.g attributes, internal Type field etc).
In fact everything you do in C# you can also do in Assembler!
However I can hardly see any benefit of avoiding the advantages of OOP.
Its a bit of a funny question, because the example using the switch is usually used to demonstrate how you usually dont want to do it.
Instead of using inheritance, you could have your document class like this:
class Doc {
public:
enum DocType{PDF,EXCEL}
private:
DocType docType;
}
And then you simply use
switch (doc.getDocType()){
...etc...
}
However, there are several reasons why usually it is nicer to use inheritance. Imagine for example, you want to add another document type. Then not only you have to add another enum field, but (and here comes the big problem) you also would have to change every single switch statement in all code that is using your Document class. That is annoying and usually you do not want to do this.
Polymorphism is the way to go for this. If you choose switch statement, you would need to use Reflection or is keyword to figure out which object's Print() you want to invoke.
I am working on a program, where I save it's project files by serializing Project class.
Because I am still working on it, some classes, that are part of Project class, do change from time to time (e.g. class got new property). It makes "simple" deserialization impossible.
Is there any way to solve it ? I mean, without writng custom serializer ? (which probably is something high above my level for now)
Just in case, I am using BinaryFormatter.
I hope I understood your problem correctly. You have a class serialized to a file which you have since changed in the program (e.g you have added another property). Now you want to deserialize this class from the file. This is not a problem as long as you have only added new properties. They will be ignored by the deserializer. It creates a new instance of your class (that is the reason why serializable classes have to have a default constructor) and tries to fill the properties it finds in the stream to derserialize. If you change a property's type or remove a property, you won't be able to deserialize the original file.
One workaround for removing properties is to keep them in the class, but just stop using them in the rest of the program. A workaround for properties that have been changed to a different type could look something like this:
[Serializable]
public class MyClass
{
int? newProperty;
[XmlElement("Property")]
public string OldProperty
{
get { return string.Empty; }
set
{
if (!newProperty.HasValue)
{
int temp;
if (int.TryParse(value, out temp))
{
newProperty.Value = temp;
}
}
}
}
public int NewProperty
{
get { return newPropery.HasValue ? newProperty.Value : 0; }
set { newProperty.Value = value; }
}
}
From my experience, I've found using BinaryFormatter for serialization/de-serialization of data types that are going to change a really bad idea. If something changes in your data type, from what I know the BinaryFormatter will fail in the process.
To overcome this issue in the data types I was using, I had to write my own serializer, which wasn't actually that much of a major task. You can use the BinaryReader and BinaryWriter classes to read and write the data in and out of your type. That way you can control the data you are expecting and handle any missing data either by adding default values, skipping the property altogether, or throwing some form of Exception to signify corrupt data. Refer to the MSDN article links above for more information.
With help from Merlyn Morgan-Graham's comments I've found solution, that will work for me.
Versioning described in Version Tolerant Serialization is really good idea, but when I use only [Serializable] attribute.
I forgot to write (my mistake), that I am using ISerializable interface.
I've found, that in deserialization constructor SerializationInfo object has MemberCount property, which solves my problem if I only add new properties/members from time to time. With this information, new members/properties, that can't be deserialized from older file, can be set to default or maybe I can use some prompt form.
Other way here would be using something like assembly version in deserialization, as a first deserialized member. This can solve deserialization problems with more complex class changes.
Either way, I agree with Merylin - "if you can't script something, you shouldn't be building it". ;)
I've run into what i belive could be a major issue for my code design and i was hoping someone here could explain to me how i would work around the issue.
I have 2 classes which each have a property of the other class creating a circular reference. I plan on serializing these classes and using XSLT to format the output but i'm assuming this will fail due to the circular reference.
Example
public class Book
{
public BookShop TheShop = new BookShop();
}
public class BookShop
{
list<Book> Books = new list<Book>();
}
So from this example each book will be in a bookShop and each bookshop will have many books. If i serialize the bookshop it will then serialize each book which then serialize a bookshop and so on round and round. How should i handle this?
Tag TheShop with an attribute to prevent its serialization.
[XmlIgnore] with the default serializer.
http://www.codeproject.com/KB/XML/GameCatalog.aspx
Probably just a problem with your example, not your real code: Don't use public fields but properties. I think XmlSerializer doesn't even serialize public fields.
Add [XmlIgnore] to the TheShop property to prevent it from being serialized.
You can then set it manually when deserializing.
Best practice would be to have the BookShop class implement an interface (IBookShop) and then have the Book class store the interface not the concrete class. You should also make BookShop into a property in the Book class:
public class Book
{
public Book(IBookShop bookShop)
{
TheStop = bookShop;
}
[XmlIgnore]
public IBookShop TheShop { get; set; }
}
public interface IBookShop
{
void SomeMethod();
}
public class BookShop : IBookShop
{
list<Book> Books = new list<Book>();
public void SomeMethod()
{
}
}
If you're going to use System.Xml.Serialization.XmlSerializer, you should decorate TheShop with System.Xml.Serialization.XmlIgnoreAttribute:
public class Book
{
[System.Xml.Serialization.XmlIgnore]
public BookShop TheShop;
}
That is, assuming the BookShop is the root object you wish to serialize. MSDN
First you need to check whether this is really a problem. If you always care about a bookshop when you have a book, and you always care about all the books a bookshop has, then it's perfectly sensible to have the whole graph serialised. This doesn't result in an infinite loop, because the serialisation uses an identifier to indicate a reference to an object already serialised (there is a bug if you do an XML serialisation of a graph with a circular reference in its types, but that's a bug rather than inherent to the problem of serialising XML, as the fact that it can be resolved proves, see Why do I get a "System.StackOverflowException was unhandled " exception when serializing? on that).
So, maybe you don't want to do anything here at all, and you're fine as you are.
Otherwise, the question is - just what do you want to serialise? Most suggestions so far have been to not serialise the TheShop property. This could be fine, or it may be useless if you will need to later access that shop.
If you have some sort of identifier (id number, uri) for each shop, then you could perhaps memoise - access to TheShop looks first at whether a private _theShop is null, and if it is, loads the relevant object into _theShop based on that identifier. Then you just need to serialise the identifier, not the full object.
Finally, if you are using XSLT to format the output to some other specification (whether XHTML for display, or something else) you may find it simpler just to roll your own XML serialisation. While this is a more complicated task in many ways, the fact that the XML produced by serialisation isn't particularly convenient for reformatting for display may mean that overall it's simpler this way. Indeed, if this is your only reason for serialising (you will never deserialise from the XML produced) then it may be much easier, as you need only consider what the XML for display needs, and not worry about anything else. Hence serialising may not be the best approach at all, but simply a ToXml() method, or a WriteBookToXml() method in another class.
Is it somehow possible to use the XmlSerializer to deserialize its data into an existing instance of a class rather than into a new one?
This would be helpful in two cases:
Easily merge two XML files into one object instance.
Let object constructer itself be the one who is loading its data from the XML file.
If the is not possible by default it should work by using reflection (copying each property after the deserialisation) but this would be an ugly solution.
Basically, you can't. XmlSerializer is strictly constructive. The only interesting thing you can do to customize XmlSerializer is to implement IXmlSerializable and do everything yourself - not an attractive option (and it will still create new instances with the default constructor, etc).
Is xml a strict requirement? If you can use a different format, protobuf-net supports merging fragments into existing instances, as simply as:
Serializer.Merge(source, obj);
I think you're on the right track with the Reflection idea.
Since you probably have a wrapper around the XML operations anyway, you could take in the destination object, do the deserialization normally into a new object, then do something similar to cloning by copying over one by one only the properties holding non-default values.
It shouldn't be that complex to implement this, and it would look to consumers from the rest of your application just like in-place deserialization.
I hit the same problem a few weeks ago.
I put a method Deserialize(string serialized form) in the ISelfSerializable interface that an entity class of mine implemented. I also made sure the interface forced the class to have a default constructor.
In my factory I created an object of that type and then deserialized the string into it.
This is not thread safe thing to do... But you can do:
[Serializable]
public class c_Settings
{
static c_Settings Default;
public static SetExistingObject(c_Settings def)
{
Default = def;
}
public string Prop1;
public bool Prop2;
public c_Settings()
{
if (Default == null)
return;
MemberInfo[] members = FormatterServices.GetSerializableMembers(typeof(c_Settings));
FormatterServices.PopulateObjectMembers(this, members, FormatterServices.GetObjectData(Default, members));
}
}
This way you feed your object to deserialiser and deserialiser only overwrites whatever is written in .xml.
Following on from my recent question on Large, Complex Objects as a Web Service Result. I have been thinking about how I can ensure all future child classes are serializable to XML.
Now, obviously I could implement the IXmlSerializable interface and then chuck a reader/writer to it but I would like to avoid that since it then means I need to instantiate a reader/writer whenever I want to do it, and 99.99% of the time I am going to be working with a string so I may just write my own.
However, to serialize to XML, I am simply decorating the class and its members with the Xml??? attributes ( XmlRoot , XmlElement etc.) and then passing it to the XmlSerializer and a StringWriter to get the string. Which is all good. I intend to put the method to return the string into a generic utility method so I don't need to worry about type etc.
The this that concerns me is this: If I do not decorate the class(es) with the required attributes an error is not thrown until run time.
Is there any way to enforce attribute decoration? Can this be done with FxCop? (I have not used FxCop yet)
UPDATE:
Sorry for the delay in getting this close off guys, lots to do!
Definitely like the idea of using reflection to do it in a test case rather than resorting to FxCop (like to keep everything together).. Fredrik Kalseth's answer was fantastic, thanks for including the code as it probably would have taken me a bit of digging to figure out how to do it myself!
+1 to the other guys for similar suggestions :)
I'd write a unit/integration test that verifies that any class matching some given criteria (ie subclassing X) is decorated appropriately. If you set up your build to run with tests, you can have the build fail when this test fails.
UPDATE: You said, "Looks like I will just have to roll my sleeves up and make sure that the unit tests are collectively maintained" - you don't have to. Just write a general test class that uses reflection to find all classes that needs to be asserted. Something like this:
[TestClass]
public class When_type_inherits_MyObject
{
private readonly List<Type> _types = new List<Type>();
public When_type_inherits_MyObject()
{
// lets find all types that inherit from MyObject, directly or indirectly
foreach(Type type in typeof(MyObject).Assembly.GetTypes())
{
if(type.IsClass && typeof(MyObject).IsAssignableFrom(type))
{
_types.Add(type);
}
}
}
[TestMethod]
public void Properties_have_XmlElement_attribute
{
foreach(Type type in _types)
{
foreach(PropertyInfo property in type.GetProperties())
{
object[] attribs = property.GetCustomAttributes(typeof(XmlElementAttribute), false);
Assert.IsTrue(attribs.Count > 0, "Missing XmlElementAttribute on property " + property.Name + " in type " + type.FullName);
}
}
}
}
You can write unit tests to check for this kind of thing - it basically uses reflection.
Given the fact this is possible I guess it would also be possible to write a FxCop rule, but I've never done such a thing.
You can write an FxCop rule or even check for the attributes by calling GetType() in the base class's constructor and reflecting over the returned type.
A good FXCop rule (and one which I am finding I need right now) would be to check that all objects that are being added to the ASP.NET Session have the Serializable attribute. I'm trying to move from InProc session state to SQL Server. First time I requested a page, my site blew up on me because non-serializable objects were being stored in Session. Then came the task of hunting through all the source code looking for every instance where an object is set in the Session... FXCop would be a nice solution. Something to work on...
You can also use this concept/post-processor to enforce relationships between attributes and use similar login to enforce relationships between classes and attributes at compile time:
http://www.st.informatik.tu-darmstadt.de/database/publications/data/cepa-mezini-gpce04.pdf?id=92