Enforce Object Property to be serializable - c#

I am building a class and in the interface for my class(es) I have a property declared
object MyObject { get; set; }
What I want to do is force whatever is stored in MyObject to be serializable. Is there a good way to do this?
Normally, I'd use where : ISerializable, but for serialization you use an attribute, not inheritance, or at least that is my assumption.

I never could figure out how to enforce a class be Serializable. I had to move away from generic classes anyway for other reasons, so through inheritance I just create a property for my object to be serialized and serialize/deserialize it in the set/get accessors and store the serialized string in a string property in the base class, which is inherited.

Related

DataContract secret behavior?

Every time I meet this attribute, I always see such usage:
[DataContract]
class DataTransferObject
{
[DataMember]
public int Value {get;set;}
}
And in this example all inherited members should apply DataMember attribute to every property or field, this can lead to VERY clumsy and poilerplate code. But, recently I found (maybe secret feature?) a very elegant way of using it:
[DataContract]
public abstract class DTOBase
{
}
public class MyDTO : DTOBase
{
public int Value {get;set;}
public MyDTO(){} //important part is here
}
Important part: You should always explicitly define parameterless constructor, otherwise it won't serialize properly.
And yeah. It will serialize all its public members, no matter how deep will be inheritance, without need to apply attributes to members or class definitions.
Is this somehow documented somewhere (I didn't found)? Because, I were very supprized how much of boilerplate can be avoided.
Actually, you don't need to use DataContract and DataMember attributes if you don't want to, however they give you flexibility in defining what needs to be serialized and how.
I suggest starting with article Serializable Types on MSDN, it has a lot of information how Data Contract serializer works. Here are first 2 paragraphs, proving that you don't need to use attributes:
By default, the DataContractSerializer serializes all publicly visible
types.
All public read/write properties and fields of the type are
serialized. You can change the default behavior by applying the
DataContractAttribute and DataMemberAttribute attributes to the types
and members This feature can be useful in situations in which you have
types that are not under your control and cannot be modified to add
attributes. The DataContractSerializer recognizes such "unmarked"
types.
The main rules that apply to your case are:
DataContract attribute is not inherited. You can either apply it or not on your base class DTOBase, it is ignored in child class MyDTO. You can remove DataContract attribute from DTOBase class and result will be the same.
If you use DataContract attribute on a class, then only members that have DataMember attribute will be serialized. This is what happened in class DataTransferObject in your first sample.
If you do not use DataContract attribute on a class, then all public members of a class are serialized. This is what happened with your class MyDTO.

Why is the C# SerializedAttribute is sealed?

I was trying to create an attribute that implies [Serializable] but I noticed that this SerializableAttribute class is sealed.
In Java it was possible to create an interface (say, MyInterface) that is inherited from Serializable interface and so all the subclasses of MyInterface would also be serializable, even its sub-sub classes would be so.
Let's say I am creating an ORM and I want customers to annotate their entity classes as [DatabaseEntity] but in order to make sure that entities are serializable, I also need to ask them to attribute their classes with extra [Serializable] which does not look quite compact and neat.
I am wondering why SerializableAttribute class is sealed and why has Inherited=false which implies that subclasses of serializable class will not be serializable unless it is explicitly stated. What motives are behind these design choices?
The SerializableAttribute is only used by the BinaryFormatter. If you are writing your own serialiser then don't worry about.
The sealed keyword is applied to the attribute not the class associated with the attribute. It is saying that the SerializableAttribute cannot be subclassed.
The BinaryFormatter uses an opt-in model. Any class (or subclass) must specify that it is serializable. This why the Inherited=false is used.
It's suggested best practice that all .Net attributes should be sealed, according to Microsoft:
The .NET Framework class library provides methods for retrieving custom attributes. By default, these methods search the attribute inheritance hierarchy; for example System.Attribute.GetCustomAttribute searches for the specified attribute type, or any attribute type that extends the specified attribute type. Sealing the attribute eliminates the search through the inheritance hierarchy, and can improve performance. [my emphasis]
So [Serializable] is sealed because it's quicker for .Net reflection to check the attributes. The cost is that you can't inherit and extend SerializableAttribute.
You can make your own un-sealed attributes if you want (you'll get code analysis warnings though).
This gets a little confusing with how attributes are used in inheritance for the classes that they apply to. It's probably best to use an example:
[Serializable]
public class A
{
public int SimpleSerialisableProperty { get; set;}
}
public class B : A
{
public C ComplexReferenceProperty { get; set; }
}
[Serializable]
public class D : A
{
public bool AnotherSerialisableProperty { get; set;}
}
You asked why SerializableAttribute.Inherited = false and this is why:
Class A is marked as [Serializable], and it is.
However class B inherits A and extends it with properties that are not serialisable. If .Net tries to serialise B it will encounter an error.
That Inherited = false tells .Net that just because A has been marked as [Serializable] not every class that inherits it will be serialisable too.
Now class D inherits A and is serialisable, so it gets its own [Serializable] attribute.
Finally, in terms of design attributes are a great way of extending behaviour (nice UI editors in property grids, etc). However they are terrible at enforcing it. If you need your customers to implement their entity classes in a particular way then an abstract base class or an interface is a much better way to go. If you make it an attribute then you're basically letting them know that [Serializable] is an option that you can handle either way.
Serialization is not a magic thing and you don't need any attribute to serialize an object. It is a process of writing your class' properties and fields to a stream (and attributes are only directives to serializers about how to behave while outputting an object).
See this over-simplified serializer code which totally ignores all attributes including NonSerializable
object obj = yourObject;
var props = obj.GetType()
.GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(obj, null));
string serializedText = String.Join("\n",
props.Select(kv => kv.Key + "=" + kv.Value ?? kv.Value.ToString()));
Above code, for example, would give
IsEmpty=False
X=3
Y=5
for object obj = new Point(3,5);
Deserialization process would be to read these values and set the properties back accordingly.
Put the [Serializable] attribute on top of the class you want serialized. Serialization is opt-in process. You have to manually do that for each class you want serialized. There are bunch of other keywords.

Serialize nested interface

how can i serialize this class?
public class MyClass {
IInterface MyProperty { get; set;}
}
You need to add a setter to MyProperty as Xml serialization rules mandate that serialization must be able to round-trip i.e. it must be able to get the property for serialization, then set the property for deserialization.
As chibacity said, you need to add a setter to the property. You also need to add the XmlInclude attribute to the property to specify the possible implementing types, otherwise the XmlSerializer won't know what type to instantiate when deserializing
The XmlSerializer cannot serialize interfaces.
If you know the concrete types you will be dealing with in advance then you can use the XmlInclude approach. If not then there have been a few discussions about how to handle this:
XML serialization of interface
property
XmlSerialization with Interfaces
Serializing without XmlInclude
Make the class that implements IInterface Serializable like you normally would and it will all work.

If Base class is marked Serializable are all child classes marked too?

I have a whole list of entity classes which I need to make Serializable (due to storing session state in SQL, but that's another story).
I have added the attribute [Serializable] and all seems to be fine.
All of my entity classes extend from the same base class.
If I mark the base class as Serializable, does this mean all children are marked as Serializable too?
Thanks
No, attribute is not inherited.
When you extend the class, it's possible to add features that might not be serializable by nature therefore .NET framework cannot assume for you that everything what extends serializable base class is also serializable.
That's why you must explicitly state [Serializable] attribute on every class individually.
Nope, each one will have to be marked as [Serializable] specifically.
Also if you intend to serialize an object to XML which is of a derived type as though it is the base type you'll also need a [XmlInclude] attribute.
EG:
[Serializable]
public class BaseClass : ParentClass
{
}
[Serializable]
[XmlInclude(typeof(BaseClass))]
public class ParentClass
{
}
(Binary serialization, like what is used for sessions, do not need this)

C# Serializing a Collection of Objects

I am working on a ASP.NET application that has a class that inherits a List of a Custom Object.
public class UserRoleList : List<UserRoleBO> {
public UserRoleList() { }
}
How do I make this class serializable in C#?
I believe you really just need to ensure that UserRoleBO is serializable and the list will take care of itself. This assumes the values you want to serialize are public properties on the UserRoleBO and UserList. For more info see What is the point of the ISerializable interface?
You need to do the following
Ensure UserRoleList is serializable
Ensure UserRoleBO is serializable
Ensure the type of all fields inside UserRoleBO are serializable (this is recursive)
The easiest way to do this is to add the [Serializable] attribute to the classes. This will work in most cases.
On a different note, deriving from List<T> is usually speaking a bad idea. The class is not meant to be derived from and any attempt to specialize it's behavior can be thwarted in sceanarios where the derived class is used from a List<T> reference. Can you explain why you want to derive in this way? There is likely a more robust solution.
Like so:
[Serializable]
public class UserRoleList : List<UserRoleBO> {
public UserRoleList() { }
}
(Note the 'Serializble' tag will need to be on all classes that need to be serialised (so the parent as well.
And then use BinarySerialization to do it.

Categories

Resources