Open sandboxFocusImprove this doc

SR0012: Method of the Base Serializer Is Sealed

Severity Error
Reported by PostSharp
Message Method '<Method>' cannot be sealed because it must be overridden by the serializer of type '<Type>'.

Cause

When a [PSerializableAttribute] class derives from a class whose serializer is written by hand, the serializer that PostSharp generates for the derived class <Type> derives from the serializer of the base class. It overrides SerializeObject and DeserializeFields to serialize the fields of <Type>, and calls the implementations of the base serializer for the fields of the base class.

PostSharp reports SR0012 on <Method> when the base serializer overrides one of these two methods as sealed.

In the following example, EntitySerializer seals SerializeObject.

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

namespace Errors.SR0012_Error;

[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
    {
        public override object CreateInstance( Type type, IArgumentsReader constructorArguments ) => new Entity();

        // The serializer of Customer cannot override a sealed method.
        public sealed override void SerializeObject( object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
            => initializationArguments.SetValue( "Id", ((Entity) obj).Id );

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

[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 SR0012: SR0012_Error.cs(23,37): Method 'Errors.SR0012_Error.Entity.EntitySerializer.SerializeObject(System.Object, PostSharp.Serialization.IArgumentsWriter, PostSharp.Serialization.IArgumentsWriter)' cannot be sealed because it must be overridden by the serializer of type 'Errors.SR0012_Error.Customer'.

Resolution

Remove the sealed modifier from SerializeObject and DeserializeFields in the serializer of the base type.

In the following example, SerializeObject is not sealed, and a Customer is serialized and deserialized with its Id and its Name.

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

namespace Errors.SR0012_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
    {
        public override object CreateInstance( Type type, IArgumentsReader constructorArguments ) => new Entity();

        // Not sealed, so that the serializer of Customer can override it.
        public override void SerializeObject( object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
            => initializationArguments.SetValue( "Id", ((Entity) obj).Id );

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

[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