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.
Related
I'm refactoring a class that represents the data in some XML. Currently, the class loads the XML itself and property implementations parse the XML every time. I'd like to factor out the XML logic and use a factory to create these objects. But there are several 'optional' properties and I'm struggling to find an elegant way to handle this.
Let's say the XML looks like this:
<data>
<foo>a</foo>
<bar>b</bar>
</data>
Assume both foo and bar are optional. The class implementation looks something like this:
interface IOptionalFoo
{
public bool HasFoo();
public string Foo { get; }
}
// Assume IOptionalBar is similar
public class Data : IOptionalFoo, IOptionalBar
{
// ...
}
(Don't ask me why there's a mix of methods and properties for it. I didn't design that interface and it's not changing.)
So I've got a factory and it looks something like this:
class DataFactory
{
public static Data Create(string xml)
{
var dataXml = new DataXml(xml);
if (dataXml.HasFoo())
{
// ???
}
// Create and return the object based on the data that was gathered
}
}
This is where I can't seem to settle on an elegant solution. I've done some searching and found some solutions I don't like. Suppose I leave out all of the optional properties from the constructor:
I can implement Foo and Bar as read/write on Data. This satisfies the interface but I don't like it from a design standpoint. The properties are meant to be immutable and this fudges that.
I could provide SetFoo() and SetBar() methods in Data. This is just putting lipstick on the last method.
I could use the internal access specifier; for the most part I don't believe this class is being used outside of its assembly so again it's just a different way to do the first technique.
The only other solution I can think of involves adding some methods to the data class:
class Data : IOptionalFoo, IOptionalBar
{
public static Data WithFoo(Data input, string foo)
{
input.Foo = foo;
return input;
}
}
If I do that, the setter on Foo can be private and that makes me happier. But I don't really like littering the data object with a lot of creation methods, either. There's a LOT of optional properties. I've thought about making some kind of DataInitialization object with a get/set API of nullable versions for each property, but so many of the properties are optional it'd end up more like the object I am refactoring becomes a facade over a read/write version. Maybe that's the best solution: an internal read/write version of the class.
Have I enumerated the options? Do I need to quit being so picky and settle on one of the techniques above? Or is there some other solution I haven't thought of?
You can think of such keywords as virtual/castle dynamic proxy/reflection/T4 scripts - each one can solve the problem on a slightly different angle.
On another note, this seems perfectably reasonable, unless I misunderstood you:
private void CopyFrom(DataXml dataXml) // in Data class
{
if (dataXml.HasFoo()) Foo = dataXml.Foo;
//etc
}
What I did:
I created a new class that represented a read/write interface for all of the properties. Now the constructor of the Data class takes an instance of that type via the constructor and wraps the read/write properties with read-only versions. It was a little tedious, but wasn't as bad as I thought.
Give an object similar to:
public class MyObject : IInterfaceA
{
public IEnumerable<IInterfaceB> MyList{get; set}
public MyComplexObjectX{get; set;}
public MyComplexObjectY{get; set;}
}
which may have a fairly complex graph.
Does anybody know the best means of serializing this whereby namespace changes would not be an issue on deserialization? Would Json be the way to go perhaps?
Secondly there is also a good bit of use of lists of interfaces, generics etc. Im happy to use known types with DataContractSerializer but I think I will have the issue with namespace changes then.
Performance, size of serialized object etc are not an issue for me right now.
Thanks.
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 must structure new model for application and I don't what is better:
using inheritance or using enum as type of object:
For example :
Books
class Book
{
public string Name {get;set;}
public string Author {get;set;}
public int NumberOfPages {get;set;}
}
public class Encyclopedie:Book
{
}
public class Novel:Book
{
}
or better use:
class Book
{
public BookType Type {get;set;}
public string Name {get;set;}
public string Author {get;set;}
public int NumberOfPages {get;set;}
}
public enum BookType
{
Encyclopedie = 0,
Novel = 1,
...
}
Use inheritance if the different types have significant differences (how you process them and treat them). That is, if you are going to use polymorphism at all, you should use inheritance.
If you only need a way to distinguish different types of books, go with the Enum.
In true object oriented systems, the type of the object is transparent to the client. So the code which handles books should not know what the type of the book is, but only invoke methods on books.
So if you need to implement different behaviour within the book in response to the method invocation, extend Book and override some of its methods. If you don't, then don't.
It appears, given the empty bodies of your subclasses, that they behave in every way the same as books. So you are merely tagging the book with some additional data - the difference between Encyclopaedia and Novel is no more essential to the book than hardback or softback or large print or standard print - a client may use these differently, and each book either is a large print book or it is a standard print book, but these are all attributes of the book rather than essential differences.
I wouldn't necessary use an enum for the book kind, since you may want to add more data - I'd either use a loose tagging system, so you can tag a book with a collection of kinds - so you would have a book tagged as { 'children's', 'ornithological', 'encyclopaedia', } - or allow structure in the roles - so there is a role for 'children's ornithological encyclopaedia' created when it is required, but no fixed enumeration.
I would say that the 2nd would be better as you are not really extending the book class in your Encyclopaedia, there are no additional properties or functionality you need to give one book type over another.
"best" is subjective and heavily depending on the purpose of the class / model.
What is your goal? What do you want to achieve?
At best at this point I can say is, inheritance is useful when the derived class has some fairly unique properties - like Encyclopedie has properties explaining which type of Encyclopedie it actually is and those properties do not, in any way, belong to a novel.
It really depends. The first solution is better if you need to use Polymorphism. From my personal opinion, I prefer using inheritance.
If the different types of books will have different attributes you should definately use an inheritance model. This also allows for polymorphism, which is usually better
If they will all have the same attributes, you might as well go with the enum. But it all depends on the application.
I think you should make this choice based on what the book "purpose" is. If the books don't need any additional stuff (methods and properties....) enum should be enough. If you have to create a common behavior for every book and something else more specific for each book type you obviously need inheritance (abstract class "book", and concrete classes).
using an enum to "type" your object sounds a bit of "old C-style" programming.
I mean, it is ok, but when inheritance is available (you're using C#) it is generally a better choice. An enum generally introduces some "trouble" for example when serializing/deserializing data: what if an old version of your application uses a "newer" scenario in which a BookType has an unknown item? (backward/forward compatibility could be a requirement for your app)
Of course, you can handle this with a bounch of "if-then-else" but inheritance seems a cleaner choice in my point of view.
Bye!
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.