Open sandboxFocusImprove this doc

SR0010: Serializer of the Base Type Has No Default Constructor

Severity Error
Reported by PostSharp
Message Cannot apply [PSerializable] to a type derived from '<BaseType>' because the serializer '<Serializer>' of '<BaseType>' does not have a default constructor.

Cause

When a [PSerializableAttribute] class derives from a class whose serializer is written by hand, the serializer that PostSharp generates for the derived class derives from the serializer of the base class. The constructor of the generated serializer has no parameter, and calls the constructor of the base serializer that has no parameter either.

PostSharp reports SR0010 on <BaseType> when its serializer <Serializer> has no parameterless constructor, for example because its only constructor takes an option. A parameterless constructor that exists but cannot be accessed from the generated serializer is reported with SR0011 instead.

In the following example, the only constructor of EntitySerializer takes the name under which the Id is serialized.

using System;
using System.IO;
using PostSharp.Serialization;

namespace Errors.SR0010_Error;

[Serializer( typeof(EntitySerializer) )]
public class Entity // EntitySerializer has no default constructor.
{
    public int Id { get; set; }

    public Entity() { }

    // The deserializing constructor, which the serializer of Customer calls.
    protected Entity( PortableFormatterConstructorContext context ) { }

    // A serializer written by hand, which the serializer generated for Customer extends.
    protected class EntitySerializer : ReferenceTypeSerializer
    {
        private readonly string idKey;

        public EntitySerializer( string idKey )
        {
            this.idKey = idKey;
        }

        public override object CreateInstance( Type type, IArgumentsReader constructorArguments ) => new Entity();

        public override void SerializeObject( object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
            => initializationArguments.SetValue( this.idKey, ((Entity) obj).Id );

        public override void DeserializeFields( object obj, IArgumentsReader initializationArguments )
            => ((Entity) obj).Id = initializationArguments.GetValue<int>( this.idKey );
    }
}

[PSerializable]
public class Customer : Entity
{
    public string? Name { get; set; }
}

public static class Program
{
    public static void Main()
    {
        var formatter = new PortableFormatter();
        var stream = new MemoryStream();
        formatter.Serialize( new Customer { Id = 1, Name = "Alice" }, stream );
        stream.Position = 0;

        var customer = (Customer) formatter.Deserialize( stream );
        Console.WriteLine( $"Customer {customer.Id}: {customer.Name}" );
    }
}
error SR0010: SR0010_Error.cs(8,14): Cannot apply [PSerializable] to a type derived from 'Errors.SR0010_Error.Entity' because the serializer 'Errors.SR0010_Error.Entity.EntitySerializer' of 'Errors.SR0010_Error.Entity' does not have a default constructor.

Resolution

Add a parameterless constructor to the serializer of the base type, public or protected, which gives a default value to the options of the other constructors.

In the following example, the default constructor of EntitySerializer calls the other one with "Id", and a Customer is serialized and deserialized with its Id and its Name.

using System;
using System.IO;
using PostSharp.Serialization;

namespace Errors.SR0010_Fixed;

[Serializer( typeof(EntitySerializer) )]
public class Entity
{
    public int Id { get; set; }

    public Entity() { }

    // The deserializing constructor, which the serializer of Customer calls.
    protected Entity( PortableFormatterConstructorContext context ) { }

    // A serializer written by hand, which the serializer generated for Customer extends.
    protected class EntitySerializer : ReferenceTypeSerializer
    {
        private readonly string idKey;

        // The default constructor, which the serializer of Customer calls.
        public EntitySerializer() : this( "Id" ) { }

        public EntitySerializer( string idKey )
        {
            this.idKey = idKey;
        }

        public override object CreateInstance( Type type, IArgumentsReader constructorArguments ) => new Entity();

        public override void SerializeObject( object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
            => initializationArguments.SetValue( this.idKey, ((Entity) obj).Id );

        public override void DeserializeFields( object obj, IArgumentsReader initializationArguments )
            => ((Entity) obj).Id = initializationArguments.GetValue<int>( this.idKey );
    }
}

[PSerializable]
public class Customer : Entity
{
    public string? Name { get; set; }
}

public static class Program
{
    public static void Main()
    {
        var formatter = new PortableFormatter();
        var stream = new MemoryStream();
        formatter.Serialize( new Customer { Id = 1, Name = "Alice" }, stream );
        stream.Position = 0;

        var customer = (Customer) formatter.Deserialize( stream );
        Console.WriteLine( $"Customer {customer.Id}: {customer.Name}" );
    }
}
Customer 1: Alice

See Also

Reference

PSerializableAttribute
ReferenceTypeSerializer
SerializerAttribute

Other Resources

Understanding Aspect Serialization