Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enforce that sub-classes must be serializable in .net

I have a class in a vb.net web API that I need to serialize sometimes. So, i marked the class as <Serializable>. Fine. However, it has a number of sub-classes at many levels. Some of these got missed (or gwet missed as new ones are added). If the element is null it's fine, but if it's not then the serialization fails:

[SerializationException] Type 'Foo.Bar' in Assembly 'Foo, Version=1.0.0.4866, Culture=neutral, PublicKeyToken=null' is not marked as serializable.

Since the serialisation is used in the background, to save a sate to recover to later, it's not always noticed immediately.

Serialization is using the BinaryFormatter in vb.net

Is there any way to mark the parent class such that all it's children (and their children, and so on) must also be serializable? I would prefer to get a compile-time error for this, rather than a run-time error.

I realised from some of the initial responses that my question wasn't clear enough. I should not have used the words parents and children since I am not so much focussed on class that inherit as members of the class

<Serializable()>
Class MyObj
  Public Property foo as new Foo
  Public Property bar as new Bar
end Class

I had expected this would require Foo and Bar to be serializable, since otherwise MyObj isn't

like image 552
Adam Avatar asked Dec 14 '18 14:12

Adam


People also ask

Do subclasses need to implement serializable?

Yes. Subclass need not be marked serializable explicitly.

Do subclasses inherit serializable?

If the superclass is Serializable, then by default, every subclass is serializable. Hence, even though subclass doesn't implement Serializable interface( and if its superclass implements Serializable), then we can serialize subclass object.

Are classes serializable by default?

It's a little bit philosophical but by convention the default type of a class is not serializable, unless you explicitely define "this class can be serialized".

How do you check if a class is serializable?

If you are curious to know if a Java Standard Class is serializable or not, check the documentation for the class. The test is simple: If the class implements java. io. Serializable, then it is serializable; otherwise, it's not.


3 Answers

No, that isn't something you can enforce simply. Your best bet may be to add a unit test that discovers the subclasses via reflection and checks whether they have the attribute, failing if it is missing.

However, I would also advise don't use BinaryFormatter. I've seen way too many people get hurt by that - it ties the types and serialized data together too tightly. There are lots of better serialization options in .NET, for both text-based and binary serialization formats.

like image 138
Marc Gravell Avatar answered Oct 18 '22 20:10

Marc Gravell


There is no way in VB.NET to have derived classes inherit the attributes from their base class, let alone force it. There is no way in .NET to add an attribute to a class dynamically at run-time either. Also, the BinaryFormatter provides no way to override it such that it can serialize non-serializable types or to force it to search for the attribute in the base classes. So, you are left with no easy options. Here are some alternatives:

  • As Mark said, don't use the BinaryFormatter. There are many other better and more standard serializers which do not have the same limitations.
  • Also as Mark said, add a unit test or some other post-build action which causes the build to fail if any of the derived classes omit the attribute
  • Implement ISerializable with MustOverride members in the base class, thereby forcing each derived class to provide an implementation (when the class implements that interface, BinaryFormatter will use that to perform the serialization even if the class doesn't have the SerializableAttribute)
  • Absolute last-resort: When serializing, if the object to be serialized is not of a type which has the SerializableAttribute, you could theoretically declare a new class, dynamically, which inherits from the given object's class, overrides nothing, but adds the SerializableAttribute. Then, create a new object of that run-time generated type, dynamically copy the data from the original one to that new one, and then serialize the copy. However, not only is this a terrible idea, it would probably be difficult to get the auto-generated class to have the exact same name (including the full assembly name) such that the BinaryFormatter would see it as the same exact type. The BinaryFormatter is exceptionally brittle, so it wouldn't shock me if it's impractical or even impossible to get it to work with dynamically created types.
like image 32
Steven Doggart Avatar answered Oct 18 '22 20:10

Steven Doggart


AS per my knowledge, there is no way to enforce compile time error in this case. Alternative to this you can use Inherited Property of AttributeUsage. Create your custom Serializable attribute just to override the Inherited value. And use that instead of [Serializable].

Internal Implementation of [Serializable] attribute:

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | 
AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false)]
            public sealed class SerializableAttribute : Attribute
            {
                //
                // Summary:
                //     Initializes a new instance of the System.SerializableAttribute class.
                public SerializableAttribute();
            }

Here Inherited is set to false; it means this attribute can not be inherited by derived class. Just override this property and use your custom attribute.

You can also verify the existence of certain attributes in your sub classes at run time.

By throwing custom exception will help you to identify the exact error.

class BaseClass
{
    public BaseClass()
    {
        Type t = GetType();
        if (t.IsDefined(typeof(SerializableAttribute), false) == false)
        {
            Console.WriteLine("Serializable attribute is missing on class");
            throw new InvalidOperationException("Serializable attribute is missing on class");
        }
    }
}
like image 1
Ashish Mishra Avatar answered Oct 18 '22 20:10

Ashish Mishra