In my application I use a list of objects implementing my ISorter interface with exposes a single method void Sort(MyClass myClass)
So far ive created this list at the entry point on my application with a hardcoded set of ISorter implementations. Now im at the point where I'd like to be able to save and load this list from file.
I'd like the format to be XML so that it can be hand edited, but i discovered that .NET XMLSerializer class cannot serialize Interfaces. It can serialize a list of base classes, providing I mark the baseclass with the appropriate attributes:
[System.Xml.Serialization.XmlInclude(typeof(MyClassA))]
[System.Xml.Serialization.XmlInclude(typeof(MyClassB))]
class MyBaseClass
I dislike this, as it clutters my class with xml specific attributes, when i may wish to replace xml serialization with a different storage method later.
What is the downside to replacing my ISort interface with a SortBase baseclass, to facilitate serialziation? Is the use of an interface here wrong to begin with? Should i keep the interface, but implement it using a SortBase class from which all my other classes derive?
How could I abstract the storage so that the storage implementation could be changed later, and avoid decorating my classes with xml attributes?
Any additional information on best practices pertaining to datastorage/loading would be helpful
EDIT: The idea is that a user can create an text file (atm XML is preferred) specifying sorting operations which can the be loaded and applied to the data set.
EDIT2: I have, simplified, this situation
class Foo{
List<ISorter> MySorters
}
interface ISorter{
void Sort(MyClass myClass)
}
class SortByColor : ISorter{
public string SomeColorProperty{get;set;}
void Sort(MyClass myClass)
}
class SortByName: ISorter{
public string SomeNameProperty{get;set;}
void Sort(MyClass myClass)
}
Id like to pass my List to some storage/loading method which can create/load the list from some underlaying datasource ( for example an XML file)
EDIT3:
Ill probably end up using DataContractserializer, or XMLSerializer as this solves my issue, as long as i provide a common base class. I had expected there to be some more elegant way this could be handled, without polluting my objects with attributes
Related
Purpose
How do I through any method, for the purposes of a unit test, make sure that a derived class does not refer to any properties in the base class? I understand that Reflection won't cut it, here. Could I create a mock of the base class somehow and observe if a property is called at the wrong time? Or any other way?
Background
I have a series of classes that are participating in serialization. There is a natural hierarchy of parts and pieces, so that for example, a Chunk1 knows how to serialize itself (starting, ending, delimiters) but will delegate the serialization of its inner parts to a Blob that itself serializes several lines.
Here is the interface that all the parts implement:
public interface ICoolSerializable {
void Serialize(Writer w);
}
And given this desired serialization result:
Chunk1:/Line1
/Line2
There is a Chunk1 class that is responsible for "Chunk1:" and inherits from the Blob class, which in turn is responsible for "/Line1", the newline, and "/Line2". (Both implement ISerializable.)
Note: please assume for the sake of the question that I truly do want an is-a relationship, and it is correct for the Chunk1 to inherit from the Blob (the Blob can be used in many different chunks, and the Chunk1 just determines how the Blob is interpreted, but not how it is serialized beyond the initial label).
The Problem
I see a potential gotcha for me or another developer in the future writing more classes like this and attempting to copy the pattern. Since the constructor of Chunk1 accepts an IEnumerable of Line items to pass to its base Blob, the developer will have in mind how the base is constructed, and might easily make this mistake in the Chunk1 serialize method:
public override void Serialize(Writer w) {
w.Write("Chunk1:");
w.WriteEnumerable(Lines); // wrong, this is a forbidden base.Lines!
}
This would yield the wrong serialization result (missing the slashes):
Chunk1:Line1
Line2
Full disclosure: I did make this mistake, and then initially "fixed" it by writing "/" before each Line from the derived class. Of course, the moment another class inherited from the base, it also was missing the slashes—I'd fixed it the wrong way.
The Question
So how can I inspect the Serialize method or take any other measure to ensure that base.Lines is never accessed from within it? Instead of the wrong way above, it needs to work like this:
public override void Serialize(Writer w) {
w.Write("Chunk1:");
base.Serialize(w); // Remember to let the superclass decide how to serialize itself
}
This pattern is not global throughout. Not all classes implementing my ICoolSerializable interface have sub-parts, nor do all of them inherit from anything else. In some cases, it may make sense to wrap another class instead of subclass from it.
Some Thoughts
For those interested, since strings are implicitly convertible to ICoolSerializable, I wish I could do this:
public override void Serialize(Writer w) {
w.WriteCoolSerializables,
"Chunk1:",
base
}
}
However, base here cannot refer to the base instance, and if I cast the current class as its parent, it still wouldn't work because the derived Serialize method (it's override!) would be called and thus cause a loop, eventually resulting in a stack overflow.
Update
I suspect that the right answer will be refactoring, but I'm not sure how that refactoring will work right now. I suspect that I may lean more heavily on Reflection, and on the serialization process working through properties or a returned series of property-or-value-accessing objects, rather than on a procedural statement. This would enable the property-accessing-objects to be inspected to see what they're referring to. This could also enable the parent class to indicate (through attributes or an attribute-like method that returns information) how it relates to any child class, a sort of template that says "the child class may only hook onto my serialization components at the head", which can then be enforced.
In this case I wouldn't make your Serialize method inheritable.
protected void SerializeCore(Writer w) { }
public void Serialize(Writer w) {
SerializeCore(w);
...
}
This way you control how your base class is serialised. If you want to be stricter you could use reflection with attributes to perform serialisation.
Example base class for the attributes:
public abstract class CustomSerializeAttribute : Attribute
{
public abstract void SerializeProperty(Writer w, object value);
}
Make the properties in the base class private.
If you are willing to wrap the functionality provided by your properties with functions, you could check the caller's source file against a blacklist or whitelist of which files can't/can contain code that accesses those properties.
Within the Blob implementation, for each property (wrapper) you want to monitor you can do something along these lines:
public int GetExampleProp([System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "")
{
CheckCaller(sourceFilePath);
return ExampleProp;
}
public void SetExampleProp(int value, [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "")
{
CheckCaller(sourceFilePath);
ExampleProp = value;
}
and then check if the call is valid in CheckCaller
private void CheckCaller(string path)
{
if (!_whitelist.Contains(path)) {
// report error
}
}
I have a class generated by Linq2Sql:
public partial class BuyerOrder : INotifyPropertyChanging, INotifyPropertyChanged
I want to clone object of this class, like it's done in this post. For this purpose I define the partial class in not generated file, which I mark as serializable:
[Serializable]
public partial class BuyerOrder
But when I'm calling
formatter.Serialize(stream, source);
I'm getting an exception, saying that this class is not marked as serializable. What am I doing wrong?
If you want to serialize a LINQ-to-SQL type, then tell the code-gen to emit serializable data. You can do this in the DBML, or more simply in the designer - just set the serialization mode to unidirectional (this is the #Serialization attribute on the root <Database> element in the DBML).
This will generate attribute markers suitable for use with DataContractSerializer; LINQ-to-SQL is designed to be serializable with DataContractSerializer. It is not designed to be serializable with BinaryFormatter.
Every class derived from BuyerOrder must also be decorated as [Serializable], as well as all objects that the serializing instance holds a reference to (unless decorated as NonSerializable).
The exception should tell you the type that is missing the serializable attribute. If you can not or do not want to decorate all the classes you will need to get a little more creative.
-- The other possibility --
One option is to use the technique described in Implementing a generic deep-clone for C# objects. Since this can be done entirely in memory and without a binary formatter it will perform many times faster than serialization based cloning.
The source code is located at http://csharptest.net/browse/src/Library/Cloning
It only takes two lines of code:
using (ObjectCloner cloner = new SerializerClone())
fooCopy = cloner.Clone(foo);
I have around 50 classes in polymorphic, inheritance relation. I used XmlSerializer to serialize them. Now for few classes I want to implement IXmlSerializable. So I started for one of class.This class not base class but derived directly from base class of all polymorphic relation.
After implementation, resultant XML contains tags only for above class which I have written in WriteXML method. There is no information for other classes. Very strange behavior!!!!
So please guide me to solve this issue, so that other classes information would maintain.
As I understand you correct - your xml contains properties that you implicit add in WriteXML (of current class)? But it is correct behavior. You should implicit add item as in example in description of interface.
If you need properties of base classes - add them. if you need properties of classes that inherit from this class - try to get them via reflection. Get Property Names using Reflection . But instead of typeof(MyClass) use .GetType() and check there how to get properties values.
Similar questions here and there.
End the ReadXml(XmlReader reader) method with the line
reader.Read();
seams to solves the problem...
I often find myself in a quandary in where to put serialisation code for a class, and was wondering what others' thoughts on the subject were.
Bog standard serialisation is a no brainer. Just decorate the class in question.
My question is more for classes that get serialised over a variety of protocols or to different formats and require some thought/optimisation to the process rather than just blindly serialising decorated properties.
I often feel it's cleaner to keep all code to do with one format in its own class. It also allows you to add more formats just by adding a new class.
eg.
class MyClass
{
}
Class JSONWriter
{
public void Save(MyClass o);
public MyClass Load();
}
Class BinaryWriter
{
public void Save(MyClass o);
public MyClass Load();
}
Class DataBaseSerialiser
{
public void Save(MyClass o);
public MyClass Load();
}
//etc
However, this often means that MyClass has to expose a lot more of its internals to the outside world in order for other classes to serialise effectively. This feels wrong, and goes against encapsulation. There are ways around it. eg in C++ you could make the serialiser a friend, or in C# you could expose certain members as an explicit interface, but it still doesn't feel great.
The other option of course, is to have MyClass know how to serialize itself to/from various formats:
class MyClass
{
public void LoadFromJSON(Stream stream);
public void LoadFromBinary(Stream stream);
public void SaveToJSON(Stream stream);
public void SaveToBinary(Stream stream);
//etc
}
This feels more encapsulated and correct, but it couples the formatting to the object. What if some external class knows how to serialise more efficiently because of some context that MyClass doesn't know about? (Maybe a whole bunch of MyClass objects are referencing the same internal object, so an external serialiser could optimise by only serialising that once). Additionally if you want a new format, you have to add support in all your objects, rather than just writing a new class.
Any thoughts? Personally I have used both methods depending on the exact needs of the project, but I just wondered if anyone had some strong reasons for or against a particular method?
The most flexible pattern is to keep the objects lightweight and use separate classes for specific types of serialization.
Imagine the situation if you were required to add another 3 types of data serialization. Your classes would become quickly bloated with code they do not care about. "Objects should not know how they are consumed"
I guess it really depends on the context in which serialization will be used and also on limitations of systems using it. For example due to Silverlight reflection limitations some class properties need to be exposed in order for serializers to work. Another one, WCF serializers require you to know possible runtime types ad-hoc.
Apart from what you pointed out, putting serialization logic into the class violates SRP. Why would a class need to know how to "translate" itself to another format?
Different solutions are required in different situations, but I've mostly seen separated serializers classes doing the work. Sure it required exposing some parts of class internals, but in some cases you'll have to do it anyways.
When employing custom attributes to store meta-data, is it best to decorate the interface, or the class that implements the interface, assuming that any class that implements the interface would have the same data in the attribute?
Update: Basically i'm writing a custom data storage mechanism for a project, and the objects represent the various tables being stored. The custom attribute is used to designate which table in the dataset is used to store the objects of that class, and also to identify which tables are involved in a n:m relationship.
So if i put the attributes on the interface, is this a clearer approach, or does it clutter the interface and make accessing the data itself more cumbersome?
It depends on the scenario. WCF, for example, decorates interfaces for the operation contracts.
However, if you are going to be talking about objects (rather than the interface itself), note that it can be painful for calling code to get hold of interface metadata, especially if the class uses explicit interface implementation.
It would be more common to decorate the class, but that isn't quite the same question ;-p
If the attribute really is specific to the interface (not the instances), then fine - decorate the interface and talk about typeof(IFoo) etc. But if you expect code to be able to set per-type values for the attributes, it will have to be at the class level.
What is the scenario?
Well it depends on whether or not the interface has anything to do with the metadata.
interface IRunnable
{
void Run();
}
class Test : IRunnable
{
public void Run() { }
}
In this example it would make sense to put the attributes on the interface if they pertain to the intent of the interface. If the attributes are applicable across all implementations then put the attributes on the interface.
However if the attributes have nothing to do with the "runnability" (with "runnability" pertaining to IRunnable not the CLR) of the class then put the attributes on the class.