The book CLR Via C# presents a simple way to clone objects via binary serialization.
It specifies StreamingContextStates.Clone when creating the BinaryFormatter like so:
var formatter = new BinaryFormatter
{
Context = new StreamingContext(StreamingContextStates.Clone)
};
The documentation for StreamingContextStates.Clone says that it
Specifies that the object graph is being cloned. Users can assume that the cloned graph will continue to exist within the same process and be safe to access handles or other references to unmanaged resources.
Well fair enough - but I don't really know what this actually means. In what way does this actually change the behaviour of the BinaryFormatter? Can anyone list any concrete effects that using this flag has?
Serialization is the subject here.
MS provided an "abstract" mini-framework to allow serialization of objects.
Binary formatter is a specific implementation of that mini-framework concepts.
A developer may choose to use that framework concepts to create his own custom formatter - or -
MS itself when creating the mini-framework thought of further implementation of serialization.
So they provided those flags as part of the framework.
To answer your specific question: those flags will not have any effect to binary formatter as it is already implemented as a tool (if you like) to track the object graph and simply convert it into bytes of raw data.
If you create your own serializer which in example can save the object to a database or to a file or to shared memory or whatever - you would want the user who using your serializer to specify the corresponding flag.
Unless I totally misunderstood MS devs since 2003 .. :) (which is possible!)
Related
If I want to serialize an object I have to use [Serializable] attribute and all member variables will be written to the file. What I don't know how to do versioning e.g. if I add a new member variable (rename a variable or just remove a variable) and then I open (deserialize) the file how can I determine the object/file version so I can correctly set the new member or take some kind of migration? How can I determine that the variable was initialized during the load or not (ignored by deserializer).
I know that there are version tolerant approaches and I can mark variables with [OptionalField(VersionAdded = 1)] attribute. If I open an old file the framework will ignore this optional (new variable) and it will be just zero/null. But again how can I determine if the variable is initialized by load or it was ignored.
I can write the class/object version number to the stream. Use the ISerializable approach and in the constructor(SerializationInfo oInfo, StreamingContext context) method read this version number. This will exactly tell me what is the class version in the stream.
However I expected that such kind of versioning is already implemented by the streaming framework in C#. I tried to obtain the Assembly version from the SerializationInfo but it is always set to current version not to the version which was used when the object was saved.
What is the preferred approach? I found a lot of articles on the net, but I could not find a good solution for this which addresses versioning...
Any help is appreciated
Thanks,
Abyss
Forgive me if some of what I write is too obvious,
First of all, please! you must stop thinking that you are serializing an object...
That is simply incorrect as the methods which are part of your object are not being persisted.
You are persisting information - and so.. DATA only.
.NET serialization also serializing the type name of your object which contain the assembly name and its version, so when you deserialize - it compares the persisted assembly information with the type that will be manifested with the information - if they are not the same it will return an exception.
Beside the versioning problem - not everything can be serialized so easily.. try to serialize a System.Drawing.Color type and you will begin to understand the problems with the over simplistic mechanism of .NET serialization.
Unless you plan to serialize something really simple which has no plans to evolve I wouldn't use the serialization mechanism provided by .NET.
Getting the focus back to your question, you can read here about the versioning ignorance ability:
http://msdn.microsoft.com/en-us/library/ms229752(v=vs.80).aspx which is provided for BinaryFormatter.
You should also check XML Serialization which has some nice abilities, but the biggest benefit is that you getting an XML which is Human readable so your data will never be lost even if you had complication with the versioning of your types.
But finally, I recommend you either use Database with Entity Framework to persist your data or write your own flat file manager.. while EF is very good for most solutions, sometime you might want something lighter to persist something very simple.
(my imply is that I can no longer see a solution where .NET serialization can be relevant.)
I hope this helps, Good luck.
Based on my understanding, SerializableAttribute provides no compile time checks, as it's all done at runtime. If that's the case, then why is it required for classes to be marked as serializable?
Couldn't the serializer just try to serialize an object and then fail? Isn't that what it does right now? When something is marked, it tries and fails. Wouldn't it be better if you had to mark things as unserializable rather than serializable? That way you wouldn't have the problem of libraries not marking things as serializable?
As I understand it, the idea behind the SerializableAttribute is to create an opt-in system for binary serialization.
Keep in mind that, unlike XML serialization, which uses public properties, binary serialization grabs all the private fields by default.
Not only this could include operating system structures and private data that is not supposed to be exposed, but deserializing it could result in corrupt state that can crash an application (silly example: a handle for a file open in a different computer).
This is only a requirement for BinaryFormatter (and the SOAP equivalent, but nobody uses that). Diego is right; there are good reasons for this in terms of what it does, but it is far from the only option - indeed, personally I only recommend BinaryFormatter for talking between AppDomains - it is not (IMO) a good way to persist data (to disk, in cache, to a database BLOB, etc).
If this behaviour causes you trouble, consider using any of the alternatives:
XmlSerializer, which works on public members (not just the fields), but demands a public parameterless constructor and public type
DataContractSerializer, which can work fully opt-in (using [DataContract]/[DataMember]), but which can also (in 3.5 and above) work against the fields instead
Also - for a 3rd-party option (me being the 3rd party); protobuf-net may have options here; "v2" (not fully released yet, but available as source) allows the model (which members to serialize, etc) to be described independently of the type, so that it can be applied to types that you don't control. And unlike BinaryFormatter the output is version-tolerant, known public format, etc.
We have a project which uses serialization by implementing ISerializable and using BinaryFormatter. We are moving to .net compact which do not have BinaryFormatter class. I was wondering if we can use ProtoBuf-Net. Can we instruct ProtoBuf-Net to use GetObjectData() for serialization? Specifically, I want to find out how to use Serializer.Serialize(SerializableInfo, ISerializable) function.
Added
I looked at the source code and I see that though the function
Serializer.Serialize(SerializableInfo, T t) where T is ISerializable
doesn't use the constraint T is ISerializable at all. Why was T declared to be ISerializable?
The ISerializable support exists (at the moment) as a mechanism for injecting protobuf-net into the middle of existing APIs that use BinaryFormatter - for example, you can do this to reduce the overhead of .NET remoting or (serialized) session-state. However, this still results in a pb-net BLOB in the middle of a BinaryFormatter wrapper (in particular, the bf header specifies the concrete type assembly-qualfied-name).
Re the question about the constraint - that is simply to help guide usage; that API is only intended to be used as part of this injection into BinaryFormatter via ISerializable. Otherwise it is preferred to just use the Stream based API.
If you are looking at CF, then of course BinaryFormatter ceases to be useful, but the Stream based API is fine. It works on CF, but you should note that for models with lots of classes there are currently some glitches on CF caused by the overuse of generics ("missing method" or some-such). The good news is that I'm making good progress on some refactoring that ditches this, making it much more stable on the smaller frameworks.
What is a better approach to serialize custom class: using XMLSerializer or BinarryFormatter and [Serializable] attribute on class?
It's not possible to answer this, without knowing how you will use the resulting file, and the lifetime of it.
The decision is based on the fact that it is harder to "upgrade" the binary format. If your object model changes, it won't deserialise correctly. But if you've implemented a custom XML serialisation/deserialisation, then you can handle the "new" cases appropriately, and life will be good.
So decide more about how you will use it, who you are sharing information with, and what the possible changes to the model are.
FWIW, I sometimes use both types of serialisation in a given project.
That really depends on how you use the serialized class. If you want to pass it to other programs or want to easily debug it, use XML (but mind that XMLSerializer might produce non-compliant XML output, like multiple root elements).
In all other cases, you can use the binary formatter. But note that XML is more suitable if you change the class later - you can use XMLIgnore and the like to keep the XML format intact.
The decision will sometimes also be made for you based on what the serialized output will be used for - while you could expose a WebService to take a binary array that is a binary serialized item, you couldn't utilize the web service easily from anything but .Net (and the end client would probably need a reference to the type).
Using XML means that the service could be exposed to any end client regardless of the platform/environment on the end client
When an object is serialized (by remoting to be sent across the wire) does the instance method code get serialized? Or are just the class level instance fields serialized?
I am asking this as some of my objects have large method and want to know wheather I should be using DTO's (data transfer objects) for sending data across the wire.
I guessing it's just the data plus some type version data ... am I right?
Thanks
Methods are never serialized.
Re "fields" - it all depends on the serializer; BinaryFormatter will do fields; you mention "remoting", which suggests BinaryFormatter, but remoting is largely a hangover now - from MSDN (on remoting):
This topic is specific to a legacy
technology that is retained for
backward compatibility with existing
applications and is not recommended
for new development. Distributed
applications should now be developed
using the Windows Communication
Foundation (WCF).
If you use web-services or WCF: XmlSerializer does public fields+properties; DataContractSerializer will do marked fields, etc.
Regular classes are often reusable as DTOs, but if you need lots of control over the wire (or have versioning issues), a separate DTO can be helpful.
(edit/additional) note also that there are other reasons not to like BinaryFormatter - it can be very brittle with versioning, and very painful to fix (although achievable). Other (more tolerant) serializers exist if this is likely to be an issue... if so, let me know and I'll update.
What gets saved is the data plus tags corresponding to your class and property names. The code itself doesn't get serialized.