What's the Difference Between Using the Serializable Attribute & Implementing Iserializable

What's the difference between using the Serializable attribute & implementing ISerializable?

When you use the SerializableAttribute attribute you are putting an attribute on a field at compile-time in such a way that when at run-time, the serializing facilities will know what to serialize based on the attributes by performing reflection on the class/module/assembly type.

[Serializable]
public class MyFoo { … }

The above indicates that the serializing facility should serialize the entire class MyFoo, whereas:

public class MyFoo
{
private int bar;

[Serializable]
public int WhatBar
{
get { return this.bar; }
}
}

Using the attribute you can selectively choose which fields needs to be serialized.

When you implement the ISerializable interface, the serialization effectively gets overridden with a custom version, by overriding GetObjectData and SetObjectData (and by providing a constructor of the form MyFoo(SerializationInfo info, StreamingContext context)), there would be a finer degree of control over the serializing of the data.

See also this example of a custom serialization here on StackOverflow. It shows how to keep the serialization backwards-compatible with different versionings of the serialized data.

Hope this helps.

What is [Serializable] and when should I use it?

What is it?

When you create an object in a .Net framework application, you don't need to think about how the data is stored in memory. Because the .Net Framework takes care of that for you. However, if you want to store the contents of an object to a file, send an object to another process or transmit it across the network, you do have to think about how the object is represented because you will need to convert to a different format. This conversion is called SERIALIZATION.

Uses for Serialization

Serialization allows the developer to save the state of an object and recreate it as needed, providing storage of objects as well as data exchange. Through serialization, a developer can perform actions like sending the object to a remote application by means of a Web Service, passing an object from one domain to another, passing an object through a firewall as an XML string, or maintaining security or user-specific information across applications.

Apply SerializableAttribute to a type to indicate that instances of this type can be serialized. Apply the SerializableAttribute even if the class also implements the ISerializable interface to control the serialization process.

All the public and private fields in a type that are marked by the SerializableAttribute are serialized by default, unless the type implements the ISerializable interface to override the serialization process. The default serialization process excludes fields that are marked with NonSerializedAttribute. If a field of a serializable type contains a pointer, a handle, or some other data structure that is specific to a particular environment, and cannot be meaningfully reconstituted in a different environment, then you might want to apply NonSerializedAttribute to that field.

See MSDN for more details.

Edit 1

Any reason to not mark something as serializable

When transferring or saving data, you need to send or save only the required data. So there will be less transfer delays and storage issues. So you can opt out unnecessary chunk of data when serializing.

What does the [Serializable] attribute do that ISerializable doesn't?

I thought you'd linked to Serializable, but you didn't:

All the public and private fields in a type that are marked by the SerializableAttribute are serialized by default, unless the type implements the ISerializable interface to override the serialization process.

and,

Apply the SerializableAttribute attribute even if the class also implements the ISerializable interface [...]

That is, the Serializable attribute indicates that this type can be serialized. ISerializable indicates that this type wants to control how this type is serialized.


Or, to put it another way, your question is phrased the wrong way around. SerializableAttribute should always be applied (to serializable classes), and is the "basic" level of serialization. ISerializable adds more (by allowing you to write code to control the process).

Difference between Java's Serializable and C#'s ISerializable

I assume that you haved used the Serializable interface in Java to inform that your class can be serialized. In .Net you should use a [Serializable] attribute for this, ISerializable interface has a bit different meaning.

So in .Net your code should look like this:

[Serializable]
public class myClass : ICloneable
{

//fields, constructors etc here.
//...
//...

public abstract Object Clone ();

//...
//...
}

OnSerializingAttribute vs ISerializable

OnSerializing / OnDeserializing is complementary to ISerializable or SerializableAttribute.

In other words: OnSerializing / OnDeserializing is not an alternative for ISerializable or the SerializableAttribute.

These 2 attributes (OnSerializing / OnDeserializing) allow you to take control / perform extra actions when an object is serialized or deserialized. But, in order to be able to do this, the type to which these attributes are applied, has to be serializable (and thus implement the ISerializable interface, or decorated with the Serializable attribute).

This is also said like this in the MSDN article you're referring to:
- OnSerializing and OnDeserializing are used to 'correct' data during and after serialization.

You can test it quite easily.
Create a type like this, and try to serialize it:

public class Foo
{
private int _bar = 5;

[OnSerializing]
public void OnSerializeFoo( StreamingContext context )
{
_bar = 10;
}
}

Note that the type does not implement ISerializable, nor is it decorated with the SerializableAttribute.
Try to serialize an instance of that type, and you'll be faced with a SerializationException, because Foo is not serializable.

So, you can use these attributes (OnSerializing, OnDeserializing) to implement additional logic that should be performed when an instance of a certain type is serialized or deserialized.

What is the point of the ISerializable interface?

ISerializable is used to provide custom binary serialization, usually for BinaryFormatter (and perhaps for remoting purposes). Without it, it uses the fields, which can be:

  • inefficient; if there are fields that are only used for efficiency at runtime, but can be removed for serialization (for example, a dictionary may look different when serialized)
  • inefficient; as even for fields that are needed it needs to include a lot of additional metadata
  • invalid; if there are fields that cannot be serialized (such as event delegates, although they can be marked [NonSerialized])
  • brittle; your serialization is now bound to the field names - but fields are meant to be an implementation detail; see also Obfuscation, serialization and automatically implemented properties

By implementing ISerializable you can provide your own binary serialization mechanism. Note that the xml equivalent of this is IXmlSerializable, as used by XmlSerializer etc.

For DTO purposes, BinaryFormatter should be avoided - things like xml (via XmlSerializer or DataContractSerializer) or json are good, as are cross-platform formats like protocol buffers.

For completeness, protobuf-net does include hooks for ISerializable (allowing you to use a portable binary format without writing lots of code), but BinaryFormatter wouldn't be your first choice here anyway.

C#: [NonSerialized] when implementing ISerializable

OK, so I found something interesting on Microsoft website:

https://learn.microsoft.com/en-us/dotnet/api/system.nonserializedattribute?view=netframework-4.7

The target objects for the NonSerializedAttribute attribute are public and private fields of a serializable class. By default, classes are not serializable unless they are marked with SerializableAttribute. During the serialization process all the public and private fields of a class are serialized by default. Fields marked with NonSerializedAttribute are excluded during serialization. If you are using the XmlSerializer class to serialize an object, use the XmlIgnoreAttribute class to get the same functionality. Alternatively, implement the ISerializable interface to explicitly control the serialization process. Note that classes that implement ISerializable must still be marked with SerializableAttribute.

So, basically, that's why I didn't understand the use of [NonSerialized] when implementing ISerializable: they're not meant to work together.

Is implementing ISerializable interface necessary when not implementing any custom serialization/deserialization

It's pretty pointless.

It could be justified if it had once implemented ISerializable for a better reason, and implementation changes meant that it was no longer as useful. It could be a breaking change to stop implementing it.

If they'd implemented it with an explicit implementation (void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) rather than public void GetObjectData(SerializationInfo info, StreamingContext context) and had the constructor that took SerializationInfo and StreamingContext private, then it'd be a less damaging change - still technically a breaking change but much less likely to actually break any real uses. This in itself is a reason for having that constructor private.

It must though be at least protected if the class isn't sealed, and derived classes must use it if they are to also be serialisable. In this case it's totally going to be a breaking change to stop using it as all derived classes would then be broken.

It would likewise be breaking change if you didn't implement it, and then started doing so, and had classes derived from it. This could be a justification for pre-empting the possibility, though to be honest I'd see that as a major failure of the YAGNI principle unless there was a very very good reason to suspect it would become useful. (Generally if you were going to add something that would make it necessary you could wrap whatever features required it in another class, implement it on that, and have a member of that type, so the existing class can still be serialised without it).

Edit: The "must" above is the "must" of "you must do this or there are bad implications" rather than the "must" of "you must do this or it won't compile". Of course, the former are worse than the latter because you can sometimes fail to do them.

Using ISerializable breaks serialization for previously supported types

As already mentioned, you need to serialize everything if you ask explicitly for it using ISerializable.

To get that fixed, you got 2 very simple solutions now:

Solution 1
Provide the serialization for all types you want to have serialized

Solution 2
Remove ISerializable and add a IgnoreDataMemberAttribute to your Color Property. Also add some serialization-only property like this:

public string ColorSerialized
{
get => new ColorConverter().ConvertToString(_RgbColor);
set => _RgbColor = (Color)ColorConverter.ConvertFromString(value);
}


Related Topics



Leave a reply



Submit